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