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