diff options
Diffstat (limited to 'mount/losetup.c')
-rw-r--r-- | mount/losetup.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/mount/losetup.c b/mount/losetup.c new file mode 100644 index 000000000..ae5886ac4 --- /dev/null +++ b/mount/losetup.c @@ -0,0 +1,225 @@ +/* + * losetup.c - setup and control loop devices + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <unistd.h> +#include <getopt.h> +#include <errno.h> +#include <sys/ioctl.h> + +#include "loop.h" +#include "lomount.h" + +#ifdef LOOP_SET_FD + +static char *progname; + +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 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 crypt_type(const char *name) +{ + int i; + + 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; +} + + +static void show_loop(const char *device) +{ + struct loop_info loopinfo; + int fd; + + if ((fd = open(device, O_RDWR)) < 0) { + perror(device); + return; + } + if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) { + perror("Cannot get loop info"); + close(fd); + return; + } + 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); +} + + +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 && !*loopro + && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { + perror (file); + return 1; + } + if ((fd = open (device, mode)) < 0) { + perror (device); + return 1; + } + *loopro = (mode == O_RDONLY); + + memset(&loopinfo, 0, sizeof(loopinfo)); + strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + loopinfo.lo_name[LO_NAME_SIZE-1] = 0; + if (encryption && (loopinfo.lo_encrypt_type = crypt_type(encryption)) + < 0) { + fprintf(stderr,"Unsupported encryption type %s",encryption); + exit(1); + } + loopinfo.lo_offset = offset; + switch (loopinfo.lo_encrypt_type) { + case LO_CRYPT_NONE: + loopinfo.lo_encrypt_key_size = 0; + break; + case LO_CRYPT_XOR: + pass = getpass("Password: "); + strncpy(loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE); + loopinfo.lo_encrypt_key[LO_KEY_SIZE-1] = 0; + 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]); + exit(1); + } + break; + default: + fprintf(stderr, + "Don't know how to get key for encryption system %d\n", + loopinfo.lo_encrypt_type); + exit(1); + } + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + perror("ioctl: LOOP_SET_FD"); + exit(1); + } + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl(fd, LOOP_CLR_FD, 0); + perror("ioctl: LOOP_SET_STATUS"); + exit(1); + } + close(fd); + close(ffd); + return 0; +} + +int del_loop(const char *device) +{ + int fd; + + if ((fd = open(device, O_RDONLY)) < 0) { + perror(device); + exit(1); + } + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + perror("ioctl: LOOP_CLR_FD"); + exit(1); + } + return(0); +} + + +static int 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); +} + +int main(int argc, char **argv) +{ + char *offset,*encryption; + int delete,off,c; + int ro = 0; + + delete = off = 0; + offset = encryption = NULL; + progname = argv[0]; + while ((c = getopt(argc,argv,"de:o:")) != EOF) { + switch (c) { + case 'd': + delete = 1; + break; + case 'e': + encryption = optarg; + break; + case 'o': + offset = optarg; + 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) + del_loop(argv[optind]); + else + show_loop(argv[optind]); + else { + if (offset && sscanf(offset,"%d",&off) != 1) + usage(); + set_loop(argv[optind],argv[optind+1],off,encryption,&ro); + } + return 0; +} + +#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 |