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