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