Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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