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#define FOR_losetup
35#include "toys.h"
36#include <linux/loop.h>
37
38GLOBALS(
39 char *j;
40 long o, S;
41
42 int openflags;
43 dev_t jdev;
44 ino_t jino;
45)
46
47
48
49
50static void loopback_setup(char *device, char *file)
51{
52 struct loop_info64 *loop = (void *)(toybuf+32);
53 int lfd = -1, ffd = ffd;
54 unsigned flags = toys.optflags;
55
56
57
58 if (file) ffd = xopen(file, TT.openflags);
59 if (!device) {
60 int i, cfd = open("/dev/loop-control", O_RDWR);
61
62
63
64
65
66 if (cfd != -1) {
67 if (0 <= (i = ioctl(cfd, 0x4C82))) {
68 sprintf(device = toybuf, "/dev/loop%d", i);
69
70 if (access(toybuf, F_OK)) sprintf(toybuf, "/dev/block/loop%d", 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 && (flags & (FLAG_a|FLAG_j))) goto done;
82 if (errno != ENXIO || !file) {
83 perror_msg_raw(device ? device : "-f");
84 goto done;
85 }
86 }
87
88
89 if (TT.j && (loop->lo_device != TT.jdev || loop->lo_inode != TT.jino))
90 goto done;
91
92
93 if (flags & (FLAG_c|FLAG_d)) {
94
95 if (ioctl(lfd, (flags & FLAG_c) ? 0x4C07 : LOOP_CLR_FD, 0)) {
96 perror_msg_raw(device);
97 goto done;
98 }
99
100 } else if (file) {
101 char *s = xabspath(file, 1);
102
103 if (!s) perror_exit("file");
104 if (ioctl(lfd, LOOP_SET_FD, ffd)) perror_exit("%s=%s", device, file);
105 loop->lo_offset = TT.o;
106 loop->lo_sizelimit = TT.S;
107 xstrncpy((char *)loop->lo_file_name, s, LO_NAME_SIZE);
108 s[LO_NAME_SIZE-1] = 0;
109 if (ioctl(lfd, LOOP_SET_STATUS64, loop)) perror_exit("%s=%s", device, file);
110 if (flags & FLAG_s) printf("%s", device);
111 free(s);
112 } else if (flags & FLAG_f) printf("%s", device);
113 else {
114 xprintf("%s: [%04llx]:%llu (%s)", device, (long long)loop->lo_device,
115 (long long)loop->lo_inode, loop->lo_file_name);
116 if (loop->lo_offset) xprintf(", offset %llu",
117 (unsigned long long)loop->lo_offset);
118 if (loop->lo_sizelimit) xprintf(", sizelimit %llu",
119 (unsigned long long)loop->lo_sizelimit);
120 xputc('\n');
121 }
122
123done:
124 if (file) close(ffd);
125 if (lfd != -1) close(lfd);
126}
127
128
129static int dash_a(struct dirtree *node)
130{
131 char *s = node->name;
132
133
134 if (!node->parent) return DIRTREE_RECURSE;
135 if (strncmp(s, "loop", 4) || !isdigit(s[4])) return 0;
136
137 s = dirtree_path(node, 0);
138 loopback_setup(s, 0);
139 free(s);
140
141 return 0;
142}
143
144void losetup_main(void)
145{
146 char **s;
147
148 TT.openflags = (toys.optflags & FLAG_r) ? O_RDONLY : O_RDWR;
149
150 if (TT.j) {
151 struct stat st;
152
153 xstat(TT.j, &st);
154 TT.jdev = st.st_dev;
155 TT.jino = st.st_ino;
156 }
157
158
159
160
161
162
163
164
165
166
167 if (toys.optflags & FLAG_f) {
168 if (toys.optc > 1) perror_exit("max 1 arg");
169 loopback_setup(NULL, *toys.optargs);
170 } else if (toys.optflags & (FLAG_a|FLAG_j)) {
171 if (toys.optc) error_exit("bad args");
172 dirtree_read("/dev", dash_a);
173
174 } else {
175 char *file = (toys.optflags & (FLAG_d|FLAG_c)) ? NULL : toys.optargs[1];
176
177 if (!toys.optc || (file && toys.optc != 2))
178 help_exit("needs %d arg%s", 1+!!file, file ? "s" : "");
179 for (s = toys.optargs; *s; s++) {
180 loopback_setup(*s, file);
181 if (file) break;
182 }
183 }
184}
185