]>
Commit | Line | Data |
---|---|---|
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 | 29 | enum { |
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 |
39 | enum { |
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 */ |
53 | static int no_headings; | |
54 | static int raw; | |
896352d3 OO |
55 | |
56 | struct colinfo { | |
57 | const char *name; | |
58 | double whint; | |
59 | int flags; | |
60 | const char *help; | |
61 | }; | |
62 | ||
63 | static 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 | ||
78 | static int columns[NCOLS] = {-1}; | |
79 | static int ncolumns; | |
6dbe3af9 | 80 | |
896352d3 OO |
81 | static 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 | ||
89 | static struct colinfo *get_column_info(int num) | |
90 | { | |
91 | return &infos[ get_column_id(num) ]; | |
92 | } | |
93 | ||
94 | static 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 |
108 | static 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 |
161 | static 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 |
193 | static 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 | ||
203 | static 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 | 217 | static 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 | 290 | static 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 |
356 | done: |
357 | if (rc == 0) | |
358 | rc = scols_print_table(tb); | |
359 | scols_unref_table(tb); | |
360 | return rc; | |
896352d3 OO |
361 | } |
362 | ||
aadb9303 KZ |
363 | static 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 |
411 | static 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 |
431 | int 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 |