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