aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util-linux/mdev.c88
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 */
814static int FAST_FUNC fileAction(const char *fileName, 815static 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");
834static 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 */
858static 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;