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