Index: klibc-1.5.15/usr/utils/Kbuild =================================================================== --- klibc-1.5.15/usr/utils/Kbuild_orig 2009-09-05 17:20:53.000000000 -0400 +++ klibc-1.5.15/usr/utils/Kbuild 2009-09-05 17:21:12.000000000 -0400 @@ -4,7 +4,7 @@ progs := chroot dd mkdir mkfifo mknod mount pivot_root umount progs += true false sleep ln nuke minips cat -progs += uname halt kill readlink cpio sync dmesg +progs += uname halt kill readlink cpio sync dmesg losetup static-y := $(addprefix static/, $(progs)) shared-y := $(addprefix shared/, $(progs)) @@ -54,6 +54,8 @@ shared/cpio-y := cpio.o static/sync-y := sync.o shared/sync-y := sync.o +static/losetup-y := losetup.o +shared/losetup-y := losetup.o # Additionally linked targets always := static/reboot static/poweroff shared/reboot shared/poweroff Index: klibc-1.5/usr/utils/losetup.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ klibc-1.5/usr/utils/losetup.c 2008-03-07 23:13:38.635692852 +0100 @@ -0,0 +1,485 @@ +/* Originally from Ted's losetup.c */ + +#define LOOPMAJOR 7 + +/* + * losetup.c - setup and control loop devices + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "loop.h" + +extern int verbose; +extern char *progname; +extern char *xstrdup (const char *s); /* not: #include "sundries.h" */ +extern void error (const char *fmt, ...); /* idem */ + +/* caller guarantees n > 0 */ +void +xstrncpy(char *dest, const char *src, size_t n) { + strncpy(dest, src, n-1); + dest[n-1] = 0; +} + + +static int +loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) +{ + memset(info, 0, sizeof(*info)); + info->lo_number = info64->lo_number; + info->lo_device = info64->lo_device; + info->lo_inode = info64->lo_inode; + info->lo_rdevice = info64->lo_rdevice; + info->lo_offset = info64->lo_offset; + info->lo_encrypt_type = info64->lo_encrypt_type; + info->lo_encrypt_key_size = info64->lo_encrypt_key_size; + info->lo_flags = info64->lo_flags; + info->lo_init[0] = info64->lo_init[0]; + info->lo_init[1] = info64->lo_init[1]; + if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI) + memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE); + else + memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE); + memcpy(info->lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE); + + /* error in case values were truncated */ + if (info->lo_device != info64->lo_device || + info->lo_rdevice != info64->lo_rdevice || + info->lo_inode != info64->lo_inode || + info->lo_offset != info64->lo_offset) + return -EOVERFLOW; + + return 0; +} + + +static int +show_loop(char *device) { + struct loop_info loopinfo; + struct loop_info64 loopinfo64; + int fd, errsv; + + 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_STATUS64, &loopinfo64) == 0) { + + loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*'; + loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0; + loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0; + + printf("%s: [%04llx]:%llu (%s)", + device, loopinfo64.lo_device, loopinfo64.lo_inode, + loopinfo64.lo_file_name); + + if (loopinfo64.lo_offset) + printf(", offset %lld", loopinfo64.lo_offset); + + if (loopinfo64.lo_sizelimit) + printf(", sizelimit %lld", loopinfo64.lo_sizelimit); + + if (loopinfo64.lo_encrypt_type || + loopinfo64.lo_crypt_name[0]) { + char *e = loopinfo64.lo_crypt_name; + + if (*e == 0 && loopinfo64.lo_encrypt_type == 1) + e = "XOR"; + printf(", encryption %s (type %d)", + e, loopinfo64.lo_encrypt_type); + } + printf("\n"); + close (fd); + return 0; + } + + if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0) { + printf ("%s: [%04x]:%ld (%s)", + device, loopinfo.lo_device, loopinfo.lo_inode, + loopinfo.lo_name); + + if (loopinfo.lo_offset) + printf(", offset %d", loopinfo.lo_offset); + + if (loopinfo.lo_encrypt_type) + printf(", encryption type %d\n", + loopinfo.lo_encrypt_type); + + printf("\n"); + close (fd); + return 0; + } + + errsv = errno; + fprintf(stderr, "loop: can't get info on device %s: %s\n", + device, strerror (errsv)); + close (fd); + return 1; +} + +int +is_loop_device (const char *device) { + struct stat statbuf; + + return (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, permission = 0; + struct stat statbuf; + struct loop_info loopinfo; + + 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); + } else if (errno == EACCES) + permission++; + + continue;/* continue trying as long as devices exist */ + } + break; + } + } + + if (!somedev) + error("%s: could not find any device /dev/loop#", progname); + else if (!someloop && permission) + error("%s: no permission to look at /dev/loop#", progname); + else if (!someloop) + error( + "%s: Could not find any loop device. Maybe this kernel " + "does not know\n" + " about the loop device? (If so, recompile or " + "`modprobe loop'.)", progname); + else + error("%s: could not find any free loop device", progname); + return 0; +} + +/* + * A function to read the passphrase either from the terminal or from + * an open file descriptor. + */ +static char * +xgetpass(int pfd, const char *prompt) { + char *pass; + int buflen, i; + + pass = NULL; + buflen = 0; + for (i=0; ; i++) { + if (i >= buflen-1) { + /* we're running out of space in the buffer. + * Make it bigger: */ + char *tmppass = pass; + buflen += 128; + pass = realloc(tmppass, buflen); + if (pass == NULL) { + /* realloc failed. Stop reading. */ + error("Out of memory while reading passphrase"); + pass = tmppass; /* the old buffer hasn't changed */ + break; + } + } + if (read(pfd, pass+i, 1) != 1 || + pass[i] == '\n' || pass[i] == 0) + break; + } + + if (pass == NULL) + return ""; + + pass[i] = 0; + return pass; +} + +static int +digits_only(const char *s) { + while (*s) + if (!isdigit(*s++)) + return 0; + return 1; +} + +int +set_loop(const char *device, const char *file, unsigned long long offset, + const char *encryption, int pfd, int *loopro) { + struct loop_info64 loopinfo64; + 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(&loopinfo64, 0, sizeof(loopinfo64)); + + xstrncpy(loopinfo64.lo_file_name, file, LO_NAME_SIZE); + + if (encryption && *encryption) { + if (digits_only(encryption)) { + loopinfo64.lo_encrypt_type = atoi(encryption); + } else { + loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI; + snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE, + "%s", encryption); + } + } + + loopinfo64.lo_offset = offset; + + + switch (loopinfo64.lo_encrypt_type) { + case LO_CRYPT_NONE: + loopinfo64.lo_encrypt_key_size = 0; + break; + case LO_CRYPT_XOR: + pass = xgetpass(pfd, "Password: "); + goto gotpass; + default: + pass = xgetpass(pfd, "Password: "); + gotpass: + memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE); + xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE); + memset(pass, 0, strlen(pass)); + loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE; + } + + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + perror("ioctl: LOOP_SET_FD"); + return 1; + } + close (ffd); + + i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64); + if (i) { + struct loop_info loopinfo; + int errsv = errno; + + i = loop_info64_to_old(&loopinfo64, &loopinfo); + if (i) { + errno = errsv; + perror("ioctl: LOOP_SET_STATUS64"); + } else { + i = ioctl(fd, LOOP_SET_STATUS, &loopinfo); + if (i) + perror("ioctl: LOOP_SET_STATUS"); + } + memset(&loopinfo, 0, sizeof(loopinfo)); + } + memset(&loopinfo64, 0, sizeof(loopinfo64)); + + if (i) { + ioctl (fd, LOOP_CLR_FD, 0); + close (fd); + return 1; + } + close (fd); + + if (verbose > 1) + printf("set_loop(%s,%s,%llu): 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; +} + + +#include +#include + +int verbose = 0; +char *progname; + +static void +usage(void) { + fprintf(stderr, "usage:\n\ + %s loop_device # give info\n\ + %s -d loop_device # delete\n\ + %s -f # find unused\n\ + %s [-e encryption] [-o offset] {-f|loop_device} file # setup\n", + progname, 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 *p, *offset, *encryption, *passfd, *device, *file; + int delete, find, c; + int res = 0; + int ro = 0; + int pfd = -1; + unsigned long long off; + + + delete = find = 0; + off = 0; + offset = encryption = passfd = NULL; + + progname = argv[0]; + if ((p = strrchr(progname, '/')) != NULL) + progname = p+1; + + while ((c = getopt(argc, argv, "de:E:fo:p:v")) != -1) { + switch (c) { + case 'd': + delete = 1; + break; + case 'E': + case 'e': + encryption = optarg; + break; + case 'f': + find = 1; + break; + case 'o': + offset = optarg; + break; + case 'p': + passfd = optarg; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + } + } + + if (argc == 1) { + usage(); + } else if (delete) { + if (argc != optind+1 || encryption || offset || find) + usage(); + } else if (find) { + if (argc < optind || argc > optind+1) + usage(); + } else { + if (argc < optind+1 || argc > optind+2) + usage(); + } + + if (find) { + device = find_unused_loop_device(); + if (device == NULL) + return -1; + if (verbose) + printf("Loop device is %s\n", device); + if (argc == optind) { + printf("%s\n", device); + return 0; + } + file = argv[optind]; + } else { + device = argv[optind]; + if (argc == optind+1) + file = NULL; + else + file = argv[optind+1]; + } + + if (delete) + res = del_loop(device); + else if (file == NULL) + res = show_loop(device); + else { + if (offset && sscanf(offset, "%llu", &off) != 1) + usage(); + if (passfd && sscanf(passfd, "%d", &pfd) != 1) + usage(); + res = set_loop(device, file, off, encryption, pfd, &ro); + } + return res; +} Index: klibc-1.5/usr/utils/loop.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ klibc-1.5/usr/utils/loop.h 2008-03-07 23:01:49.336694297 +0100 @@ -0,0 +1,51 @@ +#define LO_CRYPT_NONE 0 +#define LO_CRYPT_XOR 1 +#define LO_CRYPT_DES 2 +#define LO_CRYPT_CRYPTOAPI 18 + +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +#define LOOP_SET_STATUS 0x4C02 +#define LOOP_GET_STATUS 0x4C03 +#define LOOP_SET_STATUS64 0x4C04 +#define LOOP_GET_STATUS64 0x4C05 + +#define LO_NAME_SIZE 64 +#define LO_KEY_SIZE 32 + +#include "my_dev_t.h" + +struct loop_info { + int lo_number; + my_dev_t lo_device; + unsigned long lo_inode; + my_dev_t lo_rdevice; + int lo_offset; + int lo_encrypt_type; + int lo_encrypt_key_size; + int lo_flags; + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; + unsigned long lo_init[2]; + char reserved[4]; +}; + +/* + * Where to get __u8, __u32, __u64? Let us use unsigned char/int/long long + * and get punished when someone comes with 128-bit long longs. + */ +struct loop_info64 { + unsigned long long lo_device; + unsigned long long lo_inode; + unsigned long long lo_rdevice; + unsigned long long lo_offset; + unsigned long long lo_sizelimit; /* bytes, 0 == max available */ + unsigned int lo_number; + unsigned int lo_encrypt_type; + unsigned int lo_encrypt_key_size; + unsigned int lo_flags; + unsigned char lo_file_name[LO_NAME_SIZE]; + unsigned char lo_crypt_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; + unsigned long long lo_init[2]; +}; Index: klibc-1.5/usr/utils/my_dev_t.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ klibc-1.5/usr/utils/my_dev_t.h 2008-03-07 23:03:45.148693283 +0100 @@ -0,0 +1,20 @@ +/* silliness to get dev_t defined as the kernel defines it */ +/* glibc uses a different dev_t */ + +#include +#include + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(1,3,78) +/* for i386 - alpha uses unsigned int */ +#define my_dev_t unsigned short +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68) +#define my_dev_t __kernel_dev_t +#else +#define my_dev_t __kernel_old_dev_t +#endif +#endif