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