/* Taken from Ted's losetup.c - Mitch */ /* Added vfs mount options - aeb - 960223 */ /* Removed lomount - aeb - 960224 */ /* 1999-02-22 Arkadiusz Mi¶kiewicz * - added Native Language Support * Sun Mar 21 1999 - Arnaldo Carvalho de Melo * - fixed strerr(errno) in gettext calls */ #define PROC_DEVICES "/proc/devices" /* * losetup.c - setup and control loop devices */ #include #include #include #include #include #include #include #include #include #include #include #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 #include 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