summaryrefslogtreecommitdiff
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 37514eb..a59115d 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)
/* mknod in /dev based on a path like "/sys/block/hda/hda1"
* NB1: path parameter needs to have SCRATCH_SIZE scratch bytes
- * after NUL, but we promise to not mangle (IOW: to restore NUL if needed)
- * path string.
+ * after NUL, but we promise to not mangle it (IOW: to restore NUL if needed).
* NB2: "mdev -s" may call us many times, do not leak memory/fds!
*
* device_name = $DEVNAME (may be NULL)
@@ -810,41 +809,39 @@ static void make_device(char *device_name, char *path, int operation)
} /* for (;;) */
}
-/* File callback for /sys/ traversal */
+/* File callback for /sys/ traversal.
+ * We act only on "/sys/.../dev" (pseudo)file
+ */
static int FAST_FUNC fileAction(const char *fileName,
struct stat *statbuf UNUSED_PARAM,
void *userData,
int depth UNUSED_PARAM)
{
size_t len = strlen(fileName) - 4; /* can't underflow */
- char *scratch = userData;
-
- /* len check is for paranoid reasons */
- if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX)
- return FALSE;
-
- strcpy(scratch, fileName);
- scratch[len] = '\0';
- make_device(/*DEVNAME:*/ NULL, scratch, OP_add);
-
- return TRUE;
-}
-
-/* Directory callback for /sys/ traversal */
-static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
- struct stat *statbuf UNUSED_PARAM,
- void *userData UNUSED_PARAM,
- int depth)
-{
- /* Extract device subsystem -- the name of the directory
- * under /sys/class/ */
- if (1 == depth) {
+ char *path = userData; /* char array[PATH_MAX + SCRATCH_SIZE] */
+ char subsys[PATH_MAX];
+ int res;
+
+ /* Is it a ".../dev" file? (len check is for paranoid reasons) */
+ if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX - 32)
+ return FALSE; /* not .../dev */
+
+ strcpy(path, fileName);
+ path[len] = '\0';
+
+ /* Read ".../subsystem" symlink in the same directory where ".../dev" is */
+ strcpy(subsys, path);
+ strcpy(subsys + len, "/subsystem");
+ res = readlink(subsys, subsys, sizeof(subsys)-1);
+ if (res > 0) {
+ subsys[res] = '\0';
free(G.subsystem);
if (G.subsys_env) {
bb_unsetenv_and_free(G.subsys_env);
G.subsys_env = NULL;
}
- G.subsystem = strrchr(fileName, '/');
+ /* Set G.subsystem and $SUBSYSTEM from symlink's last component */
+ G.subsystem = strrchr(subsys, '/');
if (G.subsystem) {
G.subsystem = xstrdup(G.subsystem + 1);
G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem);
@@ -852,6 +849,17 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
}
}
+ make_device(/*DEVNAME:*/ NULL, path, OP_add);
+
+ return TRUE;
+}
+
+/* Directory callback for /sys/ traversal */
+static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
+ struct stat *statbuf UNUSED_PARAM,
+ void *userData UNUSED_PARAM,
+ int depth)
+{
return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
}
@@ -872,8 +880,9 @@ static void load_firmware(const char *firmware, const char *sysfs_path)
int firmware_fd, loading_fd;
/* check for /lib/firmware/$FIRMWARE */
- xchdir("/lib/firmware");
- firmware_fd = open(firmware, O_RDONLY); /* can fail */
+ firmware_fd = -1;
+ if (chdir("/lib/firmware") == 0)
+ firmware_fd = open(firmware, O_RDONLY); /* can fail */
/* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */
xchdir(sysfs_path);
@@ -1065,25 +1074,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
putenv((char*)"ACTION=add");
- /* ACTION_FOLLOWLINKS is needed since in newer kernels
- * /sys/block/loop* (for example) are symlinks to dirs,
- * not real directories.
- * (kernel's CONFIG_SYSFS_DEPRECATED makes them real dirs,
- * but we can't enforce that on users)
- */
- if (access("/sys/class/block", F_OK) != 0) {
- /* Scan obsolete /sys/block only if /sys/class/block
- * doesn't exist. Otherwise we'll have dupes.
- * Also, do not complain if it doesn't exist.
- * Some people configure kernel to have no blockdevs.
- */
- recursive_action("/sys/block",
- ACTION_RECURSE | ACTION_FOLLOWLINKS | ACTION_QUIET,
- fileAction, dirAction, temp, 0);
- }
- recursive_action("/sys/class",
- ACTION_RECURSE | ACTION_FOLLOWLINKS,
- fileAction, dirAction, temp, 0);
+ /* Create all devices from /sys/dev hierarchy */
+ recursive_action("/sys/dev",
+ ACTION_RECURSE | ACTION_FOLLOWLINKS,
+ fileAction, dirAction, temp, 0);
} else {
char *fw;
char *seq;