summaryrefslogtreecommitdiffhomepage
path: root/util-linux/mdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r--util-linux/mdev.c59
1 files changed, 27 insertions, 32 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 8e5b8a94b..fca4fd052 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -19,6 +19,8 @@ struct globals {
#define root_major (G.root_major)
#define root_minor (G.root_minor)
+#define MAX_SYSFS_DEPTH 3 /* prevent infinite loops in /sys symlinks */
+
/* mknod in /dev based on a path like "/sys/block/hda/hda1" */
static void make_device(char *path, int delete)
{
@@ -191,39 +193,28 @@ static void make_device(char *path, int delete)
if (delete) unlink(device_name);
}
-/* Recursive search of /sys/block or /sys/class. path must be a writeable
- * buffer of size PATH_MAX containing the directory string to start at. */
-
-static void find_dev(char *path)
+/* File callback for /sys/ traversal */
+static int fileAction(const char *fileName, struct stat *statbuf,
+ void *userData, int depth)
{
- DIR *dir;
- size_t len = strlen(path);
- struct dirent *entry;
-
- dir = opendir(path);
- if (dir == NULL)
- return;
-
- while ((entry = readdir(dir)) != NULL) {
- struct stat st;
-
- /* Skip "." and ".." (also skips hidden files, which is ok) */
-
- if (entry->d_name[0] == '.')
- continue;
+ size_t len = strlen(fileName) - 4;
+ char *scratch = userData;
- // uClibc doesn't fill out entry->d_type reliably. so we use lstat().
+ if (strcmp(fileName + len, "/dev"))
+ return FALSE;
- snprintf(path+len, PATH_MAX-len, "/%s", entry->d_name);
- if (!lstat(path, &st) && S_ISDIR(st.st_mode)) find_dev(path);
- path[len] = 0;
+ strcpy(scratch, fileName);
+ scratch[len] = 0;
+ make_device(scratch, 0);
- /* If there's a dev entry, mknod it */
-
- if (!strcmp(entry->d_name, "dev")) make_device(path, 0);
- }
+ return TRUE;
+}
- closedir(dir);
+/* Directory callback for /sys/ traversal */
+static int dirAction(const char *fileName, struct stat *statbuf,
+ void *userData, int depth)
+{
+ return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
}
/* For the full gory details, see linux/Documentation/firmware_class/README
@@ -308,10 +299,14 @@ int mdev_main(int argc, char **argv)
xstat("/", &st);
root_major = major(st.st_dev);
root_minor = minor(st.st_dev);
- strcpy(temp,"/sys/block");
- find_dev(temp);
- strcpy(temp,"/sys/class");
- find_dev(temp);
+
+ recursive_action("/sys/block",
+ ACTION_RECURSE | ACTION_FOLLOWLINKS,
+ fileAction, dirAction, temp, 0);
+
+ recursive_action("/sys/class",
+ ACTION_RECURSE | ACTION_FOLLOWLINKS,
+ fileAction, dirAction, temp, 0);
/* Hotplug */