]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/losetup.c
Merge branch 'getrandom' of git://github.com/kerolasa/lelux-utiliteetit
[thirdparty/util-linux.git] / sys-utils / losetup.c
1 /*
2 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
3 * Originally from Ted's losetup.c
4 *
5 * losetup.c - setup and control loop devices
6 */
7 #include <assert.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <sys/ioctl.h>
14 #include <sys/stat.h>
15 #include <inttypes.h>
16 #include <getopt.h>
17
18 #include <libsmartcols.h>
19
20 #include "c.h"
21 #include "nls.h"
22 #include "strutils.h"
23 #include "loopdev.h"
24 #include "closestream.h"
25 #include "optutils.h"
26 #include "xalloc.h"
27 #include "canonicalize.h"
28 #include "pathnames.h"
29
30 enum {
31 A_CREATE = 1, /* setup a new device */
32 A_DELETE, /* delete given device(s) */
33 A_DELETE_ALL, /* delete all devices */
34 A_SHOW, /* list devices */
35 A_SHOW_ONE, /* print info about one device */
36 A_FIND_FREE, /* find first unused */
37 A_SET_CAPACITY, /* set device capacity */
38 A_SET_DIRECT_IO, /* set accessing backing file by direct io */
39 };
40
41 enum {
42 COL_NAME = 0,
43 COL_AUTOCLR,
44 COL_BACK_FILE,
45 COL_BACK_INO,
46 COL_BACK_MAJMIN,
47 COL_MAJMIN,
48 COL_OFFSET,
49 COL_PARTSCAN,
50 COL_RO,
51 COL_SIZELIMIT,
52 COL_DIO,
53 };
54
55 /* basic output flags */
56 static int no_headings;
57 static int raw;
58 static int json;
59
60 struct colinfo {
61 const char *name;
62 double whint;
63 int flags;
64 const char *help;
65 };
66
67 static struct colinfo infos[] = {
68 [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set")},
69 [COL_BACK_FILE] = { "BACK-FILE", 0.3, 0, N_("device backing file")},
70 [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number")},
71 [COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")},
72 [COL_NAME] = { "NAME", 0.25, 0, N_("loop device name")},
73 [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning")},
74 [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set")},
75 [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device")},
76 [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes")},
77 [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")},
78 [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io")},
79 };
80
81 static int columns[ARRAY_SIZE(infos) * 2] = {-1};
82 static size_t ncolumns;
83
84 static int get_column_id(int num)
85 {
86 assert(num >= 0);
87 assert((size_t) num < ncolumns);
88 assert(columns[num] < (int) ARRAY_SIZE(infos));
89 return columns[num];
90 }
91
92 static struct colinfo *get_column_info(int num)
93 {
94 return &infos[ get_column_id(num) ];
95 }
96
97 static int column_name_to_id(const char *name, size_t namesz)
98 {
99 size_t i;
100
101 for (i = 0; i < ARRAY_SIZE(infos); i++) {
102 const char *cn = infos[i].name;
103
104 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
105 return i;
106 }
107 warnx(_("unknown column: %s"), name);
108 return -1;
109 }
110
111 static int printf_loopdev(struct loopdev_cxt *lc)
112 {
113 uint64_t x;
114 dev_t dev = 0;
115 ino_t ino = 0;
116 char *fname = NULL;
117 uint32_t type;
118
119 fname = loopcxt_get_backing_file(lc);
120 if (!fname)
121 return -EINVAL;
122
123 if (loopcxt_get_backing_devno(lc, &dev) == 0)
124 loopcxt_get_backing_inode(lc, &ino);
125
126 if (!dev && !ino) {
127 /*
128 * Probably non-root user (no permissions to
129 * call LOOP_GET_STATUS ioctls).
130 */
131 printf("%s: []: (%s)",
132 loopcxt_get_device(lc), fname);
133
134 if (loopcxt_get_offset(lc, &x) == 0 && x)
135 printf(_(", offset %ju"), x);
136
137 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
138 printf(_(", sizelimit %ju"), x);
139 printf("\n");
140 return 0;
141 }
142
143 printf("%s: [%04d]:%" PRIu64 " (%s)",
144 loopcxt_get_device(lc), (int) dev, ino, fname);
145
146 if (loopcxt_get_offset(lc, &x) == 0 && x)
147 printf(_(", offset %ju"), x);
148
149 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
150 printf(_(", sizelimit %ju"), x);
151
152 if (loopcxt_get_encrypt_type(lc, &type) == 0) {
153 const char *e = loopcxt_get_crypt_name(lc);
154
155 if ((!e || !*e) && type == 1)
156 e = "XOR";
157 if (e && *e)
158 printf(_(", encryption %s (type %u)"), e, type);
159 }
160 printf("\n");
161 return 0;
162 }
163
164 static int show_all_loops(struct loopdev_cxt *lc, const char *file,
165 uint64_t offset, int flags)
166 {
167 struct stat sbuf, *st = &sbuf;
168 char *cn_file = NULL;
169
170 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
171 return -1;
172
173 if (!file || stat(file, st))
174 st = NULL;
175
176 while (loopcxt_next(lc) == 0) {
177 if (file) {
178 int used;
179 const char *bf = cn_file ? cn_file : file;
180
181 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
182 if (!used && !cn_file) {
183 bf = cn_file = canonicalize_path(file);
184 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
185 }
186 if (!used)
187 continue;
188 }
189 printf_loopdev(lc);
190 }
191 loopcxt_deinit_iterator(lc);
192 free(cn_file);
193 return 0;
194 }
195
196 static int delete_loop(struct loopdev_cxt *lc)
197 {
198 if (loopcxt_delete_device(lc))
199 warn(_("%s: detach failed"), loopcxt_get_device(lc));
200 else
201 return 0;
202
203 return -1;
204 }
205
206 static int delete_all_loops(struct loopdev_cxt *lc)
207 {
208 int res = 0;
209
210 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
211 return -1;
212
213 while (loopcxt_next(lc) == 0)
214 res += delete_loop(lc);
215
216 loopcxt_deinit_iterator(lc);
217 return res;
218 }
219
220 static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln)
221 {
222 size_t i;
223
224 for (i = 0; i < ncolumns; i++) {
225 const char *p = NULL; /* external data */
226 char *np = NULL; /* allocated here */
227 uint64_t x = 0;
228
229 switch(get_column_id(i)) {
230 case COL_NAME:
231 p = loopcxt_get_device(lc);
232 break;
233 case COL_BACK_FILE:
234 p = loopcxt_get_backing_file(lc);
235 break;
236 case COL_OFFSET:
237 if (loopcxt_get_offset(lc, &x) == 0)
238 xasprintf(&np, "%jd", x);
239 break;
240 case COL_SIZELIMIT:
241 if (loopcxt_get_sizelimit(lc, &x) == 0)
242 xasprintf(&np, "%jd", x);
243 break;
244 case COL_BACK_MAJMIN:
245 {
246 dev_t dev = 0;
247 if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev)
248 xasprintf(&np, "%8u:%-3u", major(dev), minor(dev));
249 break;
250 }
251 case COL_MAJMIN:
252 {
253 struct stat st;
254
255 if (loopcxt_get_device(lc)
256 && stat(loopcxt_get_device(lc), &st) == 0
257 && S_ISBLK(st.st_mode)
258 && major(st.st_rdev) == LOOPDEV_MAJOR)
259 xasprintf(&np, "%3u:%-3u", major(st.st_rdev),
260 minor(st.st_rdev));
261 break;
262 }
263 case COL_BACK_INO:
264 {
265 ino_t ino = 0;
266 if (loopcxt_get_backing_inode(lc, &ino) == 0 && ino)
267 xasprintf(&np, "%ju", ino);
268 break;
269 }
270 case COL_AUTOCLR:
271 p = loopcxt_is_autoclear(lc) ? "1" : "0";
272 break;
273 case COL_RO:
274 p = loopcxt_is_readonly(lc) ? "1" : "0";
275 break;
276 case COL_DIO:
277 p = loopcxt_is_dio(lc) ? "1" : "0";
278 break;
279 case COL_PARTSCAN:
280 p = loopcxt_is_partscan(lc) ? "1" : "0";
281 break;
282 default:
283 return -EINVAL;
284 }
285
286
287 if (p)
288 scols_line_set_data(ln, i, p); /* calls strdup() */
289 else if (np)
290 scols_line_refer_data(ln, i, np); /* only refers */
291 }
292
293 return 0;
294 }
295
296 static int show_table(struct loopdev_cxt *lc,
297 const char *file,
298 uint64_t offset,
299 int flags)
300 {
301 struct stat sbuf, *st = &sbuf;
302 struct libscols_table *tb;
303 struct libscols_line *ln;
304 int rc = 0;
305 size_t i;
306
307 scols_init_debug(0);
308
309 if (!(tb = scols_new_table()))
310 err(EXIT_FAILURE, _("failed to initialize output table"));
311 scols_table_enable_raw(tb, raw);
312 scols_table_enable_json(tb, json);
313 scols_table_enable_noheadings(tb, no_headings);
314
315 if (json)
316 scols_table_set_name(tb, "loopdevices");
317
318 for (i = 0; i < ncolumns; i++) {
319 struct colinfo *ci = get_column_info(i);
320
321 if (!scols_table_new_column(tb, ci->name, ci->whint, ci->flags))
322 err(EXIT_FAILURE, _("failed to initialize output column"));
323 }
324
325 /* only one loopdev requested (already assigned to loopdev_cxt) */
326 if (loopcxt_get_device(lc)) {
327 ln = scols_table_new_line(tb, NULL);
328 if (!ln)
329 err(EXIT_FAILURE, _("failed to initialize output line"));
330 rc = set_scols_data(lc, ln);
331
332 /* list all loopdevs */
333 } else {
334 char *cn_file = NULL;
335
336 rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED);
337 if (rc)
338 goto done;
339 if (!file || stat(file, st))
340 st = NULL;
341
342 while (loopcxt_next(lc) == 0) {
343 if (file) {
344 int used;
345 const char *bf = cn_file ? cn_file : file;
346
347 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
348 if (!used && !cn_file) {
349 bf = cn_file = canonicalize_path(file);
350 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
351 }
352 if (!used)
353 continue;
354 }
355
356 ln = scols_table_new_line(tb, NULL);
357 if (!ln)
358 err(EXIT_FAILURE, _("failed to initialize output column"));
359 rc = set_scols_data(lc, ln);
360 if (rc)
361 break;
362 }
363
364 loopcxt_deinit_iterator(lc);
365 free(cn_file);
366 }
367 done:
368 if (rc == 0)
369 rc = scols_print_table(tb);
370 scols_unref_table(tb);
371 return rc;
372 }
373
374 static void usage(FILE *out)
375 {
376 size_t i;
377
378 fputs(USAGE_HEADER, out);
379
380 fprintf(out,
381 _(" %1$s [options] [<loopdev>]\n"
382 " %1$s [options] -f | <loopdev> <file>\n"),
383 program_invocation_short_name);
384
385 fputs(USAGE_SEPARATOR, out);
386 fputs(_("Set up and control loop devices.\n"), out);
387
388 fputs(USAGE_OPTIONS, out);
389 fputs(_(" -a, --all list all used devices\n"), out);
390 fputs(_(" -d, --detach <loopdev>... detach one or more devices\n"), out);
391 fputs(_(" -D, --detach-all detach all used devices\n"), out);
392 fputs(_(" -f, --find find first unused device\n"), out);
393 fputs(_(" -c, --set-capacity <loopdev> resize the device\n"), out);
394 fputs(_(" -j, --associated <file> list all devices associated with <file>\n"), out);
395 fputs(_(" -L, --nooverlap avoid possible conflict between devices\n"), out);
396
397 fputs(USAGE_SEPARATOR, out);
398
399 fputs(_(" -o, --offset <num> start at offset <num> into file\n"), out);
400 fputs(_(" --sizelimit <num> device is limited to <num> bytes of the file\n"), out);
401 fputs(_(" -P, --partscan create a partitioned loop device\n"), out);
402 fputs(_(" -r, --read-only set up a read-only loop device\n"), out);
403 fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out);
404 fputs(_(" --show print device name after setup (with -f)\n"), out);
405 fputs(_(" -v, --verbose verbose mode\n"), out);
406
407 fputs(USAGE_SEPARATOR, out);
408
409 fputs(_(" -l, --list list info about all or specified (default)\n"), out);
410 fputs(_(" -O, --output <cols> specify columns to output for --list\n"), out);
411 fputs(_(" -n, --noheadings don't print headings for --list output\n"), out);
412 fputs(_(" --raw use raw --list output format\n"), out);
413 fputs(_(" -J, --json use JSON --list output format\n"), out);
414
415 fputs(USAGE_SEPARATOR, out);
416 fputs(USAGE_HELP, out);
417 fputs(USAGE_VERSION, out);
418
419 fputs(_("\nAvailable --list columns:\n"), out);
420 for (i = 0; i < ARRAY_SIZE(infos); i++)
421 fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help));
422
423 fprintf(out, USAGE_MAN_TAIL("losetup(8)"));
424
425 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
426 }
427
428 static void warn_size(const char *filename, uint64_t size)
429 {
430 struct stat st;
431
432 if (!size) {
433 if (stat(filename, &st) || S_ISBLK(st.st_mode))
434 return;
435 size = st.st_size;
436 }
437
438 if (size < 512)
439 warnx(_("%s: Warning: file is smaller than 512 bytes; the loop device "
440 "may be useless or invisible for system tools."),
441 filename);
442 else if (size % 512)
443 warnx(_("%s: Warning: file does not fit into a 512-byte sector; "
444 "the end of the file will be ignored."),
445 filename);
446 }
447
448 static int create_loop(struct loopdev_cxt *lc,
449 int nooverlap, int lo_flags, int flags,
450 const char *file, uint64_t offset, uint64_t sizelimit)
451 {
452 int hasdev = loopcxt_has_device(lc);
453 int rc = 0;
454
455 /* losetup --find --noverlap file.img */
456 if (!hasdev && nooverlap) {
457 rc = loopcxt_find_overlap(lc, file, offset, sizelimit);
458 switch (rc) {
459 case 0: /* not found */
460 break;
461
462 case 1: /* overlap */
463 loopcxt_deinit(lc);
464 errx(EXIT_FAILURE, _("%s: overlapping loop device exists"), file);
465
466 case 2: /* overlap -- full size and offset match (reuse) */
467 {
468 uint32_t lc_encrypt_type;
469
470 /* Once a loop is initialized RO, there is no
471 * way to change its parameters. */
472 if (loopcxt_is_readonly(lc)
473 && !(lo_flags & LO_FLAGS_READ_ONLY)) {
474 loopcxt_deinit(lc);
475 errx(EXIT_FAILURE, _("%s: overlapping read-only loop device exists"), file);
476 }
477
478 /* This is no more supported, but check to be safe. */
479 if (loopcxt_get_encrypt_type(lc, &lc_encrypt_type) == 0
480 && lc_encrypt_type != LO_CRYPT_NONE) {
481 loopcxt_deinit(lc);
482 errx(EXIT_FAILURE, _("%s: overlapping encrypted loop device exists"), file);
483 }
484
485 lc->info.lo_flags &= !LO_FLAGS_AUTOCLEAR;
486 if (loopcxt_set_status(lc)) {
487 loopcxt_deinit(lc);
488 errx(EXIT_FAILURE, _("%s: failed to re-use loop device"), file);
489 }
490 return 0; /* success, re-use */
491 }
492 default: /* error */
493 loopcxt_deinit(lc);
494 errx(EXIT_FAILURE, _("failed to inspect loop devices"));
495 return -errno;
496 }
497 }
498
499 if (hasdev && !is_loopdev(loopcxt_get_device(lc)))
500 loopcxt_add_device(lc);
501
502 /* losetup --noverlap /dev/loopN file.img */
503 if (hasdev && nooverlap) {
504 struct loopdev_cxt lc2;
505
506 if (loopcxt_init(&lc2, 0)) {
507 loopcxt_deinit(lc);
508 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
509 }
510 rc = loopcxt_find_overlap(&lc2, file, offset, sizelimit);
511 loopcxt_deinit(&lc2);
512
513 if (rc) {
514 loopcxt_deinit(lc);
515 if (rc > 0)
516 errx(EXIT_FAILURE, _("%s: overlapping loop device exists"), file);
517 err(EXIT_FAILURE, _("%s: failed to check for conflicting loop devices"), file);
518 }
519 }
520
521 /* Create a new device */
522 do {
523 const char *errpre;
524
525 /* Note that loopcxt_{find_unused,set_device}() resets
526 * loopcxt struct.
527 */
528 if (!hasdev && (rc = loopcxt_find_unused(lc))) {
529 warnx(_("cannot find an unused loop device"));
530 break;
531 }
532 if (flags & LOOPDEV_FL_OFFSET)
533 loopcxt_set_offset(lc, offset);
534 if (flags & LOOPDEV_FL_SIZELIMIT)
535 loopcxt_set_sizelimit(lc, sizelimit);
536 if (lo_flags)
537 loopcxt_set_flags(lc, lo_flags);
538 if ((rc = loopcxt_set_backing_file(lc, file))) {
539 warn(_("%s: failed to use backing file"), file);
540 break;
541 }
542 errno = 0;
543 rc = loopcxt_setup_device(lc);
544 if (rc == 0)
545 break; /* success */
546 if (errno == EBUSY && !hasdev)
547 continue;
548
549 /* errors */
550 errpre = hasdev && loopcxt_get_fd(lc) < 0 ?
551 loopcxt_get_device(lc) : file;
552 warn(_("%s: failed to set up loop device"), errpre);
553 break;
554 } while (hasdev == 0);
555
556 return rc;
557 }
558
559 int main(int argc, char **argv)
560 {
561 struct loopdev_cxt lc;
562 int act = 0, flags = 0, no_overlap = 0, c;
563 char *file = NULL;
564 uint64_t offset = 0, sizelimit = 0;
565 int res = 0, showdev = 0, lo_flags = 0;
566 char *outarg = NULL;
567 int list = 0;
568 unsigned long use_dio = 0, set_dio = 0;
569
570 enum {
571 OPT_SIZELIMIT = CHAR_MAX + 1,
572 OPT_SHOW,
573 OPT_RAW,
574 OPT_DIO
575 };
576 static const struct option longopts[] = {
577 { "all", 0, 0, 'a' },
578 { "set-capacity", 1, 0, 'c' },
579 { "detach", 1, 0, 'd' },
580 { "detach-all", 0, 0, 'D' },
581 { "find", 0, 0, 'f' },
582 { "nooverlap", 0, 0, 'L' },
583 { "help", 0, 0, 'h' },
584 { "associated", 1, 0, 'j' },
585 { "json", 0, 0, 'J' },
586 { "list", 0, 0, 'l' },
587 { "noheadings", 0, 0, 'n' },
588 { "offset", 1, 0, 'o' },
589 { "output", 1, 0, 'O' },
590 { "sizelimit", 1, 0, OPT_SIZELIMIT },
591 { "partscan", 0, 0, 'P' },
592 { "read-only", 0, 0, 'r' },
593 { "direct-io", 2, 0, OPT_DIO },
594 { "raw", 0, 0, OPT_RAW },
595 { "show", 0, 0, OPT_SHOW },
596 { "verbose", 0, 0, 'v' },
597 { "version", 0, 0, 'V' },
598 { NULL, 0, 0, 0 }
599 };
600
601 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
602 { 'D','a','c','d','f','j' },
603 { 'D','c','d','f','l' },
604 { 'D','c','d','f','O' },
605 { 'J',OPT_RAW },
606 { 0 }
607 };
608 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
609
610 setlocale(LC_ALL, "");
611 bindtextdomain(PACKAGE, LOCALEDIR);
612 textdomain(PACKAGE);
613 atexit(close_stdout);
614
615 if (loopcxt_init(&lc, 0))
616 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
617
618 while ((c = getopt_long(argc, argv, "ac:d:Dfhj:JlLno:O:PrvV",
619 longopts, NULL)) != -1) {
620
621 err_exclusive_options(c, longopts, excl, excl_st);
622
623 switch (c) {
624 case 'a':
625 act = A_SHOW;
626 break;
627 case 'c':
628 act = A_SET_CAPACITY;
629 if (!is_loopdev(optarg) ||
630 loopcxt_set_device(&lc, optarg))
631 err(EXIT_FAILURE, _("%s: failed to use device"),
632 optarg);
633 break;
634 case 'r':
635 lo_flags |= LO_FLAGS_READ_ONLY;
636 break;
637 case 'd':
638 act = A_DELETE;
639 if (!is_loopdev(optarg) ||
640 loopcxt_set_device(&lc, optarg))
641 err(EXIT_FAILURE, _("%s: failed to use device"),
642 optarg);
643 break;
644 case 'D':
645 act = A_DELETE_ALL;
646 break;
647 case 'f':
648 act = A_FIND_FREE;
649 break;
650 case 'h':
651 usage(stdout);
652 break;
653 case 'J':
654 json = 1;
655 break;
656 case 'j':
657 act = A_SHOW;
658 file = optarg;
659 break;
660 case 'l':
661 list = 1;
662 break;
663 case 'L':
664 no_overlap = 1;
665 break;
666 case 'n':
667 no_headings = 1;
668 break;
669 case OPT_RAW:
670 raw = 1;
671 break;
672 case 'o':
673 offset = strtosize_or_err(optarg, _("failed to parse offset"));
674 flags |= LOOPDEV_FL_OFFSET;
675 break;
676 case 'O':
677 outarg = optarg;
678 list = 1;
679 break;
680 case 'P':
681 lo_flags |= LO_FLAGS_PARTSCAN;
682 break;
683 case OPT_SHOW:
684 showdev = 1;
685 break;
686 case OPT_DIO:
687 use_dio = set_dio = 1;
688 if (optarg)
689 use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL);
690 break;
691 case 'v':
692 break;
693 case 'V':
694 printf(UTIL_LINUX_VERSION);
695 return EXIT_SUCCESS;
696 case OPT_SIZELIMIT: /* --sizelimit */
697 sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
698 flags |= LOOPDEV_FL_SIZELIMIT;
699 break;
700 default:
701 errtryhelp(EXIT_FAILURE);
702 }
703 }
704
705 /* default is --list --all */
706 if (argc == 1) {
707 act = A_SHOW;
708 list = 1;
709 }
710
711 if (!act && argc == 2 && (raw || json)) {
712 act = A_SHOW;
713 list = 1;
714 }
715
716 /* default --list output columns */
717 if (list && !ncolumns) {
718 columns[ncolumns++] = COL_NAME;
719 columns[ncolumns++] = COL_SIZELIMIT;
720 columns[ncolumns++] = COL_OFFSET;
721 columns[ncolumns++] = COL_AUTOCLR;
722 columns[ncolumns++] = COL_RO;
723 columns[ncolumns++] = COL_BACK_FILE;
724 columns[ncolumns++] = COL_DIO;
725 }
726
727 if (act == A_FIND_FREE && optind < argc) {
728 /*
729 * losetup -f <backing_file>
730 */
731 act = A_CREATE;
732 file = argv[optind++];
733 }
734
735 if (list && !act && optind == argc)
736 /*
737 * losetup --list defaults to --all
738 */
739 act = A_SHOW;
740
741 if (!act && optind + 1 == argc) {
742 /*
743 * losetup [--list] <device>
744 * OR
745 * losetup --direct-io[=off] <device>
746 */
747 if (!set_dio)
748 act = A_SHOW_ONE;
749 else
750 act = A_SET_DIRECT_IO;
751 if (!is_loopdev(argv[optind]) ||
752 loopcxt_set_device(&lc, argv[optind]))
753 err(EXIT_FAILURE, _("%s: failed to use device"),
754 argv[optind]);
755 optind++;
756 }
757 if (!act) {
758 /*
759 * losetup <loopdev> <backing_file>
760 */
761 act = A_CREATE;
762
763 if (optind >= argc)
764 errx(EXIT_FAILURE, _("no loop device specified"));
765 /* don't use is_loopdev() here, the device does not have exist yet */
766 if (loopcxt_set_device(&lc, argv[optind]))
767 err(EXIT_FAILURE, _("%s: failed to use device"),
768 argv[optind]);
769 optind++;
770
771 if (optind >= argc)
772 errx(EXIT_FAILURE, _("no file specified"));
773 file = argv[optind++];
774 }
775
776 if (act != A_CREATE &&
777 (sizelimit || lo_flags || showdev))
778 errx(EXIT_FAILURE,
779 _("the options %s are allowed during loop device setup only"),
780 "--{sizelimit,read-only,show}");
781
782 if ((flags & LOOPDEV_FL_OFFSET) &&
783 act != A_CREATE && (act != A_SHOW || !file))
784 errx(EXIT_FAILURE, _("the option --offset is not allowed in this context"));
785
786 if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
787 &ncolumns, column_name_to_id) < 0)
788 return EXIT_FAILURE;
789
790 switch (act) {
791 case A_CREATE:
792 res = create_loop(&lc, no_overlap, lo_flags, flags, file, offset, sizelimit);
793 if (res == 0) {
794 if (showdev)
795 printf("%s\n", loopcxt_get_device(&lc));
796 warn_size(file, sizelimit);
797 if (set_dio)
798 goto lo_set_dio;
799 }
800 break;
801 case A_DELETE:
802 res = delete_loop(&lc);
803 while (optind < argc) {
804 if (!is_loopdev(argv[optind]) ||
805 loopcxt_set_device(&lc, argv[optind]))
806 warn(_("%s: failed to use device"),
807 argv[optind]);
808 optind++;
809 res += delete_loop(&lc);
810 }
811 break;
812 case A_DELETE_ALL:
813 res = delete_all_loops(&lc);
814 break;
815 case A_FIND_FREE:
816 res = loopcxt_find_unused(&lc);
817 if (res) {
818 int errsv = errno;
819
820 if (access(_PATH_DEV_LOOPCTL, F_OK) == 0 &&
821 access(_PATH_DEV_LOOPCTL, W_OK) != 0)
822 ;
823 else
824 errno = errsv;
825
826 warn(_("cannot find an unused loop device"));
827 } else
828 printf("%s\n", loopcxt_get_device(&lc));
829 break;
830 case A_SHOW:
831 if (list)
832 res = show_table(&lc, file, offset, flags);
833 else
834 res = show_all_loops(&lc, file, offset, flags);
835 break;
836 case A_SHOW_ONE:
837 if (list)
838 res = show_table(&lc, NULL, 0, 0);
839 else
840 res = printf_loopdev(&lc);
841 if (res)
842 warn("%s", loopcxt_get_device(&lc));
843 break;
844 case A_SET_CAPACITY:
845 res = loopcxt_set_capacity(&lc);
846 if (res)
847 warn(_("%s: set capacity failed"),
848 loopcxt_get_device(&lc));
849 break;
850 case A_SET_DIRECT_IO:
851 lo_set_dio:
852 res = loopcxt_set_dio(&lc, use_dio);
853 if (res)
854 warn(_("%s: set direct io failed"),
855 loopcxt_get_device(&lc));
856 break;
857 default:
858 usage(stderr);
859 break;
860 }
861
862 loopcxt_deinit(&lc);
863 return res ? EXIT_FAILURE : EXIT_SUCCESS;
864 }
865