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