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