diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-02-24 10:39:47 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-02-24 10:39:47 +0100 |
commit | 64bb95a361c9d82e2abed90e0402459c68fb14b2 (patch) | |
tree | 3b2618d7b09e6d7db4b9c3e4ec20447b3ab20479 | |
parent | bf1d347964eac6bf25c1595d29fcb761e58c99c3 (diff) | |
download | busybox-64bb95a361c9d82e2abed90e0402459c68fb14b2.tar.gz |
mdev: fix subsystem passing (new kernels broke it again) - bugs 639, 721.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | util-linux/mdev.c | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 69e1e6937..9c9d95f8a 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -66,9 +66,6 @@ struct globals { char *subsystem; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#define root_major (G.root_major) -#define root_minor (G.root_minor) -#define subsystem (G.subsystem ) /* Prevent infinite loops in /sys symlinks */ #define MAX_SYSFS_DEPTH 3 @@ -109,7 +106,7 @@ static char *build_alias(char *alias, const char *device_name) */ static void make_device(char *path, int delete) { - char *device_name; + char *device_name, *subsystem_slash_devname; int major, minor, type, len; mode_t mode; parser_t *parser; @@ -140,17 +137,29 @@ static void make_device(char *path, int delete) device_name = (char*) bb_basename(path); /* http://kernel.org/doc/pending/hotplug.txt says that only * "/sys/block/..." is for block devices. "/sys/bus" etc is not. - * But since 2.6.25 block devices are also in /sys/class/block, - * we use strstr("/block/") to forestall future surprises. */ + * But since 2.6.25 block devices are also in /sys/class/block. + * We use strstr("/block/") to forestall future surprises. */ type = S_IFCHR; - if (strstr(path, "/block/")) + if (strstr(path, "/block/") || strncmp(G.subsystem, "block", 5) == 0) type = S_IFBLK; /* Make path point to "subsystem/device_name" */ - if (path[5] == 'b') /* legacy /sys/block? */ + subsystem_slash_devname = NULL; + /* Check for coldplug invocations first */ + if (strncmp(path, "/sys/block/", 11) == 0) /* legacy case */ path += sizeof("/sys/") - 1; - else + else if (strncmp(path, "/sys/class/", 11) == 0) path += sizeof("/sys/class/") - 1; + else { + /* Example of a hotplug invocation: + * SUBSYSTEM="block" + * DEVPATH="/sys" + "/devices/virtual/mtd/mtd3/mtdblock3" + * ("/sys" is added by mdev_main) + * - path does not contain subsystem + */ + subsystem_slash_devname = concat_path_file(G.subsystem, device_name); + path = subsystem_slash_devname; + } /* If we have config file, look up user settings */ if (ENABLE_FEATURE_MDEV_CONF) @@ -332,7 +341,7 @@ static void make_device(char *path, int delete) if (!delete && major >= 0) { if (mknod(node_name, mode | type, makedev(major, minor)) && errno != EEXIST) bb_perror_msg("can't create %s", node_name); - if (major == root_major && minor == root_minor) + if (major == G.root_major && minor == G.root_minor) symlink(node_name, "root"); if (ENABLE_FEATURE_MDEV_CONF) { chmod(node_name, mode); @@ -347,7 +356,7 @@ static void make_device(char *path, int delete) if (ENABLE_FEATURE_MDEV_EXEC && command) { /* setenv will leak memory, use putenv/unsetenv/free */ char *s = xasprintf("%s=%s", "MDEV", node_name); - char *s1 = xasprintf("%s=%s", "SUBSYSTEM", subsystem); + char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); putenv(s); putenv(s1); if (system(command) == -1) @@ -381,6 +390,7 @@ static void make_device(char *path, int delete) if (ENABLE_FEATURE_MDEV_CONF) config_close(parser); + free(subsystem_slash_devname); } /* File callback for /sys/ traversal */ @@ -398,7 +408,7 @@ static int FAST_FUNC fileAction(const char *fileName, strcpy(scratch, fileName); scratch[len] = '\0'; - make_device(scratch, 0); + make_device(scratch, /*delete:*/ 0); return TRUE; } @@ -412,10 +422,10 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, /* Extract device subsystem -- the name of the directory * under /sys/class/ */ if (1 == depth) { - free(subsystem); - subsystem = strrchr(fileName, '/'); - if (subsystem) - subsystem = xstrdup(subsystem + 1); + free(G.subsystem); + G.subsystem = strrchr(fileName, '/'); + if (G.subsystem) + G.subsystem = xstrdup(G.subsystem + 1); } return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); @@ -500,8 +510,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) struct stat st; xstat("/", &st); - root_major = major(st.st_dev); - root_minor = minor(st.st_dev); + G.root_major = major(st.st_dev); + G.root_minor = minor(st.st_dev); /* ACTION_FOLLOWLINKS is needed since in newer kernels * /sys/block/loop* (for example) are symlinks to dirs, @@ -538,8 +548,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) */ action = getenv("ACTION"); env_path = getenv("DEVPATH"); - subsystem = getenv("SUBSYSTEM"); - if (!action || !env_path /*|| !subsystem*/) + G.subsystem = getenv("SUBSYSTEM"); + if (!action || !env_path /*|| !G.subsystem*/) bb_show_usage(); fw = getenv("FIRMWARE"); op = index_in_strings(keywords, action); @@ -574,10 +584,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) * to happen and to cause erroneous deletion * of device nodes. */ if (!fw) - make_device(temp, 1); + make_device(temp, /*delete:*/ 1); } else if (op == OP_add) { - make_device(temp, 0); + make_device(temp, /*delete:*/ 0); if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { if (fw) load_firmware(fw, temp); |