diff options
Diffstat (limited to 'util-linux')
| -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; |
