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