X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=util-linux%2Fmdev.c;h=73a82314c3cf3ef572ffcdf7b697898c83c2c06f;hb=1449a2014a4e715a7a52b27caec528a9c802fa5f;hp=f6d4d8df00c103ef4ec7af8bf699b75a9f6352c6;hpb=271aa40a15be3d111f2016e24832a86657661cca;p=oweals%2Fbusybox.git diff --git a/util-linux/mdev.c b/util-linux/mdev.c index f6d4d8df0..73a82314c 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,13 @@ #include +struct mdev_globals +{ + int root_major, root_minor; +} mdev_globals; + +#define bbg mdev_globals + /* mknod in /dev based on a path like "/sys/block/hda/hda1" */ static void make_device(char *path) { @@ -35,23 +43,25 @@ static void make_device(char *path) int mode = 0660; uid_t uid = 0; gid_t gid = 0; + char *temp = path + strlen(path); - RESERVE_CONFIG_BUFFER(temp, PATH_MAX); + /* Try to read major/minor string. Note that the kernel puts \n after + * the data, so we don't need to worry about null terminating the string + * because sscanf() will stop at the first nondigit, which \n is. We + * also depend on path having writeable space after it. */ - /* Try to read major/minor string */ - - snprintf(temp, PATH_MAX, "%s/dev", path); - fd = open(temp, O_RDONLY); - len = read(fd, temp, PATH_MAX-1); + strcat(path, "/dev"); + fd = open(path, O_RDONLY); + len = read(fd, temp + 1, 64); + *temp++ = 0; close(fd); - if (len < 1) goto end; + if (len < 1) return; /* Determine device name, type, major and minor */ device_name = strrchr(path, '/') + 1; - type = strncmp(path+5, "block/", 6) ? S_IFCHR : S_IFBLK; - if (sscanf(temp, "%d:%d", &major, &minor) != 2) - goto end; + type = path[5]=='c' ? S_IFCHR : S_IFBLK; + if (sscanf(temp, "%d:%d", &major, &minor) != 2) return; /* If we have a config file, look up permissions for this device */ @@ -164,15 +174,14 @@ found_device: } } - sprintf(temp, "%s/%s", DEV_PATH, device_name); umask(0); - if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST) - bb_perror_msg_and_die("mknod %s failed", temp); - - if (ENABLE_FEATURE_MDEV_CONF) chown(temp,uid,gid); + if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) + bb_perror_msg_and_die("mknod %s failed", device_name); -end: - RELEASE_CONFIG_BUFFER(temp); + if (major==bbg.root_major && minor==bbg.root_minor) + symlink(device_name, "root"); + + if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid); } /* Recursive search of /sys/block or /sys/class. path must be a writeable @@ -188,17 +197,18 @@ static void find_dev(char *path) return; while ((entry = readdir(dir)) != NULL) { + struct stat st; /* Skip "." and ".." (also skips hidden files, which is ok) */ if (entry->d_name[0] == '.') continue; - if (entry->d_type == DT_DIR) { - snprintf(path+len, PATH_MAX-len, "/%s", entry->d_name); - find_dev(path); - path[len] = 0; - } + // uClibc doesn't fill out entry->d_type reliably. so we use lstat(). + + 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; /* If there's a dev entry, mknod it */ @@ -214,9 +224,16 @@ int mdev_main(int argc, char *argv[]) char *env_path; RESERVE_CONFIG_BUFFER(temp,PATH_MAX); + bb_xchdir(DEV_PATH); + /* Scan */ if (argc == 2 && !strcmp(argv[1],"-s")) { + struct stat st; + + stat("/", &st); // If this fails, we have bigger problems. + bbg.root_major=major(st.st_dev); + bbg.root_minor=minor(st.st_dev); strcpy(temp,"/sys/block"); find_dev(temp); strcpy(temp,"/sys/class"); @@ -234,8 +251,7 @@ int mdev_main(int argc, char *argv[]) sprintf(temp, "/sys%s", env_path); make_device(temp); } else if (!strcmp(action, "remove")) { - sprintf(temp, "%s/%s", DEV_PATH, strrchr(env_path, '/') + 1); - unlink(temp); + unlink(strrchr(env_path, '/') + 1); } }