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