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