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