Mercurial > hg > toybox
comparison toys/other/losetup.c @ 778:14aabcd31fd9
Add losetup. (Who knows, it might even work.)
author | Rob Landley <rob@landley.net> |
---|---|
date | Sun, 30 Dec 2012 21:35:01 -0600 |
parents | |
children | 6cc69be43c42 |
comparison
equal
deleted
inserted
replaced
777:85e5097c49c1 | 778:14aabcd31fd9 |
---|---|
1 /* losetup.c - Loopback setup | |
2 * | |
3 * Copyright 2012 Rob Landley <rob@landley.net> | |
4 * | |
5 * No standard. (Sigh.) | |
6 | |
7 USE_LOSETUP(NEWTOY(losetup, ">2S(sizelimit)#s(show)ro#j:fdca[!afj]", TOYFLAG_SBIN)) | |
8 | |
9 config LOSETUP | |
10 bool "losetup" | |
11 default y | |
12 help | |
13 usage: losetup [-cdrs] [-o OFFSET] [-S SIZE] {-d DEVICE...|-j FILE|-af|{DEVICE FILE}} | |
14 | |
15 Associate a loopback device with a file, or show current file (if any) | |
16 associated with a loop device. | |
17 | |
18 Instead of a device: | |
19 -a Iterate through all loopback devices | |
20 -f Find first unused loop device (may create one) | |
21 -j Iterate through all loopback devices associated with FILE | |
22 | |
23 existing: | |
24 -c Check capacity (file size changed) | |
25 -d Detach loopback device | |
26 | |
27 new: | |
28 -s Show device name (alias --show) | |
29 -o Start assocation at OFFSET into FILE | |
30 -r Read only | |
31 -S Limit SIZE of loopback association (alias --sizelimit) | |
32 */ | |
33 | |
34 #define FOR_losetup | |
35 #include "toys.h" | |
36 #include <linux/loop.h> | |
37 | |
38 GLOBALS( | |
39 char *jfile; | |
40 long offset; | |
41 long size; | |
42 | |
43 int openflags; | |
44 dev_t jdev; | |
45 ino_t jino; | |
46 ) | |
47 | |
48 /* | |
49 todo: basic /dev file association | |
50 associate DEV FILE | |
51 #-a | |
52 cdfjosS | |
53 allocate new loop device: | |
54 /dev/loop-control | |
55 https://lkml.org/lkml/2011/7/26/148 | |
56 */ | |
57 | |
58 // -f: *device is NULL | |
59 | |
60 // Perform requested operation on one device. Returns 1 if handled, 0 if error | |
61 static void loopback_setup(char *device, char *file) | |
62 { | |
63 struct loop_info64 *loop = (void *)(toybuf+32); | |
64 int rc = 0, lfd = -1, ffd; | |
65 unsigned flags = toys.optflags; | |
66 | |
67 // Open file (ffd) and loop device (lfd) | |
68 | |
69 if (file) ffd = xopen(file, TT.openflags); | |
70 if (!device) { | |
71 int i, cfd = open("/dev/loop-control", O_RDWR); | |
72 | |
73 // We assume /dev is devtmpfs so device creation has no lag. Otherwise | |
74 // just preallocate loop devices and stay within them. | |
75 | |
76 // mount -o loop depends on found device being at the start of toybuf. | |
77 if (cfd != -1) { | |
78 if (0 <= (i = ioctl(cfd, LOOP_CTL_GET_FREE))) | |
79 sprintf(device = toybuf, "/dev/loop%d", i); | |
80 close(cfd); | |
81 } | |
82 } | |
83 | |
84 if (device) lfd = open(device, TT.openflags); | |
85 | |
86 // Stat the loop device to see if there's a current association. | |
87 memset(loop, 0, sizeof(struct loop_info64)); | |
88 if (-1 == lfd || ioctl(lfd, LOOP_GET_STATUS64, loop)) { | |
89 if (errno == ENXIO && (flags & (FLAG_a|FLAG_j))) return; | |
90 if (errno != ENXIO || !file) { | |
91 perror_msg("%s", device ? device : "-f"); | |
92 rc = 1; | |
93 goto done; | |
94 } | |
95 } | |
96 | |
97 // Skip -j filtered devices | |
98 if (TT.jfile && (loop->lo_device != TT.jdev || loop->lo_inode != TT.jino)) | |
99 goto done; | |
100 | |
101 // Check size of file or delete existing association | |
102 if (flags & (FLAG_c|FLAG_d)) { | |
103 if (ioctl(lfd, (flags & FLAG_c) ? LOOP_SET_CAPACITY : LOOP_CLR_FD, 0)) { | |
104 perror_msg("%s", device); | |
105 rc = 1; | |
106 goto done; | |
107 } | |
108 // Associate file with this device? | |
109 } else if (file) { | |
110 char *s = xrealpath(file); | |
111 | |
112 if (ioctl(lfd, LOOP_SET_FD, ffd)) perror_exit("%s=%s", device, file); | |
113 loop->lo_offset = TT.offset; | |
114 loop->lo_sizelimit = TT.size; | |
115 strncpy((char *)loop->lo_file_name, s, LO_NAME_SIZE); | |
116 s[LO_NAME_SIZE-1] = 0; | |
117 if (ioctl(lfd, LOOP_SET_STATUS64, loop)) perror_exit("%s=%s", device, file); | |
118 if (flags & FLAG_s) printf("%s", device); | |
119 free(s); | |
120 } else if (flags & FLAG_f) printf("%s", device); | |
121 else { | |
122 xprintf("%s: [%04llx]:%llu (%s)", device, loop->lo_device, loop->lo_inode, | |
123 loop->lo_file_name); | |
124 if (loop->lo_offset) xprintf(", offset %llu", loop->lo_offset); | |
125 if (loop->lo_sizelimit) xprintf(", sizelimit %llu", loop->lo_sizelimit); | |
126 xputc('\n'); | |
127 } | |
128 | |
129 done: | |
130 if (file) close(ffd); | |
131 if (lfd != -1) close(lfd); | |
132 toys.exitval |= rc; | |
133 } | |
134 | |
135 // Perform an action on all currently existing loop devices | |
136 static int dash_a(struct dirtree *node) | |
137 { | |
138 char *s = node->name; | |
139 | |
140 // Initial /dev node needs to recurse down one level, then only loop[0-9]* | |
141 if (*s == '/') return DIRTREE_RECURSE; | |
142 if (strncmp(s, "loop", 4) || !isdigit(s[4])) return 0; | |
143 | |
144 s = dirtree_path(node, 0); | |
145 loopback_setup(s, 0); | |
146 free(s); | |
147 | |
148 return 0; | |
149 } | |
150 | |
151 void losetup_main(void) | |
152 { | |
153 char **s; | |
154 | |
155 TT.openflags = (toys.optflags & FLAG_r) ? O_RDONLY : O_RDWR; | |
156 | |
157 if (TT.jfile) { | |
158 struct stat st; | |
159 | |
160 xstat(TT.jfile, &st); | |
161 TT.jdev = st.st_dev; | |
162 TT.jino = st.st_ino; | |
163 } | |
164 | |
165 // With just device, display current association | |
166 // -a, -f substitute for device | |
167 // -j substitute for device | |
168 | |
169 // new association: S size o offset rs - need a file | |
170 // existing association: cd | |
171 | |
172 // -f(dc FILE) | |
173 | |
174 if (toys.optflags & FLAG_f) { | |
175 if (toys.optc > 1) perror_exit("max 1 arg"); | |
176 loopback_setup(NULL, *toys.optargs); | |
177 } else if (toys.optflags & (FLAG_a|FLAG_j)) { | |
178 if (toys.optc) error_exit("bad args"); | |
179 dirtree_read("/dev", dash_a); | |
180 // Do we need one DEVICE argument? | |
181 } else { | |
182 char *file = (toys.optflags & (FLAG_d|FLAG_c)) ? NULL : toys.optargs[1]; | |
183 | |
184 if (!toys.optc || (file && toys.optc>1)) { | |
185 if (CFG_HELP) toys.exithelp++; | |
186 perror_exit("needs 1 arg"); | |
187 } | |
188 for (s = toys.optargs; *s; s++) loopback_setup(*s, file); | |
189 } | |
190 } |