]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/losetup.c
build-sys: release++ (v2.34)
[thirdparty/util-linux.git] / sys-utils / losetup.c
CommitLineData
6dbe3af9 1/*
39fde137
KZ
2 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
3 * Originally from Ted's losetup.c
4 *
6dbe3af9
KZ
5 * losetup.c - setup and control loop devices
6 */
896352d3 7#include <assert.h>
6dbe3af9
KZ
8#include <stdio.h>
9#include <string.h>
fd6b7a7f 10#include <errno.h>
6dbe3af9
KZ
11#include <stdlib.h>
12#include <unistd.h>
13#include <sys/ioctl.h>
fd6b7a7f 14#include <sys/stat.h>
7711bc17 15#include <inttypes.h>
65329058 16#include <getopt.h>
6dbe3af9 17
7e86cd54
OO
18#include <libsmartcols.h>
19
934df30d 20#include "c.h"
7eda085c 21#include "nls.h"
934df30d 22#include "strutils.h"
de4acb05 23#include "loopdev.h"
efb8854f 24#include "closestream.h"
96801c48 25#include "optutils.h"
896352d3 26#include "xalloc.h"
114ade3d 27#include "canonicalize.h"
362f5d20 28#include "pathnames.h"
96801c48 29
39fde137 30enum {
c7e0925d 31 A_CREATE = 1, /* setup a new device */
c654c4f0
KZ
32 A_DELETE, /* delete given device(s) */
33 A_DELETE_ALL, /* delete all devices */
39fde137 34 A_SHOW, /* list devices */
09ec0c0a 35 A_SHOW_ONE, /* print info about one device */
39fde137
KZ
36 A_FIND_FREE, /* find first unused */
37 A_SET_CAPACITY, /* set device capacity */
64c3bb3c 38 A_SET_DIRECT_IO, /* set accessing backing file by direct io */
a1a41597 39 A_SET_BLOCKSIZE, /* set logical block size of the loop device */
39fde137
KZ
40};
41
896352d3
OO
42enum {
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,
4ad996d7 52 COL_SIZELIMIT,
faeef4d2 53 COL_DIO,
76493ceb 54 COL_LOGSEC,
896352d3
OO
55};
56
7e86cd54
OO
57/* basic output flags */
58static int no_headings;
59static int raw;
4827093d 60static int json;
896352d3
OO
61
62struct colinfo {
63 const char *name;
64 double whint;
65 int flags;
66 const char *help;
46de0fe6
KZ
67
68 int json_type; /* default is string */
896352d3
OO
69};
70
71static struct colinfo infos[] = {
46de0fe6 72 [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN},
896352d3 73 [COL_BACK_FILE] = { "BACK-FILE", 0.3, 0, N_("device backing file")},
46de0fe6 74 [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number"), SCOLS_JSON_NUMBER},
896352d3
OO
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")},
46de0fe6
KZ
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},
896352d3 81 [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")},
46de0fe6
KZ
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},
896352d3
OO
84};
85
d78deddc 86static int columns[ARRAY_SIZE(infos) * 2] = {-1};
40b17508 87static size_t ncolumns;
6dbe3af9 88
896352d3
OO
89static int get_column_id(int num)
90{
40b17508
KZ
91 assert(num >= 0);
92 assert((size_t) num < ncolumns);
d78deddc 93 assert(columns[num] < (int) ARRAY_SIZE(infos));
896352d3
OO
94 return columns[num];
95}
96
97static struct colinfo *get_column_info(int num)
98{
99 return &infos[ get_column_id(num) ];
100}
101
102static int column_name_to_id(const char *name, size_t namesz)
103{
104 size_t i;
105
d78deddc 106 for (i = 0; i < ARRAY_SIZE(infos); i++) {
896352d3
OO
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}
d03dd608 115
39fde137
KZ
116static int printf_loopdev(struct loopdev_cxt *lc)
117{
118 uint64_t x;
119 dev_t dev = 0;
120 ino_t ino = 0;
1b504263 121 char *fname;
a3b421df 122 uint32_t type;
39fde137
KZ
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);
9c6af25c 144 goto done;
39fde137
KZ
145 }
146
147 printf("%s: [%04d]:%" PRIu64 " (%s)",
a3b421df 148 loopcxt_get_device(lc), (int) dev, ino, fname);
39fde137
KZ
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)
a3b421df 162 printf(_(", encryption %s (type %u)"), e, type);
39fde137 163 }
9c6af25c
KZ
164
165done:
166 free(fname);
39fde137
KZ
167 printf("\n");
168 return 0;
169}
170
bc0ac075
KZ
171static int show_all_loops(struct loopdev_cxt *lc, const char *file,
172 uint64_t offset, int flags)
39fde137 173{
bc0ac075 174 struct stat sbuf, *st = &sbuf;
6d62bc0f 175 char *cn_file = NULL;
bc0ac075 176
39fde137 177 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
6e90a44c 178 return -1;
39fde137 179
bc0ac075
KZ
180 if (!file || stat(file, st))
181 st = NULL;
182
183 while (loopcxt_next(lc) == 0) {
6d62bc0f
KZ
184 if (file) {
185 int used;
186 const char *bf = cn_file ? cn_file : file;
187
74a4705a 188 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
6d62bc0f
KZ
189 if (!used && !cn_file) {
190 bf = cn_file = canonicalize_path(file);
74a4705a 191 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
6d62bc0f
KZ
192 }
193 if (!used)
114ade3d
SK
194 continue;
195 }
bc0ac075
KZ
196 printf_loopdev(lc);
197 }
c654c4f0 198 loopcxt_deinit_iterator(lc);
f614b73c 199 free(cn_file);
6e90a44c
KZ
200 return 0;
201}
202
c654c4f0
KZ
203static 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
213static 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;
39fde137
KZ
225}
226
7e86cd54 227static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln)
896352d3 228{
40b17508 229 size_t i;
896352d3
OO
230
231 for (i = 0; i < ncolumns; i++) {
48f1f38b
KZ
232 const char *p = NULL; /* external data */
233 char *np = NULL; /* allocated here */
896352d3 234 uint64_t x = 0;
a9e3ec19 235 int rc = 0;
896352d3
OO
236
237 switch(get_column_id(i)) {
238 case COL_NAME:
239 p = loopcxt_get_device(lc);
896352d3
OO
240 break;
241 case COL_BACK_FILE:
242 p = loopcxt_get_backing_file(lc);
896352d3
OO
243 break;
244 case COL_OFFSET:
245 if (loopcxt_get_offset(lc, &x) == 0)
246 xasprintf(&np, "%jd", x);
896352d3 247 break;
4ad996d7 248 case COL_SIZELIMIT:
896352d3
OO
249 if (loopcxt_get_sizelimit(lc, &x) == 0)
250 xasprintf(&np, "%jd", x);
896352d3
OO
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));
896352d3
OO
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));
896352d3
OO
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);
896352d3
OO
276 break;
277 }
278 case COL_AUTOCLR:
48f1f38b 279 p = loopcxt_is_autoclear(lc) ? "1" : "0";
896352d3
OO
280 break;
281 case COL_RO:
48f1f38b 282 p = loopcxt_is_readonly(lc) ? "1" : "0";
896352d3 283 break;
faeef4d2
ML
284 case COL_DIO:
285 p = loopcxt_is_dio(lc) ? "1" : "0";
286 break;
896352d3 287 case COL_PARTSCAN:
48f1f38b 288 p = loopcxt_is_partscan(lc) ? "1" : "0";
896352d3 289 break;
76493ceb 290 case COL_LOGSEC:
a1a41597
SB
291 if (loopcxt_get_blocksize(lc, &x) == 0)
292 xasprintf(&np, "%jd", x);
293 break;
896352d3
OO
294 default:
295 return -EINVAL;
296 }
48f1f38b
KZ
297
298
299 if (p)
780ce22c 300 rc = scols_line_set_data(ln, i, p); /* calls strdup() */
48f1f38b 301 else if (np)
780ce22c
KZ
302 rc = scols_line_refer_data(ln, i, np); /* only refers */
303
304 if (rc)
305 err(EXIT_FAILURE, _("failed to add output data"));
896352d3 306 }
48f1f38b 307
896352d3
OO
308 return 0;
309}
310
48f1f38b 311static int show_table(struct loopdev_cxt *lc,
9f56106d
KZ
312 const char *file,
313 uint64_t offset,
7e86cd54 314 int flags)
896352d3
OO
315{
316 struct stat sbuf, *st = &sbuf;
48f1f38b 317 struct libscols_table *tb;
7e86cd54 318 struct libscols_line *ln;
40b17508
KZ
319 int rc = 0;
320 size_t i;
896352d3 321
710ed55d
KZ
322 scols_init_debug(0);
323
0925a9dd 324 if (!(tb = scols_new_table()))
780ce22c 325 err(EXIT_FAILURE, _("failed to allocate output table"));
0925a9dd 326 scols_table_enable_raw(tb, raw);
4827093d 327 scols_table_enable_json(tb, json);
0925a9dd 328 scols_table_enable_noheadings(tb, no_headings);
896352d3 329
4827093d
KZ
330 if (json)
331 scols_table_set_name(tb, "loopdevices");
332
e0b06769 333 for (i = 0; i < ncolumns; i++) {
896352d3 334 struct colinfo *ci = get_column_info(i);
46de0fe6 335 struct libscols_column *cl;
896352d3 336
46de0fe6
KZ
337 cl = scols_table_new_column(tb, ci->name, ci->whint, ci->flags);
338 if (!cl)
780ce22c 339 err(EXIT_FAILURE, _("failed to allocate output column"));
46de0fe6
KZ
340 if (json)
341 scols_column_set_json_type(cl, ci->json_type);
896352d3
OO
342 }
343
9f56106d 344 /* only one loopdev requested (already assigned to loopdev_cxt) */
896352d3 345 if (loopcxt_get_device(lc)) {
48f1f38b 346 ln = scols_table_new_line(tb, NULL);
7e86cd54 347 if (!ln)
780ce22c 348 err(EXIT_FAILURE, _("failed to allocate output line"));
48f1f38b 349 rc = set_scols_data(lc, ln);
896352d3 350
9f56106d 351 /* list all loopdevs */
48f1f38b
KZ
352 } else {
353 char *cn_file = NULL;
896352d3 354
48f1f38b
KZ
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;
6d62bc0f 365
74a4705a 366 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
48f1f38b
KZ
367 if (!used && !cn_file) {
368 bf = cn_file = canonicalize_path(file);
74a4705a 369 used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
48f1f38b
KZ
370 }
371 if (!used)
372 continue;
6d62bc0f 373 }
48f1f38b
KZ
374
375 ln = scols_table_new_line(tb, NULL);
376 if (!ln)
780ce22c 377 err(EXIT_FAILURE, _("failed to allocate output line"));
48f1f38b
KZ
378 rc = set_scols_data(lc, ln);
379 if (rc)
380 break;
6d62bc0f 381 }
896352d3 382
48f1f38b
KZ
383 loopcxt_deinit_iterator(lc);
384 free(cn_file);
896352d3 385 }
48f1f38b
KZ
386done:
387 if (rc == 0)
388 rc = scols_print_table(tb);
389 scols_unref_table(tb);
390 return rc;
896352d3
OO
391}
392
6e1eda6f 393static void __attribute__((__noreturn__)) usage(void)
aadb9303 394{
6e1eda6f 395 FILE *out = stdout;
e0b06769
SK
396 size_t i;
397
aadb9303
KZ
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
451dbcfa
BS
405 fputs(USAGE_SEPARATOR, out);
406 fputs(_("Set up and control loop devices.\n"), out);
407
ec3624aa 408 /* commands */
aadb9303 409 fputs(USAGE_OPTIONS, out);
9c47f25e 410 fputs(_(" -a, --all list all used devices\n"), out);
aa06617f 411 fputs(_(" -d, --detach <loopdev>... detach one or more devices\n"), out);
9c47f25e
BS
412 fputs(_(" -D, --detach-all detach all used devices\n"), out);
413 fputs(_(" -f, --find find first unused device\n"), out);
aa06617f 414 fputs(_(" -c, --set-capacity <loopdev> resize the device\n"), out);
9c47f25e 415 fputs(_(" -j, --associated <file> list all devices associated with <file>\n"), out);
9a94b634 416 fputs(_(" -L, --nooverlap avoid possible conflict between devices\n"), out);
9c47f25e 417
ec3624aa 418 /* commands options */
aadb9303 419 fputs(USAGE_SEPARATOR, out);
59a4ed11 420 fputs(_(" -o, --offset <num> start at offset <num> into file\n"), out);
aa06617f 421 fputs(_(" --sizelimit <num> device is limited to <num> bytes of the file\n"), out);
76493ceb 422 fputs(_(" -b --sector-size <num> set the logical sector size to <num>\n"), out);
aa06617f
BS
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);
f98d9641 425 fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out);
59a4ed11
SK
426 fputs(_(" --show print device name after setup (with -f)\n"), out);
427 fputs(_(" -v, --verbose verbose mode\n"), out);
aadb9303 428
ec3624aa 429 /* output options */
9f56106d 430 fputs(USAGE_SEPARATOR, out);
ec3624aa 431 fputs(_(" -J, --json use JSON --list output format\n"), out);
14576644 432 fputs(_(" -l, --list list info about all or specified (default)\n"), out);
0d0d12ad 433 fputs(_(" -n, --noheadings don't print headings for --list output\n"), out);
ec3624aa 434 fputs(_(" -O, --output <cols> specify columns to output for --list\n"), out);
289673b1 435 fputs(_(" --output-all output all columns\n"), out);
9f56106d
KZ
436 fputs(_(" --raw use raw --list output format\n"), out);
437
aadb9303 438 fputs(USAGE_SEPARATOR, out);
f45f3ec3 439 printf(USAGE_HELP_OPTIONS(31));
aadb9303 440
c3a4cfc5 441 fputs(USAGE_COLUMNS, out);
d78deddc 442 for (i = 0; i < ARRAY_SIZE(infos); i++)
896352d3
OO
443 fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help));
444
f45f3ec3 445 printf(USAGE_MAN_TAIL("losetup(8)"));
6997468e 446
6e1eda6f 447 exit(EXIT_SUCCESS);
aadb9303 448}
22853e4a 449
6daf185c 450static void warn_size(const char *filename, uint64_t size, uint64_t offset, int flags)
35545456
KZ
451{
452 struct stat st;
453
454 if (!size) {
b048b8af 455 if (stat(filename, &st) || S_ISBLK(st.st_mode))
35545456
KZ
456 return;
457 size = st.st_size;
6daf185c
KZ
458
459 if (flags & LOOPDEV_FL_OFFSET)
460 size -= offset;
35545456
KZ
461 }
462
463 if (size < 512)
97b820bf
BS
464 warnx(_("%s: Warning: file is smaller than 512 bytes; the loop device "
465 "may be useless or invisible for system tools."),
35545456
KZ
466 filename);
467 else if (size % 512)
97b820bf 468 warnx(_("%s: Warning: file does not fit into a 512-byte sector; "
35545456
KZ
469 "the end of the file will be ignored."),
470 filename);
471}
472
9a94b634
KZ
473static int create_loop(struct loopdev_cxt *lc,
474 int nooverlap, int lo_flags, int flags,
422f0e9f
KZ
475 const char *file, uint64_t offset, uint64_t sizelimit,
476 uint64_t blocksize)
9a94b634
KZ
477{
478 int hasdev = loopcxt_has_device(lc);
479 int rc = 0;
480
d8ba61fc 481 /* losetup --find --noverlap file.img */
9a94b634
KZ
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 }
f27d989c 510
e9aa2a14 511 lc->info.lo_flags &= ~LO_FLAGS_AUTOCLEAR;
9fcc8936 512 if (loopcxt_ioctl_status(lc)) {
f27d989c
SB
513 loopcxt_deinit(lc);
514 errx(EXIT_FAILURE, _("%s: failed to re-use loop device"), file);
515 }
9a94b634
KZ
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 && !is_loopdev(loopcxt_get_device(lc)))
526 loopcxt_add_device(lc);
527
d8ba61fc
KZ
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
9a94b634
KZ
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);
422f0e9f
KZ
564 if (blocksize > 0)
565 loopcxt_set_blocksize(lc, blocksize);
566
9a94b634
KZ
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 if (errno == EBUSY && !hasdev)
576 continue;
577
578 /* errors */
579 errpre = hasdev && loopcxt_get_fd(lc) < 0 ?
580 loopcxt_get_device(lc) : file;
581 warn(_("%s: failed to set up loop device"), errpre);
582 break;
583 } while (hasdev == 0);
584
585 return rc;
586}
587
39fde137
KZ
588int main(int argc, char **argv)
589{
590 struct loopdev_cxt lc;
9a94b634 591 int act = 0, flags = 0, no_overlap = 0, c;
5cf05c71 592 char *file = NULL;
a1a41597 593 uint64_t offset = 0, sizelimit = 0, blocksize = 0;
7e86cd54 594 int res = 0, showdev = 0, lo_flags = 0;
896352d3
OO
595 char *outarg = NULL;
596 int list = 0;
a1a41597 597 unsigned long use_dio = 0, set_dio = 0, set_blocksize = 0;
6c7d5ae9 598
aadb9303
KZ
599 enum {
600 OPT_SIZELIMIT = CHAR_MAX + 1,
9f56106d 601 OPT_SHOW,
64c3bb3c 602 OPT_RAW,
289673b1
SK
603 OPT_DIO,
604 OPT_OUTPUT_ALL
aadb9303
KZ
605 };
606 static const struct option longopts[] = {
87918040
SK
607 { "all", no_argument, NULL, 'a' },
608 { "set-capacity", required_argument, NULL, 'c' },
609 { "detach", required_argument, NULL, 'd' },
610 { "detach-all", no_argument, NULL, 'D' },
611 { "find", no_argument, NULL, 'f' },
612 { "nooverlap", no_argument, NULL, 'L' },
613 { "help", no_argument, NULL, 'h' },
614 { "associated", required_argument, NULL, 'j' },
615 { "json", no_argument, NULL, 'J' },
616 { "list", no_argument, NULL, 'l' },
76493ceb 617 { "sector-size", required_argument, NULL, 'b' },
87918040
SK
618 { "noheadings", no_argument, NULL, 'n' },
619 { "offset", required_argument, NULL, 'o' },
620 { "output", required_argument, NULL, 'O' },
289673b1 621 { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
87918040
SK
622 { "sizelimit", required_argument, NULL, OPT_SIZELIMIT },
623 { "partscan", no_argument, NULL, 'P' },
624 { "read-only", no_argument, NULL, 'r' },
625 { "direct-io", optional_argument, NULL, OPT_DIO },
626 { "raw", no_argument, NULL, OPT_RAW },
627 { "show", no_argument, NULL, OPT_SHOW },
628 { "verbose", no_argument, NULL, 'v' },
629 { "version", no_argument, NULL, 'V' },
630 { NULL, 0, NULL, 0 }
d99f0140 631 };
22853e4a 632
c1ac3144
KZ
633 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
634 { 'D','a','c','d','f','j' },
896352d3 635 { 'D','c','d','f','l' },
65178cb3 636 { 'D','c','d','f','O' },
4827093d 637 { 'J',OPT_RAW },
c1ac3144
KZ
638 { 0 }
639 };
640 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
641
22853e4a
KZ
642 setlocale(LC_ALL, "");
643 bindtextdomain(PACKAGE, LOCALEDIR);
644 textdomain(PACKAGE);
efb8854f 645 atexit(close_stdout);
22853e4a 646
defa0710
KZ
647 if (loopcxt_init(&lc, 0))
648 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
649
a1a41597 650 while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV",
d99f0140 651 longopts, NULL)) != -1) {
c1ac3144
KZ
652
653 err_exclusive_options(c, longopts, excl, excl_st);
654
22853e4a 655 switch (c) {
8b125fae 656 case 'a':
39fde137 657 act = A_SHOW;
8b125fae 658 break;
a1a41597
SB
659 case 'b':
660 set_blocksize = 1;
661 blocksize = strtosize_or_err(optarg, _("failed to parse logical block size"));
662 break;
d34ac93a 663 case 'c':
6e90a44c 664 act = A_SET_CAPACITY;
21ce3f3a
KZ
665 if (!is_loopdev(optarg) ||
666 loopcxt_set_device(&lc, optarg))
defa0710
KZ
667 err(EXIT_FAILURE, _("%s: failed to use device"),
668 optarg);
d34ac93a 669 break;
faf142b6 670 case 'r':
c7e0925d 671 lo_flags |= LO_FLAGS_READ_ONLY;
faf142b6 672 break;
22853e4a 673 case 'd':
c654c4f0 674 act = A_DELETE;
21ce3f3a
KZ
675 if (!is_loopdev(optarg) ||
676 loopcxt_set_device(&lc, optarg))
defa0710
KZ
677 err(EXIT_FAILURE, _("%s: failed to use device"),
678 optarg);
22853e4a 679 break;
34f9b684 680 case 'D':
c654c4f0 681 act = A_DELETE_ALL;
34f9b684 682 break;
d162fcb5 683 case 'f':
bcdbdc72 684 act = A_FIND_FREE;
d162fcb5 685 break;
4827093d
KZ
686 case 'J':
687 json = 1;
688 break;
259fcc57 689 case 'j':
bc0ac075
KZ
690 act = A_SHOW;
691 file = optarg;
259fcc57 692 break;
896352d3
OO
693 case 'l':
694 list = 1;
695 break;
9a94b634
KZ
696 case 'L':
697 no_overlap = 1;
698 break;
9f56106d 699 case 'n':
7e86cd54 700 no_headings = 1;
9f56106d
KZ
701 break;
702 case OPT_RAW:
7e86cd54 703 raw = 1;
9f56106d 704 break;
22853e4a 705 case 'o':
e9e426eb 706 offset = strtosize_or_err(optarg, _("failed to parse offset"));
bc0ac075 707 flags |= LOOPDEV_FL_OFFSET;
22853e4a 708 break;
896352d3
OO
709 case 'O':
710 outarg = optarg;
65178cb3 711 list = 1;
896352d3 712 break;
289673b1
SK
713 case OPT_OUTPUT_ALL:
714 for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
715 columns[ncolumns] = ncolumns;
716 break;
916bf85e
KZ
717 case 'P':
718 lo_flags |= LO_FLAGS_PARTSCAN;
719 break;
aadb9303 720 case OPT_SHOW:
ba3809b0
KZ
721 showdev = 1;
722 break;
64c3bb3c 723 case OPT_DIO:
f98d9641
KZ
724 use_dio = set_dio = 1;
725 if (optarg)
726 use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL);
64c3bb3c 727 break;
22853e4a 728 case 'v':
22853e4a 729 break;
aadb9303 730 case OPT_SIZELIMIT: /* --sizelimit */
e9e426eb 731 sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
c7e0925d 732 flags |= LOOPDEV_FL_SIZELIMIT;
7bcefc7f 733 break;
2c308875
KZ
734
735 case 'h':
736 usage();
737 case 'V':
738 print_version(EXIT_SUCCESS);
22853e4a 739 default:
677ec86c 740 errtryhelp(EXIT_FAILURE);
22853e4a
KZ
741 }
742 }
d162fcb5 743
bcf445fd
KZ
744 ul_path_init_debug();
745 ul_sysfs_init_debug();
746
896352d3
OO
747 /* default is --list --all */
748 if (argc == 1) {
749 act = A_SHOW;
750 list = 1;
751 }
752
4827093d
KZ
753 if (!act && argc == 2 && (raw || json)) {
754 act = A_SHOW;
755 list = 1;
756 }
757
896352d3
OO
758 /* default --list output columns */
759 if (list && !ncolumns) {
760 columns[ncolumns++] = COL_NAME;
4ad996d7 761 columns[ncolumns++] = COL_SIZELIMIT;
896352d3
OO
762 columns[ncolumns++] = COL_OFFSET;
763 columns[ncolumns++] = COL_AUTOCLR;
764 columns[ncolumns++] = COL_RO;
765 columns[ncolumns++] = COL_BACK_FILE;
faeef4d2 766 columns[ncolumns++] = COL_DIO;
76493ceb 767 columns[ncolumns++] = COL_LOGSEC;
896352d3 768 }
39fde137 769
c7e0925d
KZ
770 if (act == A_FIND_FREE && optind < argc) {
771 /*
772 * losetup -f <backing_file>
773 */
774 act = A_CREATE;
775 file = argv[optind++];
c3f5a0f1
KZ
776
777 if (optind < argc)
778 errx(EXIT_FAILURE, _("unexpected arguments"));
c7e0925d 779 }
896352d3
OO
780
781 if (list && !act && optind == argc)
782 /*
783 * losetup --list defaults to --all
784 */
785 act = A_SHOW;
786
09ec0c0a
KZ
787 if (!act && optind + 1 == argc) {
788 /*
896352d3 789 * losetup [--list] <device>
64c3bb3c 790 * OR
a1a41597 791 * losetup {--direct-io[=off]|--logical-blocksize=size}... <device>
09ec0c0a 792 */
a1a41597 793 if (!(set_dio || set_blocksize))
64c3bb3c 794 act = A_SHOW_ONE;
a1a41597 795 if (set_dio)
64c3bb3c 796 act = A_SET_DIRECT_IO;
a1a41597
SB
797 if (set_blocksize)
798 act = A_SET_BLOCKSIZE;
21ce3f3a
KZ
799 if (!is_loopdev(argv[optind]) ||
800 loopcxt_set_device(&lc, argv[optind]))
defa0710
KZ
801 err(EXIT_FAILURE, _("%s: failed to use device"),
802 argv[optind]);
803 optind++;
09ec0c0a 804 }
c7e0925d
KZ
805 if (!act) {
806 /*
807 * losetup <loopdev> <backing_file>
808 */
809 act = A_CREATE;
810
811 if (optind >= argc)
812 errx(EXIT_FAILURE, _("no loop device specified"));
21ce3f3a 813 /* don't use is_loopdev() here, the device does not have exist yet */
defa0710 814 if (loopcxt_set_device(&lc, argv[optind]))
e9e7698e 815 err(EXIT_FAILURE, _("%s: failed to use device"),
defa0710
KZ
816 argv[optind]);
817 optind++;
c7e0925d
KZ
818
819 if (optind >= argc)
820 errx(EXIT_FAILURE, _("no file specified"));
821 file = argv[optind++];
822 }
823
824 if (act != A_CREATE &&
5cf05c71 825 (sizelimit || lo_flags || showdev))
c7e0925d 826 errx(EXIT_FAILURE,
136b23ef 827 _("the options %s are allowed during loop device setup only"),
014e7eb3 828 "--{sizelimit,partscan,read-only,show}");
c7e0925d 829
934df30d
KZ
830 if ((flags & LOOPDEV_FL_OFFSET) &&
831 act != A_CREATE && (act != A_SHOW || !file))
136b23ef 832 errx(EXIT_FAILURE, _("the option --offset is not allowed in this context"));
c654c4f0 833
896352d3
OO
834 if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
835 &ncolumns, column_name_to_id) < 0)
836 return EXIT_FAILURE;
837
39fde137 838 switch (act) {
c7e0925d 839 case A_CREATE:
422f0e9f
KZ
840 res = create_loop(&lc, no_overlap, lo_flags, flags, file,
841 offset, sizelimit, blocksize);
35545456
KZ
842 if (res == 0) {
843 if (showdev)
844 printf("%s\n", loopcxt_get_device(&lc));
6daf185c 845 warn_size(file, sizelimit, offset, flags);
422f0e9f
KZ
846 if (set_dio)
847 goto lo_set_dio;
35545456 848 }
c7e0925d 849 break;
c654c4f0
KZ
850 case A_DELETE:
851 res = delete_loop(&lc);
852 while (optind < argc) {
21ce3f3a
KZ
853 if (!is_loopdev(argv[optind]) ||
854 loopcxt_set_device(&lc, argv[optind]))
defa0710
KZ
855 warn(_("%s: failed to use device"),
856 argv[optind]);
857 optind++;
c654c4f0
KZ
858 res += delete_loop(&lc);
859 }
860 break;
861 case A_DELETE_ALL:
862 res = delete_all_loops(&lc);
863 break;
bcdbdc72 864 case A_FIND_FREE:
3e55659f 865 res = loopcxt_find_unused(&lc);
362f5d20
KZ
866 if (res) {
867 int errsv = errno;
868
869 if (access(_PATH_DEV_LOOPCTL, F_OK) == 0 &&
870 access(_PATH_DEV_LOOPCTL, W_OK) != 0)
871 ;
872 else
873 errno = errsv;
874
136b23ef 875 warn(_("cannot find an unused loop device"));
362f5d20 876 } else
bcdbdc72
KZ
877 printf("%s\n", loopcxt_get_device(&lc));
878 break;
39fde137 879 case A_SHOW:
896352d3 880 if (list)
48f1f38b 881 res = show_table(&lc, file, offset, flags);
896352d3
OO
882 else
883 res = show_all_loops(&lc, file, offset, flags);
bc0ac075 884 break;
09ec0c0a 885 case A_SHOW_ONE:
896352d3 886 if (list)
48f1f38b 887 res = show_table(&lc, NULL, 0, 0);
896352d3
OO
888 else
889 res = printf_loopdev(&lc);
09ec0c0a 890 if (res)
136b23ef 891 warn("%s", loopcxt_get_device(&lc));
09ec0c0a 892 break;
6e90a44c 893 case A_SET_CAPACITY:
9fcc8936 894 res = loopcxt_ioctl_capacity(&lc);
293714c0
JM
895 if (res)
896 warn(_("%s: set capacity failed"),
897 loopcxt_get_device(&lc));
6e90a44c 898 break;
64c3bb3c 899 case A_SET_DIRECT_IO:
422f0e9f
KZ
900lo_set_dio:
901 res = loopcxt_ioctl_dio(&lc, use_dio);
902 if (res)
903 warn(_("%s: set direct io failed"),
904 loopcxt_get_device(&lc));
905 break;
a1a41597 906 case A_SET_BLOCKSIZE:
422f0e9f
KZ
907 res = loopcxt_ioctl_blocksize(&lc, blocksize);
908 if (res)
909 warn(_("%s: set logical block size failed"),
910 loopcxt_get_device(&lc));
64c3bb3c 911 break;
39fde137 912 default:
6e1eda6f
RM
913 warnx(_("bad usage"));
914 errtryhelp(EXIT_FAILURE);
39fde137
KZ
915 break;
916 }
917
918 loopcxt_deinit(&lc);
c7e0925d 919 return res ? EXIT_FAILURE : EXIT_SUCCESS;
22853e4a
KZ
920}
921