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