dd: code shrink
[oweals/busybox.git] / util-linux / mdev.c
index c5c0d613c8a4a08f5be0b6f9c26110931a0b5fa0..e80b58f2e270396fcd58022d749c00d265bd328c 100644 (file)
@@ -295,8 +295,8 @@ struct globals {
 /* Prevent infinite loops in /sys symlinks */
 #define MAX_SYSFS_DEPTH 3
 
-/* We use additional 64+ bytes in make_device() */
-#define SCRATCH_SIZE 80
+/* We use additional bytes in make_device() */
+#define SCRATCH_SIZE 128
 
 #if ENABLE_FEATURE_MDEV_CONF
 
@@ -541,7 +541,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 if needed)
+ * after NUL, but we promise to not mangle (IOW: to restore NUL if needed)
  * path string.
  * NB2: "mdev -s" may call us many times, do not leak memory/fds!
  *
@@ -551,6 +551,7 @@ static char *build_alias(char *alias, const char *device_name)
 static void make_device(char *device_name, char *path, int operation)
 {
        int major, minor, type, len;
+       char *path_end = path + strlen(path);
 
        /* 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
@@ -559,17 +560,15 @@ static void make_device(char *device_name, char *path, int operation)
         */
        major = -1;
        if (operation == OP_add) {
-               char *dev_maj_min = path + strlen(path);
-
-               strcpy(dev_maj_min, "/dev");
-               len = open_read_close(path, dev_maj_min + 1, 64);
-               *dev_maj_min = '\0';
+               strcpy(path_end, "/dev");
+               len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1);
+               *path_end = '\0';
                if (len < 1) {
                        if (!ENABLE_FEATURE_MDEV_EXEC)
                                return;
                        /* no "dev" file, but we can still run scripts
                         * based on device name */
-               } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) {
+               } else if (sscanf(path_end + 1, "%u:%u", &major, &minor) == 2) {
                        dbg1("dev %u,%u", major, minor);
                } else {
                        major = -1;
@@ -577,9 +576,33 @@ static void make_device(char *device_name, char *path, int operation)
        }
        /* else: for delete, -1 still deletes the node, but < -1 suppresses that */
 
-       /* Determine device name, type, major and minor */
-       if (!device_name)
-               device_name = (char*) bb_basename(path);
+       /* Determine device name */
+       if (!device_name) {
+               /*
+                * There was no $DEVNAME envvar (for example, mdev -s never has).
+                * But it is very useful: it contains the *path*, not only basename,
+                * Thankfully, uevent file has it.
+                * Example of .../sound/card0/controlC0/uevent file on Linux-3.7.7:
+                * MAJOR=116
+                * MINOR=7
+                * DEVNAME=snd/controlC0
+                */
+               strcpy(path_end, "/uevent");
+               len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1);
+               if (len < 0)
+                       len = 0;
+               *path_end = '\0';
+               path_end[1 + len] = '\0';
+               device_name = strstr(path_end + 1, "\nDEVNAME=");
+               if (device_name) {
+                       device_name += sizeof("\nDEVNAME=")-1;
+                       strchrnul(device_name, '\n')[0] = '\0';
+               } else {
+                       /* Fall back to just basename */
+                       device_name = (char*) bb_basename(path);
+               }
+       }
+       /* Determine device type */
        /*
         * http://kernel.org/doc/pending/hotplug.txt says that only
         * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
@@ -646,9 +669,8 @@ static void make_device(char *device_name, char *path, int operation)
                }
                /* else: it's final implicit "match-all" rule */
  rule_matches:
-#endif
                dbg2("rule matched, line %d", G.parser ? G.parser->lineno : -1);
-
+#endif
                /* Build alias name */
                alias = NULL;
                if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) {
@@ -1061,15 +1083,15 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
                 * ACTION can be "add", "remove", "change"
                 * DEVPATH is like "/block/sda" or "/class/input/mice"
                 */
-               action = getenv("ACTION");
-               op = index_in_strings(keywords, action);
                env_devname = getenv("DEVNAME"); /* can be NULL */
-               env_devpath = getenv("DEVPATH");
                G.subsystem = getenv("SUBSYSTEM");
+               action = getenv("ACTION");
+               env_devpath = getenv("DEVPATH");
                if (!action || !env_devpath /*|| !G.subsystem*/)
                        bb_show_usage();
                fw = getenv("FIRMWARE");
                seq = getenv("SEQNUM");
+               op = index_in_strings(keywords, action);
 
                my_pid = getpid();
                open_mdev_log(seq, my_pid);