| /* Taken from Ted's losetup.c - Mitch <m.dsouza@mrc-apu.cam.ac.uk> */ |
| /* Added vfs mount options - aeb - 960223 */ |
| /* Removed lomount - aeb - 960224 */ |
| |
| /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> |
| * - added Native Language Support |
| * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
| * - fixed strerr(errno) in gettext calls |
| */ |
| |
| #define PROC_DEVICES "/proc/devices" |
| |
| /* |
| * losetup.c - setup and control loop devices |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <sys/ioctl.h> |
| #include <sys/stat.h> |
| #include <sys/mman.h> |
| #include <sys/sysmacros.h> |
| |
| #include "loop.h" |
| #include "lomount.h" |
| #include "xstrncpy.h" |
| #include "nls.h" |
| |
| extern int verbose; |
| extern char *xstrdup (const char *s); /* not: #include "sundries.h" */ |
| extern void error (const char *fmt, ...); /* idem */ |
| |
| #ifdef LOOP_SET_FD |
| struct crypt_type_struct { |
| int id; |
| char *name; |
| } crypt_type_tbl[] = { |
| { LO_CRYPT_NONE, "no" }, |
| { LO_CRYPT_NONE, "none" }, |
| { LO_CRYPT_XOR, "xor" }, |
| { LO_CRYPT_DES, "DES" }, |
| { -1, NULL } |
| }; |
| |
| static int |
| crypt_type (const char *name) { |
| int i; |
| |
| if (name) { |
| for (i = 0; crypt_type_tbl[i].id != -1; i++) |
| if (!strcasecmp (name, crypt_type_tbl[i].name)) |
| return crypt_type_tbl[i].id; |
| } |
| return -1; |
| } |
| |
| #ifdef MAIN |
| static char * |
| crypt_name (int id) { |
| int i; |
| |
| for (i = 0; crypt_type_tbl[i].id != -1; i++) |
| if (id == crypt_type_tbl[i].id) |
| return crypt_type_tbl[i].name; |
| return "undefined"; |
| } |
| |
| static int |
| show_loop (char *device) { |
| struct loop_info loopinfo; |
| int fd; |
| |
| if ((fd = open (device, O_RDONLY)) < 0) { |
| int errsv = errno; |
| fprintf(stderr, _("loop: can't open device %s: %s\n"), |
| device, strerror (errsv)); |
| return 2; |
| } |
| if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) < 0) { |
| int errsv = errno; |
| fprintf(stderr, _("loop: can't get info on device %s: %s\n"), |
| device, strerror (errsv)); |
| close (fd); |
| return 1; |
| } |
| printf (_("%s: [%04x]:%ld (%s) offset %d, %s encryption\n"), |
| device, loopinfo.lo_device, loopinfo.lo_inode, |
| loopinfo.lo_name, loopinfo.lo_offset, |
| crypt_name (loopinfo.lo_encrypt_type)); |
| close (fd); |
| |
| return 0; |
| } |
| #endif |
| |
| int |
| is_loop_device (const char *device) { |
| struct stat statbuf; |
| int loopmajor; |
| #if 1 |
| loopmajor = 7; |
| #else |
| FILE *procdev; |
| char line[100], *cp; |
| |
| loopmajor = 0; |
| if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) { |
| while (fgets (line, sizeof(line), procdev)) { |
| if ((cp = strstr (line, " loop\n")) != NULL) { |
| *cp='\0'; |
| loopmajor=atoi(line); |
| break; |
| } |
| } |
| fclose(procdev); |
| } |
| #endif |
| return (loopmajor && stat(device, &statbuf) == 0 && |
| S_ISBLK(statbuf.st_mode) && |
| major(statbuf.st_rdev) == loopmajor); |
| } |
| |
| #define SIZE(a) (sizeof(a)/sizeof(a[0])) |
| |
| char * |
| find_unused_loop_device (void) { |
| /* Just creating a device, say in /tmp, is probably a bad idea - |
| people might have problems with backup or so. |
| So, we just try /dev/loop[0-7]. */ |
| char dev[20]; |
| char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" }; |
| int i, j, fd, somedev = 0, someloop = 0, loop_known = 0; |
| struct stat statbuf; |
| struct loop_info loopinfo; |
| FILE *procdev; |
| |
| for (j = 0; j < SIZE(loop_formats); j++) { |
| for(i = 0; i < 256; i++) { |
| sprintf(dev, loop_formats[j], i); |
| if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { |
| somedev++; |
| fd = open (dev, O_RDONLY); |
| if (fd >= 0) { |
| if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0) |
| someloop++; /* in use */ |
| else if (errno == ENXIO) { |
| close (fd); |
| return xstrdup(dev);/* probably free */ |
| } |
| close (fd); |
| } |
| continue;/* continue trying as long as devices exist */ |
| } |
| break; |
| } |
| } |
| |
| /* Nothing found. Why not? */ |
| if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) { |
| char line[100]; |
| while (fgets (line, sizeof(line), procdev)) |
| if (strstr (line, " loop\n")) { |
| loop_known = 1; |
| break; |
| } |
| fclose(procdev); |
| if (!loop_known) |
| loop_known = -1; |
| } |
| |
| if (!somedev) |
| error(_("mount: could not find any device /dev/loop#")); |
| else if (!someloop) { |
| if (loop_known == 1) |
| error(_( |
| "mount: Could not find any loop device.\n" |
| " Maybe /dev/loop# has a wrong major number?")); |
| else if (loop_known == -1) |
| error(_( |
| "mount: Could not find any loop device, and, according to %s,\n" |
| " this kernel does not know about the loop device.\n" |
| " (If so, then recompile or `insmod loop.o'.)"), |
| PROC_DEVICES); |
| else |
| error(_( |
| "mount: Could not find any loop device. Maybe this kernel does not know\n" |
| " about the loop device (then recompile or `insmod loop.o'), or\n" |
| " maybe /dev/loop# has the wrong major number?")); |
| } else |
| error(_("mount: could not find any free loop device")); |
| return 0; |
| } |
| |
| int |
| set_loop (const char *device, const char *file, int offset, |
| const char *encryption, int *loopro) { |
| struct loop_info loopinfo; |
| int fd, ffd, mode, i; |
| char *pass; |
| |
| mode = (*loopro ? O_RDONLY : O_RDWR); |
| if ((ffd = open (file, mode)) < 0) { |
| if (!*loopro && errno == EROFS) |
| ffd = open (file, mode = O_RDONLY); |
| if (ffd < 0) { |
| perror (file); |
| return 1; |
| } |
| } |
| if ((fd = open (device, mode)) < 0) { |
| perror (device); |
| return 1; |
| } |
| *loopro = (mode == O_RDONLY); |
| |
| memset (&loopinfo, 0, sizeof (loopinfo)); |
| xstrncpy (loopinfo.lo_name, file, LO_NAME_SIZE); |
| if (encryption && (loopinfo.lo_encrypt_type = crypt_type (encryption)) |
| < 0) { |
| fprintf (stderr, _("Unsupported encryption type %s\n"), |
| encryption); |
| return 1; |
| } |
| loopinfo.lo_offset = offset; |
| |
| #ifdef MCL_FUTURE |
| /* |
| * Oh-oh, sensitive data coming up. Better lock into memory to prevent |
| * passwd etc being swapped out and left somewhere on disk. |
| */ |
| |
| if(mlockall(MCL_CURRENT | MCL_FUTURE)) { |
| perror("memlock"); |
| fprintf(stderr, _("Couldn't lock into memory, exiting.\n")); |
| exit(1); |
| } |
| #endif |
| |
| switch (loopinfo.lo_encrypt_type) { |
| case LO_CRYPT_NONE: |
| loopinfo.lo_encrypt_key_size = 0; |
| break; |
| case LO_CRYPT_XOR: |
| pass = getpass (_("Password: ")); |
| xstrncpy (loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE); |
| loopinfo.lo_encrypt_key_size = strlen(loopinfo.lo_encrypt_key); |
| break; |
| case LO_CRYPT_DES: |
| pass = getpass (_("Password: ")); |
| strncpy (loopinfo.lo_encrypt_key, pass, 8); |
| loopinfo.lo_encrypt_key[8] = 0; |
| loopinfo.lo_encrypt_key_size = 8; |
| pass = getpass (_("Init (up to 16 hex digits): ")); |
| for (i = 0; i < 16 && pass[i]; i++) |
| if (isxdigit (pass[i])) { |
| loopinfo.lo_init[i >> 3] |= (pass[i] > '9' ? |
| (islower (pass[i]) ? toupper (pass[i]) : |
| pass[i])-'A'+10 : pass[i]-'0') << (i&7) * 4; |
| } else { |
| fprintf (stderr, _("Non-hex digit '%c'.\n"), |
| pass[i]); |
| return 1; |
| } |
| break; |
| default: |
| fprintf (stderr, |
| _("Don't know how to get key for encryption system %d\n"), |
| loopinfo.lo_encrypt_type); |
| return 1; |
| } |
| if (ioctl (fd, LOOP_SET_FD, ffd) < 0) { |
| perror ("ioctl: LOOP_SET_FD"); |
| return 1; |
| } |
| if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) { |
| (void) ioctl (fd, LOOP_CLR_FD, 0); |
| perror ("ioctl: LOOP_SET_STATUS"); |
| return 1; |
| } |
| close (fd); |
| close (ffd); |
| if (verbose > 1) |
| printf(_("set_loop(%s,%s,%d): success\n"), |
| device, file, offset); |
| return 0; |
| } |
| |
| int |
| del_loop (const char *device) { |
| int fd; |
| |
| if ((fd = open (device, O_RDONLY)) < 0) { |
| int errsv = errno; |
| fprintf(stderr, _("loop: can't delete device %s: %s\n"), |
| device, strerror (errsv)); |
| return 1; |
| } |
| if (ioctl (fd, LOOP_CLR_FD, 0) < 0) { |
| perror ("ioctl: LOOP_CLR_FD"); |
| return 1; |
| } |
| close (fd); |
| if (verbose > 1) |
| printf(_("del_loop(%s): success\n"), device); |
| return 0; |
| } |
| |
| #else /* no LOOP_SET_FD defined */ |
| static void |
| mutter(void) { |
| fprintf(stderr, |
| _("This mount was compiled without loop support. " |
| "Please recompile.\n")); |
| } |
| |
| int |
| set_loop (const char *device, const char *file, int offset, |
| const char *encryption, int *loopro) { |
| mutter(); |
| return 1; |
| } |
| |
| int |
| del_loop (const char *device) { |
| mutter(); |
| return 1; |
| } |
| |
| char * |
| find_unused_loop_device (void) { |
| mutter(); |
| return 0; |
| } |
| |
| #endif |
| |
| #ifdef MAIN |
| |
| #ifdef LOOP_SET_FD |
| |
| #include <getopt.h> |
| #include <stdarg.h> |
| |
| int verbose = 0; |
| static char *progname; |
| |
| static void |
| usage(void) { |
| fprintf(stderr, _("usage:\n\ |
| %s loop_device # give info\n\ |
| %s -d loop_device # delete\n\ |
| %s [ -e encryption ] [ -o offset ] loop_device file # setup\n"), |
| progname, progname, progname); |
| exit(1); |
| } |
| |
| char * |
| xstrdup (const char *s) { |
| char *t; |
| |
| if (s == NULL) |
| return NULL; |
| |
| t = strdup (s); |
| |
| if (t == NULL) { |
| fprintf(stderr, _("not enough memory")); |
| exit(1); |
| } |
| |
| return t; |
| } |
| |
| void |
| error (const char *fmt, ...) { |
| va_list args; |
| |
| va_start (args, fmt); |
| vfprintf (stderr, fmt, args); |
| va_end (args); |
| fprintf (stderr, "\n"); |
| } |
| |
| int |
| main(int argc, char **argv) { |
| char *offset, *encryption; |
| int delete,off,c; |
| int res = 0; |
| int ro = 0; |
| |
| setlocale(LC_ALL, ""); |
| bindtextdomain(PACKAGE, LOCALEDIR); |
| textdomain(PACKAGE); |
| |
| delete = off = 0; |
| offset = encryption = NULL; |
| progname = argv[0]; |
| while ((c = getopt(argc,argv,"de:o:v")) != -1) { |
| switch (c) { |
| case 'd': |
| delete = 1; |
| break; |
| case 'e': |
| encryption = optarg; |
| break; |
| case 'o': |
| offset = optarg; |
| break; |
| case 'v': |
| verbose = 1; |
| break; |
| default: |
| usage(); |
| } |
| } |
| if (argc == 1) usage(); |
| if ((delete && (argc != optind+1 || encryption || offset)) || |
| (!delete && (argc < optind+1 || argc > optind+2))) |
| usage(); |
| if (argc == optind+1) { |
| if (delete) |
| res = del_loop(argv[optind]); |
| else |
| res = show_loop(argv[optind]); |
| } else { |
| if (offset && sscanf(offset,"%d",&off) != 1) |
| usage(); |
| res = set_loop(argv[optind],argv[optind+1],off,encryption,&ro); |
| } |
| return res; |
| } |
| |
| #else /* LOOP_SET_FD not defined */ |
| |
| int |
| main(int argc, char **argv) { |
| fprintf(stderr, |
| _("No loop support was available at compile time. " |
| "Please recompile.\n")); |
| return -1; |
| } |
| #endif |
| #endif |