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>
23 #include "closestream.h"
26 #include "canonicalize.h"
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 */
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")},
73 #define NCOLS ARRAY_SIZE(infos)
75 static int columns
[NCOLS
] = {-1};
79 static int get_column_id(int num
)
81 assert(ARRAY_SIZE(columns
) == NCOLS
);
82 assert(num
< ncolumns
);
83 assert(columns
[num
] < (int) NCOLS
);
87 static struct colinfo
*get_column_info(int num
)
89 return &infos
[ get_column_id(num
) ];
92 static int column_name_to_id(const char *name
, size_t namesz
)
96 for (i
= 0; i
< NCOLS
; i
++) {
97 const char *cn
= infos
[i
].name
;
99 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
102 warnx(_("unknown column: %s"), name
);
106 static int printf_loopdev(struct loopdev_cxt
*lc
)
114 fname
= loopcxt_get_backing_file(lc
);
118 if (loopcxt_get_backing_devno(lc
, &dev
) == 0)
119 loopcxt_get_backing_inode(lc
, &ino
);
123 * Probably non-root user (no permissions to
124 * call LOOP_GET_STATUS ioctls).
126 printf("%s: []: (%s)",
127 loopcxt_get_device(lc
), fname
);
129 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
130 printf(_(", offset %ju"), x
);
132 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
133 printf(_(", sizelimit %ju"), x
);
138 printf("%s: [%04d]:%" PRIu64
" (%s)",
139 loopcxt_get_device(lc
), (int) dev
, ino
, fname
);
141 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
142 printf(_(", offset %ju"), x
);
144 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
145 printf(_(", sizelimit %ju"), x
);
147 if (loopcxt_get_encrypt_type(lc
, &type
) == 0) {
148 const char *e
= loopcxt_get_crypt_name(lc
);
150 if ((!e
|| !*e
) && type
== 1)
153 printf(_(", encryption %s (type %u)"), e
, type
);
159 static int show_all_loops(struct loopdev_cxt
*lc
, const char *file
,
160 uint64_t offset
, int flags
)
162 struct stat sbuf
, *st
= &sbuf
;
163 char *cn_file
= NULL
;
165 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
168 if (!file
|| stat(file
, st
))
171 while (loopcxt_next(lc
) == 0) {
174 const char *bf
= cn_file
? cn_file
: file
;
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
);
186 loopcxt_deinit_iterator(lc
);
192 static int delete_loop(struct loopdev_cxt
*lc
)
194 if (loopcxt_delete_device(lc
))
195 warn(_("%s: detach failed"), loopcxt_get_device(lc
));
202 static int delete_all_loops(struct loopdev_cxt
*lc
)
206 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
209 while (loopcxt_next(lc
) == 0)
210 res
+= delete_loop(lc
);
212 loopcxt_deinit_iterator(lc
);
216 static int set_tt_data(struct loopdev_cxt
*lc
, struct tt_line
*ln
)
220 for (i
= 0; i
< ncolumns
; i
++) {
221 const char *p
= NULL
;
225 switch(get_column_id(i
)) {
227 p
= loopcxt_get_device(lc
);
229 tt_line_set_data(ln
, i
, xstrdup(p
));
232 p
= loopcxt_get_backing_file(lc
);
234 tt_line_set_data(ln
, i
, xstrdup(p
));
237 if (loopcxt_get_offset(lc
, &x
) == 0)
238 xasprintf(&np
, "%jd", x
);
240 tt_line_set_data(ln
, i
, np
);
243 if (loopcxt_get_sizelimit(lc
, &x
) == 0)
244 xasprintf(&np
, "%jd", x
);
246 tt_line_set_data(ln
, i
, np
);
248 case COL_BACK_MAJMIN
:
251 if (loopcxt_get_backing_devno(lc
, &dev
) == 0 && dev
)
252 xasprintf(&np
, "%8u:%-3u", major(dev
), minor(dev
));
254 tt_line_set_data(ln
, i
, np
);
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
),
268 tt_line_set_data(ln
, i
, np
);
274 if (loopcxt_get_backing_inode(lc
, &ino
) == 0 && ino
)
275 xasprintf(&np
, "%ju", ino
);
277 tt_line_set_data(ln
, i
, np
);
281 tt_line_set_data(ln
, i
,
282 xstrdup(loopcxt_is_autoclear(lc
) ? "1" : "0"));
285 tt_line_set_data(ln
, i
,
286 xstrdup(loopcxt_is_readonly(lc
) ? "1" : "0"));
289 tt_line_set_data(ln
, i
,
290 xstrdup(loopcxt_is_partscan(lc
) ? "1" : "0"));
299 static int make_table(struct loopdev_cxt
*lc
,
305 struct stat sbuf
, *st
= &sbuf
;
307 char *cn_file
= NULL
;
310 if (!(tt
= tt_new_table(tt_flags
| TT_FL_FREEDATA
)))
311 errx(EXIT_FAILURE
, _("failed to initialize output table"));
313 for (i
= 0; i
< ncolumns
; i
++) {
314 struct colinfo
*ci
= get_column_info(i
);
316 if (!tt_define_column(tt
, ci
->name
, ci
->whint
, ci
->flags
))
317 warn(_("failed to initialize output column"));
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
))
328 /* list all loopdevs */
329 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
331 if (!file
|| stat(file
, st
))
334 while (loopcxt_next(lc
) == 0) {
337 const char *bf
= cn_file
? cn_file
: file
;
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
);
348 ln
= tt_add_line(tt
, NULL
);
349 if (set_tt_data(lc
, ln
))
353 loopcxt_deinit_iterator(lc
);
359 static void usage(FILE *out
)
363 fputs(USAGE_HEADER
, out
);
366 _(" %1$s [options] [<loopdev>]\n"
367 " %1$s [options] -f | <loopdev> <file>\n"),
368 program_invocation_short_name
);
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
);
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
);
386 fputs(USAGE_SEPARATOR
, out
);
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
);
393 fputs(USAGE_SEPARATOR
, out
);
394 fputs(USAGE_HELP
, out
);
395 fputs(USAGE_VERSION
, out
);
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
));
401 fprintf(out
, USAGE_MAN_TAIL("losetup(8)"));
403 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
406 static void warn_size(const char *filename
, uint64_t size
)
411 if (stat(filename
, &st
) || S_ISBLK(st
.st_mode
))
417 warnx(_("%s: Warning: file is smaller than 512 bytes; the loop device "
418 "may be useless or invisible for system tools."),
421 warnx(_("%s: Warning: file does not fit into a 512-byte sector; "
422 "the end of the file will be ignored."),
426 int main(int argc
, char **argv
)
428 struct loopdev_cxt lc
;
429 int act
= 0, flags
= 0, c
;
431 uint64_t offset
= 0, sizelimit
= 0;
432 int res
= 0, showdev
= 0, lo_flags
= 0, tt_flags
= 0;
437 OPT_SIZELIMIT
= CHAR_MAX
+ 1,
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' },
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' },
471 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
473 setlocale(LC_ALL
, "");
474 bindtextdomain(PACKAGE
, LOCALEDIR
);
476 atexit(close_stdout
);
478 if (loopcxt_init(&lc
, 0))
479 err(EXIT_FAILURE
, _("failed to initialize loopcxt"));
481 while ((c
= getopt_long(argc
, argv
, "ac:d:De:E:fhj:lno:O:p:PrvV",
482 longopts
, NULL
)) != -1) {
484 err_exclusive_options(c
, longopts
, excl
, excl_st
);
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"),
498 lo_flags
|= LO_FLAGS_READ_ONLY
;
502 if (!is_loopdev(optarg
) ||
503 loopcxt_set_device(&lc
, optarg
))
504 err(EXIT_FAILURE
, _("%s: failed to use device"),
512 errx(EXIT_FAILURE
, _("encryption not supported, use cryptsetup(8) instead"));
528 tt_flags
|= TT_FL_NOHEADINGS
;
531 tt_flags
|= TT_FL_RAW
;
534 offset
= strtosize_or_err(optarg
, _("failed to parse offset"));
535 flags
|= LOOPDEV_FL_OFFSET
;
542 warn(_("--pass-fd is no longer supported"));
545 lo_flags
|= LO_FLAGS_PARTSCAN
;
554 printf(UTIL_LINUX_VERSION
);
556 case OPT_SIZELIMIT
: /* --sizelimit */
557 sizelimit
= strtosize_or_err(optarg
, _("failed to parse size"));
558 flags
|= LOOPDEV_FL_SIZELIMIT
;
565 /* default is --list --all */
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
;
581 if (act
== A_FIND_FREE
&& optind
< argc
) {
583 * losetup -f <backing_file>
586 file
= argv
[optind
++];
589 if (list
&& !act
&& optind
== argc
)
591 * losetup --list defaults to --all
595 if (!act
&& optind
+ 1 == argc
) {
597 * losetup [--list] <device>
600 if (!is_loopdev(argv
[optind
]) ||
601 loopcxt_set_device(&lc
, argv
[optind
]))
602 err(EXIT_FAILURE
, _("%s: failed to use device"),
608 * losetup <loopdev> <backing_file>
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"),
621 errx(EXIT_FAILURE
, _("no file specified"));
622 file
= argv
[optind
++];
625 if (act
!= A_CREATE
&&
626 (sizelimit
|| lo_flags
|| showdev
))
628 _("the options %s are allowed during loop device setup only"),
629 "--{sizelimit,read-only,show}");
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"));
635 if (outarg
&& string_add_to_idarray(outarg
, columns
, ARRAY_SIZE(columns
),
636 &ncolumns
, column_name_to_id
) < 0)
642 int hasdev
= loopcxt_has_device(&lc
);
644 if (hasdev
&& !is_loopdev(loopcxt_get_device(&lc
)))
645 loopcxt_add_device(&lc
);
649 /* Note that loopcxt_{find_unused,set_device}() resets
652 if (!hasdev
&& (res
= loopcxt_find_unused(&lc
))) {
653 warnx(_("cannot find an unused loop device"));
656 if (flags
& LOOPDEV_FL_OFFSET
)
657 loopcxt_set_offset(&lc
, offset
);
658 if (flags
& LOOPDEV_FL_SIZELIMIT
)
659 loopcxt_set_sizelimit(&lc
, sizelimit
);
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
);
667 res
= loopcxt_setup_device(&lc
);
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
);
680 warn(_("%s: failed to set up loop device"), errpre
);
682 } while (hasdev
== 0);
686 printf("%s\n", loopcxt_get_device(&lc
));
687 warn_size(file
, sizelimit
);
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"),
699 res
+= delete_loop(&lc
);
703 res
= delete_all_loops(&lc
);
706 if (loopcxt_find_unused(&lc
))
707 warn(_("cannot find an unused loop device"));
709 printf("%s\n", loopcxt_get_device(&lc
));
713 res
= make_table(&lc
, file
, offset
, flags
, tt_flags
);
715 res
= show_all_loops(&lc
, file
, offset
, flags
);
719 res
= make_table( &lc
, NULL
, 0, 0, tt_flags
);
721 res
= printf_loopdev(&lc
);
723 warn("%s", loopcxt_get_device(&lc
));
726 res
= loopcxt_set_capacity(&lc
);
728 warn(_("%s: set capacity failed"),
729 loopcxt_get_device(&lc
));
742 return res
? EXIT_FAILURE
: EXIT_SUCCESS
;