]>
Commit | Line | Data |
---|---|---|
6dbe3af9 | 1 | /* |
39fde137 KZ |
2 | * Copyright (C) 2011 Karel Zak <kzak@redhat.com> |
3 | * Originally from Ted's losetup.c | |
4 | * | |
6dbe3af9 KZ |
5 | * losetup.c - setup and control loop devices |
6 | */ | |
896352d3 | 7 | #include <assert.h> |
6dbe3af9 KZ |
8 | #include <stdio.h> |
9 | #include <string.h> | |
fd6b7a7f | 10 | #include <errno.h> |
6dbe3af9 KZ |
11 | #include <stdlib.h> |
12 | #include <unistd.h> | |
13 | #include <sys/ioctl.h> | |
fd6b7a7f | 14 | #include <sys/stat.h> |
7711bc17 | 15 | #include <inttypes.h> |
65329058 | 16 | #include <getopt.h> |
6dbe3af9 | 17 | |
934df30d | 18 | #include "c.h" |
896352d3 | 19 | #include "tt.h" |
7eda085c | 20 | #include "nls.h" |
934df30d | 21 | #include "strutils.h" |
de4acb05 | 22 | #include "loopdev.h" |
efb8854f | 23 | #include "closestream.h" |
96801c48 | 24 | #include "optutils.h" |
896352d3 | 25 | #include "xalloc.h" |
96801c48 | 26 | |
39fde137 | 27 | enum { |
c7e0925d | 28 | A_CREATE = 1, /* setup a new device */ |
c654c4f0 KZ |
29 | A_DELETE, /* delete given device(s) */ |
30 | A_DELETE_ALL, /* delete all devices */ | |
39fde137 | 31 | A_SHOW, /* list devices */ |
09ec0c0a | 32 | A_SHOW_ONE, /* print info about one device */ |
39fde137 KZ |
33 | A_FIND_FREE, /* find first unused */ |
34 | A_SET_CAPACITY, /* set device capacity */ | |
35 | }; | |
36 | ||
896352d3 OO |
37 | enum { |
38 | COL_NAME = 0, | |
39 | COL_AUTOCLR, | |
40 | COL_BACK_FILE, | |
41 | COL_BACK_INO, | |
42 | COL_BACK_MAJMIN, | |
43 | COL_MAJMIN, | |
44 | COL_OFFSET, | |
45 | COL_PARTSCAN, | |
46 | COL_RO, | |
4ad996d7 | 47 | COL_SIZELIMIT, |
896352d3 OO |
48 | }; |
49 | ||
50 | struct tt *tt; | |
51 | ||
52 | struct colinfo { | |
53 | const char *name; | |
54 | double whint; | |
55 | int flags; | |
56 | const char *help; | |
57 | }; | |
58 | ||
59 | static struct colinfo infos[] = { | |
60 | [COL_AUTOCLR] = { "AUTOCLEAR", 1, TT_FL_RIGHT, N_("autoclear flag set")}, | |
61 | [COL_BACK_FILE] = { "BACK-FILE", 0.3, 0, N_("device backing file")}, | |
62 | [COL_BACK_INO] = { "BACK-INO", 4, TT_FL_RIGHT, N_("backing file inode number")}, | |
63 | [COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")}, | |
64 | [COL_NAME] = { "NAME", 0.25, 0, N_("loop device name")}, | |
65 | [COL_OFFSET] = { "OFFSET", 5, TT_FL_RIGHT, N_("offset from the beginning")}, | |
66 | [COL_PARTSCAN] = { "PARTSCAN", 1, TT_FL_RIGHT, N_("partscan flag set")}, | |
67 | [COL_RO] = { "RO", 1, TT_FL_RIGHT, N_("read-only device")}, | |
4ad996d7 | 68 | [COL_SIZELIMIT] = { "SIZELIMIT", 5, TT_FL_RIGHT, N_("size limit of the file in bytes")}, |
896352d3 OO |
69 | [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")}, |
70 | }; | |
71 | ||
72 | #define NCOLS ARRAY_SIZE(infos) | |
73 | ||
74 | static int columns[NCOLS] = {-1}; | |
75 | static int ncolumns; | |
0a719a7c | 76 | static int verbose; |
6dbe3af9 | 77 | |
896352d3 OO |
78 | static int get_column_id(int num) |
79 | { | |
80 | assert(ARRAY_SIZE(columns) == NCOLS); | |
81 | assert(num < ncolumns); | |
82 | assert(columns[num] < (int) NCOLS); | |
83 | return columns[num]; | |
84 | } | |
85 | ||
86 | static struct colinfo *get_column_info(int num) | |
87 | { | |
88 | return &infos[ get_column_id(num) ]; | |
89 | } | |
90 | ||
91 | static int column_name_to_id(const char *name, size_t namesz) | |
92 | { | |
93 | size_t i; | |
94 | ||
95 | for (i = 0; i < NCOLS; i++) { | |
96 | const char *cn = infos[i].name; | |
97 | ||
98 | if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) | |
99 | return i; | |
100 | } | |
101 | warnx(_("unknown column: %s"), name); | |
102 | return -1; | |
103 | } | |
d03dd608 | 104 | |
39fde137 KZ |
105 | static int printf_loopdev(struct loopdev_cxt *lc) |
106 | { | |
107 | uint64_t x; | |
108 | dev_t dev = 0; | |
109 | ino_t ino = 0; | |
110 | char *fname = NULL; | |
a3b421df | 111 | uint32_t type; |
39fde137 KZ |
112 | |
113 | fname = loopcxt_get_backing_file(lc); | |
114 | if (!fname) | |
115 | return -EINVAL; | |
116 | ||
117 | if (loopcxt_get_backing_devno(lc, &dev) == 0) | |
118 | loopcxt_get_backing_inode(lc, &ino); | |
119 | ||
120 | if (!dev && !ino) { | |
121 | /* | |
122 | * Probably non-root user (no permissions to | |
123 | * call LOOP_GET_STATUS ioctls). | |
124 | */ | |
125 | printf("%s: []: (%s)", | |
126 | loopcxt_get_device(lc), fname); | |
127 | ||
128 | if (loopcxt_get_offset(lc, &x) == 0 && x) | |
129 | printf(_(", offset %ju"), x); | |
130 | ||
131 | if (loopcxt_get_sizelimit(lc, &x) == 0 && x) | |
132 | printf(_(", sizelimit %ju"), x); | |
133 | printf("\n"); | |
134 | return 0; | |
135 | } | |
136 | ||
137 | printf("%s: [%04d]:%" PRIu64 " (%s)", | |
a3b421df | 138 | loopcxt_get_device(lc), (int) dev, ino, fname); |
39fde137 KZ |
139 | |
140 | if (loopcxt_get_offset(lc, &x) == 0 && x) | |
141 | printf(_(", offset %ju"), x); | |
142 | ||
143 | if (loopcxt_get_sizelimit(lc, &x) == 0 && x) | |
144 | printf(_(", sizelimit %ju"), x); | |
145 | ||
146 | if (loopcxt_get_encrypt_type(lc, &type) == 0) { | |
147 | const char *e = loopcxt_get_crypt_name(lc); | |
148 | ||
149 | if ((!e || !*e) && type == 1) | |
150 | e = "XOR"; | |
151 | if (e && *e) | |
a3b421df | 152 | printf(_(", encryption %s (type %u)"), e, type); |
39fde137 KZ |
153 | } |
154 | printf("\n"); | |
155 | return 0; | |
156 | } | |
157 | ||
bc0ac075 KZ |
158 | static int show_all_loops(struct loopdev_cxt *lc, const char *file, |
159 | uint64_t offset, int flags) | |
39fde137 | 160 | { |
bc0ac075 KZ |
161 | struct stat sbuf, *st = &sbuf; |
162 | ||
39fde137 | 163 | if (loopcxt_init_iterator(lc, LOOPITER_FL_USED)) |
6e90a44c | 164 | return -1; |
39fde137 | 165 | |
bc0ac075 KZ |
166 | if (!file || stat(file, st)) |
167 | st = NULL; | |
168 | ||
169 | while (loopcxt_next(lc) == 0) { | |
39fde137 | 170 | |
bc0ac075 KZ |
171 | if (file && !loopcxt_is_used(lc, st, file, offset, flags)) |
172 | continue; | |
bc0ac075 KZ |
173 | printf_loopdev(lc); |
174 | } | |
c654c4f0 | 175 | loopcxt_deinit_iterator(lc); |
6e90a44c KZ |
176 | return 0; |
177 | } | |
178 | ||
179 | static int set_capacity(struct loopdev_cxt *lc) | |
180 | { | |
181 | int fd = loopcxt_get_fd(lc); | |
182 | ||
183 | if (fd < 0) | |
289dcc90 | 184 | warn(_("cannot open %s"), loopcxt_get_device(lc)); |
6e90a44c KZ |
185 | else if (ioctl(fd, LOOP_SET_CAPACITY) != 0) |
186 | warnx(_("%s: set capacity failed"), loopcxt_get_device(lc)); | |
187 | else | |
188 | return 0; | |
189 | ||
c654c4f0 KZ |
190 | return -1; |
191 | } | |
192 | ||
193 | static int delete_loop(struct loopdev_cxt *lc) | |
194 | { | |
195 | if (loopcxt_delete_device(lc)) | |
196 | warn(_("%s: detach failed"), loopcxt_get_device(lc)); | |
197 | else | |
198 | return 0; | |
199 | ||
200 | return -1; | |
201 | } | |
202 | ||
203 | static int delete_all_loops(struct loopdev_cxt *lc) | |
204 | { | |
205 | int res = 0; | |
206 | ||
207 | if (loopcxt_init_iterator(lc, LOOPITER_FL_USED)) | |
208 | return -1; | |
209 | ||
210 | while (loopcxt_next(lc) == 0) | |
211 | res += delete_loop(lc); | |
212 | ||
213 | loopcxt_deinit_iterator(lc); | |
214 | return res; | |
39fde137 KZ |
215 | } |
216 | ||
896352d3 OO |
217 | static int set_tt_data(struct loopdev_cxt *lc, struct tt_line *ln) |
218 | { | |
219 | int i; | |
220 | ||
221 | for (i = 0; i < ncolumns; i++) { | |
222 | const char *p = NULL; | |
223 | char *np = NULL; | |
224 | uint64_t x = 0; | |
225 | ||
226 | switch(get_column_id(i)) { | |
227 | case COL_NAME: | |
228 | p = loopcxt_get_device(lc); | |
229 | if (p) | |
230 | tt_line_set_data(ln, i, xstrdup(p)); | |
231 | break; | |
232 | case COL_BACK_FILE: | |
233 | p = loopcxt_get_backing_file(lc); | |
234 | if (p) | |
235 | tt_line_set_data(ln, i, xstrdup(p)); | |
236 | break; | |
237 | case COL_OFFSET: | |
238 | if (loopcxt_get_offset(lc, &x) == 0) | |
239 | xasprintf(&np, "%jd", x); | |
240 | if (np) | |
241 | tt_line_set_data(ln, i, np); | |
242 | break; | |
4ad996d7 | 243 | case COL_SIZELIMIT: |
896352d3 OO |
244 | if (loopcxt_get_sizelimit(lc, &x) == 0) |
245 | xasprintf(&np, "%jd", x); | |
246 | if (np) | |
247 | tt_line_set_data(ln, i, np); | |
248 | break; | |
249 | case COL_BACK_MAJMIN: | |
250 | { | |
251 | dev_t dev = 0; | |
252 | if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev) | |
253 | xasprintf(&np, "%8u:%-3u", major(dev), minor(dev)); | |
254 | if (np) | |
255 | tt_line_set_data(ln, i, np); | |
256 | break; | |
257 | } | |
258 | case COL_MAJMIN: | |
259 | { | |
260 | struct stat st; | |
261 | ||
262 | if (loopcxt_get_device(lc) | |
263 | && stat(loopcxt_get_device(lc), &st) == 0 | |
264 | && S_ISBLK(st.st_mode) | |
265 | && major(st.st_rdev) == LOOPDEV_MAJOR) | |
266 | xasprintf(&np, "%3u:%-3u", major(st.st_rdev), | |
267 | minor(st.st_rdev)); | |
268 | if (np) | |
269 | tt_line_set_data(ln, i, np); | |
270 | break; | |
271 | } | |
272 | case COL_BACK_INO: | |
273 | { | |
274 | ino_t ino = 0; | |
275 | if (loopcxt_get_backing_inode(lc, &ino) == 0 && ino) | |
276 | xasprintf(&np, "%ju", ino); | |
277 | if (np) | |
278 | tt_line_set_data(ln, i, np); | |
279 | break; | |
280 | } | |
281 | case COL_AUTOCLR: | |
282 | tt_line_set_data(ln, i, | |
283 | xstrdup(loopcxt_is_autoclear(lc) ? "1" : "0")); | |
284 | break; | |
285 | case COL_RO: | |
286 | tt_line_set_data(ln, i, | |
287 | xstrdup(loopcxt_is_readonly(lc) ? "1" : "0")); | |
288 | break; | |
289 | case COL_PARTSCAN: | |
290 | tt_line_set_data(ln, i, | |
291 | xstrdup(loopcxt_is_partscan(lc) ? "1" : "0")); | |
292 | break; | |
293 | default: | |
294 | return -EINVAL; | |
295 | } | |
296 | } | |
297 | return 0; | |
298 | } | |
299 | ||
300 | static int make_table(struct loopdev_cxt *lc, const char *file, | |
301 | uint64_t offset, int flags) | |
302 | { | |
303 | struct stat sbuf, *st = &sbuf; | |
304 | struct tt_line *ln; | |
305 | ||
306 | if (!(tt = tt_new_table(0))) | |
307 | errx(EXIT_FAILURE, _("failed to initialize output table")); | |
308 | ||
309 | for (int i = 0; i < ncolumns; i++) { | |
310 | struct colinfo *ci = get_column_info(i); | |
311 | ||
312 | if (!tt_define_column(tt, ci->name, ci->whint, ci->flags)) | |
313 | warn(_("failed to initialize output column")); | |
314 | } | |
315 | ||
316 | if (loopcxt_get_device(lc)) { | |
317 | ln = tt_add_line(tt, NULL); | |
318 | if (set_tt_data(lc, ln)) | |
319 | return -EINVAL; | |
320 | return 0; | |
321 | } | |
322 | ||
323 | if (loopcxt_init_iterator(lc, LOOPITER_FL_USED)) | |
324 | return -1; | |
325 | if (!file || stat(file, st)) | |
326 | st = NULL; | |
327 | ||
328 | while (loopcxt_next(lc) == 0) { | |
329 | if (file && !loopcxt_is_used(lc, st, file, offset, flags)) | |
330 | continue; | |
331 | ||
332 | ||
333 | ln = tt_add_line(tt, NULL); | |
334 | if (set_tt_data(lc, ln)) | |
335 | return -EINVAL; | |
336 | } | |
337 | ||
338 | loopcxt_deinit_iterator(lc); | |
339 | return 0; | |
340 | } | |
341 | ||
aadb9303 KZ |
342 | static void usage(FILE *out) |
343 | { | |
344 | fputs(USAGE_HEADER, out); | |
345 | ||
346 | fprintf(out, | |
347 | _(" %1$s [options] [<loopdev>]\n" | |
348 | " %1$s [options] -f | <loopdev> <file>\n"), | |
349 | program_invocation_short_name); | |
350 | ||
351 | fputs(USAGE_OPTIONS, out); | |
352 | fputs(_(" -a, --all list all used devices\n" | |
353 | " -d, --detach <loopdev> [...] detach one or more devices\n" | |
354 | " -D, --detach-all detach all used devices\n" | |
355 | " -f, --find find first unused device\n" | |
356 | " -c, --set-capacity <loopdev> resize device\n" | |
357 | " -j, --associated <file> list all devices associated with <file>\n"), out); | |
358 | fputs(USAGE_SEPARATOR, out); | |
359 | ||
896352d3 OO |
360 | fputs(_(" -l, --list list info about all or specified\n" |
361 | " -o, --offset <num> start at offset <num> into file\n" | |
362 | " -O, --output <cols> specify columns to output for --list\n" | |
aadb9303 | 363 | " --sizelimit <num> device limited to <num> bytes of the file\n" |
916bf85e | 364 | " -P, --partscan create partitioned loop device\n" |
aadb9303 KZ |
365 | " -r, --read-only setup read-only loop device\n" |
366 | " --show print device name after setup (with -f)\n" | |
367 | " -v, --verbose verbose mode\n"), out); | |
368 | ||
369 | fputs(USAGE_SEPARATOR, out); | |
370 | fputs(USAGE_HELP, out); | |
371 | fputs(USAGE_VERSION, out); | |
372 | ||
896352d3 OO |
373 | fputs(_("\nAvailable --list columns:\n"), out); |
374 | for (size_t i = 0; i < NCOLS; i++) | |
375 | fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help)); | |
376 | ||
aadb9303 | 377 | fprintf(out, USAGE_MAN_TAIL("losetup(8)")); |
6997468e KZ |
378 | |
379 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
aadb9303 | 380 | } |
22853e4a | 381 | |
35545456 KZ |
382 | static void warn_size(const char *filename, uint64_t size) |
383 | { | |
384 | struct stat st; | |
385 | ||
386 | if (!size) { | |
387 | if (stat(filename, &st)) | |
388 | return; | |
389 | size = st.st_size; | |
390 | } | |
391 | ||
392 | if (size < 512) | |
393 | warnx(_("%s: warning: file smaller than 512 bytes, the loop device " | |
394 | "maybe be useless or invisible for system tools."), | |
395 | filename); | |
396 | else if (size % 512) | |
397 | warnx(_("%s: warning: file does not fit into a 512-byte sector " | |
398 | "the end of the file will be ignored."), | |
399 | filename); | |
400 | } | |
401 | ||
39fde137 KZ |
402 | int main(int argc, char **argv) |
403 | { | |
404 | struct loopdev_cxt lc; | |
5cf05c71 LN |
405 | int act = 0, flags = 0, c; |
406 | char *file = NULL; | |
c7e0925d KZ |
407 | uint64_t offset = 0, sizelimit = 0; |
408 | int res = 0, showdev = 0, lo_flags = 0; | |
896352d3 OO |
409 | char *outarg = NULL; |
410 | int list = 0; | |
6c7d5ae9 | 411 | |
aadb9303 KZ |
412 | enum { |
413 | OPT_SIZELIMIT = CHAR_MAX + 1, | |
414 | OPT_SHOW | |
415 | }; | |
416 | static const struct option longopts[] = { | |
d99f0140 | 417 | { "all", 0, 0, 'a' }, |
6e90a44c | 418 | { "set-capacity", 1, 0, 'c' }, |
c654c4f0 | 419 | { "detach", 1, 0, 'd' }, |
34f9b684 | 420 | { "detach-all", 0, 0, 'D' }, |
d99f0140 KZ |
421 | { "encryption", 1, 0, 'e' }, |
422 | { "find", 0, 0, 'f' }, | |
423 | { "help", 0, 0, 'h' }, | |
259fcc57 | 424 | { "associated", 1, 0, 'j' }, |
896352d3 | 425 | { "list", 0, 0, 'l' }, |
d99f0140 | 426 | { "offset", 1, 0, 'o' }, |
896352d3 | 427 | { "output", 1, 0, 'O' }, |
aadb9303 | 428 | { "sizelimit", 1, 0, OPT_SIZELIMIT }, |
d99f0140 | 429 | { "pass-fd", 1, 0, 'p' }, |
916bf85e | 430 | { "partscan", 0, 0, 'P' }, |
d99f0140 | 431 | { "read-only", 0, 0, 'r' }, |
896352d3 | 432 | { "show", 0, 0, OPT_SHOW }, |
d99f0140 | 433 | { "verbose", 0, 0, 'v' }, |
aadb9303 | 434 | { "version", 0, 0, 'V' }, |
d99f0140 KZ |
435 | { NULL, 0, 0, 0 } |
436 | }; | |
22853e4a | 437 | |
c1ac3144 KZ |
438 | static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ |
439 | { 'D','a','c','d','f','j' }, | |
896352d3 | 440 | { 'D','c','d','f','l' }, |
65178cb3 | 441 | { 'D','c','d','f','O' }, |
c1ac3144 KZ |
442 | { 0 } |
443 | }; | |
444 | int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; | |
445 | ||
22853e4a KZ |
446 | setlocale(LC_ALL, ""); |
447 | bindtextdomain(PACKAGE, LOCALEDIR); | |
448 | textdomain(PACKAGE); | |
efb8854f | 449 | atexit(close_stdout); |
22853e4a | 450 | |
defa0710 KZ |
451 | if (loopcxt_init(&lc, 0)) |
452 | err(EXIT_FAILURE, _("failed to initialize loopcxt")); | |
453 | ||
896352d3 | 454 | while ((c = getopt_long(argc, argv, "ac:d:De:E:fhj:lo:O:p:PrvV", |
d99f0140 | 455 | longopts, NULL)) != -1) { |
c1ac3144 KZ |
456 | |
457 | err_exclusive_options(c, longopts, excl, excl_st); | |
458 | ||
22853e4a | 459 | switch (c) { |
8b125fae | 460 | case 'a': |
39fde137 | 461 | act = A_SHOW; |
8b125fae | 462 | break; |
d34ac93a | 463 | case 'c': |
6e90a44c | 464 | act = A_SET_CAPACITY; |
defa0710 KZ |
465 | if (loopcxt_set_device(&lc, optarg)) |
466 | err(EXIT_FAILURE, _("%s: failed to use device"), | |
467 | optarg); | |
d34ac93a | 468 | break; |
faf142b6 | 469 | case 'r': |
c7e0925d | 470 | lo_flags |= LO_FLAGS_READ_ONLY; |
faf142b6 | 471 | break; |
22853e4a | 472 | case 'd': |
c654c4f0 | 473 | act = A_DELETE; |
defa0710 KZ |
474 | if (loopcxt_set_device(&lc, optarg)) |
475 | err(EXIT_FAILURE, _("%s: failed to use device"), | |
476 | optarg); | |
22853e4a | 477 | break; |
34f9b684 | 478 | case 'D': |
c654c4f0 | 479 | act = A_DELETE_ALL; |
34f9b684 | 480 | break; |
d03dd608 | 481 | case 'E': |
22853e4a | 482 | case 'e': |
5cf05c71 | 483 | errx(EXIT_FAILURE, _("encryption not supported, use cryptsetup(8) instead")); |
22853e4a | 484 | break; |
d162fcb5 | 485 | case 'f': |
bcdbdc72 | 486 | act = A_FIND_FREE; |
d162fcb5 | 487 | break; |
108591d2 KZ |
488 | case 'h': |
489 | usage(stdout); | |
490 | break; | |
259fcc57 | 491 | case 'j': |
bc0ac075 KZ |
492 | act = A_SHOW; |
493 | file = optarg; | |
259fcc57 | 494 | break; |
896352d3 OO |
495 | case 'l': |
496 | list = 1; | |
497 | break; | |
22853e4a | 498 | case 'o': |
e9e426eb | 499 | offset = strtosize_or_err(optarg, _("failed to parse offset")); |
bc0ac075 | 500 | flags |= LOOPDEV_FL_OFFSET; |
22853e4a | 501 | break; |
896352d3 OO |
502 | case 'O': |
503 | outarg = optarg; | |
65178cb3 | 504 | list = 1; |
896352d3 | 505 | break; |
d03dd608 | 506 | case 'p': |
5cf05c71 | 507 | warn(_("--pass-fd is no longer supported")); |
d03dd608 | 508 | break; |
916bf85e KZ |
509 | case 'P': |
510 | lo_flags |= LO_FLAGS_PARTSCAN; | |
511 | break; | |
aadb9303 | 512 | case OPT_SHOW: |
ba3809b0 KZ |
513 | showdev = 1; |
514 | break; | |
22853e4a KZ |
515 | case 'v': |
516 | verbose = 1; | |
517 | break; | |
aadb9303 KZ |
518 | case 'V': |
519 | printf(UTIL_LINUX_VERSION); | |
520 | return EXIT_SUCCESS; | |
521 | case OPT_SIZELIMIT: /* --sizelimit */ | |
e9e426eb | 522 | sizelimit = strtosize_or_err(optarg, _("failed to parse size")); |
c7e0925d | 523 | flags |= LOOPDEV_FL_SIZELIMIT; |
7bcefc7f | 524 | break; |
22853e4a | 525 | default: |
108591d2 | 526 | usage(stderr); |
22853e4a KZ |
527 | } |
528 | } | |
d162fcb5 | 529 | |
896352d3 OO |
530 | /* default is --list --all */ |
531 | if (argc == 1) { | |
532 | act = A_SHOW; | |
533 | list = 1; | |
534 | } | |
535 | ||
536 | /* default --list output columns */ | |
537 | if (list && !ncolumns) { | |
538 | columns[ncolumns++] = COL_NAME; | |
4ad996d7 | 539 | columns[ncolumns++] = COL_SIZELIMIT; |
896352d3 OO |
540 | columns[ncolumns++] = COL_OFFSET; |
541 | columns[ncolumns++] = COL_AUTOCLR; | |
542 | columns[ncolumns++] = COL_RO; | |
543 | columns[ncolumns++] = COL_BACK_FILE; | |
544 | } | |
39fde137 | 545 | |
c7e0925d KZ |
546 | if (act == A_FIND_FREE && optind < argc) { |
547 | /* | |
548 | * losetup -f <backing_file> | |
549 | */ | |
550 | act = A_CREATE; | |
551 | file = argv[optind++]; | |
552 | } | |
896352d3 OO |
553 | |
554 | if (list && !act && optind == argc) | |
555 | /* | |
556 | * losetup --list defaults to --all | |
557 | */ | |
558 | act = A_SHOW; | |
559 | ||
09ec0c0a KZ |
560 | if (!act && optind + 1 == argc) { |
561 | /* | |
896352d3 | 562 | * losetup [--list] <device> |
09ec0c0a KZ |
563 | */ |
564 | act = A_SHOW_ONE; | |
defa0710 KZ |
565 | if (loopcxt_set_device(&lc, argv[optind])) |
566 | err(EXIT_FAILURE, _("%s: failed to use device"), | |
567 | argv[optind]); | |
568 | optind++; | |
09ec0c0a | 569 | } |
c7e0925d KZ |
570 | if (!act) { |
571 | /* | |
572 | * losetup <loopdev> <backing_file> | |
573 | */ | |
574 | act = A_CREATE; | |
575 | ||
576 | if (optind >= argc) | |
577 | errx(EXIT_FAILURE, _("no loop device specified")); | |
defa0710 | 578 | if (loopcxt_set_device(&lc, argv[optind])) |
e9e7698e | 579 | err(EXIT_FAILURE, _("%s: failed to use device"), |
defa0710 KZ |
580 | argv[optind]); |
581 | optind++; | |
c7e0925d KZ |
582 | |
583 | if (optind >= argc) | |
584 | errx(EXIT_FAILURE, _("no file specified")); | |
585 | file = argv[optind++]; | |
586 | } | |
587 | ||
588 | if (act != A_CREATE && | |
5cf05c71 | 589 | (sizelimit || lo_flags || showdev)) |
c7e0925d KZ |
590 | errx(EXIT_FAILURE, |
591 | _("the options %s are allowed to loop device setup only"), | |
5cf05c71 | 592 | "--{sizelimit,read-only,show}"); |
c7e0925d | 593 | |
934df30d KZ |
594 | if ((flags & LOOPDEV_FL_OFFSET) && |
595 | act != A_CREATE && (act != A_SHOW || !file)) | |
c7e0925d | 596 | errx(EXIT_FAILURE, _("the option --offset is not allowed in this context.")); |
c654c4f0 | 597 | |
896352d3 OO |
598 | if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), |
599 | &ncolumns, column_name_to_id) < 0) | |
600 | return EXIT_FAILURE; | |
601 | ||
39fde137 | 602 | switch (act) { |
c7e0925d KZ |
603 | case A_CREATE: |
604 | { | |
c7e0925d KZ |
605 | int hasdev = loopcxt_has_device(&lc); |
606 | ||
c7e0925d KZ |
607 | do { |
608 | /* Note that loopcxt_{find_unused,set_device}() resets | |
609 | * loopcxt struct. | |
610 | */ | |
611 | if (!hasdev && (res = loopcxt_find_unused(&lc))) { | |
612 | warnx(_("not found unused device")); | |
613 | break; | |
614 | } | |
c7e0925d KZ |
615 | if (flags & LOOPDEV_FL_OFFSET) |
616 | loopcxt_set_offset(&lc, offset); | |
617 | if (flags & LOOPDEV_FL_SIZELIMIT) | |
ce65b29a | 618 | loopcxt_set_sizelimit(&lc, sizelimit); |
c7e0925d KZ |
619 | if (lo_flags) |
620 | loopcxt_set_flags(&lc, lo_flags); | |
621 | if ((res = loopcxt_set_backing_file(&lc, file))) { | |
622 | warn(_("%s: failed to use backing file"), file); | |
623 | break; | |
624 | } | |
625 | errno = 0; | |
626 | res = loopcxt_setup_device(&lc); | |
627 | if (res == 0) | |
628 | break; /* success */ | |
629 | if (errno != EBUSY) { | |
cda4f8f1 KZ |
630 | warn(_("%s: failed to setup loop device"), |
631 | hasdev && loopcxt_get_fd(&lc) < 0 ? | |
632 | loopcxt_get_device(&lc) : file); | |
c7e0925d KZ |
633 | break; |
634 | } | |
635 | } while (hasdev == 0); | |
636 | ||
35545456 KZ |
637 | if (res == 0) { |
638 | if (showdev) | |
639 | printf("%s\n", loopcxt_get_device(&lc)); | |
640 | warn_size(file, sizelimit); | |
641 | } | |
c7e0925d KZ |
642 | break; |
643 | } | |
c654c4f0 KZ |
644 | case A_DELETE: |
645 | res = delete_loop(&lc); | |
646 | while (optind < argc) { | |
defa0710 KZ |
647 | if (loopcxt_set_device(&lc, argv[optind])) |
648 | warn(_("%s: failed to use device"), | |
649 | argv[optind]); | |
650 | optind++; | |
c654c4f0 KZ |
651 | res += delete_loop(&lc); |
652 | } | |
653 | break; | |
654 | case A_DELETE_ALL: | |
655 | res = delete_all_loops(&lc); | |
656 | break; | |
bcdbdc72 KZ |
657 | case A_FIND_FREE: |
658 | if (loopcxt_find_unused(&lc)) | |
659 | warn(_("find unused loop device failed")); | |
660 | else | |
661 | printf("%s\n", loopcxt_get_device(&lc)); | |
662 | break; | |
39fde137 | 663 | case A_SHOW: |
896352d3 OO |
664 | if (list) |
665 | res = make_table(&lc, file, offset, flags); | |
666 | else | |
667 | res = show_all_loops(&lc, file, offset, flags); | |
bc0ac075 | 668 | break; |
09ec0c0a | 669 | case A_SHOW_ONE: |
896352d3 OO |
670 | if (list) |
671 | res = make_table( &lc, NULL, 0, 0); | |
672 | else | |
673 | res = printf_loopdev(&lc); | |
09ec0c0a KZ |
674 | if (res) |
675 | warn(_("%s"), loopcxt_get_device(&lc)); | |
676 | break; | |
6e90a44c KZ |
677 | case A_SET_CAPACITY: |
678 | res = set_capacity(&lc); | |
679 | break; | |
39fde137 | 680 | default: |
c7e0925d | 681 | usage(stderr); |
39fde137 KZ |
682 | break; |
683 | } | |
896352d3 OO |
684 | if (tt) { |
685 | if (!res) | |
686 | tt_print_table(tt); | |
687 | tt_free_table(tt); | |
688 | } | |
39fde137 KZ |
689 | |
690 | loopcxt_deinit(&lc); | |
c7e0925d | 691 | return res ? EXIT_FAILURE : EXIT_SUCCESS; |
22853e4a KZ |
692 | } |
693 |