Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (show 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 /* 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 <stdarg.h>
21 #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 close (fd);
344 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 }