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