1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35#define FOR_losetup
36#include "toys.h"
37#include <linux/loop.h>
38
39GLOBALS(
40 char *j;
41 long o, S;
42
43 int openflags;
44 dev_t jdev;
45 ino_t jino;
46 char *dir;
47)
48
49
50
51
52static int loopback_setup(char *device, char *file)
53{
54 struct loop_info64 *loop = (void *)(toybuf+32);
55 int lfd = -1, ffd = -1;
56 int racy = !device;
57
58
59
60 if (file) ffd = xopen(file, TT.openflags);
61 if (!device) {
62 int i, cfd = open("/dev/loop-control", O_RDWR);
63
64
65
66
67
68 if (cfd != -1) {
69 if (0 <= (i = ioctl(cfd, LOOP_CTL_GET_FREE))) {
70 sprintf(device = toybuf, "%s/loop%d", TT.dir, i);
71 }
72 close(cfd);
73 }
74 }
75
76 if (device) lfd = open(device, TT.openflags);
77
78
79 memset(loop, 0, sizeof(struct loop_info64));
80 if (-1 == lfd || ioctl(lfd, LOOP_GET_STATUS64, loop)) {
81 if (errno == ENXIO && (FLAG(a) || FLAG(j))) goto done;
82
83 if (errno == ENXIO && FLAG(f) && !file) {
84 puts(device);
85 goto done;
86 }
87 if (errno != ENXIO || !file) {
88 perror_msg_raw(device ? device : "-f");
89 goto done;
90 }
91 }
92
93
94 if (TT.j && (loop->lo_device != TT.jdev || loop->lo_inode != TT.jino))
95 goto done;
96
97
98 if (FLAG(c) || FLAG(d)) {
99
100 if (ioctl(lfd, FLAG(c) ? 0x4C07 : LOOP_CLR_FD, 0)) {
101 perror_msg_raw(device);
102 goto done;
103 }
104
105 } else if (file) {
106 char *f_path = xabspath(file, ABS_PATH);
107
108 if (!f_path) perror_exit("%s", file);
109 if (ioctl(lfd, LOOP_SET_FD, ffd)) {
110 free(f_path);
111 if (racy && errno == EBUSY) return 1;
112 perror_exit("%s=%s", device, file);
113 }
114 xstrncpy((char *)loop->lo_file_name, f_path, LO_NAME_SIZE);
115 free(f_path);
116 loop->lo_offset = TT.o;
117 loop->lo_sizelimit = TT.S;
118 if (ioctl(lfd, LOOP_SET_STATUS64, loop)) perror_exit("%s=%s", device, file);
119 if (FLAG(s)) puts(device);
120 }
121 else {
122 xprintf("%s: [%lld]:%llu (%s)", device, (long long)loop->lo_device,
123 (long long)loop->lo_inode, loop->lo_file_name);
124 if (loop->lo_offset) xprintf(", offset %llu",
125 (unsigned long long)loop->lo_offset);
126 if (loop->lo_sizelimit) xprintf(", sizelimit %llu",
127 (unsigned long long)loop->lo_sizelimit);
128 xputc('\n');
129 }
130
131done:
132 xclose(ffd);
133 xclose(lfd);
134 return 0;
135}
136
137
138static int dash_a(struct dirtree *node)
139{
140 char *s = node->name;
141
142
143 if (!node->parent) return DIRTREE_RECURSE;
144 if (strncmp(s, "loop", 4) || !isdigit(s[4])) return 0;
145
146 s = dirtree_path(node, 0);
147 loopback_setup(s, 0);
148 free(s);
149
150 return 0;
151}
152
153void losetup_main(void)
154{
155 char **s;
156
157 TT.dir = CFG_TOYBOX_ON_ANDROID ? "/dev/block" : "/dev";
158 TT.openflags = FLAG(r) ? O_RDONLY : O_RDWR;
159
160 if (TT.j) {
161 struct stat st;
162
163 xstat(TT.j, &st);
164 TT.jdev = st.st_dev;
165 TT.jino = st.st_ino;
166 }
167
168
169
170
171
172
173
174
175
176
177 if (FLAG(D)) toys.optflags |= FLAG_a | FLAG_d;
178
179 if (FLAG(f)) {
180 if (toys.optc > 1) perror_exit("max 1 arg");
181 while (loopback_setup(NULL, *toys.optargs));
182 } else if (FLAG(a) || FLAG(j)) {
183 if (toys.optc) error_exit("bad args");
184 dirtree_read(TT.dir, dash_a);
185
186 } else {
187 char *file = (FLAG(c) || FLAG(d)) ? NULL : toys.optargs[1];
188
189 if (!toys.optc || (file && toys.optc != 2))
190 help_exit("needs %d arg%s", 1+!!file, file ? "s" : "");
191 for (s = toys.optargs; *s; s++) {
192 loopback_setup(*s, file);
193 if (file) break;
194 }
195 }
196}
197