diff options
-rw-r--r-- | util-linux/mdev.c | 88 |
1 files changed, 41 insertions, 47 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 37514eb54..a59115dd4 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -543,8 +543,7 @@ static char *build_alias(char *alias, const char *device_name) | |||
543 | 543 | ||
544 | /* mknod in /dev based on a path like "/sys/block/hda/hda1" | 544 | /* mknod in /dev based on a path like "/sys/block/hda/hda1" |
545 | * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes | 545 | * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes |
546 | * after NUL, but we promise to not mangle (IOW: to restore NUL if needed) | 546 | * after NUL, but we promise to not mangle it (IOW: to restore NUL if needed). |
547 | * path string. | ||
548 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! | 547 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! |
549 | * | 548 | * |
550 | * device_name = $DEVNAME (may be NULL) | 549 | * device_name = $DEVNAME (may be NULL) |
@@ -810,41 +809,39 @@ static void make_device(char *device_name, char *path, int operation) | |||
810 | } /* for (;;) */ | 809 | } /* for (;;) */ |
811 | } | 810 | } |
812 | 811 | ||
813 | /* File callback for /sys/ traversal */ | 812 | /* File callback for /sys/ traversal. |
813 | * We act only on "/sys/.../dev" (pseudo)file | ||
814 | */ | ||
814 | static int FAST_FUNC fileAction(const char *fileName, | 815 | static int FAST_FUNC fileAction(const char *fileName, |
815 | struct stat *statbuf UNUSED_PARAM, | 816 | struct stat *statbuf UNUSED_PARAM, |
816 | void *userData, | 817 | void *userData, |
817 | int depth UNUSED_PARAM) | 818 | int depth UNUSED_PARAM) |
818 | { | 819 | { |
819 | size_t len = strlen(fileName) - 4; /* can't underflow */ | 820 | size_t len = strlen(fileName) - 4; /* can't underflow */ |
820 | char *scratch = userData; | 821 | char *path = userData; /* char array[PATH_MAX + SCRATCH_SIZE] */ |
821 | 822 | char subsys[PATH_MAX]; | |
822 | /* len check is for paranoid reasons */ | 823 | int res; |
823 | if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX) | 824 | |
824 | return FALSE; | 825 | /* Is it a ".../dev" file? (len check is for paranoid reasons) */ |
825 | 826 | if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX - 32) | |
826 | strcpy(scratch, fileName); | 827 | return FALSE; /* not .../dev */ |
827 | scratch[len] = '\0'; | 828 | |
828 | make_device(/*DEVNAME:*/ NULL, scratch, OP_add); | 829 | strcpy(path, fileName); |
829 | 830 | path[len] = '\0'; | |
830 | return TRUE; | 831 | |
831 | } | 832 | /* Read ".../subsystem" symlink in the same directory where ".../dev" is */ |
832 | 833 | strcpy(subsys, path); | |
833 | /* Directory callback for /sys/ traversal */ | 834 | strcpy(subsys + len, "/subsystem"); |
834 | static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | 835 | res = readlink(subsys, subsys, sizeof(subsys)-1); |
835 | struct stat *statbuf UNUSED_PARAM, | 836 | if (res > 0) { |
836 | void *userData UNUSED_PARAM, | 837 | subsys[res] = '\0'; |
837 | int depth) | ||
838 | { | ||
839 | /* Extract device subsystem -- the name of the directory | ||
840 | * under /sys/class/ */ | ||
841 | if (1 == depth) { | ||
842 | free(G.subsystem); | 838 | free(G.subsystem); |
843 | if (G.subsys_env) { | 839 | if (G.subsys_env) { |
844 | bb_unsetenv_and_free(G.subsys_env); | 840 | bb_unsetenv_and_free(G.subsys_env); |
845 | G.subsys_env = NULL; | 841 | G.subsys_env = NULL; |
846 | } | 842 | } |
847 | G.subsystem = strrchr(fileName, '/'); | 843 | /* Set G.subsystem and $SUBSYSTEM from symlink's last component */ |
844 | G.subsystem = strrchr(subsys, '/'); | ||
848 | if (G.subsystem) { | 845 | if (G.subsystem) { |
849 | G.subsystem = xstrdup(G.subsystem + 1); | 846 | G.subsystem = xstrdup(G.subsystem + 1); |
850 | G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | 847 | G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); |
@@ -852,6 +849,17 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | |||
852 | } | 849 | } |
853 | } | 850 | } |
854 | 851 | ||
852 | make_device(/*DEVNAME:*/ NULL, path, OP_add); | ||
853 | |||
854 | return TRUE; | ||
855 | } | ||
856 | |||
857 | /* Directory callback for /sys/ traversal */ | ||
858 | static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | ||
859 | struct stat *statbuf UNUSED_PARAM, | ||
860 | void *userData UNUSED_PARAM, | ||
861 | int depth) | ||
862 | { | ||
855 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); | 863 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); |
856 | } | 864 | } |
857 | 865 | ||
@@ -872,8 +880,9 @@ static void load_firmware(const char *firmware, const char *sysfs_path) | |||
872 | int firmware_fd, loading_fd; | 880 | int firmware_fd, loading_fd; |
873 | 881 | ||
874 | /* check for /lib/firmware/$FIRMWARE */ | 882 | /* check for /lib/firmware/$FIRMWARE */ |
875 | xchdir("/lib/firmware"); | 883 | firmware_fd = -1; |
876 | firmware_fd = open(firmware, O_RDONLY); /* can fail */ | 884 | if (chdir("/lib/firmware") == 0) |
885 | firmware_fd = open(firmware, O_RDONLY); /* can fail */ | ||
877 | 886 | ||
878 | /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */ | 887 | /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */ |
879 | xchdir(sysfs_path); | 888 | xchdir(sysfs_path); |
@@ -1065,25 +1074,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
1065 | 1074 | ||
1066 | putenv((char*)"ACTION=add"); | 1075 | putenv((char*)"ACTION=add"); |
1067 | 1076 | ||
1068 | /* ACTION_FOLLOWLINKS is needed since in newer kernels | 1077 | /* Create all devices from /sys/dev hierarchy */ |
1069 | * /sys/block/loop* (for example) are symlinks to dirs, | 1078 | recursive_action("/sys/dev", |
1070 | * not real directories. | 1079 | ACTION_RECURSE | ACTION_FOLLOWLINKS, |
1071 | * (kernel's CONFIG_SYSFS_DEPRECATED makes them real dirs, | 1080 | fileAction, dirAction, temp, 0); |
1072 | * but we can't enforce that on users) | ||
1073 | */ | ||
1074 | if (access("/sys/class/block", F_OK) != 0) { | ||
1075 | /* Scan obsolete /sys/block only if /sys/class/block | ||
1076 | * doesn't exist. Otherwise we'll have dupes. | ||
1077 | * Also, do not complain if it doesn't exist. | ||
1078 | * Some people configure kernel to have no blockdevs. | ||
1079 | */ | ||
1080 | recursive_action("/sys/block", | ||
1081 | ACTION_RECURSE | ACTION_FOLLOWLINKS | ACTION_QUIET, | ||
1082 | fileAction, dirAction, temp, 0); | ||
1083 | } | ||
1084 | recursive_action("/sys/class", | ||
1085 | ACTION_RECURSE | ACTION_FOLLOWLINKS, | ||
1086 | fileAction, dirAction, temp, 0); | ||
1087 | } else { | 1081 | } else { |
1088 | char *fw; | 1082 | char *fw; |
1089 | char *seq; | 1083 | char *seq; |