diff -Naur busybox-1.01-orig/include/applets.h busybox-1.01/include/applets.h --- busybox-1.01-orig/include/applets.h 2005-08-16 18:29:15.000000000 -0700 +++ busybox-1.01/include/applets.h 2005-12-14 16:11:01.000000000 -0800 @@ -382,6 +382,9 @@ #ifdef CONFIG_MKSWAP APPLET(mkswap, mkswap_main, _BB_DIR_SBIN, _BB_SUID_NEVER) #endif +#ifdef CONFIG_MKROOTDEV + APPLET(mkrootdev, mkrootdev_main, _BB_DIR_BIN, _BB_SUID_NEVER) +#endif #ifdef CONFIG_MKTEMP APPLET(mktemp, mktemp_main, _BB_DIR_BIN, _BB_SUID_NEVER) #endif diff -Naur busybox-1.01-orig/include/usage.h busybox-1.01/include/usage.h --- busybox-1.01-orig/include/usage.h 2005-08-16 18:29:15.000000000 -0700 +++ busybox-1.01/include/usage.h 2005-12-14 16:11:38.000000000 -0800 @@ -1652,6 +1652,13 @@ "$ mknod /dev/fd0 b 2 0\n" \ "$ mknod -m 644 /tmp/pipe p\n" +#define mkrootdev_trivial_usage \ + "" +#define mkrootdev_full_usage \ + "Creates a /dev/root block node by examining kernel boot paramters\n" \ + "Syntax:\n" \ + "\tmkrootdev \n" + #define mkswap_trivial_usage \ "[-c] [-v0|-v1] device [block-count]" #define mkswap_full_usage \ diff -Naur busybox-1.01-orig/init/Config.in busybox-1.01/init/Config.in --- busybox-1.01-orig/init/Config.in 2005-08-16 18:29:16.000000000 -0700 +++ busybox-1.01/init/Config.in 2005-12-14 16:08:07.000000000 -0800 @@ -76,5 +76,12 @@ Mesg controls access to your terminal by others. It is typically used to allow or disallow other users to write to your terminal +config CONFIG_MKROOTDEV + bool "mkrootdev" + default y + help + Create a /dev/root block device by examining kernel boot parameters + to determine the actual root device. + endmenu diff -Naur busybox-1.01-orig/init/Makefile.in busybox-1.01/init/Makefile.in --- busybox-1.01-orig/init/Makefile.in 2005-08-16 18:29:16.000000000 -0700 +++ busybox-1.01/init/Makefile.in 2005-12-14 16:08:07.000000000 -0800 @@ -29,10 +29,14 @@ INIT-$(CONFIG_MESG) += mesg.o INIT-$(CONFIG_POWEROFF) += poweroff.o INIT-$(CONFIG_REBOOT) += reboot.o +INIT-$(CONFIG_MKROOTDEV) += mkrootdev.o ifeq ($(CONFIG_HALT), y) CONFIG_INIT_SHARED=y else +ifeq ($(CONFIG_MKROOTDEV), y) +CONFIG_INIT_SHARED=y +else ifeq ($(CONFIG_INIT), y) CONFIG_INIT_SHARED=y else @@ -47,6 +51,7 @@ endif endif endif +endif ifeq ($(CONFIG_INIT_SHARED), y) INIT-$(CONFIG_INIT_SHARED) += init_shared.o diff -Naur busybox-1.01-orig/init/mkrootdev.c busybox-1.01/init/mkrootdev.c --- busybox-1.01-orig/init/mkrootdev.c 1969-12-31 16:00:00.000000000 -0800 +++ busybox-1.01/init/mkrootdev.c 2005-12-14 16:08:07.000000000 -0800 @@ -0,0 +1,283 @@ +/* mkrootdev.c + * + * This code was taken from RedHat's nash code in mkinitrd-4.1.11 and + * adapted for Arch Linux. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "busybox.h" + +#define CMDLINESIZE 1024 + +static dev_t try_name(char *name, int part) +{ + char path[64]; + char buf[32]; + int range; + dev_t res; + char *s; + int len; + int fd; + unsigned int maj, min; + + /* read device number from .../dev */ + sprintf(path, "/sys/block/%s/dev", name); + fd = open(path, O_RDONLY); + if (fd < 0) + goto fail; + len = read(fd, buf, 32); + close(fd); + if (len <= 0 || len == 32 || buf[len - 1] != '\n') + goto fail; + buf[len - 1] = '\0'; + if (sscanf(buf, "%u:%u", &maj, &min) != 2) + goto fail; + res = makedev(maj, min); + if (maj != major(res) || min != minor(res)) + goto fail; + + /* if it's there and we are not looking for a partition - that's it */ + if (!part) + return res; + + /* otherwise read range from .../range */ + snprintf(path, 64, "/sys/block/%s/range", name); + fd = open(path, O_RDONLY); + if (fd < 0) + goto fail; + len = read(fd, buf, 32); + close(fd); + if (len <= 0 || len == 32 || buf[len - 1] != '\n') + goto fail; + buf[len - 1] = '\0'; + range = strtoul(buf, &s, 10); + if (*s) + goto fail; + + /* if partition is within range - we got it */ + if (part < range) + return res + part; +fail: + return 0; +} + +/* + * Convert a name into device number. We accept the following variants: + * + * 1) device number in hexadecimal represents itself + * 2) /dev/nfs represents Root_NFS (0xff) + * 3) /dev/ represents the device number of disk + * 4) /dev/ represents the device number + * of partition - device number of disk plus the partition number + * 5) /dev/p - same as the above, that form is + * used when disk name of partitioned disk ends on a digit. + * + * If name doesn't have fall into the categories above, we return 0. + * sysfs is used to check if something is a disk name - it has + * all known disks under bus/block/devices. If the disk name + * contains slashes, name of driverfs node has them replaced with + * bangs. try_name() does the actual checks, assuming that sysfs + * is mounted on /sys. + * + * Note that cases (1) and (2) are already handled by the kernel, + * so we can ifdef them out, provided that we check real-root-dev + * first. + */ + +dev_t name_to_dev_t(char *name) +{ + char s[32]; + char *p; + dev_t res = 0; + int part; + + if (strncmp(name, "/dev/", 5) != 0) { +#if 1 /* kernel used to do this */ + unsigned maj, min; + + if (sscanf(name, "%u:%u", &maj, &min) == 2) { + res = makedev(maj, min); + if (maj != major(res) || min != minor(res)) + return 0; + } else { + res = strtoul(name, &p, 16); + if (*p) + return 0; + } +#endif + return res; + } + + name += 5; + +#if 1 /* kernel used to do this */ + if (strcmp(name, "nfs") == 0) + return makedev(0, 255); +#endif + + if (strlen(name) > 31) + return 0; + strcpy(s, name); + for (p = s; *p; p++) + if (*p == '/') + *p = '!'; + res = try_name(s, 0); + if (res) + return res; + + while (p > s && isdigit(p[-1])) + p--; + if (p == s || !*p || *p == '0') + return 0; + part = strtoul(p, NULL, 10); + *p = '\0'; + res = try_name(s, part); + if (res) + return res; + + if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') + return 0; + p[-1] = '\0'; + return try_name(s, part); +} + +int smartmknod(char * device, mode_t mode, dev_t dev) { + char buf[256]; + char * end; + + strncpy(buf, device, 256); + + end = buf; + while (*end) { + if (*end == '/') { + *end = '\0'; + if (access(buf, F_OK) && errno == ENOENT) + mkdir(buf, 0755); + *end = '/'; + } + + end++; + } + + return mknod(device, mode, dev); +} + +/* get the contents of the kernel command line from /proc/cmdline */ +static char *getKernelCmdLine(void) { + int fd, i; + char * buf; + + fd = open("/proc/cmdline", O_RDONLY, 0); + if (fd < 0) { + printf("getKernelCmdLine: failed to open /proc/cmdline: %d\n", errno); + return NULL; + } + + buf = malloc(CMDLINESIZE); + if (!buf) + return buf; + + i = read(fd, buf, CMDLINESIZE); + if (i < 0) { + printf("getKernelCmdLine: failed to read /proc/cmdline: %d\n", errno); + close(fd); + return NULL; + } + + close(fd); + if (i == 0) + buf[0] = '\0'; + else + buf[i - 1] = '\0'; + return buf; +} + +/* get the start of a kernel arg "arg". returns everything after it + * (useful for things like getting the args to init=). so if you only + * want one arg, you need to terminate it at the n */ +static char * getKernelArg(char * arg) { + char * start, * cmdline; + + cmdline = start = getKernelCmdLine(); + if (start == NULL) return NULL; + while (*start) { + if (isspace(*start)) { + start++; + continue; + } + if (strncmp(start, arg, strlen(arg)) == 0) { + return start + strlen(arg); + } + while (*++start && !isspace(*start)) + ; + } + + return NULL; +} + +int mkrootdev_main(int argc, char **argv) { + char path[1024]; + char *root, *chptr; + int devNum = 0; + int fd; + int i; + char buf[1024]; + int major, minor; + + if(argc < 2) { + printf("usage: mkrootdev \n"); + return 1; + } + strncpy(path, argv[1], 1023); + + root = getKernelArg("root="); + if (root) { + chptr = root; + while (*chptr && !isspace(*chptr)) chptr++; + *chptr = '\0'; + } + + fd = open("/proc/sys/kernel/real-root-dev", O_RDONLY, 0); + if(fd < 0) { + printf("mkrootdev: failed to open /proc/sys/kernel/real-root-dev: %d\n", errno); + return 1; + } + + i = read(fd, buf, sizeof(buf)); + if(i < 0) { + printf("mkrootdev: failed to read real-root-dev: %d\n", errno); + close(fd); + return 1; + } + + close(fd); + if(i == 0) + buf[i] = '\0'; + else + buf[i - 1] = '\0'; + + devNum = atoi(buf); + if(devNum < 0) { + printf("mkrootdev: bad device %s\n", buf); + return 1; + } + + if(!devNum && root) + devNum = name_to_dev_t(root); + + if(smartmknod(path, S_IFBLK | 0700, devNum)) { + printf("mkrootdev: mknod failed: %d\n", errno); + return 1; + } + + return 0; +}