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 #include "pathnames.h"
29
30 enum {
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 */
40 };
41
42 enum {
43 COL_NAME = 0,
44 COL_AUTOCLR,
45 COL_BACK_FILE,
46 COL_BACK_INO,
47 COL_BACK_MAJMIN,
48 COL_MAJMIN,
49 COL_OFFSET,
50 COL_PARTSCAN,
51 COL_RO,
52 COL_SIZELIMIT,
53 COL_DIO,
54 COL_LOGSEC,
55 };
56
57 /* basic output flags */
58 static int no_headings;
59 static int raw;
60 static int json;
61
62 struct colinfo {
63 const char *name;
64 double whint;
65 int flags;
66 const char *help;
67
68 int json_type; /* default is string */
69 };
70
71 static struct colinfo infos[] = {
72 [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN},
73 [COL_BACK_FILE] = { "BACK-FILE", 0.3, SCOLS_FL_NOEXTREMES, N_("device backing file")},
74 [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number"), SCOLS_JSON_NUMBER},
75 [COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")},
76 [COL_NAME] = { "NAME", 0.25, 0, N_("loop device name")},
77 [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning"), SCOLS_JSON_NUMBER},
78 [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set"), SCOLS_JSON_BOOLEAN},
79 [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device"), SCOLS_JSON_BOOLEAN},
80 [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes"), SCOLS_JSON_NUMBER},
81 [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")},
82 [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io"), SCOLS_JSON_BOOLEAN},
83 [COL_LOGSEC] = { "LOG-SEC", 4, SCOLS_FL_RIGHT, N_("logical sector size in bytes"), SCOLS_JSON_NUMBER},
84 };
85
86 static int columns[ARRAY_SIZE(infos) * 2] = {-1};
87 static size_t ncolumns;
88
89 static int get_column_id(int num)
90 {
91 assert(num >= 0);
92 assert((size_t) num < ncolumns);
93 assert(columns[num] < (int) ARRAY_SIZE(infos));
94 return columns[num];
95 }
96
97 static struct colinfo *get_column_info(int num)
98 {
99 return &infos[ get_column_id(num) ];
100 }
101
102 static int column_name_to_id(const char *name, size_t namesz)
103 {
104 size_t i;
105
106 for (i = 0; i < ARRAY_SIZE(infos); i++) {
107 const char *cn = infos[i].name;
108
109 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
110 return i;
111 }
112 warnx(_("unknown column: %s"), name);
113 return -1;
114 }
115
116 static int printf_loopdev(struct loopdev_cxt *lc)
117 {
118 uint64_t x;
119 dev_t dev = 0;
120 ino_t ino = 0;
121 char *fname;
122 uint32_t type;
123
124 fname = loopcxt_get_backing_file(lc);
125 if (!fname)
126 return -EINVAL;
127
128 if (loopcxt_get_backing_devno(lc, &dev) == 0)
129 loopcxt_get_backing_inode(lc, &ino);
130
131 if (!dev && !ino) {
132 /*
133 * Probably non-root user (no permissions to
134 * call LOOP_GET_STATUS ioctls).
135 */
136 printf("%s: []: (%s)",
137 loopcxt_get_device(lc), fname);
138
139 if (loopcxt_get_offset(lc, &x) == 0 && x)
140 printf(_(", offset %ju"), x);
141
142 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
143 printf(_(", sizelimit %ju"), x);
144 goto done;
145 }
146
147 printf("%s: [%04jd]:%ju (%s)",
148 loopcxt_get_device(lc), (intmax_t) dev, (uintmax_t) ino, fname);
149
150 if (loopcxt_get_offset(lc, &x) == 0 && x)
151 printf(_(", offset %ju"), x);
152
153 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
154 printf(_(", sizelimit %ju"), x);
155
156 if (loopcxt_get_encrypt_type(lc, &type) == 0) {
157 const char *e = loopcxt_get_crypt_name(lc);
158
159 if ((!e || !*e) && type == 1)
160 e = "XOR";
161 if (e && *e)
162 printf(_(", encryption %s (type %u)"), e, type);
163 }
164
165 done:
166 free(fname);
167 printf("\n");
168 return 0;
169 }
170
171 static int show_all_loops(struct loopdev_cxt *lc, const char *file,
172 uint64_t offset, int flags)
173 {
174 struct stat sbuf, *st = &sbuf;
175 char *cn_file = NULL;
176
177 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
178 return -1;
179
180 if (!file || stat(file, st))
181 st = NULL;
182
183 while (loopcxt_next(lc) == 0) {
184 if (file) {
185 int used;
186 const char *bf = cn_file ? cn_file : file;
187
188 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
189 if (!used && !cn_file) {
190 bf = cn_file = canonicalize_path(file);
191 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
192 }
193 if (!used)
194 continue;
195 }
196 printf_loopdev(lc);
197 }
198 loopcxt_deinit_iterator(lc);
199 free(cn_file);
200 return 0;
201 }
202
203 static int delete_loop(struct loopdev_cxt *lc)
204 {
205 if (loopcxt_delete_device(lc))
206 warn(_("%s: detach failed"), loopcxt_get_device(lc));
207 else
208 return 0;
209
210 return -1;
211 }
212
213 static int delete_all_loops(struct loopdev_cxt *lc)
214 {
215 int res = 0;
216
217 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
218 return -1;
219
220 while (loopcxt_next(lc) == 0)
221 res += delete_loop(lc);
222
223 loopcxt_deinit_iterator(lc);
224 return res;
225 }
226
227 static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln)
228 {
229 size_t i;
230
231 for (i = 0; i < ncolumns; i++) {
232 const char *p = NULL; /* external data */
233 char *np = NULL; /* allocated here */
234 uint64_t x = 0;
235 int rc = 0;
236
237 switch(get_column_id(i)) {
238 case COL_NAME:
239 p = loopcxt_get_device(lc);
240 break;
241 case COL_BACK_FILE:
242 np = loopcxt_get_backing_file(lc);
243 break;
244 case COL_OFFSET:
245 if (loopcxt_get_offset(lc, &x) == 0)
246 xasprintf(&np, "%jd", x);
247 break;
248 case COL_SIZELIMIT:
249 if (loopcxt_get_sizelimit(lc, &x) == 0)
250 xasprintf(&np, "%jd", x);
251 break;
252 case COL_BACK_MAJMIN:
253 {
254 dev_t dev = 0;
255 if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev)
256 xasprintf(&np, "%8u:%-3u", major(dev), minor(dev));
257 break;
258 }
259 case COL_MAJMIN:
260 {
261 struct stat st;
262
263 if (loopcxt_get_device(lc)
264 && stat(loopcxt_get_device(lc), &st) == 0
265 && S_ISBLK(st.st_mode)
266 && major(st.st_rdev) == LOOPDEV_MAJOR)
267 xasprintf(&np, "%3u:%-3u", major(st.st_rdev),
268 minor(st.st_rdev));
269 break;
270 }
271 case COL_BACK_INO:
272 {
273 ino_t ino = 0;
274 if (loopcxt_get_backing_inode(lc, &ino) == 0 && ino)
275 xasprintf(&np, "%ju", ino);
276 break;
277 }
278 case COL_AUTOCLR:
279 p = loopcxt_is_autoclear(lc) ? "1" : "0";
280 break;
281 case COL_RO:
282 p = loopcxt_is_readonly(lc) ? "1" : "0";
283 break;
284 case COL_DIO:
285 p = loopcxt_is_dio(lc) ? "1" : "0";
286 break;
287 case COL_PARTSCAN:
288 p = loopcxt_is_partscan(lc) ? "1" : "0";
289 break;
290 case COL_LOGSEC:
291 if (loopcxt_get_blocksize(lc, &x) == 0)
292 xasprintf(&np, "%jd", x);
293 break;
294 default:
295 return -EINVAL;
296 }
297
298
299 if (p)
300 rc = scols_line_set_data(ln, i, p); /* calls strdup() */
301 else if (np)
302 rc = scols_line_refer_data(ln, i, np); /* only refers */
303
304 if (rc)
305 err(EXIT_FAILURE, _("failed to add output data"));
306 }
307
308 return 0;
309 }
310
311 static int show_table(struct loopdev_cxt *lc,
312 const char *file,
313 uint64_t offset,
314 int flags)
315 {
316 struct stat sbuf, *st = &sbuf;
317 struct libscols_table *tb;
318 struct libscols_line *ln;
319 int rc = 0;
320 size_t i;
321
322 scols_init_debug(0);
323
324 if (!(tb = scols_new_table()))
325 err(EXIT_FAILURE, _("failed to allocate output table"));
326 scols_table_enable_raw(tb, raw);
327 scols_table_enable_json(tb, json);
328 scols_table_enable_noheadings(tb, no_headings);
329
330 if (json)
331 scols_table_set_name(tb, "loopdevices");
332
333 for (i = 0; i < ncolumns; i++) {
334 struct colinfo *ci = get_column_info(i);
335 struct libscols_column *cl;
336
337 cl = scols_table_new_column(tb, ci->name, ci->whint, ci->flags);
338 if (!cl)
339 err(EXIT_FAILURE, _("failed to allocate output column"));
340 if (json)
341 scols_column_set_json_type(cl, ci->json_type);
342 }
343
344 /* only one loopdev requested (already assigned to loopdev_cxt) */
345 if (loopcxt_get_device(lc)) {
346 ln = scols_table_new_line(tb, NULL);
347 if (!ln)
348 err(EXIT_FAILURE, _("failed to allocate output line"));
349 rc = set_scols_data(lc, ln);
350
351 /* list all loopdevs */
352 } else {
353 char *cn_file = NULL;
354
355 rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED);
356 if (rc)
357 goto done;
358 if (!file || stat(file, st))
359 st = NULL;
360
361 while (loopcxt_next(lc) == 0) {
362 if (file) {
363 int used;
364 const char *bf = cn_file ? cn_file : file;
365
366 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
367 if (!used && !cn_file) {
368 bf = cn_file = canonicalize_path(file);
369 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
370 }
371 if (!used)
372 continue;
373 }
374
375 ln = scols_table_new_line(tb, NULL);
376 if (!ln)
377 err(EXIT_FAILURE, _("failed to allocate output line"));
378 rc = set_scols_data(lc, ln);
379 if (rc)
380 break;
381 }
382
383 loopcxt_deinit_iterator(lc);
384 free(cn_file);
385 }
386 done:
387 if (rc == 0)
388 rc = scols_print_table(tb);
389 scols_unref_table(tb);
390 return rc;
391 }
392
393 static void __attribute__((__noreturn__)) usage(void)
394 {
395 FILE *out = stdout;
396 size_t i;
397
398 fputs(USAGE_HEADER, out);
399
400 fprintf(out,
401 _(" %1$s [options] [<loopdev>]\n"
402 " %1$s [options] -f | <loopdev> <file>\n"),
403 program_invocation_short_name);
404
405 fputs(USAGE_SEPARATOR, out);
406 fputs(_("Set up and control loop devices.\n"), out);
407
408 /* commands */
409 fputs(USAGE_OPTIONS, out);
410 fputs(_(" -a, --all list all used devices\n"), out);
411 fputs(_(" -d, --detach <loopdev>... detach one or more devices\n"), out);
412 fputs(_(" -D, --detach-all detach all used devices\n"), out);
413 fputs(_(" -f, --find find first unused device\n"), out);
414 fputs(_(" -c, --set-capacity <loopdev> resize the device\n"), out);
415 fputs(_(" -j, --associated <file> list all devices associated with <file>\n"), out);
416 fputs(_(" -L, --nooverlap avoid possible conflict between devices\n"), out);
417
418 /* commands options */
419 fputs(USAGE_SEPARATOR, out);
420 fputs(_(" -o, --offset <num> start at offset <num> into file\n"), out);
421 fputs(_(" --sizelimit <num> device is limited to <num> bytes of the file\n"), out);
422 fputs(_(" -b, --sector-size <num> set the logical sector size to <num>\n"), out);
423 fputs(_(" -P, --partscan create a partitioned loop device\n"), out);
424 fputs(_(" -r, --read-only set up a read-only loop device\n"), out);
425 fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out);
426 fputs(_(" --show print device name after setup (with -f)\n"), out);
427 fputs(_(" -v, --verbose verbose mode\n"), out);
428
429 /* output options */
430 fputs(USAGE_SEPARATOR, out);
431 fputs(_(" -J, --json use JSON --list output format\n"), out);
432 fputs(_(" -l, --list list info about all or specified (default)\n"), out);
433 fputs(_(" -n, --noheadings don't print headings for --list output\n"), out);
434 fputs(_(" -O, --output <cols> specify columns to output for --list\n"), out);
435 fputs(_(" --output-all output all columns\n"), out);
436 fputs(_(" --raw use raw --list output format\n"), out);
437
438 fputs(USAGE_SEPARATOR, out);
439 printf(USAGE_HELP_OPTIONS(31));
440
441 fputs(USAGE_COLUMNS, out);
442 for (i = 0; i < ARRAY_SIZE(infos); i++)
443 fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help));
444
445 printf(USAGE_MAN_TAIL("losetup(8)"));
446
447 exit(EXIT_SUCCESS);
448 }
449
450 static void warn_size(const char *filename, uint64_t size, uint64_t offset, int flags)
451 {
452 struct stat st;
453
454 if (!size) {
455 if (stat(filename, &st) || S_ISBLK(st.st_mode))
456 return;
457 size = st.st_size;
458
459 if (flags & LOOPDEV_FL_OFFSET)
460 size -= offset;
461 }
462
463 if (size < 512)
464 warnx(_("%s: Warning: file is smaller than 512 bytes; the loop device "
465 "may be useless or invisible for system tools."),
466 filename);
467 else if (size % 512)
468 warnx(_("%s: Warning: file does not fit into a 512-byte sector; "
469 "the end of the file will be ignored."),
470 filename);
471 }
472
473 static int create_loop(struct loopdev_cxt *lc,
474 int nooverlap, int lo_flags, int flags,
475 const char *file, uint64_t offset, uint64_t sizelimit,
476 uint64_t blocksize)
477 {
478 int hasdev = loopcxt_has_device(lc);
479 int rc = 0, ntries = 0;
480
481 /* losetup --find --noverlap file.img */
482 if (!hasdev && nooverlap) {
483 rc = loopcxt_find_overlap(lc, file, offset, sizelimit);
484 switch (rc) {
485 case 0: /* not found */
486 break;
487
488 case 1: /* overlap */
489 loopcxt_deinit(lc);
490 errx(EXIT_FAILURE, _("%s: overlapping loop device exists"), file);
491
492 case 2: /* overlap -- full size and offset match (reuse) */
493 {
494 uint32_t lc_encrypt_type;
495
496 /* Once a loop is initialized RO, there is no
497 * way to change its parameters. */
498 if (loopcxt_is_readonly(lc)
499 && !(lo_flags & LO_FLAGS_READ_ONLY)) {
500 loopcxt_deinit(lc);
501 errx(EXIT_FAILURE, _("%s: overlapping read-only loop device exists"), file);
502 }
503
504 /* This is no more supported, but check to be safe. */
505 if (loopcxt_get_encrypt_type(lc, &lc_encrypt_type) == 0
506 && lc_encrypt_type != LO_CRYPT_NONE) {
507 loopcxt_deinit(lc);
508 errx(EXIT_FAILURE, _("%s: overlapping encrypted loop device exists"), file);
509 }
510
511 lc->config.info.lo_flags &= ~LO_FLAGS_AUTOCLEAR;
512 if (loopcxt_ioctl_status(lc)) {
513 loopcxt_deinit(lc);
514 errx(EXIT_FAILURE, _("%s: failed to re-use loop device"), file);
515 }
516 return 0; /* success, re-use */
517 }
518 default: /* error */
519 loopcxt_deinit(lc);
520 errx(EXIT_FAILURE, _("failed to inspect loop devices"));
521 return -errno;
522 }
523 }
524
525 if (hasdev)
526 loopcxt_add_device(lc);
527
528 /* losetup --noverlap /dev/loopN file.img */
529 if (hasdev && nooverlap) {
530 struct loopdev_cxt lc2;
531
532 if (loopcxt_init(&lc2, 0)) {
533 loopcxt_deinit(lc);
534 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
535 }
536 rc = loopcxt_find_overlap(&lc2, file, offset, sizelimit);
537 loopcxt_deinit(&lc2);
538
539 if (rc) {
540 loopcxt_deinit(lc);
541 if (rc > 0)
542 errx(EXIT_FAILURE, _("%s: overlapping loop device exists"), file);
543 err(EXIT_FAILURE, _("%s: failed to check for conflicting loop devices"), file);
544 }
545 }
546
547 /* Create a new device */
548 do {
549 const char *errpre;
550
551 /* Note that loopcxt_{find_unused,set_device}() resets
552 * loopcxt struct.
553 */
554 if (!hasdev && (rc = loopcxt_find_unused(lc))) {
555 warnx(_("cannot find an unused loop device"));
556 break;
557 }
558 if (flags & LOOPDEV_FL_OFFSET)
559 loopcxt_set_offset(lc, offset);
560 if (flags & LOOPDEV_FL_SIZELIMIT)
561 loopcxt_set_sizelimit(lc, sizelimit);
562 if (lo_flags)
563 loopcxt_set_flags(lc, lo_flags);
564 if (blocksize > 0)
565 loopcxt_set_blocksize(lc, blocksize);
566
567 if ((rc = loopcxt_set_backing_file(lc, file))) {
568 warn(_("%s: failed to use backing file"), file);
569 break;
570 }
571 errno = 0;
572 rc = loopcxt_setup_device(lc);
573 if (rc == 0)
574 break; /* success */
575
576 if ((errno == EBUSY || errno == EAGAIN) && !hasdev && ntries < 64) {
577 xusleep(200000);
578 ntries++;
579 continue;
580 }
581
582 /* errors */
583 errpre = hasdev && loopcxt_get_fd(lc) < 0 ?
584 loopcxt_get_device(lc) : file;
585 warn(_("%s: failed to set up loop device"), errpre);
586 break;
587 } while (hasdev == 0);
588
589 return rc;
590 }
591
592 int main(int argc, char **argv)
593 {
594 struct loopdev_cxt lc;
595 int act = 0, flags = 0, no_overlap = 0, c;
596 char *file = NULL;
597 uint64_t offset = 0, sizelimit = 0, blocksize = 0;
598 int res = 0, showdev = 0, lo_flags = 0;
599 char *outarg = NULL;
600 int list = 0;
601 unsigned long use_dio = 0, set_dio = 0, set_blocksize = 0;
602
603 enum {
604 OPT_SIZELIMIT = CHAR_MAX + 1,
605 OPT_SHOW,
606 OPT_RAW,
607 OPT_DIO,
608 OPT_OUTPUT_ALL
609 };
610 static const struct option longopts[] = {
611 { "all", no_argument, NULL, 'a' },
612 { "set-capacity", required_argument, NULL, 'c' },
613 { "detach", required_argument, NULL, 'd' },
614 { "detach-all", no_argument, NULL, 'D' },
615 { "find", no_argument, NULL, 'f' },
616 { "nooverlap", no_argument, NULL, 'L' },
617 { "help", no_argument, NULL, 'h' },
618 { "associated", required_argument, NULL, 'j' },
619 { "json", no_argument, NULL, 'J' },
620 { "list", no_argument, NULL, 'l' },
621 { "sector-size", required_argument, NULL, 'b' },
622 { "noheadings", no_argument, NULL, 'n' },
623 { "offset", required_argument, NULL, 'o' },
624 { "output", required_argument, NULL, 'O' },
625 { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
626 { "sizelimit", required_argument, NULL, OPT_SIZELIMIT },
627 { "partscan", no_argument, NULL, 'P' },
628 { "read-only", no_argument, NULL, 'r' },
629 { "direct-io", optional_argument, NULL, OPT_DIO },
630 { "raw", no_argument, NULL, OPT_RAW },
631 { "show", no_argument, NULL, OPT_SHOW },
632 { "verbose", no_argument, NULL, 'v' },
633 { "version", no_argument, NULL, 'V' },
634 { NULL, 0, NULL, 0 }
635 };
636
637 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
638 { 'D','a','c','d','f','j' },
639 { 'D','c','d','f','l' },
640 { 'D','c','d','f','O' },
641 { 'J',OPT_RAW },
642 { 0 }
643 };
644 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
645
646 setlocale(LC_ALL, "");
647 bindtextdomain(PACKAGE, LOCALEDIR);
648 textdomain(PACKAGE);
649 close_stdout_atexit();
650
651 if (loopcxt_init(&lc, 0))
652 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
653
654 while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV",
655 longopts, NULL)) != -1) {
656
657 err_exclusive_options(c, longopts, excl, excl_st);
658
659 switch (c) {
660 case 'a':
661 act = A_SHOW;
662 break;
663 case 'b':
664 set_blocksize = 1;
665 blocksize = strtosize_or_err(optarg, _("failed to parse logical block size"));
666 break;
667 case 'c':
668 act = A_SET_CAPACITY;
669 if (!is_loopdev(optarg) ||
670 loopcxt_set_device(&lc, optarg))
671 err(EXIT_FAILURE, _("%s: failed to use device"),
672 optarg);
673 break;
674 case 'r':
675 lo_flags |= LO_FLAGS_READ_ONLY;
676 break;
677 case 'd':
678 act = A_DELETE;
679 if (!is_loopdev(optarg) ||
680 loopcxt_set_device(&lc, optarg))
681 err(EXIT_FAILURE, _("%s: failed to use device"),
682 optarg);
683 break;
684 case 'D':
685 act = A_DELETE_ALL;
686 break;
687 case 'f':
688 act = A_FIND_FREE;
689 break;
690 case 'J':
691 json = 1;
692 break;
693 case 'j':
694 act = A_SHOW;
695 file = optarg;
696 break;
697 case 'l':
698 list = 1;
699 break;
700 case 'L':
701 no_overlap = 1;
702 break;
703 case 'n':
704 no_headings = 1;
705 break;
706 case OPT_RAW:
707 raw = 1;
708 break;
709 case 'o':
710 offset = strtosize_or_err(optarg, _("failed to parse offset"));
711 flags |= LOOPDEV_FL_OFFSET;
712 break;
713 case 'O':
714 outarg = optarg;
715 list = 1;
716 break;
717 case OPT_OUTPUT_ALL:
718 for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
719 columns[ncolumns] = ncolumns;
720 break;
721 case 'P':
722 lo_flags |= LO_FLAGS_PARTSCAN;
723 break;
724 case OPT_SHOW:
725 showdev = 1;
726 break;
727 case OPT_DIO:
728 use_dio = set_dio = 1;
729 if (optarg)
730 use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL);
731 if (use_dio)
732 lo_flags |= LO_FLAGS_DIRECT_IO;
733 break;
734 case 'v':
735 break;
736 case OPT_SIZELIMIT: /* --sizelimit */
737 sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
738 flags |= LOOPDEV_FL_SIZELIMIT;
739 break;
740
741 case 'h':
742 usage();
743 case 'V':
744 print_version(EXIT_SUCCESS);
745 default:
746 errtryhelp(EXIT_FAILURE);
747 }
748 }
749
750 ul_path_init_debug();
751 ul_sysfs_init_debug();
752
753 /* default is --list --all */
754 if (argc == 1) {
755 act = A_SHOW;
756 list = 1;
757 }
758
759 if (!act && argc == 2 && (raw || json)) {
760 act = A_SHOW;
761 list = 1;
762 }
763
764 /* default --list output columns */
765 if (list && !ncolumns) {
766 columns[ncolumns++] = COL_NAME;
767 columns[ncolumns++] = COL_SIZELIMIT;
768 columns[ncolumns++] = COL_OFFSET;
769 columns[ncolumns++] = COL_AUTOCLR;
770 columns[ncolumns++] = COL_RO;
771 columns[ncolumns++] = COL_BACK_FILE;
772 columns[ncolumns++] = COL_DIO;
773 columns[ncolumns++] = COL_LOGSEC;
774 }
775
776 if (act == A_FIND_FREE && optind < argc) {
777 /*
778 * losetup -f <backing_file>
779 */
780 act = A_CREATE;
781 file = argv[optind++];
782
783 if (optind < argc)
784 errx(EXIT_FAILURE, _("unexpected arguments"));
785 }
786
787 if (list && !act && optind == argc)
788 /*
789 * losetup --list defaults to --all
790 */
791 act = A_SHOW;
792
793 if (!act && optind + 1 == argc) {
794 /*
795 * losetup [--list] <device>
796 * OR
797 * losetup {--direct-io[=off]|--logical-blocksize=size}... <device>
798 */
799 if (set_dio) {
800 act = A_SET_DIRECT_IO;
801 lo_flags &= ~LO_FLAGS_DIRECT_IO;
802 } else if (set_blocksize)
803 act = A_SET_BLOCKSIZE;
804 else
805 act = A_SHOW_ONE;
806
807 if (!is_loopdev(argv[optind]) ||
808 loopcxt_set_device(&lc, argv[optind]))
809 err(EXIT_FAILURE, _("%s: failed to use device"),
810 argv[optind]);
811 optind++;
812 }
813 if (!act) {
814 /*
815 * losetup <loopdev> <backing_file>
816 */
817 act = A_CREATE;
818
819 if (optind >= argc)
820 errx(EXIT_FAILURE, _("no loop device specified"));
821 /* don't use is_loopdev() here, the device does not have exist yet */
822 if (loopcxt_set_device(&lc, argv[optind]))
823 err(EXIT_FAILURE, _("%s: failed to use device"),
824 argv[optind]);
825 optind++;
826
827 if (optind >= argc)
828 errx(EXIT_FAILURE, _("no file specified"));
829 file = argv[optind++];
830 }
831
832 if (act != A_CREATE &&
833 (sizelimit || lo_flags || showdev))
834 errx(EXIT_FAILURE,
835 _("the options %s are allowed during loop device setup only"),
836 "--{sizelimit,partscan,read-only,show}");
837
838 if ((flags & LOOPDEV_FL_OFFSET) &&
839 act != A_CREATE && (act != A_SHOW || !file))
840 errx(EXIT_FAILURE, _("the option --offset is not allowed in this context"));
841
842 if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
843 &ncolumns, column_name_to_id) < 0)
844 return EXIT_FAILURE;
845
846 switch (act) {
847 case A_CREATE:
848 res = create_loop(&lc, no_overlap, lo_flags, flags, file,
849 offset, sizelimit, blocksize);
850 if (res == 0) {
851 if (showdev)
852 printf("%s\n", loopcxt_get_device(&lc));
853 warn_size(file, sizelimit, offset, flags);
854 }
855 break;
856 case A_DELETE:
857 res = delete_loop(&lc);
858 while (optind < argc) {
859 if (!is_loopdev(argv[optind]) ||
860 loopcxt_set_device(&lc, argv[optind]))
861 warn(_("%s: failed to use device"),
862 argv[optind]);
863 optind++;
864 res += delete_loop(&lc);
865 }
866 break;
867 case A_DELETE_ALL:
868 res = delete_all_loops(&lc);
869 break;
870 case A_FIND_FREE:
871 res = loopcxt_find_unused(&lc);
872 if (res) {
873 int errsv = errno;
874
875 if (access(_PATH_DEV_LOOPCTL, F_OK) == 0 &&
876 access(_PATH_DEV_LOOPCTL, W_OK) != 0)
877 ;
878 else
879 errno = errsv;
880
881 warn(_("cannot find an unused loop device"));
882 } else
883 printf("%s\n", loopcxt_get_device(&lc));
884 break;
885 case A_SHOW:
886 if (list)
887 res = show_table(&lc, file, offset, flags);
888 else
889 res = show_all_loops(&lc, file, offset, flags);
890 break;
891 case A_SHOW_ONE:
892 if (list)
893 res = show_table(&lc, NULL, 0, 0);
894 else
895 res = printf_loopdev(&lc);
896 if (res)
897 warn("%s", loopcxt_get_device(&lc));
898 break;
899 case A_SET_CAPACITY:
900 res = loopcxt_ioctl_capacity(&lc);
901 if (res)
902 warn(_("%s: set capacity failed"),
903 loopcxt_get_device(&lc));
904 break;
905 case A_SET_DIRECT_IO:
906 res = loopcxt_ioctl_dio(&lc, use_dio);
907 if (res)
908 warn(_("%s: set direct io failed"),
909 loopcxt_get_device(&lc));
910 break;
911 case A_SET_BLOCKSIZE:
912 res = loopcxt_ioctl_blocksize(&lc, blocksize);
913 if (res)
914 warn(_("%s: set logical block size failed"),
915 loopcxt_get_device(&lc));
916 break;
917 default:
918 warnx(_("bad usage"));
919 errtryhelp(EXIT_FAILURE);
920 break;
921 }
922
923 loopcxt_deinit(&lc);
924 return res ? EXIT_FAILURE : EXIT_SUCCESS;
925 }
926