Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/utils/losetup.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (hide annotations) (download)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 10670 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
1 niro 1122 /* Originally from Ted's losetup.c */
2    
3     #define LOOPMAJOR 7
4    
5     /*
6     * losetup.c - setup and control loop devices
7     */
8    
9     #include <stdio.h>
10     #include <string.h>
11     #include <ctype.h>
12     #include <fcntl.h>
13     #include <errno.h>
14     #include <stdlib.h>
15     #include <unistd.h>
16     #include <sys/ioctl.h>
17     #include <sys/stat.h>
18     #include <sys/mman.h>
19     #include <sys/sysmacros.h>
20 niro 1297 #include <stdarg.h>
21 niro 1122 #include <string.h>
22    
23     #include "loop.h"
24    
25     extern int verbose;
26     extern char *progname;
27     extern char *xstrdup (const char *s); /* not: #include "sundries.h" */
28     extern void error (const char *fmt, ...); /* idem */
29    
30     /* caller guarantees n > 0 */
31     void xstrncpy(char *dest, const char *src, size_t n)
32     {
33     strncpy(dest, src, n-1);
34     dest[n-1] = 0;
35     }
36    
37    
38     static int loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info)
39     {
40     memset(info, 0, sizeof(*info));
41     info->lo_number = info64->lo_number;
42     info->lo_device = info64->lo_device;
43     info->lo_inode = info64->lo_inode;
44     info->lo_rdevice = info64->lo_rdevice;
45     info->lo_offset = info64->lo_offset;
46     info->lo_encrypt_type = info64->lo_encrypt_type;
47     info->lo_encrypt_key_size = info64->lo_encrypt_key_size;
48     info->lo_flags = info64->lo_flags;
49     info->lo_init[0] = info64->lo_init[0];
50     info->lo_init[1] = info64->lo_init[1];
51     if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
52     memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
53     else
54     memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE);
55     memcpy(info->lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE);
56    
57     /* error in case values were truncated */
58     if (info->lo_device != info64->lo_device ||
59     info->lo_rdevice != info64->lo_rdevice ||
60     info->lo_inode != info64->lo_inode ||
61     info->lo_offset != info64->lo_offset)
62     return -EOVERFLOW;
63    
64     return 0;
65     }
66    
67    
68     static int show_loop(char *device)
69     {
70     struct loop_info loopinfo;
71     struct loop_info64 loopinfo64;
72     int fd, errsv;
73    
74     if ((fd = open(device, O_RDONLY)) < 0) {
75     int errsv = errno;
76     fprintf(stderr, "loop: can't open device %s: %s\n",
77     device, strerror (errsv));
78     return 2;
79     }
80    
81     if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) {
82    
83     loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*';
84     loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0;
85     loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0;
86    
87     printf("%s: [%04llx]:%llu (%s)",
88     device, loopinfo64.lo_device, loopinfo64.lo_inode,
89     loopinfo64.lo_file_name);
90    
91     if (loopinfo64.lo_offset)
92     printf(", offset %lld", loopinfo64.lo_offset);
93    
94     if (loopinfo64.lo_sizelimit)
95     printf(", sizelimit %lld", loopinfo64.lo_sizelimit);
96    
97     if (loopinfo64.lo_encrypt_type ||
98     loopinfo64.lo_crypt_name[0]) {
99     char *e = loopinfo64.lo_crypt_name;
100    
101     if (*e == 0 && loopinfo64.lo_encrypt_type == 1)
102     e = "XOR";
103     printf(", encryption %s (type %d)",
104     e, loopinfo64.lo_encrypt_type);
105     }
106     printf("\n");
107     close (fd);
108     return 0;
109     }
110    
111     if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0) {
112     printf ("%s: [%04x]:%ld (%s)",
113     device, loopinfo.lo_device, loopinfo.lo_inode,
114     loopinfo.lo_name);
115    
116     if (loopinfo.lo_offset)
117     printf(", offset %d", loopinfo.lo_offset);
118    
119     if (loopinfo.lo_encrypt_type)
120     printf(", encryption type %d\n",
121     loopinfo.lo_encrypt_type);
122    
123     printf("\n");
124     close (fd);
125     return 0;
126     }
127    
128     errsv = errno;
129     fprintf(stderr, "loop: can't get info on device %s: %s\n",
130     device, strerror (errsv));
131     close (fd);
132     return 1;
133     }
134    
135     int
136     is_loop_device (const char *device) {
137     struct stat statbuf;
138    
139     return (stat(device, &statbuf) == 0 &&
140     S_ISBLK(statbuf.st_mode) &&
141     major(statbuf.st_rdev) == LOOPMAJOR);
142     }
143    
144     #define SIZE(a) (sizeof(a)/sizeof(a[0]))
145    
146     char * find_unused_loop_device (void)
147     {
148     /* Just creating a device, say in /tmp, is probably a bad idea -
149     people might have problems with backup or so.
150     So, we just try /dev/loop[0-7]. */
151     char dev[20];
152     char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
153     int i, j, fd, somedev = 0, someloop = 0, permission = 0;
154     struct stat statbuf;
155     struct loop_info loopinfo;
156    
157     for (j = 0; j < SIZE(loop_formats); j++) {
158     for(i = 0; i < 256; i++) {
159     sprintf(dev, loop_formats[j], i);
160     if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
161     somedev++;
162     fd = open (dev, O_RDONLY);
163     if (fd >= 0) {
164     if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
165     someloop++; /* in use */
166     else if (errno == ENXIO) {
167     close (fd);
168     return xstrdup(dev);/* probably free */
169     }
170     close (fd);
171     } else if (errno == EACCES)
172     permission++;
173    
174     continue;/* continue trying as long as devices exist */
175     }
176     break;
177     }
178     }
179    
180     if (!somedev)
181     error("%s: could not find any device /dev/loop#", progname);
182     else if (!someloop && permission)
183     error("%s: no permission to look at /dev/loop#", progname);
184     else if (!someloop)
185     error(
186     "%s: Could not find any loop device. Maybe this kernel "
187     "does not know\n"
188     " about the loop device? (If so, recompile or "
189     "`modprobe loop'.)", progname);
190     else
191     error("%s: could not find any free loop device", progname);
192     return 0;
193     }
194    
195     /*
196     * A function to read the passphrase either from the terminal or from
197     * an open file descriptor.
198     */
199     static char * xgetpass(int pfd, const char *prompt)
200     {
201     char *pass;
202     int buflen, i;
203    
204     pass = NULL;
205     buflen = 0;
206     for (i=0; ; i++) {
207     if (i >= buflen-1) {
208     /* we're running out of space in the buffer.
209     * Make it bigger: */
210     char *tmppass = pass;
211     buflen += 128;
212     pass = realloc(tmppass, buflen);
213     if (pass == NULL) {
214     /* realloc failed. Stop reading. */
215     error("Out of memory while reading passphrase");
216     pass = tmppass; /* the old buffer hasn't changed */
217     break;
218     }
219     }
220     if (read(pfd, pass+i, 1) != 1 ||
221     pass[i] == '\n' || pass[i] == 0)
222     break;
223     }
224    
225     if (pass == NULL)
226     return "";
227    
228     pass[i] = 0;
229     return pass;
230     }
231    
232     static int digits_only(const char *s)
233     {
234     while (*s)
235     if (!isdigit(*s++))
236     return 0;
237     return 1;
238     }
239    
240     int set_loop(const char *device, const char *file, unsigned long long offset,
241     const char *encryption, int pfd, int *loopro) {
242     struct loop_info64 loopinfo64;
243     int fd, ffd, mode, i;
244     char *pass;
245    
246     mode = (*loopro ? O_RDONLY : O_RDWR);
247     if ((ffd = open(file, mode)) < 0) {
248     if (!*loopro && errno == EROFS)
249     ffd = open(file, mode = O_RDONLY);
250     if (ffd < 0) {
251     perror(file);
252     return 1;
253     }
254     }
255     if ((fd = open(device, mode)) < 0) {
256     perror (device);
257     return 1;
258     }
259     *loopro = (mode == O_RDONLY);
260    
261     memset(&loopinfo64, 0, sizeof(loopinfo64));
262    
263     xstrncpy(loopinfo64.lo_file_name, file, LO_NAME_SIZE);
264    
265     if (encryption && *encryption) {
266     if (digits_only(encryption)) {
267     loopinfo64.lo_encrypt_type = atoi(encryption);
268     } else {
269     loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
270     snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE,
271     "%s", encryption);
272     }
273     }
274    
275     loopinfo64.lo_offset = offset;
276    
277    
278     switch (loopinfo64.lo_encrypt_type) {
279     case LO_CRYPT_NONE:
280     loopinfo64.lo_encrypt_key_size = 0;
281     break;
282     case LO_CRYPT_XOR:
283     pass = xgetpass(pfd, "Password: ");
284     goto gotpass;
285     default:
286     pass = xgetpass(pfd, "Password: ");
287     gotpass:
288     memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE);
289     xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
290     memset(pass, 0, strlen(pass));
291     loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE;
292     }
293    
294     if (ioctl(fd, LOOP_SET_FD, (void *)(size_t)ffd) < 0) {
295     perror("ioctl: LOOP_SET_FD");
296     return 1;
297     }
298     close (ffd);
299    
300     i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64);
301     if (i) {
302     struct loop_info loopinfo;
303     int errsv = errno;
304    
305     i = loop_info64_to_old(&loopinfo64, &loopinfo);
306     if (i) {
307     errno = errsv;
308     perror("ioctl: LOOP_SET_STATUS64");
309     } else {
310     i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
311     if (i)
312     perror("ioctl: LOOP_SET_STATUS");
313     }
314     memset(&loopinfo, 0, sizeof(loopinfo));
315     }
316     memset(&loopinfo64, 0, sizeof(loopinfo64));
317    
318     if (i) {
319     ioctl (fd, LOOP_CLR_FD, 0);
320     close (fd);
321     return 1;
322     }
323     close (fd);
324    
325     if (verbose > 1)
326     printf("set_loop(%s,%s,%llu): success\n",
327     device, file, offset);
328     return 0;
329     }
330    
331     int del_loop (const char *device)
332     {
333     int fd;
334    
335     if ((fd = open (device, O_RDONLY)) < 0) {
336     int errsv = errno;
337     fprintf(stderr, "loop: can't delete device %s: %s\n",
338     device, strerror (errsv));
339     return 1;
340     }
341     if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
342     perror ("ioctl: LOOP_CLR_FD");
343 niro 1297 close (fd);
344 niro 1122 return 1;
345     }
346     close (fd);
347     if (verbose > 1)
348     printf("del_loop(%s): success\n", device);
349     return 0;
350     }
351    
352    
353     int verbose = 0;
354     char *progname;
355    
356     static void usage(void) {
357     fprintf(stderr, "usage:\n\
358     %s loop_device # give info\n\
359     %s -d loop_device # delete\n\
360     %s -f # find unused\n\
361     %s [-e encryption] [-o offset] {-f|loop_device} file # setup\n",
362     progname, progname, progname, progname);
363     exit(1);
364     }
365    
366     char * xstrdup (const char *s) {
367     char *t;
368    
369     if (s == NULL)
370     return NULL;
371    
372     t = strdup (s);
373    
374     if (t == NULL) {
375     fprintf(stderr, "not enough memory");
376     exit(1);
377     }
378    
379     return t;
380     }
381    
382     void error (const char *fmt, ...)
383     {
384     va_list args;
385    
386     va_start (args, fmt);
387     vfprintf (stderr, fmt, args);
388     va_end (args);
389     fprintf (stderr, "\n");
390     }
391    
392     int main(int argc, char **argv)
393     {
394     char *p, *offset, *encryption, *passfd, *device, *file;
395     int delete, find, c;
396     int res = 0;
397     int ro = 0;
398     int pfd = -1;
399     unsigned long long off;
400    
401    
402     delete = find = 0;
403     off = 0;
404     offset = encryption = passfd = NULL;
405    
406     progname = argv[0];
407     if ((p = strrchr(progname, '/')) != NULL)
408     progname = p+1;
409    
410     while ((c = getopt(argc, argv, "de:E:fo:p:v")) != -1) {
411     switch (c) {
412     case 'd':
413     delete = 1;
414     break;
415     case 'E':
416     case 'e':
417     encryption = optarg;
418     break;
419     case 'f':
420     find = 1;
421     break;
422     case 'o':
423     offset = optarg;
424     break;
425     case 'p':
426     passfd = optarg;
427     break;
428     case 'v':
429     verbose = 1;
430     break;
431     default:
432     usage();
433     }
434     }
435    
436     if (argc == 1) {
437     usage();
438     } else if (delete) {
439     if (argc != optind+1 || encryption || offset || find)
440     usage();
441     } else if (find) {
442     if (argc < optind || argc > optind+1)
443     usage();
444     } else {
445     if (argc < optind+1 || argc > optind+2)
446     usage();
447     }
448    
449     if (find) {
450     device = find_unused_loop_device();
451     if (device == NULL)
452     return -1;
453     if (verbose)
454     printf("Loop device is %s\n", device);
455     if (argc == optind) {
456     printf("%s\n", device);
457     return 0;
458     }
459     file = argv[optind];
460     } else {
461     device = argv[optind];
462     if (argc == optind+1)
463     file = NULL;
464     else
465     file = argv[optind+1];
466     }
467    
468     if (delete)
469     res = del_loop(device);
470     else if (file == NULL)
471     res = show_loop(device);
472     else {
473     if (offset && sscanf(offset, "%llu", &off) != 1)
474     usage();
475     if (passfd && sscanf(passfd, "%d", &pfd) != 1)
476     usage();
477     res = set_loop(device, file, off, encryption, pfd, &ro);
478     }
479     return res;
480     }