aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-09-07 14:09:01 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-09-07 14:09:01 +0200
commit20a3262cd756aadf8771969a4764cd3c571f0a3e (patch)
treed0d64a79b6c0a86cba0c5454f7d39085828d550b
parentb9f56e82da9a0821011e1e0924acd1d781643070 (diff)
downloadbusybox-w32-20a3262cd756aadf8771969a4764cd3c571f0a3e.tar.gz
busybox-w32-20a3262cd756aadf8771969a4764cd3c571f0a3e.tar.bz2
busybox-w32-20a3262cd756aadf8771969a4764cd3c571f0a3e.zip
mdev: create devices from /sys/dev
Currently some new devices that have a bus but no class will be missed by mdev coldplug device creation after boot. This happens because mdev recursively searches /sys/class which will by definition only find class devices. Some important devices such as iio and gpiochip does not have a class. But users will need them. This switches from using /sys/class as the place to look for devices to create to using /sys/dev where all char and block devices are listed. The subsystem lookup code that provide the G.subsystem environment variable is changed from using the directory name of the class device to instead dereference the "subsystem" symlink for the device, and look at the last element of the path of the symlink for the subsystem, which will work with class devices and bus devices alike. (The new bus-only devices only symlink to the /sys/bus/* hierarchy.) We delete the legacy kernel v2.6.2x /sys/block device path code as part of this change. It's too old to be kept alive. Tested on kernel v4.6-rc2 with a bunch of devices, including some IIO and gpiochip devices. With a print inserted before make_device() the log looks like so: Create device from "/sys/dev/char/1:1", subsystem "mem" Create device from "/sys/dev/char/1:2", subsystem "mem" Create device from "/sys/dev/char/1:3", subsystem "mem" Create device from "/sys/dev/char/1:5", subsystem "mem" (...) Create device from "/sys/dev/block/179:56", subsystem "block" Create device from "/sys/dev/block/179:64", subsystem "block" function old new delta mdev_main 1388 1346 -42 dirAction 134 14 -120 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-162) Total: -162 bytes Cc: Isaac Dunham <ibid.ag@gmail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-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;