]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/losetup.c
translation: unify file open error messages
[thirdparty/util-linux.git] / sys-utils / losetup.c
1 /*
2 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
3 * Originally from Ted's losetup.c
4 *
5 * losetup.c - setup and control loop devices
6 */
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/ioctl.h>
13 #include <sys/stat.h>
14 #include <inttypes.h>
15 #include <getopt.h>
16
17 #include "c.h"
18 #include "nls.h"
19 #include "strutils.h"
20 #include "loopdev.h"
21 #include "xgetpass.h"
22 #include "closestream.h"
23 #include "optutils.h"
24
25 #define EXCL_ERROR "--{all,associated,set-capacity,detach,detach-all,find}"
26
27 enum {
28 A_CREATE = 1, /* setup a new device */
29 A_DELETE, /* delete given device(s) */
30 A_DELETE_ALL, /* delete all devices */
31 A_SHOW, /* list devices */
32 A_SHOW_ONE, /* print info about one device */
33 A_FIND_FREE, /* find first unused */
34 A_SET_CAPACITY, /* set device capacity */
35 };
36
37 static int verbose;
38
39
40 static int printf_loopdev(struct loopdev_cxt *lc)
41 {
42 uint64_t x;
43 dev_t dev = 0;
44 ino_t ino = 0;
45 char *fname = NULL;
46 uint32_t type;
47
48 fname = loopcxt_get_backing_file(lc);
49 if (!fname)
50 return -EINVAL;
51
52 if (loopcxt_get_backing_devno(lc, &dev) == 0)
53 loopcxt_get_backing_inode(lc, &ino);
54
55 if (!dev && !ino) {
56 /*
57 * Probably non-root user (no permissions to
58 * call LOOP_GET_STATUS ioctls).
59 */
60 printf("%s: []: (%s)",
61 loopcxt_get_device(lc), fname);
62
63 if (loopcxt_get_offset(lc, &x) == 0 && x)
64 printf(_(", offset %ju"), x);
65
66 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
67 printf(_(", sizelimit %ju"), x);
68 printf("\n");
69 return 0;
70 }
71
72 printf("%s: [%04d]:%" PRIu64 " (%s)",
73 loopcxt_get_device(lc), (int) dev, ino, fname);
74
75 if (loopcxt_get_offset(lc, &x) == 0 && x)
76 printf(_(", offset %ju"), x);
77
78 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
79 printf(_(", sizelimit %ju"), x);
80
81 if (loopcxt_get_encrypt_type(lc, &type) == 0) {
82 const char *e = loopcxt_get_crypt_name(lc);
83
84 if ((!e || !*e) && type == 1)
85 e = "XOR";
86 if (e && *e)
87 printf(_(", encryption %s (type %u)"), e, type);
88 }
89 printf("\n");
90 return 0;
91 }
92
93 static int show_all_loops(struct loopdev_cxt *lc, const char *file,
94 uint64_t offset, int flags)
95 {
96 struct stat sbuf, *st = &sbuf;
97
98 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
99 return -1;
100
101 if (!file || stat(file, st))
102 st = NULL;
103
104 while (loopcxt_next(lc) == 0) {
105
106 if (file && !loopcxt_is_used(lc, st, file, offset, flags))
107 continue;
108
109 printf_loopdev(lc);
110 }
111 loopcxt_deinit_iterator(lc);
112 return 0;
113 }
114
115 static int set_capacity(struct loopdev_cxt *lc)
116 {
117 int fd = loopcxt_get_fd(lc);
118
119 if (fd < 0)
120 warn(_("cannot open %s"), loopcxt_get_device(lc));
121 else if (ioctl(fd, LOOP_SET_CAPACITY) != 0)
122 warnx(_("%s: set capacity failed"), loopcxt_get_device(lc));
123 else
124 return 0;
125
126 return -1;
127 }
128
129 static int delete_loop(struct loopdev_cxt *lc)
130 {
131 if (loopcxt_delete_device(lc))
132 warn(_("%s: detach failed"), loopcxt_get_device(lc));
133 else
134 return 0;
135
136 return -1;
137 }
138
139 static int delete_all_loops(struct loopdev_cxt *lc)
140 {
141 int res = 0;
142
143 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
144 return -1;
145
146 while (loopcxt_next(lc) == 0)
147 res += delete_loop(lc);
148
149 loopcxt_deinit_iterator(lc);
150 return res;
151 }
152
153 static void usage(FILE *out)
154 {
155 fputs(USAGE_HEADER, out);
156
157 fprintf(out,
158 _(" %1$s [options] [<loopdev>]\n"
159 " %1$s [options] -f | <loopdev> <file>\n"),
160 program_invocation_short_name);
161
162 fputs(USAGE_OPTIONS, out);
163 fputs(_(" -a, --all list all used devices\n"
164 " -d, --detach <loopdev> [...] detach one or more devices\n"
165 " -D, --detach-all detach all used devices\n"
166 " -f, --find find first unused device\n"
167 " -c, --set-capacity <loopdev> resize device\n"
168 " -j, --associated <file> list all devices associated with <file>\n"), out);
169 fputs(USAGE_SEPARATOR, out);
170
171 fputs(_(" -e, --encryption <type> enable encryption with specified <name/num>\n"
172 " -o, --offset <num> start at offset <num> into file\n"
173 " --sizelimit <num> device limited to <num> bytes of the file\n"
174 " -p, --pass-fd <num> read passphrase from file descriptor <num>\n"
175 " -P, --partscan create partitioned loop device\n"
176 " -r, --read-only setup read-only loop device\n"
177 " --show print device name after setup (with -f)\n"
178 " -v, --verbose verbose mode\n"), out);
179
180 fputs(USAGE_SEPARATOR, out);
181 fputs(USAGE_HELP, out);
182 fputs(USAGE_VERSION, out);
183
184 fprintf(out, USAGE_MAN_TAIL("losetup(8)"));
185
186 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
187 }
188
189 static void warn_size(const char *filename, uint64_t size)
190 {
191 struct stat st;
192
193 if (!size) {
194 if (stat(filename, &st))
195 return;
196 size = st.st_size;
197 }
198
199 if (size < 512)
200 warnx(_("%s: warning: file smaller than 512 bytes, the loop device "
201 "maybe be useless or invisible for system tools."),
202 filename);
203 else if (size % 512)
204 warnx(_("%s: warning: file does not fit into a 512-byte sector "
205 "the end of the file will be ignored."),
206 filename);
207 }
208
209 int main(int argc, char **argv)
210 {
211 struct loopdev_cxt lc;
212 int act = 0, flags = 0, passfd = -1, c;
213 char *file = NULL, *encryption = NULL;
214 uint64_t offset = 0, sizelimit = 0;
215 int res = 0, showdev = 0, lo_flags = 0;
216
217 enum {
218 EXCL_NONE,
219 EXCL_ALL,
220 EXCL_ASSOCIATED,
221 EXCL_SET_CAPACITY,
222 EXCL_DETACH,
223 EXCL_DETACH_ALL,
224 EXCL_FIND
225 };
226 int excl_any = EXCL_NONE;
227
228 enum {
229 OPT_SIZELIMIT = CHAR_MAX + 1,
230 OPT_SHOW
231 };
232 static const struct option longopts[] = {
233 { "all", 0, 0, 'a' },
234 { "set-capacity", 1, 0, 'c' },
235 { "detach", 1, 0, 'd' },
236 { "detach-all", 0, 0, 'D' },
237 { "encryption", 1, 0, 'e' },
238 { "find", 0, 0, 'f' },
239 { "help", 0, 0, 'h' },
240 { "associated", 1, 0, 'j' },
241 { "offset", 1, 0, 'o' },
242 { "sizelimit", 1, 0, OPT_SIZELIMIT },
243 { "pass-fd", 1, 0, 'p' },
244 { "partscan", 0, 0, 'P' },
245 { "read-only", 0, 0, 'r' },
246 { "show", 0, 0, OPT_SHOW },
247 { "verbose", 0, 0, 'v' },
248 { "version", 0, 0, 'V' },
249 { NULL, 0, 0, 0 }
250 };
251
252 setlocale(LC_ALL, "");
253 bindtextdomain(PACKAGE, LOCALEDIR);
254 textdomain(PACKAGE);
255 atexit(close_stdout);
256
257 if (loopcxt_init(&lc, 0))
258 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
259
260 loopcxt_enable_debug(&lc, getenv("LOOPDEV_DEBUG") ? TRUE : FALSE);
261
262 while ((c = getopt_long(argc, argv, "ac:d:De:E:fhj:o:p:PrvV",
263 longopts, NULL)) != -1) {
264 switch (c) {
265 case 'a':
266 exclusive_option(&excl_any, EXCL_ALL, EXCL_ERROR);
267 act = A_SHOW;
268 break;
269 case 'c':
270 exclusive_option(&excl_any, EXCL_SET_CAPACITY, EXCL_ERROR);
271 act = A_SET_CAPACITY;
272 if (loopcxt_set_device(&lc, optarg))
273 err(EXIT_FAILURE, _("%s: failed to use device"),
274 optarg);
275 break;
276 case 'r':
277 lo_flags |= LO_FLAGS_READ_ONLY;
278 break;
279 case 'd':
280 exclusive_option(&excl_any, EXCL_DETACH, EXCL_ERROR);
281 act = A_DELETE;
282 if (loopcxt_set_device(&lc, optarg))
283 err(EXIT_FAILURE, _("%s: failed to use device"),
284 optarg);
285 break;
286 case 'D':
287 exclusive_option(&excl_any, EXCL_DETACH_ALL, EXCL_ERROR);
288 act = A_DELETE_ALL;
289 break;
290 case 'E':
291 case 'e':
292 encryption = optarg;
293 break;
294 case 'f':
295 exclusive_option(&excl_any, EXCL_FIND, EXCL_ERROR);
296 act = A_FIND_FREE;
297 break;
298 case 'h':
299 usage(stdout);
300 break;
301 case 'j':
302 exclusive_option(&excl_any, EXCL_ASSOCIATED, EXCL_ERROR);
303 act = A_SHOW;
304 file = optarg;
305 break;
306 case 'o':
307 offset = strtosize_or_err(optarg, _("failed to parse offset"));
308 flags |= LOOPDEV_FL_OFFSET;
309 break;
310 case 'p':
311 passfd = strtou32_or_err(optarg,
312 _("invalid passphrase file descriptor"));
313 break;
314 case 'P':
315 lo_flags |= LO_FLAGS_PARTSCAN;
316 break;
317 case OPT_SHOW:
318 showdev = 1;
319 break;
320 case 'v':
321 verbose = 1;
322 break;
323 case 'V':
324 printf(UTIL_LINUX_VERSION);
325 return EXIT_SUCCESS;
326 case OPT_SIZELIMIT: /* --sizelimit */
327 sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
328 flags |= LOOPDEV_FL_SIZELIMIT;
329 break;
330 default:
331 usage(stderr);
332 }
333 }
334
335 if (argc == 1)
336 usage(stderr);
337
338 if (act == A_FIND_FREE && optind < argc) {
339 /*
340 * losetup -f <backing_file>
341 */
342 act = A_CREATE;
343 file = argv[optind++];
344 }
345 if (!act && optind + 1 == argc) {
346 /*
347 * losetup <device>
348 */
349 act = A_SHOW_ONE;
350 if (loopcxt_set_device(&lc, argv[optind]))
351 err(EXIT_FAILURE, _("%s: failed to use device"),
352 argv[optind]);
353 optind++;
354 }
355 if (!act) {
356 /*
357 * losetup <loopdev> <backing_file>
358 */
359 act = A_CREATE;
360
361 if (optind >= argc)
362 errx(EXIT_FAILURE, _("no loop device specified"));
363 if (loopcxt_set_device(&lc, argv[optind]))
364 err(EXIT_FAILURE, _("%s failed to use device"),
365 argv[optind]);
366 optind++;
367
368 if (optind >= argc)
369 errx(EXIT_FAILURE, _("no file specified"));
370 file = argv[optind++];
371 }
372
373 if (act != A_CREATE &&
374 (encryption || sizelimit || passfd != -1 || lo_flags || showdev))
375 errx(EXIT_FAILURE,
376 _("the options %s are allowed to loop device setup only"),
377 "--{encryption,sizelimit,pass-fd,read-only,show}");
378
379 if ((flags & LOOPDEV_FL_OFFSET) &&
380 act != A_CREATE && (act != A_SHOW || !file))
381 errx(EXIT_FAILURE, _("the option --offset is not allowed in this context."));
382
383 switch (act) {
384 case A_CREATE:
385 {
386 char *pass = NULL;
387 int hasdev = loopcxt_has_device(&lc);
388
389 if (encryption) {
390 #ifdef MCL_FUTURE
391 if(mlockall(MCL_CURRENT | MCL_FUTURE))
392 err(EXIT_FAILURE, _("couldn't lock into memory"));
393 #endif
394 pass = xgetpass(passfd, _("Password: "));
395 }
396 do {
397 /* Note that loopcxt_{find_unused,set_device}() resets
398 * loopcxt struct.
399 */
400 if (!hasdev && (res = loopcxt_find_unused(&lc))) {
401 warnx(_("not found unused device"));
402 break;
403 }
404 if (encryption && pass)
405 loopcxt_set_encryption(&lc, encryption, pass);
406 if (flags & LOOPDEV_FL_OFFSET)
407 loopcxt_set_offset(&lc, offset);
408 if (flags & LOOPDEV_FL_SIZELIMIT)
409 loopcxt_set_sizelimit(&lc, sizelimit);
410 if (lo_flags)
411 loopcxt_set_flags(&lc, lo_flags);
412 if ((res = loopcxt_set_backing_file(&lc, file))) {
413 warn(_("%s: failed to use backing file"), file);
414 break;
415 }
416 errno = 0;
417 res = loopcxt_setup_device(&lc);
418 if (res == 0)
419 break; /* success */
420 if (errno != EBUSY) {
421 warn(_("%s: failed to setup loop device"),
422 hasdev && loopcxt_get_fd(&lc) < 0 ?
423 loopcxt_get_device(&lc) : file);
424 break;
425 }
426 } while (hasdev == 0);
427
428 free(pass);
429
430 if (res == 0) {
431 if (showdev)
432 printf("%s\n", loopcxt_get_device(&lc));
433 warn_size(file, sizelimit);
434 }
435 break;
436 }
437 case A_DELETE:
438 res = delete_loop(&lc);
439 while (optind < argc) {
440 if (loopcxt_set_device(&lc, argv[optind]))
441 warn(_("%s: failed to use device"),
442 argv[optind]);
443 optind++;
444 res += delete_loop(&lc);
445 }
446 break;
447 case A_DELETE_ALL:
448 res = delete_all_loops(&lc);
449 break;
450 case A_FIND_FREE:
451 if (loopcxt_find_unused(&lc))
452 warn(_("find unused loop device failed"));
453 else
454 printf("%s\n", loopcxt_get_device(&lc));
455 break;
456 case A_SHOW:
457 res = show_all_loops(&lc, file, offset, flags);
458 break;
459 case A_SHOW_ONE:
460 res = printf_loopdev(&lc);
461 if (res)
462 warn(_("%s"), loopcxt_get_device(&lc));
463 break;
464 case A_SET_CAPACITY:
465 res = set_capacity(&lc);
466 break;
467 default:
468 usage(stderr);
469 break;
470 }
471
472 loopcxt_deinit(&lc);
473 return res ? EXIT_FAILURE : EXIT_SUCCESS;
474 }
475