2 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
3 * Originally from Ted's losetup.c
5 * losetup.c - setup and control loop devices
13 #include <sys/ioctl.h>
18 #include <libsmartcols.h>
24 #include "closestream.h"
27 #include "canonicalize.h"
28 #include "pathnames.h"
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 */
57 /* basic output flags */
58 static int no_headings
;
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")},
84 static int columns
[ARRAY_SIZE(infos
) * 2] = {-1};
85 static size_t ncolumns
;
87 static int get_column_id(int num
)
90 assert((size_t) num
< ncolumns
);
91 assert(columns
[num
] < (int) ARRAY_SIZE(infos
));
95 static struct colinfo
*get_column_info(int num
)
97 return &infos
[ get_column_id(num
) ];
100 static int column_name_to_id(const char *name
, size_t namesz
)
104 for (i
= 0; i
< ARRAY_SIZE(infos
); i
++) {
105 const char *cn
= infos
[i
].name
;
107 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
110 warnx(_("unknown column: %s"), name
);
114 static int printf_loopdev(struct loopdev_cxt
*lc
)
122 fname
= loopcxt_get_backing_file(lc
);
126 if (loopcxt_get_backing_devno(lc
, &dev
) == 0)
127 loopcxt_get_backing_inode(lc
, &ino
);
131 * Probably non-root user (no permissions to
132 * call LOOP_GET_STATUS ioctls).
134 printf("%s: []: (%s)",
135 loopcxt_get_device(lc
), fname
);
137 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
138 printf(_(", offset %ju"), x
);
140 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
141 printf(_(", sizelimit %ju"), x
);
146 printf("%s: [%04d]:%" PRIu64
" (%s)",
147 loopcxt_get_device(lc
), (int) dev
, ino
, fname
);
149 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
150 printf(_(", offset %ju"), x
);
152 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
153 printf(_(", sizelimit %ju"), x
);
155 if (loopcxt_get_encrypt_type(lc
, &type
) == 0) {
156 const char *e
= loopcxt_get_crypt_name(lc
);
158 if ((!e
|| !*e
) && type
== 1)
161 printf(_(", encryption %s (type %u)"), e
, type
);
167 static int show_all_loops(struct loopdev_cxt
*lc
, const char *file
,
168 uint64_t offset
, int flags
)
170 struct stat sbuf
, *st
= &sbuf
;
171 char *cn_file
= NULL
;
173 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
176 if (!file
|| stat(file
, st
))
179 while (loopcxt_next(lc
) == 0) {
182 const char *bf
= cn_file
? cn_file
: file
;
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
);
194 loopcxt_deinit_iterator(lc
);
199 static int delete_loop(struct loopdev_cxt
*lc
)
201 if (loopcxt_delete_device(lc
))
202 warn(_("%s: detach failed"), loopcxt_get_device(lc
));
209 static int delete_all_loops(struct loopdev_cxt
*lc
)
213 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
216 while (loopcxt_next(lc
) == 0)
217 res
+= delete_loop(lc
);
219 loopcxt_deinit_iterator(lc
);
223 static int set_scols_data(struct loopdev_cxt
*lc
, struct libscols_line
*ln
)
227 for (i
= 0; i
< ncolumns
; i
++) {
228 const char *p
= NULL
; /* external data */
229 char *np
= NULL
; /* allocated here */
233 switch(get_column_id(i
)) {
235 p
= loopcxt_get_device(lc
);
238 p
= loopcxt_get_backing_file(lc
);
241 if (loopcxt_get_offset(lc
, &x
) == 0)
242 xasprintf(&np
, "%jd", x
);
245 if (loopcxt_get_sizelimit(lc
, &x
) == 0)
246 xasprintf(&np
, "%jd", x
);
248 case COL_BACK_MAJMIN
:
251 if (loopcxt_get_backing_devno(lc
, &dev
) == 0 && dev
)
252 xasprintf(&np
, "%8u:%-3u", major(dev
), minor(dev
));
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
),
270 if (loopcxt_get_backing_inode(lc
, &ino
) == 0 && ino
)
271 xasprintf(&np
, "%ju", ino
);
275 p
= loopcxt_is_autoclear(lc
) ? "1" : "0";
278 p
= loopcxt_is_readonly(lc
) ? "1" : "0";
281 p
= loopcxt_is_dio(lc
) ? "1" : "0";
284 p
= loopcxt_is_partscan(lc
) ? "1" : "0";
287 if (loopcxt_get_blocksize(lc
, &x
) == 0)
288 xasprintf(&np
, "%jd", x
);
296 rc
= scols_line_set_data(ln
, i
, p
); /* calls strdup() */
298 rc
= scols_line_refer_data(ln
, i
, np
); /* only refers */
301 err(EXIT_FAILURE
, _("failed to add output data"));
307 static int show_table(struct loopdev_cxt
*lc
,
312 struct stat sbuf
, *st
= &sbuf
;
313 struct libscols_table
*tb
;
314 struct libscols_line
*ln
;
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
);
327 scols_table_set_name(tb
, "loopdevices");
329 for (i
= 0; i
< ncolumns
; i
++) {
330 struct colinfo
*ci
= get_column_info(i
);
332 if (!scols_table_new_column(tb
, ci
->name
, ci
->whint
, ci
->flags
))
333 err(EXIT_FAILURE
, _("failed to allocate output column"));
336 /* only one loopdev requested (already assigned to loopdev_cxt) */
337 if (loopcxt_get_device(lc
)) {
338 ln
= scols_table_new_line(tb
, NULL
);
340 err(EXIT_FAILURE
, _("failed to allocate output line"));
341 rc
= set_scols_data(lc
, ln
);
343 /* list all loopdevs */
345 char *cn_file
= NULL
;
347 rc
= loopcxt_init_iterator(lc
, LOOPITER_FL_USED
);
350 if (!file
|| stat(file
, st
))
353 while (loopcxt_next(lc
) == 0) {
356 const char *bf
= cn_file
? cn_file
: file
;
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
);
367 ln
= scols_table_new_line(tb
, NULL
);
369 err(EXIT_FAILURE
, _("failed to allocate output line"));
370 rc
= set_scols_data(lc
, ln
);
375 loopcxt_deinit_iterator(lc
);
380 rc
= scols_print_table(tb
);
381 scols_unref_table(tb
);
385 static void __attribute__((__noreturn__
)) usage(void)
390 fputs(USAGE_HEADER
, out
);
393 _(" %1$s [options] [<loopdev>]\n"
394 " %1$s [options] -f | <loopdev> <file>\n"),
395 program_invocation_short_name
);
397 fputs(USAGE_SEPARATOR
, out
);
398 fputs(_("Set up and control loop devices.\n"), out
);
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
);
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
);
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
);
429 fputs(USAGE_SEPARATOR
, out
);
430 printf(USAGE_HELP_OPTIONS(31));
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
));
436 printf(USAGE_MAN_TAIL("losetup(8)"));
441 static void warn_size(const char *filename
, uint64_t size
)
446 if (stat(filename
, &st
) || S_ISBLK(st
.st_mode
))
452 warnx(_("%s: Warning: file is smaller than 512 bytes; the loop device "
453 "may be useless or invisible for system tools."),
456 warnx(_("%s: Warning: file does not fit into a 512-byte sector; "
457 "the end of the file will be ignored."),
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
)
465 int hasdev
= loopcxt_has_device(lc
);
468 /* losetup --find --noverlap file.img */
469 if (!hasdev
&& nooverlap
) {
470 rc
= loopcxt_find_overlap(lc
, file
, offset
, sizelimit
);
472 case 0: /* not found */
475 case 1: /* overlap */
477 errx(EXIT_FAILURE
, _("%s: overlapping loop device exists"), file
);
479 case 2: /* overlap -- full size and offset match (reuse) */
481 uint32_t lc_encrypt_type
;
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
)) {
488 errx(EXIT_FAILURE
, _("%s: overlapping read-only loop device exists"), file
);
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
) {
495 errx(EXIT_FAILURE
, _("%s: overlapping encrypted loop device exists"), file
);
498 lc
->info
.lo_flags
&= ~LO_FLAGS_AUTOCLEAR
;
499 if (loopcxt_set_status(lc
)) {
501 errx(EXIT_FAILURE
, _("%s: failed to re-use loop device"), file
);
503 return 0; /* success, re-use */
507 errx(EXIT_FAILURE
, _("failed to inspect loop devices"));
512 if (hasdev
&& !is_loopdev(loopcxt_get_device(lc
)))
513 loopcxt_add_device(lc
);
515 /* losetup --noverlap /dev/loopN file.img */
516 if (hasdev
&& nooverlap
) {
517 struct loopdev_cxt lc2
;
519 if (loopcxt_init(&lc2
, 0)) {
521 err(EXIT_FAILURE
, _("failed to initialize loopcxt"));
523 rc
= loopcxt_find_overlap(&lc2
, file
, offset
, sizelimit
);
524 loopcxt_deinit(&lc2
);
529 errx(EXIT_FAILURE
, _("%s: overlapping loop device exists"), file
);
530 err(EXIT_FAILURE
, _("%s: failed to check for conflicting loop devices"), file
);
534 /* Create a new device */
538 /* Note that loopcxt_{find_unused,set_device}() resets
541 if (!hasdev
&& (rc
= loopcxt_find_unused(lc
))) {
542 warnx(_("cannot find an unused loop device"));
545 if (flags
& LOOPDEV_FL_OFFSET
)
546 loopcxt_set_offset(lc
, offset
);
547 if (flags
& LOOPDEV_FL_SIZELIMIT
)
548 loopcxt_set_sizelimit(lc
, sizelimit
);
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
);
556 rc
= loopcxt_setup_device(lc
);
559 if (errno
== EBUSY
&& !hasdev
)
563 errpre
= hasdev
&& loopcxt_get_fd(lc
) < 0 ?
564 loopcxt_get_device(lc
) : file
;
565 warn(_("%s: failed to set up loop device"), errpre
);
567 } while (hasdev
== 0);
572 int main(int argc
, char **argv
)
574 struct loopdev_cxt lc
;
575 int act
= 0, flags
= 0, no_overlap
= 0, c
;
577 uint64_t offset
= 0, sizelimit
= 0, blocksize
= 0;
578 int res
= 0, showdev
= 0, lo_flags
= 0;
581 unsigned long use_dio
= 0, set_dio
= 0, set_blocksize
= 0;
584 OPT_SIZELIMIT
= CHAR_MAX
+ 1,
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' },
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' },
622 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
624 setlocale(LC_ALL
, "");
625 bindtextdomain(PACKAGE
, LOCALEDIR
);
627 atexit(close_stdout
);
629 if (loopcxt_init(&lc
, 0))
630 err(EXIT_FAILURE
, _("failed to initialize loopcxt"));
632 while ((c
= getopt_long(argc
, argv
, "ab:c:d:Dfhj:JlLno:O:PrvV",
633 longopts
, NULL
)) != -1) {
635 err_exclusive_options(c
, longopts
, excl
, excl_st
);
643 blocksize
= strtosize_or_err(optarg
, _("failed to parse logical block size"));
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"),
653 lo_flags
|= LO_FLAGS_READ_ONLY
;
657 if (!is_loopdev(optarg
) ||
658 loopcxt_set_device(&lc
, optarg
))
659 err(EXIT_FAILURE
, _("%s: failed to use device"),
691 offset
= strtosize_or_err(optarg
, _("failed to parse offset"));
692 flags
|= LOOPDEV_FL_OFFSET
;
699 lo_flags
|= LO_FLAGS_PARTSCAN
;
705 use_dio
= set_dio
= 1;
707 use_dio
= parse_switch(optarg
, _("argument error"), "on", "off", NULL
);
712 printf(UTIL_LINUX_VERSION
);
714 case OPT_SIZELIMIT
: /* --sizelimit */
715 sizelimit
= strtosize_or_err(optarg
, _("failed to parse size"));
716 flags
|= LOOPDEV_FL_SIZELIMIT
;
719 errtryhelp(EXIT_FAILURE
);
723 /* default is --list --all */
729 if (!act
&& argc
== 2 && (raw
|| json
)) {
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
;
746 if (act
== A_FIND_FREE
&& optind
< argc
) {
748 * losetup -f <backing_file>
751 file
= argv
[optind
++];
754 if (list
&& !act
&& optind
== argc
)
756 * losetup --list defaults to --all
760 if (!act
&& optind
+ 1 == argc
) {
762 * losetup [--list] <device>
764 * losetup {--direct-io[=off]|--logical-blocksize=size}... <device>
766 if (!(set_dio
|| set_blocksize
))
769 act
= A_SET_DIRECT_IO
;
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"),
780 * losetup <loopdev> <backing_file>
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"),
793 errx(EXIT_FAILURE
, _("no file specified"));
794 file
= argv
[optind
++];
797 if (act
!= A_CREATE
&&
798 (sizelimit
|| lo_flags
|| showdev
))
800 _("the options %s are allowed during loop device setup only"),
801 "--{sizelimit,read-only,show}");
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"));
807 if (outarg
&& string_add_to_idarray(outarg
, columns
, ARRAY_SIZE(columns
),
808 &ncolumns
, column_name_to_id
) < 0)
813 res
= create_loop(&lc
, no_overlap
, lo_flags
, flags
, file
, offset
, sizelimit
);
816 printf("%s\n", loopcxt_get_device(&lc
));
817 warn_size(file
, sizelimit
);
818 if (set_dio
|| set_blocksize
)
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"),
830 res
+= delete_loop(&lc
);
834 res
= delete_all_loops(&lc
);
837 res
= loopcxt_find_unused(&lc
);
841 if (access(_PATH_DEV_LOOPCTL
, F_OK
) == 0 &&
842 access(_PATH_DEV_LOOPCTL
, W_OK
) != 0)
847 warn(_("cannot find an unused loop device"));
849 printf("%s\n", loopcxt_get_device(&lc
));
853 res
= show_table(&lc
, file
, offset
, flags
);
855 res
= show_all_loops(&lc
, file
, offset
, flags
);
859 res
= show_table(&lc
, NULL
, 0, 0);
861 res
= printf_loopdev(&lc
);
863 warn("%s", loopcxt_get_device(&lc
));
866 res
= loopcxt_set_capacity(&lc
);
868 warn(_("%s: set capacity failed"),
869 loopcxt_get_device(&lc
));
871 case A_SET_DIRECT_IO
:
872 case A_SET_BLOCKSIZE
:
875 res
= loopcxt_set_dio(&lc
, use_dio
);
877 warn(_("%s: set direct io failed"),
878 loopcxt_get_device(&lc
));
881 res
= loopcxt_set_blocksize(&lc
, blocksize
);
883 warn(_("%s: set logical block size failed"),
884 loopcxt_get_device(&lc
));
888 warnx(_("bad usage"));
889 errtryhelp(EXIT_FAILURE
);
894 return res
? EXIT_FAILURE
: EXIT_SUCCESS
;