]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/losetup.c
losetup: rewrite -f
[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>
9#include <ctype.h>
10#include <fcntl.h>
fd6b7a7f 11#include <errno.h>
6dbe3af9
KZ
12#include <stdlib.h>
13#include <unistd.h>
14#include <sys/ioctl.h>
fd6b7a7f 15#include <sys/stat.h>
22853e4a 16#include <sys/mman.h>
95f1bdee 17#include <sys/sysmacros.h>
7711bc17 18#include <inttypes.h>
2b326e7c 19#include <dirent.h>
65329058
KZ
20#include <getopt.h>
21#include <stdarg.h>
6dbe3af9 22
8abcf290 23#include "strutils.h"
7eda085c 24#include "nls.h"
edb68d0c 25#include "pathnames.h"
de4acb05 26#include "loopdev.h"
0a719a7c
KZ
27#include "xalloc.h"
28#include "canonicalize.h"
29
39fde137
KZ
30enum {
31 A_CREATE, /* setup a new device */
c654c4f0
KZ
32 A_DELETE, /* delete given device(s) */
33 A_DELETE_ALL, /* delete all devices */
39fde137
KZ
34 A_SHOW, /* list devices */
35 A_FIND_FREE, /* find first unused */
36 A_SET_CAPACITY, /* set device capacity */
37};
38
0a719a7c 39static int verbose;
6dbe3af9 40
259fcc57
KZ
41static int is_associated(int dev, struct stat *file, unsigned long long offset, int isoff);
42
2b326e7c
KZ
43#define LOOPMAJOR 7
44#define NLOOPS_DEFAULT 8 /* /dev/loop[0-7] */
45
46struct looplist {
47 int flag; /* scanning options */
edb68d0c 48 FILE *proc; /* /proc/partitions */
b642d0e0 49 int ncur; /* current position */
edb68d0c
KZ
50 int *minors; /* ary of minor numbers (when scan whole /dev) */
51 int nminors; /* number of items in *minors */
52 char name[128]; /* device name */
2b326e7c
KZ
53 int ct_perm; /* count permission problems */
54 int ct_succ; /* count number of successfully
55 detected devices */
56};
57
58#define LLFLG_USEDONLY (1 << 1) /* return used devices only */
59#define LLFLG_FREEONLY (1 << 2) /* return non-used devices */
60#define LLFLG_DONE (1 << 3) /* all is done */
edb68d0c 61#define LLFLG_PROCFS (1 << 4) /* try to found used devices in /proc/partitions */
2b326e7c
KZ
62#define LLFLG_SUBDIR (1 << 5) /* /dev/loop/N */
63#define LLFLG_DFLT (1 << 6) /* directly try to check default loops */
64
de4acb05
KZ
65#define SETLOOP_RDONLY (1<<0) /* Open loop read-only */
66#define SETLOOP_AUTOCLEAR (1<<1) /* Automatically detach loop on close (2.6.25?) */
67
b61e9390
KZ
68/* TODO: move to lib/sysfs.c */
69static char *loopfile_from_sysfs(const char *device)
70{
71 FILE *f;
72 struct stat st;
73 char buf[PATH_MAX], *res = NULL;
74
75 if (stat(device, &st) || !S_ISBLK(st.st_mode))
76 return NULL;
77
78 snprintf(buf, sizeof(buf), _PATH_SYS_DEVBLOCK "/%d:%d/loop/backing_file",
79 major(st.st_rdev), minor(st.st_rdev));
80
81 f = fopen(buf, "r");
82 if (!f)
83 return NULL;
84
85 if (fgets(buf, sizeof(buf), f)) {
86 size_t sz = strlen(buf);
87 if (sz) {
88 buf[sz - 1] = '\0';
89 res = xstrdup(buf);
90 }
91 }
92
93 fclose(f);
94 return res;
95}
96
db3b5b76
KZ
97char *loopdev_get_loopfile(const char *device)
98{
99 char *res = loopfile_from_sysfs(device);
100
101 if (!res) {
db3b5b76
KZ
102 struct loop_info64 lo64;
103 int fd;
104
105 if ((fd = open(device, O_RDONLY)) < 0)
106 return NULL;
107
108 if (ioctl(fd, LOOP_GET_STATUS64, &lo64) == 0) {
109 lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
110 lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
111 res = xstrdup((char *) lo64.lo_file_name);
112
db3b5b76
KZ
113 }
114 close(fd);
115 }
116 return res;
117}
118
2b326e7c
KZ
119int
120is_loop_device (const char *device) {
121 struct stat st;
122
123 return (stat(device, &st) == 0 &&
124 S_ISBLK(st.st_mode) &&
125 major(st.st_rdev) == LOOPMAJOR);
126}
127
128static int
129is_loop_used(int fd)
130{
846985f7 131 struct loop_info64 li;
fc08b4bb
KZ
132
133 errno = 0;
846985f7 134 if (ioctl (fd, LOOP_GET_STATUS64, &li) < 0 && errno == ENXIO)
fc08b4bb
KZ
135 return 0;
136 return 1;
2b326e7c
KZ
137}
138
b4cbb7b8
KZ
139static int
140is_loopfd_autoclear(int fd)
e84feaec 141{
e84feaec 142 struct loop_info64 lo64;
e84feaec
KZ
143
144 if (ioctl(fd, LOOP_GET_STATUS64, &lo64) == 0) {
145 if (lo64.lo_flags & LO_FLAGS_AUTOCLEAR)
b4cbb7b8 146 return 1;
e84feaec 147
e84feaec 148 }
b4cbb7b8
KZ
149 return 0;
150}
151
152int
153is_loop_autoclear(const char *device)
154{
155 int fd, rc;
156
157 if ((fd = open(device, O_RDONLY)) < 0)
158 return 0;
159 rc = is_loopfd_autoclear(fd);
e84feaec
KZ
160
161 close(fd);
162 return rc;
163}
164
2b326e7c
KZ
165static int
166looplist_open(struct looplist *ll, int flag)
167{
168 struct stat st;
169
170 memset(ll, 0, sizeof(*ll));
171 ll->flag = flag;
2b326e7c
KZ
172 ll->ncur = -1;
173
c74c0daf 174 if (stat(_PATH_DEV, &st) == -1 || (!S_ISDIR(st.st_mode)))
2b326e7c
KZ
175 return -1; /* /dev doesn't exist */
176
c74c0daf 177 if (stat(_PATH_DEV_LOOP, &st) == 0 && S_ISDIR(st.st_mode))
2b326e7c
KZ
178 ll->flag |= LLFLG_SUBDIR; /* /dev/loop/ exists */
179
180 if ((ll->flag & LLFLG_USEDONLY) &&
edb68d0c
KZ
181 stat(_PATH_PROC_PARTITIONS, &st) == 0)
182 ll->flag |= LLFLG_PROCFS; /* try /proc/partitions */
2b326e7c
KZ
183
184 ll->flag |= LLFLG_DFLT; /* required! */
185 return 0;
186}
187
188static void
189looplist_close(struct looplist *ll)
190{
63754e71 191 free(ll->minors);
edb68d0c
KZ
192 if (ll->proc)
193 fclose(ll->proc);
194 ll->minors = NULL;
195 ll->proc = NULL;
2b326e7c
KZ
196 ll->ncur = -1;
197 ll->flag |= LLFLG_DONE;
198}
199
200static int
edb68d0c 201looplist_open_dev(struct looplist *ll, int lnum)
2b326e7c 202{
edb68d0c
KZ
203 struct stat st;
204 int used;
205 int fd;
206
207 /* create a full device path */
208 snprintf(ll->name, sizeof(ll->name),
209 ll->flag & LLFLG_SUBDIR ?
c74c0daf 210 _PATH_DEV_LOOP "/%d" :
14b613f3 211 _PATH_DEV "loop%d",
edb68d0c 212 lnum);
2b326e7c 213
edb68d0c
KZ
214 fd = open(ll->name, O_RDONLY);
215 if (fd == -1) {
216 if (errno == EACCES)
217 ll->ct_perm++;
218 return -1;
219 }
220 if (fstat(fd, &st) == -1)
221 goto error;
222 if (!S_ISBLK(st.st_mode) || major(st.st_rdev) != LOOPMAJOR)
223 goto error;
224
225 ll->ct_succ++;
226
227 /* check if the device is wanted */
2b326e7c 228 if (!(ll->flag & (LLFLG_USEDONLY | LLFLG_FREEONLY)))
edb68d0c 229 return fd;
2b326e7c 230
edb68d0c 231 used = is_loop_used(fd);
2b326e7c 232
edb68d0c
KZ
233 if ((ll->flag & LLFLG_USEDONLY) && used)
234 return fd;
235 if ((ll->flag & LLFLG_FREEONLY) && !used)
236 return fd;
237error:
238 close(fd);
239 return -1;
240}
241
242/* returns <N> from "loop<N>" */
243static int
244name2minor(int hasprefix, const char *name)
245{
246 int n;
247 char *end;
248
249 if (hasprefix) {
250 if (strncmp(name, "loop", 4))
251 return -1;
252 name += 4;
253 }
254 n = strtol(name, &end, 10);
255 if (end && end != name && *end == '\0' && n >= 0)
256 return n;
257 return -1;
258}
259
260static int
261cmpnum(const void *p1, const void *p2)
262{
3c55d914 263 return (*(int *) p1 > *(int *) p2) - (*(int *) p1 < *(int *) p2);
edb68d0c
KZ
264}
265
266/*
267 * The classic scandir() is more expensive and less portable.
b642d0e0 268 * We needn't full loop device names -- minor numbers (loop<N>)
edb68d0c
KZ
269 * are enough.
270 */
271static int
272loop_scandir(const char *dirname, int **ary, int hasprefix)
273{
274 DIR *dir;
275 struct dirent *d;
276 int n, count = 0, arylen = 0;
277
278 if (!dirname || !ary)
279 return -1;
280 dir = opendir(dirname);
281 if (!dir)
282 return -1;
283
284 *ary = NULL;
285
286 while((d = readdir(dir))) {
72f6902e 287 if (d->d_type != DT_BLK && d->d_type != DT_UNKNOWN && d->d_type != DT_LNK)
edb68d0c
KZ
288 continue;
289 n = name2minor(hasprefix, d->d_name);
290 if (n == -1 || n < NLOOPS_DEFAULT)
291 continue;
292 if (count + 1 > arylen) {
9695a7c6
TK
293 int *tmp;
294
edb68d0c 295 arylen += 1;
9695a7c6
TK
296
297 tmp = realloc(*ary, arylen * sizeof(int));
298 if (!tmp) {
299 free(*ary);
edb68d0c 300 return -1;
9695a7c6
TK
301 }
302 *ary = tmp;
edb68d0c
KZ
303 }
304 (*ary)[count++] = n;
305 }
306 if (count)
307 qsort(*ary, count, sizeof(int), cmpnum);
308
309 closedir(dir);
310 return count;
2b326e7c
KZ
311}
312
313static int
314looplist_next(struct looplist *ll)
315{
edb68d0c 316 int fd, n;
2b326e7c
KZ
317
318 if (ll->flag & LLFLG_DONE)
319 return -1;
320
edb68d0c 321 /* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
2b326e7c 322 */
edb68d0c
KZ
323 if (ll->flag & LLFLG_PROCFS) {
324 char buf[BUFSIZ];
2b326e7c 325
edb68d0c
KZ
326 if (!ll->proc)
327 ll->proc = fopen(_PATH_PROC_PARTITIONS, "r");
328
329 while (ll->proc && fgets(buf, sizeof(buf), ll->proc)) {
330 int m;
331 unsigned long long sz;
332 char name[128];
333
334 if (sscanf(buf, " %d %d %llu %128[^\n ]",
335 &m, &n, &sz, name) != 4)
2b326e7c 336 continue;
edb68d0c
KZ
337 if (m != LOOPMAJOR)
338 continue;
65158b10
KZ
339 /* unfortunately, real minor numbers needn't to match
340 * loop<N> device name. We have to follow device name.
341 */
342 n = name2minor(1, name);
edb68d0c
KZ
343 fd = looplist_open_dev(ll, n);
344 if (fd != -1)
345 return fd;
2b326e7c 346 }
2b326e7c
KZ
347 goto done;
348 }
349
edb68d0c 350
2b326e7c
KZ
351 /* B) Classic way, try first eight loop devices (default number
352 * of loop devices). This is enough for 99% of all cases.
353 */
354 if (ll->flag & LLFLG_DFLT) {
355 for (++ll->ncur; ll->ncur < NLOOPS_DEFAULT; ll->ncur++) {
edb68d0c
KZ
356 fd = looplist_open_dev(ll, ll->ncur);
357 if (fd != -1)
358 return fd;
2b326e7c
KZ
359 }
360 ll->flag &= ~LLFLG_DFLT;
2b326e7c
KZ
361 }
362
b642d0e0 363 /* C) the worst possibility, scan all /dev or /dev/loop
2b326e7c 364 */
edb68d0c
KZ
365 if (!ll->minors) {
366 ll->nminors = (ll->flag & LLFLG_SUBDIR) ?
c74c0daf
KZ
367 loop_scandir(_PATH_DEV_LOOP, &ll->minors, 0) :
368 loop_scandir(_PATH_DEV, &ll->minors, 1);
2b326e7c
KZ
369 ll->ncur = -1;
370 }
edb68d0c
KZ
371 for (++ll->ncur; ll->ncur < ll->nminors; ll->ncur++) {
372 fd = looplist_open_dev(ll, ll->minors[ll->ncur]);
373 if (fd != -1)
374 return fd;
2b326e7c 375 }
edb68d0c 376
2b326e7c
KZ
377done:
378 looplist_close(ll);
379 return -1;
380}
381
f4612577
PU
382/* Find loop device associated with given @filename. Used for unmounting loop
383 * device specified by associated backing file.
384 *
385 * returns: 1 no such device/error
386 * 2 more than one loop device associated with @filename
387 * 0 exactly one loop device associated with @filename
388 * (@loopdev points to string containing full device name)
389 */
390int
391find_loopdev_by_backing_file(const char *filename, char **loopdev)
392{
393 struct looplist ll;
394 struct stat filestat;
395 int fd;
396 int devs_n = 0; /* number of loop devices found */
397 char* devname = NULL;
398
399 if (stat(filename, &filestat) == -1) {
400 perror(filename);
401 return 1;
402 }
403
404 if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
0a719a7c 405 warnx(_("/dev directory does not exist."));
f4612577
PU
406 return 1;
407 }
408
409 while((devs_n < 2) && (fd = looplist_next(&ll)) != -1) {
410 if (is_associated(fd, &filestat, 0, 0) == 1) {
411 if (!devname)
412 devname = xstrdup(ll.name);
413 devs_n++;
414 }
415 close(fd);
416 }
417 looplist_close(&ll);
418
419 if (devs_n == 1) {
420 *loopdev = devname;
421 return 0; /* exactly one loopdev */
422 }
423 free(devname);
424 return devs_n ? 2 : 1; /* more loopdevs or error */
425}
426
d34ac93a 427
66ee8158 428static int
2b326e7c 429show_loop_fd(int fd, char *device) {
d03dd608 430 struct loop_info64 loopinfo64;
2b326e7c 431 int errsv;
d03dd608
KZ
432
433 if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) {
434
b61e9390
KZ
435 char *lofile = NULL;
436
d03dd608
KZ
437 loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*';
438 loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0;
439 loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0;
440
b61e9390
KZ
441 /* ioctl has limited buffer for backing file name, since
442 * kernel 2.6.37 the filename is available in sysfs too
443 */
444 if (strlen((char *) loopinfo64.lo_file_name) == LO_NAME_SIZE - 1)
445 lofile = loopfile_from_sysfs(device);
446 if (!lofile)
447 lofile = (char *) loopinfo64.lo_file_name;
448
7711bc17 449 printf("%s: [%04" PRIx64 "]:%" PRIu64 " (%s)",
d03dd608 450 device, loopinfo64.lo_device, loopinfo64.lo_inode,
b61e9390
KZ
451 lofile);
452
453 if (lofile != (char *) loopinfo64.lo_file_name)
454 free(lofile);
d03dd608
KZ
455
456 if (loopinfo64.lo_offset)
7711bc17 457 printf(_(", offset %" PRIu64 ), loopinfo64.lo_offset);
d03dd608
KZ
458
459 if (loopinfo64.lo_sizelimit)
7711bc17 460 printf(_(", sizelimit %" PRIu64 ), loopinfo64.lo_sizelimit);
d03dd608
KZ
461
462 if (loopinfo64.lo_encrypt_type ||
463 loopinfo64.lo_crypt_name[0]) {
830d6af0 464 char *e = (char *)loopinfo64.lo_crypt_name;
d03dd608
KZ
465
466 if (*e == 0 && loopinfo64.lo_encrypt_type == 1)
467 e = "XOR";
7711bc17 468 printf(_(", encryption %s (type %" PRIu32 ")"),
d03dd608
KZ
469 e, loopinfo64.lo_encrypt_type);
470 }
471 printf("\n");
d03dd608 472 return 0;
df1dddf9 473 }
a21409f5 474
d03dd608
KZ
475 errsv = errno;
476 fprintf(stderr, _("loop: can't get info on device %s: %s\n"),
477 device, strerror (errsv));
d03dd608 478 return 1;
6dbe3af9 479}
8b125fae 480
2b326e7c
KZ
481static int
482show_loop(char *device) {
483 int ret, fd;
484
485 if ((fd = open(device, O_RDONLY)) < 0) {
486 int errsv = errno;
487 fprintf(stderr, _("loop: can't open device %s: %s\n"),
488 device, strerror (errsv));
489 return 2;
490 }
491 ret = show_loop_fd(fd, device);
492 close(fd);
493 return ret;
494}
495
496
8b125fae
KZ
497static int
498show_used_loop_devices (void) {
2b326e7c
KZ
499 struct looplist ll;
500 int fd;
8b125fae 501
2b326e7c 502 if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
0a719a7c 503 warnx(_("/dev directory does not exist."));
2b326e7c
KZ
504 return 1;
505 }
506
507 while((fd = looplist_next(&ll)) != -1) {
508 show_loop_fd(fd, ll.name);
509 close(fd);
8b125fae 510 }
2b326e7c 511 looplist_close(&ll);
8b125fae 512
edb68d0c 513 if (!ll.ct_succ && ll.ct_perm) {
0a719a7c 514 warnx(_("no permission to look at /dev/loop%s<N>"),
edb68d0c 515 (ll.flag & LLFLG_SUBDIR) ? "/" : "");
8b125fae
KZ
516 return 1;
517 }
518 return 0;
519}
520
23680772
KZ
521/* check if the loopfile is already associated with the same given
522 * parameters.
523 *
26d51308 524 * returns: 0 unused / error
23680772
KZ
525 * 1 loop device already used
526 */
527static int
259fcc57 528is_associated(int dev, struct stat *file, unsigned long long offset, int isoff)
23680772
KZ
529{
530 struct loop_info64 linfo64;
23680772
KZ
531 int ret = 0;
532
533 if (ioctl(dev, LOOP_GET_STATUS64, &linfo64) == 0) {
534 if (file->st_dev == linfo64.lo_device &&
535 file->st_ino == linfo64.lo_inode &&
259fcc57 536 (isoff == 0 || offset == linfo64.lo_offset))
23680772 537 ret = 1;
26d51308 538
23680772
KZ
539 }
540
26d51308 541 return ret;
23680772
KZ
542}
543
544/* check if the loop file is already used with the same given
545 * parameters. We check for device no, inode and offset.
546 * returns: associated devname or NULL
547 */
548char *
549loopfile_used (const char *filename, unsigned long long offset) {
2b326e7c
KZ
550 struct looplist ll;
551 char *devname = NULL;
552 struct stat filestat;
553 int fd;
23680772
KZ
554
555 if (stat(filename, &filestat) == -1) {
556 perror(filename);
557 return NULL;
558 }
559
2b326e7c 560 if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
0a719a7c 561 warnx(_("/dev directory does not exist."));
2b326e7c
KZ
562 return NULL;
563 }
23680772 564
2b326e7c 565 while((fd = looplist_next(&ll)) != -1) {
259fcc57 566 int res = is_associated(fd, &filestat, offset, 1);
2b326e7c
KZ
567 close(fd);
568 if (res == 1) {
569 devname = xstrdup(ll.name);
570 break;
23680772 571 }
23680772 572 }
2b326e7c
KZ
573 looplist_close(&ll);
574
575 return devname;
23680772
KZ
576}
577
578int
579loopfile_used_with(char *devname, const char *filename, unsigned long long offset)
580{
581 struct stat statbuf;
582 int fd, ret;
583
584 if (!is_loop_device(devname))
585 return 0;
586
26d51308
KZ
587 if (stat(filename, &statbuf) == -1)
588 return 0;
23680772
KZ
589
590 fd = open(devname, O_RDONLY);
26d51308
KZ
591 if (fd == -1)
592 return 0;
23680772 593
26d51308 594 ret = is_associated(fd, &statbuf, offset, 1);
23680772
KZ
595 close(fd);
596 return ret;
597}
598
fd6b7a7f 599char *
22853e4a 600find_unused_loop_device (void) {
2b326e7c
KZ
601 struct looplist ll;
602 char *devname = NULL;
603 int fd;
22853e4a 604
2b326e7c 605 if (looplist_open(&ll, LLFLG_FREEONLY) == -1) {
0a719a7c 606 warnx(_("/dev directory does not exist."));
2b326e7c
KZ
607 return NULL;
608 }
b22550fa 609
2b326e7c
KZ
610 if ((fd = looplist_next(&ll)) != -1) {
611 close(fd);
612 devname = xstrdup(ll.name);
fd6b7a7f 613 }
2b326e7c
KZ
614 looplist_close(&ll);
615 if (devname)
616 return devname;
22853e4a 617
edb68d0c 618 if (!ll.ct_succ && ll.ct_perm)
0a719a7c 619 warnx(_("no permission to look at /dev/loop%s<N>"),
edb68d0c 620 (ll.flag & LLFLG_SUBDIR) ? "/" : "");
2b326e7c 621 else if (ll.ct_succ)
0a719a7c 622 warnx(_("could not find any free loop device"));
2b326e7c 623 else
0a719a7c
KZ
624 warnx(_(
625 "Could not find any loop device. Maybe this kernel "
d03dd608
KZ
626 "does not know\n"
627 " about the loop device? (If so, recompile or "
0a719a7c 628 "`modprobe loop'.)"));
2b326e7c 629 return NULL;
fd6b7a7f 630}
6dbe3af9 631
d03dd608
KZ
632/*
633 * A function to read the passphrase either from the terminal or from
634 * an open file descriptor.
635 */
636static char *
637xgetpass(int pfd, const char *prompt) {
638 char *pass;
639 int buflen, i;
640
641 if (pfd < 0) /* terminal */
642 return getpass(prompt);
643
644 pass = NULL;
645 buflen = 0;
646 for (i=0; ; i++) {
647 if (i >= buflen-1) {
648 /* we're running out of space in the buffer.
649 * Make it bigger: */
650 char *tmppass = pass;
651 buflen += 128;
652 pass = realloc(tmppass, buflen);
653 if (pass == NULL) {
654 /* realloc failed. Stop reading. */
0a719a7c 655 warn(_("Out of memory while reading passphrase"));
d03dd608
KZ
656 pass = tmppass; /* the old buffer hasn't changed */
657 break;
658 }
659 }
d162fcb5
KZ
660 if (read(pfd, pass+i, 1) != 1 ||
661 pass[i] == '\n' || pass[i] == 0)
d03dd608
KZ
662 break;
663 }
d162fcb5 664
d03dd608
KZ
665 if (pass == NULL)
666 return "";
d162fcb5
KZ
667
668 pass[i] = 0;
669 return pass;
d03dd608
KZ
670}
671
672static int
673digits_only(const char *s) {
674 while (*s)
675 if (!isdigit(*s++))
676 return 0;
677 return 1;
678}
679
af17e0d1
KZ
680/*
681 * return codes:
682 * 0 - success
683 * 1 - error
684 * 2 - error (EBUSY)
685 */
6dbe3af9 686int
c129767e 687set_loop(const char *device, const char *file, unsigned long long offset,
7bcefc7f 688 unsigned long long sizelimit, const char *encryption, int pfd, int *options) {
d03dd608 689 struct loop_info64 loopinfo64;
756bfd01 690 int fd, ffd, mode, i;
22853e4a 691 char *pass;
bfdb8be5 692 char *filename;
22853e4a 693
23680772
KZ
694 if (verbose) {
695 char *xdev = loopfile_used(file, offset);
696
697 if (xdev) {
698 printf(_("warning: %s is already associated with %s\n"),
699 file, xdev);
700 free(xdev);
701 }
702 }
703
024e1a4f 704 mode = (*options & SETLOOP_RDONLY) ? O_RDONLY : O_RDWR;
d03dd608 705 if ((ffd = open(file, mode)) < 0) {
bc984ef9
MK
706 if (!(*options & SETLOOP_RDONLY) &&
707 (errno == EROFS || errno == EACCES))
d03dd608 708 ffd = open(file, mode = O_RDONLY);
22853e4a 709 if (ffd < 0) {
d03dd608 710 perror(file);
22853e4a
KZ
711 return 1;
712 }
c268327e
KZ
713 if (verbose)
714 printf(_("warning: %s: is write-protected, using read-only.\n"),
715 file);
024e1a4f 716 *options |= SETLOOP_RDONLY;
22853e4a 717 }
d03dd608 718 if ((fd = open(device, mode)) < 0) {
22853e4a 719 perror (device);
f7858f66 720 close(ffd);
22853e4a
KZ
721 return 1;
722 }
d03dd608
KZ
723 memset(&loopinfo64, 0, sizeof(loopinfo64));
724
0a719a7c 725 if (!(filename = canonicalize_path(file)))
bfdb8be5
KZ
726 filename = (char *) file;
727 xstrncpy((char *)loopinfo64.lo_file_name, filename, LO_NAME_SIZE);
d03dd608
KZ
728
729 if (encryption && *encryption) {
730 if (digits_only(encryption)) {
731 loopinfo64.lo_encrypt_type = atoi(encryption);
732 } else {
733 loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
830d6af0 734 snprintf((char *)loopinfo64.lo_crypt_name, LO_NAME_SIZE,
d03dd608
KZ
735 "%s", encryption);
736 }
22853e4a 737 }
d03dd608
KZ
738
739 loopinfo64.lo_offset = offset;
7bcefc7f 740 loopinfo64.lo_sizelimit = sizelimit;
22853e4a 741
d33279c2 742#ifdef MCL_FUTURE
22853e4a
KZ
743 /*
744 * Oh-oh, sensitive data coming up. Better lock into memory to prevent
745 * passwd etc being swapped out and left somewhere on disk.
746 */
d33279c2
MY
747 if (loopinfo64.lo_encrypt_type != LO_CRYPT_NONE) {
748 if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
749 perror("memlock");
750 fprintf(stderr, _("Couldn't lock into memory, exiting.\n"));
751 exit(1);
752 }
22853e4a
KZ
753 }
754#endif
755
d03dd608 756 switch (loopinfo64.lo_encrypt_type) {
22853e4a 757 case LO_CRYPT_NONE:
d03dd608 758 loopinfo64.lo_encrypt_key_size = 0;
22853e4a
KZ
759 break;
760 case LO_CRYPT_XOR:
d03dd608 761 pass = getpass(_("Password: "));
d162fcb5 762 goto gotpass;
22853e4a 763 default:
d03dd608 764 pass = xgetpass(pfd, _("Password: "));
d162fcb5 765 gotpass:
756bfd01 766 memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE);
830d6af0 767 xstrncpy((char *)loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
756bfd01
KZ
768 memset(pass, 0, strlen(pass));
769 loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE;
22853e4a 770 }
d03dd608
KZ
771
772 if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
0e7cd33e
KZ
773 int rc = 1;
774
95ba33f7
MK
775 if (errno == EBUSY) {
776 if (verbose)
960cf573 777 printf(_("ioctl LOOP_SET_FD failed: %m\n"));
0e7cd33e
KZ
778 rc = 2;
779 } else
95ba33f7 780 perror("ioctl: LOOP_SET_FD");
0e7cd33e
KZ
781
782 close(fd);
783 close(ffd);
bfdb8be5
KZ
784 if (file != filename)
785 free(filename);
0e7cd33e 786 return rc;
22853e4a 787 }
d03dd608
KZ
788 close (ffd);
789
024e1a4f
BI
790 if (*options & SETLOOP_AUTOCLEAR)
791 loopinfo64.lo_flags = LO_FLAGS_AUTOCLEAR;
792
d26aa358 793 i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64);
846985f7
KZ
794 if (i)
795 perror("ioctl: LOOP_SET_STATUS64");
d03dd608 796
b4cbb7b8
KZ
797 if ((*options & SETLOOP_AUTOCLEAR) && !is_loopfd_autoclear(fd))
798 /* kernel doesn't support loop auto-destruction */
799 *options &= ~SETLOOP_AUTOCLEAR;
800
801 memset(&loopinfo64, 0, sizeof(loopinfo64));
024e1a4f 802
d26aa358
KZ
803 if (i) {
804 ioctl (fd, LOOP_CLR_FD, 0);
805 close (fd);
bfdb8be5
KZ
806 if (file != filename)
807 free(filename);
d26aa358
KZ
808 return 1;
809 }
024e1a4f
BI
810
811 /*
b642d0e0 812 * HACK: here we're leaking a file descriptor,
024e1a4f
BI
813 * but mount is a short-lived process anyway.
814 */
815 if (!(*options & SETLOOP_AUTOCLEAR))
816 close (fd);
d26aa358 817
c6455a94 818 if (verbose)
7bcefc7f
SS
819 printf(_("set_loop(%s,%s,%llu,%llu): success\n"),
820 device, filename, offset, sizelimit);
bfdb8be5
KZ
821 if (file != filename)
822 free(filename);
22853e4a 823 return 0;
6dbe3af9
KZ
824}
825
39fde137
KZ
826static int printf_loopdev(struct loopdev_cxt *lc)
827{
828 uint64_t x;
829 dev_t dev = 0;
830 ino_t ino = 0;
831 char *fname = NULL;
832 int type;
833
834 fname = loopcxt_get_backing_file(lc);
835 if (!fname)
836 return -EINVAL;
837
838 if (loopcxt_get_backing_devno(lc, &dev) == 0)
839 loopcxt_get_backing_inode(lc, &ino);
840
841 if (!dev && !ino) {
842 /*
843 * Probably non-root user (no permissions to
844 * call LOOP_GET_STATUS ioctls).
845 */
846 printf("%s: []: (%s)",
847 loopcxt_get_device(lc), fname);
848
849 if (loopcxt_get_offset(lc, &x) == 0 && x)
850 printf(_(", offset %ju"), x);
851
852 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
853 printf(_(", sizelimit %ju"), x);
854 printf("\n");
855 return 0;
856 }
857
858 printf("%s: [%04d]:%" PRIu64 " (%s)",
859 loopcxt_get_device(lc), dev, ino, fname);
860
861 if (loopcxt_get_offset(lc, &x) == 0 && x)
862 printf(_(", offset %ju"), x);
863
864 if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
865 printf(_(", sizelimit %ju"), x);
866
867 if (loopcxt_get_encrypt_type(lc, &type) == 0) {
868 const char *e = loopcxt_get_crypt_name(lc);
869
870 if ((!e || !*e) && type == 1)
871 e = "XOR";
872 if (e && *e)
873 printf(_(", encryption %s (type %ju)"), e, type);
874 }
875 printf("\n");
876 return 0;
877}
878
bc0ac075
KZ
879static int show_all_loops(struct loopdev_cxt *lc, const char *file,
880 uint64_t offset, int flags)
39fde137 881{
bc0ac075
KZ
882 struct stat sbuf, *st = &sbuf;
883
39fde137 884 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
6e90a44c 885 return -1;
39fde137 886
bc0ac075
KZ
887 if (!file || stat(file, st))
888 st = NULL;
889
890 while (loopcxt_next(lc) == 0) {
39fde137 891
bc0ac075
KZ
892 if (file && !loopcxt_is_used(lc, st, file, offset, flags))
893 continue;
894
895 printf_loopdev(lc);
896 }
c654c4f0 897 loopcxt_deinit_iterator(lc);
6e90a44c
KZ
898 return 0;
899}
900
901static int set_capacity(struct loopdev_cxt *lc)
902{
903 int fd = loopcxt_get_fd(lc);
904
905 if (fd < 0)
906 warn(_("%s: open failed"), loopcxt_get_device(lc));
907 else if (ioctl(fd, LOOP_SET_CAPACITY) != 0)
908 warnx(_("%s: set capacity failed"), loopcxt_get_device(lc));
909 else
910 return 0;
911
c654c4f0
KZ
912 return -1;
913}
914
915static int delete_loop(struct loopdev_cxt *lc)
916{
917 if (loopcxt_delete_device(lc))
918 warn(_("%s: detach failed"), loopcxt_get_device(lc));
919 else
920 return 0;
921
922 return -1;
923}
924
925static int delete_all_loops(struct loopdev_cxt *lc)
926{
927 int res = 0;
928
929 if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
930 return -1;
931
932 while (loopcxt_next(lc) == 0)
933 res += delete_loop(lc);
934
935 loopcxt_deinit_iterator(lc);
936 return res;
39fde137
KZ
937}
938
22853e4a 939static void
6997468e
KZ
940usage(FILE *out) {
941
942 fputs(_("\nUsage:\n"), out);
943 fprintf(out,
944 _(" %1$s loop_device give info\n"
945 " %1$s -a | --all list all used\n"
946 " %1$s -d | --detach <loopdev> [<loopdev> ...] delete\n"
34f9b684 947 " %1$s -D | --detach-all delete all used\n"
6997468e
KZ
948 " %1$s -f | --find find unused\n"
949 " %1$s -c | --set-capacity <loopdev> resize\n"
950 " %1$s -j | --associated <file> [-o <num>] list all associated with <file>\n"
951 " %1$s [options] {-f|--find|loopdev} <file> setup\n"),
0a719a7c 952 program_invocation_short_name);
6997468e
KZ
953
954 fputs(_("\nOptions:\n"), out);
955 fputs(_(" -e, --encryption <type> enable data encryption with specified <name/num>\n"
956 " -h, --help this help\n"
957 " -o, --offset <num> start at offset <num> into file\n"
958 " --sizelimit <num> loop limited to only <num> bytes of the file\n"
959 " -p, --pass-fd <num> read passphrase from file descriptor <num>\n"
960 " -r, --read-only setup read-only loop device\n"
961 " --show print device name (with -f <file>)\n"
962 " -v, --verbose verbose mode\n\n"), out);
963
964 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
d99f0140 965 }
22853e4a 966
39fde137
KZ
967int main(int argc, char **argv)
968{
969 struct loopdev_cxt lc;
bc0ac075
KZ
970 int act = 0, flags = 0;
971 char *file = NULL;
972 uint64_t offset = 0;
39fde137 973
bc0ac075 974 char *p, *sizelimit, *encryption, *passfd, *device;
c654c4f0 975 int find, c;
22853e4a 976 int res = 0;
ba3809b0 977 int showdev = 0;
22853e4a 978 int ro = 0;
d03dd608 979 int pfd = -1;
bc0ac075 980 uintmax_t slimit = 0;
6c7d5ae9 981
39fde137
KZ
982 loopcxt_init(&lc, 0);
983 /*loopcxt_enable_debug(&lc, TRUE);*/
984
6c7d5ae9 985 static const struct option longopts[] = {
d99f0140 986 { "all", 0, 0, 'a' },
6e90a44c 987 { "set-capacity", 1, 0, 'c' },
c654c4f0 988 { "detach", 1, 0, 'd' },
34f9b684 989 { "detach-all", 0, 0, 'D' },
d99f0140
KZ
990 { "encryption", 1, 0, 'e' },
991 { "find", 0, 0, 'f' },
992 { "help", 0, 0, 'h' },
259fcc57 993 { "associated", 1, 0, 'j' },
d99f0140 994 { "offset", 1, 0, 'o' },
7bcefc7f 995 { "sizelimit", 1, 0, 128 },
d99f0140
KZ
996 { "pass-fd", 1, 0, 'p' },
997 { "read-only", 0, 0, 'r' },
998 { "show", 0, 0, 's' },
999 { "verbose", 0, 0, 'v' },
1000 { NULL, 0, 0, 0 }
1001 };
22853e4a
KZ
1002
1003 setlocale(LC_ALL, "");
1004 bindtextdomain(PACKAGE, LOCALEDIR);
1005 textdomain(PACKAGE);
1006
c654c4f0 1007 find = 0;
bc0ac075 1008 sizelimit = encryption = passfd = NULL;
d162fcb5 1009
c654c4f0 1010 while ((c = getopt_long(argc, argv, "ac:d:De:E:fhj:o:p:rsv",
d99f0140 1011 longopts, NULL)) != -1) {
39fde137 1012
bc0ac075 1013 if (act && strchr("acdDfj", c))
39fde137
KZ
1014 errx(EXIT_FAILURE,
1015 _("the options %s are mutually exclusive"),
bc0ac075 1016 "--{all,associated,set-capacity,detach,detach-all,find}");
39fde137 1017
22853e4a 1018 switch (c) {
8b125fae 1019 case 'a':
39fde137 1020 act = A_SHOW;
8b125fae 1021 break;
d34ac93a 1022 case 'c':
6e90a44c
KZ
1023 act = A_SET_CAPACITY;
1024 loopcxt_set_device(&lc, optarg);
d34ac93a 1025 break;
faf142b6
KZ
1026 case 'r':
1027 ro = 1;
1028 break;
22853e4a 1029 case 'd':
c654c4f0
KZ
1030 act = A_DELETE;
1031 loopcxt_set_device(&lc, optarg);
22853e4a 1032 break;
34f9b684 1033 case 'D':
c654c4f0 1034 act = A_DELETE_ALL;
34f9b684 1035 break;
d03dd608 1036 case 'E':
22853e4a
KZ
1037 case 'e':
1038 encryption = optarg;
1039 break;
d162fcb5 1040 case 'f':
bcdbdc72 1041 act = A_FIND_FREE;
d162fcb5
KZ
1042 find = 1;
1043 break;
108591d2
KZ
1044 case 'h':
1045 usage(stdout);
1046 break;
259fcc57 1047 case 'j':
bc0ac075
KZ
1048 act = A_SHOW;
1049 file = optarg;
259fcc57 1050 break;
22853e4a 1051 case 'o':
bc0ac075
KZ
1052 if (strtosize(optarg, &offset))
1053 errx(EXIT_FAILURE,
1054 _("invalid offset '%s' specified"), optarg);
1055 flags |= LOOPDEV_FL_OFFSET;
22853e4a 1056 break;
d03dd608
KZ
1057 case 'p':
1058 passfd = optarg;
1059 break;
ba3809b0
KZ
1060 case 's':
1061 showdev = 1;
1062 break;
22853e4a
KZ
1063 case 'v':
1064 verbose = 1;
1065 break;
7bcefc7f
SS
1066
1067 case 128: /* --sizelimit */
1068 sizelimit = optarg;
1069 break;
1070
22853e4a 1071 default:
108591d2 1072 usage(stderr);
22853e4a
KZ
1073 }
1074 }
d162fcb5 1075
39fde137 1076 if (argc == 1)
108591d2 1077 usage(stderr);
39fde137 1078
c654c4f0 1079
39fde137 1080 switch (act) {
c654c4f0
KZ
1081 case A_DELETE:
1082 res = delete_loop(&lc);
1083 while (optind < argc) {
1084 loopcxt_set_device(&lc, argv[optind++]);
1085 res += delete_loop(&lc);
1086 }
1087 break;
1088 case A_DELETE_ALL:
1089 res = delete_all_loops(&lc);
1090 break;
bcdbdc72
KZ
1091 case A_FIND_FREE:
1092 if (loopcxt_find_unused(&lc))
1093 warn(_("find unused loop device failed"));
1094 else
1095 printf("%s\n", loopcxt_get_device(&lc));
1096 break;
39fde137 1097 case A_SHOW:
bc0ac075
KZ
1098 res = show_all_loops(&lc, file, offset, flags);
1099 break;
6e90a44c
KZ
1100 case A_SET_CAPACITY:
1101 res = set_capacity(&lc);
1102 break;
39fde137
KZ
1103 default:
1104 break;
1105 }
1106
1107 loopcxt_deinit(&lc);
1108
1109 if (act)
6e90a44c 1110 return res ? EXIT_FAILURE : EXIT_SUCCESS;
39fde137 1111
c654c4f0 1112 if (find) {
6e90a44c 1113 if ( argc < optind || argc > optind+1)
108591d2 1114 usage(stderr);
d162fcb5
KZ
1115 } else {
1116 if (argc < optind+1 || argc > optind+2)
108591d2 1117 usage(stderr);
d162fcb5
KZ
1118 }
1119
ca1e1363 1120 if (sizelimit && strtosize(sizelimit, &slimit)) {
0a719a7c 1121 warnx(_("invalid sizelimit '%s' specified"), sizelimit);
108591d2 1122 usage(stderr);
ca1e1363 1123 }
7bcefc7f 1124
c654c4f0 1125 if (find) {
d162fcb5
KZ
1126 device = find_unused_loop_device();
1127 if (device == NULL)
1128 return -1;
d162fcb5 1129 if (argc == optind) {
6ffa7c93 1130 if (verbose)
5bbba4a5 1131 printf(_("Loop device is %s\n"), device);
d162fcb5
KZ
1132 printf("%s\n", device);
1133 return 0;
1134 }
1135 file = argv[optind];
c654c4f0 1136 } else {
d162fcb5
KZ
1137 device = argv[optind];
1138 if (argc == optind+1)
1139 file = NULL;
1140 else
1141 file = argv[optind+1];
1142 }
1143
c654c4f0 1144 if (file == NULL)
d162fcb5
KZ
1145 res = show_loop(device);
1146 else {
c129767e 1147 if (passfd && sscanf(passfd, "%d", &pfd) != 1)
108591d2 1148 usage(stderr);
6ffa7c93 1149 do {
bc0ac075 1150 res = set_loop(device, file, offset, slimit, encryption, pfd, &ro);
6ffa7c93
MK
1151 if (res == 2 && find) {
1152 if (verbose)
5bbba4a5 1153 printf(_("stolen loop=%s...trying again\n"),
6ffa7c93
MK
1154 device);
1155 free(device);
1156 if (!(device = find_unused_loop_device()))
1157 return -1;
1158 }
1159 } while (find && res == 2);
1160
af17e0d1
KZ
1161 if (device) {
1162 if (res == 2)
0a719a7c 1163 warnx(_("%s: device is busy"), device);
af17e0d1
KZ
1164 else if (res == 0) {
1165 if (verbose)
5bbba4a5 1166 printf(_("Loop device is %s\n"), device);
af17e0d1
KZ
1167 if (showdev && find)
1168 printf("%s\n", device);
1169 }
1170 }
22853e4a
KZ
1171 }
1172 return res;
1173}
1174