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