]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/losetup.c
losetup: fix outdated comment
[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, flags);
182 if (!used && !cn_file) {
183 bf = cn_file = canonicalize_path(file);
184 used = loopcxt_is_used(lc, st, bf, offset, 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, flags);
348 if (!used && !cn_file) {
349 bf = cn_file = canonicalize_path(file);
350 used = loopcxt_is_used(lc, st, bf, offset, 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
396 fputs(USAGE_SEPARATOR, out);
397
398 fputs(_(" -o, --offset <num> start at offset <num> into file\n"), out);
399 fputs(_(" --sizelimit <num> device is limited to <num> bytes of the file\n"), out);
400 fputs(_(" -P, --partscan create a partitioned loop device\n"), out);
401 fputs(_(" -r, --read-only set up a read-only loop device\n"), out);
402 fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out);
403 fputs(_(" --show print device name after setup (with -f)\n"), out);
404 fputs(_(" -v, --verbose verbose mode\n"), out);
405
406 fputs(USAGE_SEPARATOR, out);
407
408 fputs(_(" -l, --list list info about all or specified (default)\n"), out);
409 fputs(_(" -O, --output <cols> specify columns to output for --list\n"), out);
410 fputs(_(" -n, --noheadings don't print headings for --list output\n"), out);
411 fputs(_(" --raw use raw --list output format\n"), out);
412 fputs(_(" -J, --json use JSON --list output format\n"), out);
413
414 fputs(USAGE_SEPARATOR, out);
415 fputs(USAGE_HELP, out);
416 fputs(USAGE_VERSION, out);
417
418 fputs(_("\nAvailable --list columns:\n"), out);
419 for (i = 0; i < ARRAY_SIZE(infos); i++)
420 fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help));
421
422 fprintf(out, USAGE_MAN_TAIL("losetup(8)"));
423
424 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
425 }
426
427 static void warn_size(const char *filename, uint64_t size)
428 {
429 struct stat st;
430
431 if (!size) {
432 if (stat(filename, &st) || S_ISBLK(st.st_mode))
433 return;
434 size = st.st_size;
435 }
436
437 if (size < 512)
438 warnx(_("%s: Warning: file is smaller than 512 bytes; the loop device "
439 "may be useless or invisible for system tools."),
440 filename);
441 else if (size % 512)
442 warnx(_("%s: Warning: file does not fit into a 512-byte sector; "
443 "the end of the file will be ignored."),
444 filename);
445 }
446
447 int main(int argc, char **argv)
448 {
449 struct loopdev_cxt lc;
450 int act = 0, flags = 0, c;
451 char *file = NULL;
452 uint64_t offset = 0, sizelimit = 0;
453 int res = 0, showdev = 0, lo_flags = 0;
454 char *outarg = NULL;
455 int list = 0;
456 unsigned long use_dio = 0, set_dio = 0;
457
458 enum {
459 OPT_SIZELIMIT = CHAR_MAX + 1,
460 OPT_SHOW,
461 OPT_RAW,
462 OPT_DIO
463 };
464 static const struct option longopts[] = {
465 { "all", 0, 0, 'a' },
466 { "set-capacity", 1, 0, 'c' },
467 { "detach", 1, 0, 'd' },
468 { "detach-all", 0, 0, 'D' },
469 { "find", 0, 0, 'f' },
470 { "help", 0, 0, 'h' },
471 { "associated", 1, 0, 'j' },
472 { "json", 0, 0, 'J' },
473 { "list", 0, 0, 'l' },
474 { "noheadings", 0, 0, 'n' },
475 { "offset", 1, 0, 'o' },
476 { "output", 1, 0, 'O' },
477 { "sizelimit", 1, 0, OPT_SIZELIMIT },
478 { "partscan", 0, 0, 'P' },
479 { "read-only", 0, 0, 'r' },
480 { "direct-io", 2, 0, OPT_DIO },
481 { "raw", 0, 0, OPT_RAW },
482 { "show", 0, 0, OPT_SHOW },
483 { "verbose", 0, 0, 'v' },
484 { "version", 0, 0, 'V' },
485 { NULL, 0, 0, 0 }
486 };
487
488 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
489 { 'D','a','c','d','f','j' },
490 { 'D','c','d','f','l' },
491 { 'D','c','d','f','O' },
492 { 'J',OPT_RAW },
493 { 0 }
494 };
495 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
496
497 setlocale(LC_ALL, "");
498 bindtextdomain(PACKAGE, LOCALEDIR);
499 textdomain(PACKAGE);
500 atexit(close_stdout);
501
502 if (loopcxt_init(&lc, 0))
503 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
504
505 while ((c = getopt_long(argc, argv, "ac:d:Dfhj:Jlno:O:PrvV",
506 longopts, NULL)) != -1) {
507
508 err_exclusive_options(c, longopts, excl, excl_st);
509
510 switch (c) {
511 case 'a':
512 act = A_SHOW;
513 break;
514 case 'c':
515 act = A_SET_CAPACITY;
516 if (!is_loopdev(optarg) ||
517 loopcxt_set_device(&lc, optarg))
518 err(EXIT_FAILURE, _("%s: failed to use device"),
519 optarg);
520 break;
521 case 'r':
522 lo_flags |= LO_FLAGS_READ_ONLY;
523 break;
524 case 'd':
525 act = A_DELETE;
526 if (!is_loopdev(optarg) ||
527 loopcxt_set_device(&lc, optarg))
528 err(EXIT_FAILURE, _("%s: failed to use device"),
529 optarg);
530 break;
531 case 'D':
532 act = A_DELETE_ALL;
533 break;
534 case 'f':
535 act = A_FIND_FREE;
536 break;
537 case 'h':
538 usage(stdout);
539 break;
540 case 'J':
541 json = 1;
542 break;
543 case 'j':
544 act = A_SHOW;
545 file = optarg;
546 break;
547 case 'l':
548 list = 1;
549 break;
550 case 'n':
551 no_headings = 1;
552 break;
553 case OPT_RAW:
554 raw = 1;
555 break;
556 case 'o':
557 offset = strtosize_or_err(optarg, _("failed to parse offset"));
558 flags |= LOOPDEV_FL_OFFSET;
559 break;
560 case 'O':
561 outarg = optarg;
562 list = 1;
563 break;
564 case 'P':
565 lo_flags |= LO_FLAGS_PARTSCAN;
566 break;
567 case OPT_SHOW:
568 showdev = 1;
569 break;
570 case OPT_DIO:
571 use_dio = set_dio = 1;
572 if (optarg)
573 use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL);
574 break;
575 case 'v':
576 break;
577 case 'V':
578 printf(UTIL_LINUX_VERSION);
579 return EXIT_SUCCESS;
580 case OPT_SIZELIMIT: /* --sizelimit */
581 sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
582 flags |= LOOPDEV_FL_SIZELIMIT;
583 break;
584 default:
585 usage(stderr);
586 }
587 }
588
589 /* default is --list --all */
590 if (argc == 1) {
591 act = A_SHOW;
592 list = 1;
593 }
594
595 if (!act && argc == 2 && (raw || json)) {
596 act = A_SHOW;
597 list = 1;
598 }
599
600 /* default --list output columns */
601 if (list && !ncolumns) {
602 columns[ncolumns++] = COL_NAME;
603 columns[ncolumns++] = COL_SIZELIMIT;
604 columns[ncolumns++] = COL_OFFSET;
605 columns[ncolumns++] = COL_AUTOCLR;
606 columns[ncolumns++] = COL_RO;
607 columns[ncolumns++] = COL_BACK_FILE;
608 columns[ncolumns++] = COL_DIO;
609 }
610
611 if (act == A_FIND_FREE && optind < argc) {
612 /*
613 * losetup -f <backing_file>
614 */
615 act = A_CREATE;
616 file = argv[optind++];
617 }
618
619 if (list && !act && optind == argc)
620 /*
621 * losetup --list defaults to --all
622 */
623 act = A_SHOW;
624
625 if (!act && optind + 1 == argc) {
626 /*
627 * losetup [--list] <device>
628 * OR
629 * losetup --direct-io[=off] <device>
630 */
631 if (!set_dio)
632 act = A_SHOW_ONE;
633 else
634 act = A_SET_DIRECT_IO;
635 if (!is_loopdev(argv[optind]) ||
636 loopcxt_set_device(&lc, argv[optind]))
637 err(EXIT_FAILURE, _("%s: failed to use device"),
638 argv[optind]);
639 optind++;
640 }
641 if (!act) {
642 /*
643 * losetup <loopdev> <backing_file>
644 */
645 act = A_CREATE;
646
647 if (optind >= argc)
648 errx(EXIT_FAILURE, _("no loop device specified"));
649 /* don't use is_loopdev() here, the device does not have exist yet */
650 if (loopcxt_set_device(&lc, argv[optind]))
651 err(EXIT_FAILURE, _("%s: failed to use device"),
652 argv[optind]);
653 optind++;
654
655 if (optind >= argc)
656 errx(EXIT_FAILURE, _("no file specified"));
657 file = argv[optind++];
658 }
659
660 if (act != A_CREATE &&
661 (sizelimit || lo_flags || showdev))
662 errx(EXIT_FAILURE,
663 _("the options %s are allowed during loop device setup only"),
664 "--{sizelimit,read-only,show}");
665
666 if ((flags & LOOPDEV_FL_OFFSET) &&
667 act != A_CREATE && (act != A_SHOW || !file))
668 errx(EXIT_FAILURE, _("the option --offset is not allowed in this context"));
669
670 if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
671 &ncolumns, column_name_to_id) < 0)
672 return EXIT_FAILURE;
673
674 switch (act) {
675 case A_CREATE:
676 {
677 int hasdev = loopcxt_has_device(&lc);
678
679 if (hasdev && !is_loopdev(loopcxt_get_device(&lc)))
680 loopcxt_add_device(&lc);
681 do {
682 const char *errpre;
683
684 /* Note that loopcxt_{find_unused,set_device}() resets
685 * loopcxt struct.
686 */
687 if (!hasdev && (res = loopcxt_find_unused(&lc))) {
688 warnx(_("cannot find an unused loop device"));
689 break;
690 }
691 if (flags & LOOPDEV_FL_OFFSET)
692 loopcxt_set_offset(&lc, offset);
693 if (flags & LOOPDEV_FL_SIZELIMIT)
694 loopcxt_set_sizelimit(&lc, sizelimit);
695 if (lo_flags)
696 loopcxt_set_flags(&lc, lo_flags);
697 if ((res = loopcxt_set_backing_file(&lc, file))) {
698 warn(_("%s: failed to use backing file"), file);
699 break;
700 }
701 errno = 0;
702 res = loopcxt_setup_device(&lc);
703 if (res == 0)
704 break; /* success */
705 if (errno == EBUSY && !hasdev)
706 continue;
707
708 /* errors */
709 errpre = hasdev && loopcxt_get_fd(&lc) < 0 ?
710 loopcxt_get_device(&lc) : file;
711 warn(_("%s: failed to set up loop device"), errpre);
712 break;
713 } while (hasdev == 0);
714
715 if (res == 0) {
716 if (showdev)
717 printf("%s\n", loopcxt_get_device(&lc));
718 warn_size(file, sizelimit);
719 if (set_dio)
720 goto lo_set_dio;
721 }
722 break;
723 }
724 case A_DELETE:
725 res = delete_loop(&lc);
726 while (optind < argc) {
727 if (!is_loopdev(argv[optind]) ||
728 loopcxt_set_device(&lc, argv[optind]))
729 warn(_("%s: failed to use device"),
730 argv[optind]);
731 optind++;
732 res += delete_loop(&lc);
733 }
734 break;
735 case A_DELETE_ALL:
736 res = delete_all_loops(&lc);
737 break;
738 case A_FIND_FREE:
739 res = loopcxt_find_unused(&lc);
740 if (res) {
741 int errsv = errno;
742
743 if (access(_PATH_DEV_LOOPCTL, F_OK) == 0 &&
744 access(_PATH_DEV_LOOPCTL, W_OK) != 0)
745 ;
746 else
747 errno = errsv;
748
749 warn(_("cannot find an unused loop device"));
750 } else
751 printf("%s\n", loopcxt_get_device(&lc));
752 break;
753 case A_SHOW:
754 if (list)
755 res = show_table(&lc, file, offset, flags);
756 else
757 res = show_all_loops(&lc, file, offset, flags);
758 break;
759 case A_SHOW_ONE:
760 if (list)
761 res = show_table(&lc, NULL, 0, 0);
762 else
763 res = printf_loopdev(&lc);
764 if (res)
765 warn("%s", loopcxt_get_device(&lc));
766 break;
767 case A_SET_CAPACITY:
768 res = loopcxt_set_capacity(&lc);
769 if (res)
770 warn(_("%s: set capacity failed"),
771 loopcxt_get_device(&lc));
772 break;
773 case A_SET_DIRECT_IO:
774 lo_set_dio:
775 res = loopcxt_set_dio(&lc, use_dio);
776 if (res)
777 warn(_("%s: set direct io failed"),
778 loopcxt_get_device(&lc));
779 break;
780 default:
781 usage(stderr);
782 break;
783 }
784
785 loopcxt_deinit(&lc);
786 return res ? EXIT_FAILURE : EXIT_SUCCESS;
787 }
788