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