]> git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/lomount.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / mount / lomount.c
1 /* Taken from Ted's losetup.c - Mitch <m.dsouza@mrc-apu.cam.ac.uk> */
2 /* Added vfs mount options - aeb - 960223 */
3 /* Removed lomount - aeb - 960224 */
4
5 /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
6 * - added Native Language Support
7 * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
8 * - fixed strerr(errno) in gettext calls
9 */
10
11 #define PROC_DEVICES "/proc/devices"
12
13 /*
14 * losetup.c - setup and control loop devices
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/ioctl.h>
25 #include <sys/stat.h>
26 #include <sys/mman.h>
27
28 #include "loop.h"
29 #include "lomount.h"
30 #include "nls.h"
31
32 extern int verbose;
33 extern char *xstrdup (const char *s); /* not: #include "sundries.h" */
34 extern void error (const char *fmt, ...); /* idem */
35
36 #ifdef LOOP_SET_FD
37 struct crypt_type_struct {
38 int id;
39 char *name;
40 } crypt_type_tbl[] = {
41 { LO_CRYPT_NONE, "no" },
42 { LO_CRYPT_NONE, "none" },
43 { LO_CRYPT_XOR, "xor" },
44 { LO_CRYPT_DES, "DES" },
45 { -1, NULL }
46 };
47
48 static int
49 crypt_type (const char *name) {
50 int i;
51
52 if (name) {
53 for (i = 0; crypt_type_tbl[i].id != -1; i++)
54 if (!strcasecmp (name, crypt_type_tbl[i].name))
55 return crypt_type_tbl[i].id;
56 }
57 return -1;
58 }
59
60 #ifdef MAIN
61 static char *
62 crypt_name (int id) {
63 int i;
64
65 for (i = 0; crypt_type_tbl[i].id != -1; i++)
66 if (id == crypt_type_tbl[i].id)
67 return crypt_type_tbl[i].name;
68 return "undefined";
69 }
70
71 static int
72 show_loop (char *device) {
73 struct loop_info loopinfo;
74 int fd;
75
76 if ((fd = open (device, O_RDONLY)) < 0) {
77 int errsv = errno;
78 fprintf(stderr, _("loop: can't open device %s: %s\n"),
79 device, strerror (errsv));
80 return 2;
81 }
82 if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) < 0) {
83 int errsv = errno;
84 fprintf(stderr, _("loop: can't get info on device %s: %s\n"),
85 device, strerror (errsv));
86 close (fd);
87 return 1;
88 }
89 printf (_("%s: [%04x]:%ld (%s) offset %d, %s encryption\n"),
90 device, loopinfo.lo_device, loopinfo.lo_inode,
91 loopinfo.lo_name, loopinfo.lo_offset,
92 crypt_name (loopinfo.lo_encrypt_type));
93 close (fd);
94
95 return 0;
96 }
97 #endif
98
99 int
100 is_loop_device (const char *device) {
101 struct stat statbuf;
102 int loopmajor;
103 #if 1
104 loopmajor = 7;
105 #else
106 FILE *procdev;
107 char line[100], *cp;
108
109 loopmajor = 0;
110 if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
111 while (fgets (line, sizeof(line), procdev)) {
112 if ((cp = strstr (line, " loop\n")) != NULL) {
113 *cp='\0';
114 loopmajor=atoi(line);
115 break;
116 }
117 }
118 fclose(procdev);
119 }
120 #endif
121 return (loopmajor && stat(device, &statbuf) == 0 &&
122 S_ISBLK(statbuf.st_mode) &&
123 (statbuf.st_rdev>>8) == loopmajor);
124 }
125
126 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
127
128 char *
129 find_unused_loop_device (void) {
130 /* Just creating a device, say in /tmp, is probably a bad idea -
131 people might have problems with backup or so.
132 So, we just try /dev/loop[0-7]. */
133 char dev[20];
134 char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
135 int i, j, fd, somedev = 0, someloop = 0, loop_known = 0;
136 struct stat statbuf;
137 struct loop_info loopinfo;
138 FILE *procdev;
139
140 for (j = 0; j < SIZE(loop_formats); j++) {
141 for(i = 0; i < 256; i++) {
142 sprintf(dev, loop_formats[j], i);
143 if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
144 somedev++;
145 fd = open (dev, O_RDONLY);
146 if (fd >= 0) {
147 if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
148 someloop++; /* in use */
149 else if (errno == ENXIO) {
150 close (fd);
151 return xstrdup(dev);/* probably free */
152 }
153 close (fd);
154 }
155 continue;/* continue trying as long as devices exist */
156 }
157 break;
158 }
159 }
160
161 /* Nothing found. Why not? */
162 if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
163 char line[100];
164 while (fgets (line, sizeof(line), procdev))
165 if (strstr (line, " loop\n")) {
166 loop_known = 1;
167 break;
168 }
169 fclose(procdev);
170 if (!loop_known)
171 loop_known = -1;
172 }
173
174 if (!somedev)
175 error(_("mount: could not find any device /dev/loop#"));
176 else if(!someloop) {
177 if (loop_known == 1)
178 error(_(
179 "mount: Could not find any loop device.\n"
180 " Maybe /dev/loop# has a wrong major number?"));
181 else if (loop_known == -1)
182 error(_(
183 "mount: Could not find any loop device, and, according to %s,\n"
184 " this kernel does not know about the loop device.\n"
185 " (If so, then recompile or `insmod loop.o'.)"),
186 PROC_DEVICES);
187 else
188 error(_(
189 "mount: Could not find any loop device. Maybe this kernel does not know\n"
190 " about the loop device (then recompile or `insmod loop.o'), or\n"
191 " maybe /dev/loop# has the wrong major number?"));
192 } else
193 error(_("mount: could not find any free loop device"));
194 return 0;
195 }
196
197 int
198 set_loop (const char *device, const char *file, int offset,
199 const char *encryption, int *loopro) {
200 struct loop_info loopinfo;
201 int fd, ffd, mode, i;
202 char *pass;
203
204 mode = (*loopro ? O_RDONLY : O_RDWR);
205 if ((ffd = open (file, mode)) < 0) {
206 if (!*loopro && errno == EROFS)
207 ffd = open (file, mode = O_RDONLY);
208 if (ffd < 0) {
209 perror (file);
210 return 1;
211 }
212 }
213 if ((fd = open (device, mode)) < 0) {
214 perror (device);
215 return 1;
216 }
217 *loopro = (mode == O_RDONLY);
218
219 memset (&loopinfo, 0, sizeof (loopinfo));
220 strncpy (loopinfo.lo_name, file, LO_NAME_SIZE);
221 loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
222 if (encryption && (loopinfo.lo_encrypt_type = crypt_type (encryption))
223 < 0) {
224 fprintf (stderr, _("Unsupported encryption type %s\n"),
225 encryption);
226 return 1;
227 }
228 loopinfo.lo_offset = offset;
229
230 #ifdef MCL_FUTURE
231 /*
232 * Oh-oh, sensitive data coming up. Better lock into memory to prevent
233 * passwd etc being swapped out and left somewhere on disk.
234 */
235
236 if(mlockall(MCL_CURRENT|MCL_FUTURE)) {
237 perror("memlock");
238 fprintf(stderr, _("Couldn't lock into memory, exiting.\n"));
239 exit(1);
240 }
241 #endif
242
243 switch (loopinfo.lo_encrypt_type) {
244 case LO_CRYPT_NONE:
245 loopinfo.lo_encrypt_key_size = 0;
246 break;
247 case LO_CRYPT_XOR:
248 pass = getpass (_("Password: "));
249 strncpy (loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE);
250 loopinfo.lo_encrypt_key[LO_KEY_SIZE - 1] = 0;
251 loopinfo.lo_encrypt_key_size = strlen(loopinfo.lo_encrypt_key);
252 break;
253 case LO_CRYPT_DES:
254 pass = getpass (_("Password: "));
255 strncpy (loopinfo.lo_encrypt_key, pass, 8);
256 loopinfo.lo_encrypt_key[8] = 0;
257 loopinfo.lo_encrypt_key_size = 8;
258 pass = getpass (_("Init (up to 16 hex digits): "));
259 for (i = 0; i < 16 && pass[i]; i++)
260 if (isxdigit (pass[i])) {
261 loopinfo.lo_init[i >> 3] |= (pass[i] > '9' ?
262 (islower (pass[i]) ? toupper (pass[i]) :
263 pass[i])-'A'+10 : pass[i]-'0') << (i&7) * 4;
264 } else {
265 fprintf (stderr, _("Non-hex digit '%c'.\n"),
266 pass[i]);
267 return 1;
268 }
269 break;
270 default:
271 fprintf (stderr,
272 _("Don't know how to get key for encryption system %d\n"),
273 loopinfo.lo_encrypt_type);
274 return 1;
275 }
276 if (ioctl (fd, LOOP_SET_FD, ffd) < 0) {
277 perror ("ioctl: LOOP_SET_FD");
278 return 1;
279 }
280 if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
281 (void) ioctl (fd, LOOP_CLR_FD, 0);
282 perror ("ioctl: LOOP_SET_STATUS");
283 return 1;
284 }
285 close (fd);
286 close (ffd);
287 if (verbose > 1)
288 printf(_("set_loop(%s,%s,%d): success\n"),
289 device, file, offset);
290 return 0;
291 }
292
293 int
294 del_loop (const char *device) {
295 int fd;
296
297 if ((fd = open (device, O_RDONLY)) < 0) {
298 int errsv = errno;
299 fprintf(stderr, _("loop: can't delete device %s: %s\n"),
300 device, strerror (errsv));
301 return 1;
302 }
303 if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
304 perror ("ioctl: LOOP_CLR_FD");
305 return 1;
306 }
307 close (fd);
308 if (verbose > 1)
309 printf(_("del_loop(%s): success\n"), device);
310 return 0;
311 }
312
313 #else /* no LOOP_SET_FD defined */
314 static void
315 mutter(void) {
316 fprintf(stderr,
317 _("This mount was compiled without loop support. "
318 "Please recompile.\n"));
319 }
320
321 int
322 set_loop (const char *device, const char *file, int offset,
323 const char *encryption, int *loopro) {
324 mutter();
325 return 1;
326 }
327
328 int
329 del_loop (const char *device) {
330 mutter();
331 return 1;
332 }
333
334 char *
335 find_unused_loop_device (void) {
336 mutter();
337 return 0;
338 }
339
340 #endif
341
342 #ifdef MAIN
343
344 #ifdef LOOP_SET_FD
345
346 #include <getopt.h>
347 #include <stdarg.h>
348
349 int verbose = 0;
350 static char *progname;
351
352 static void
353 usage(void) {
354 fprintf(stderr, _("usage:\n\
355 %s loop_device # give info\n\
356 %s -d loop_device # delete\n\
357 %s [ -e encryption ] [ -o offset ] loop_device file # setup\n"),
358 progname, progname, progname);
359 exit(1);
360 }
361
362 char *
363 xstrdup (const char *s) {
364 char *t;
365
366 if (s == NULL)
367 return NULL;
368
369 t = strdup (s);
370
371 if (t == NULL) {
372 fprintf(stderr, _("not enough memory"));
373 exit(1);
374 }
375
376 return t;
377 }
378
379 void
380 error (const char *fmt, ...) {
381 va_list args;
382
383 va_start (args, fmt);
384 vfprintf (stderr, fmt, args);
385 va_end (args);
386 fprintf (stderr, "\n");
387 }
388
389 int
390 main(int argc, char **argv) {
391 char *offset, *encryption;
392 int delete,off,c;
393 int res = 0;
394 int ro = 0;
395
396 setlocale(LC_ALL, "");
397 bindtextdomain(PACKAGE, LOCALEDIR);
398 textdomain(PACKAGE);
399
400 delete = off = 0;
401 offset = encryption = NULL;
402 progname = argv[0];
403 while ((c = getopt(argc,argv,"de:o:v")) != EOF) {
404 switch (c) {
405 case 'd':
406 delete = 1;
407 break;
408 case 'e':
409 encryption = optarg;
410 break;
411 case 'o':
412 offset = optarg;
413 break;
414 case 'v':
415 verbose = 1;
416 break;
417 default:
418 usage();
419 }
420 }
421 if (argc == 1) usage();
422 if ((delete && (argc != optind+1 || encryption || offset)) ||
423 (!delete && (argc < optind+1 || argc > optind+2)))
424 usage();
425 if (argc == optind+1) {
426 if (delete)
427 res = del_loop(argv[optind]);
428 else
429 res = show_loop(argv[optind]);
430 } else {
431 if (offset && sscanf(offset,"%d",&off) != 1)
432 usage();
433 res = set_loop(argv[optind],argv[optind+1],off,encryption,&ro);
434 }
435 return res;
436 }
437
438 #else /* LOOP_SET_FD not defined */
439
440 int
441 main(int argc, char **argv) {
442 fprintf(stderr,
443 _("No loop support was available at compile time. "
444 "Please recompile.\n"));
445 return -1;
446 }
447 #endif
448 #endif