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