Hello Rob,
Today I decided to see if I could implement hotplug support cleanly.
Here's a patch that adds support for hotplug (including device removal),
as well as making mdev probe for partitions. It costs about 30 lines of
new code; most of the "deletions" are just reindented.

I think it would be possible to implement this more concisely by doing
roughly this in the hotplug section:
    char *temp, *devpath = getenv("DEVPATH");

    if (!devpath) show_usage();
    temp = xmprintf("/sys%s/dev", devpath);
    make_device(devpath);
    free(devpath);

and in make_device(), if optflags is 0 then use the getenv("SUBSYSTEM")
path to determine if it's a block device.
This would still require checking for ACTION=remove.

But this feels "wrong", since MAJOR/MINOR/DEVNAME are there.

In case anyone thinks this is about to replace busybox mdev, here's what's
not supported from busybox:
* spawning helpers (FEATURE_MDEV_EXECUTE: @|$|*)
* serializing events via $SEQNUM and /dev/mdev.seq
* environment rules ($MODALIAS=.*)
  - this implies that module autoloading doesn't work; apparently the
    kernel does *not* autoload modules in most cases, although there
    seem to be a few places where it does. Some people object to
    autoloading modules, FWIW.
* move device (=dir/ | >dir/), regex-based rename
* username/group lookup
...in other words, most of the features people use mdev for.

If you want module autoloading without a rewrite of the config file stuff,
it would be trivial to implement it via something like this (in the hotplug
part of mdev_main):
    char alias = getenv("MODALIAS");
    if (alias) xexec((char *[]){"modprobe", "-abq", alias, NULL});
But I don't see how to make that configureable.


While I've worked on busybox mdev recently (within the past month),
I have found the way it's structured to be cumbersome and hideous.
Even if it were license compatible (which it isn't), I wouldn't want
to copy it.

Thanks,
Isaac Dunham
>From 39baa24fb84a03e76f3c278108e002deec495d7d Mon Sep 17 00:00:00 2001
From: Isaac Dunham <[email protected]>
Date: Sat, 18 Apr 2015 18:25:06 +0000
Subject: [PATCH] mdev: implement hotplug support.

Use DEVPATH, DEVNAME, MAJOR, MINOR, and SUBSYSTEM instead of
checking the current path and reading .../dev.
While we're here, probe for partitions in block devices.

This uses a very lame check for ACTION (which can be add, remove,
or change): if it is "remove", then unlink the device.
---
 toys/pending/mdev.c | 74 +++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 52 insertions(+), 22 deletions(-)

diff --git a/toys/pending/mdev.c b/toys/pending/mdev.c
index 2d98c25..0c49633 100644
--- a/toys/pending/mdev.c
+++ b/toys/pending/mdev.c
@@ -31,34 +31,53 @@ config MDEV_CONF
 
 #include "toys.h"
 
-// todo, open() block devices to trigger partition scanning.
-
 // mknod in /dev based on a path like "/sys/block/hda/hda1"
 static void make_device(char *path)
 {
-  char *device_name, *s, *temp;
+  char *device_name = NULL, *s, *temp;
   int major, minor, type, len, fd;
   int mode = 0660;
   uid_t uid = 0;
   gid_t gid = 0;
 
-  // Try to read major/minor string
-
-  temp = strrchr(path, '/');
-  fd = open(path, O_RDONLY);
-  *temp=0;
-  temp = toybuf;
-  len = read(fd, temp, 64);
-  close(fd);
-  if (len<1) return;
-  temp[len] = 0;
-
-  // Determine device name, type, major and minor
-
-  device_name = strrchr(path, '/') + 1;
-  type = path[5]=='c' ? S_IFCHR : S_IFBLK;
-  major = minor = 0;
-  sscanf(temp, "%u:%u", &major, &minor);
+  if (path) {
+    // Try to read major/minor string
+
+    temp = strrchr(path, '/');
+    fd = open(path, O_RDONLY);
+    *temp=0;
+    temp = toybuf;
+    len = read(fd, temp, 64);
+    close(fd);
+    if (len<1) return;
+    temp[len] = 0;
+
+    // Determine device type, major and minor
+
+    type = path[5]=='c' ? S_IFCHR : S_IFBLK;
+    major = minor = 0;
+    sscanf(temp, "%u:%u", &major, &minor);
+  } else {
+    // if (!path), do hotplug
+
+    if (!(temp = getenv("SUBSYSTEM")))
+      return;
+    type = strcmp(temp, "block") ? S_IFCHR : S_IFBLK;
+    major = minor = 0;
+    if (!(temp = getenv("MAJOR")))
+      return;
+    sscanf(temp, "%u", &major);
+    if (!(temp = getenv("MINOR")))
+      return;
+    sscanf(temp, "%u", &minor);
+    path = getenv("DEVPATH");
+    device_name = getenv("DEVNAME");
+    if (!path)
+      return;
+    temp = toybuf;
+  }
+  if (!device_name)
+    device_name = strrchr(path, '/') + 1;
 
   // If we have a config file, look up permissions for this device
 
@@ -167,9 +186,20 @@ found_device:
   }
 
   sprintf(temp, "/dev/%s", device_name);
+
+  if (getenv("ACTION") && !strcmp(getenv("ACTION"), "remove")) {
+    unlink(temp);
+    return;
+  }
+
+  if (strchr(device_name, '/'))
+    mkpathat(AT_FDCWD, temp, 0, 2);
   if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
     perror_exit("mknod %s failed", temp);
 
+ 
+  if (type == S_IFBLK) close(open(temp, O_RDONLY)); // scan for partitions
+
   if (CFG_MDEV_CONF) mode=chown(temp, uid, gid);
 }
 
@@ -202,7 +232,7 @@ void mdev_main(void)
   if (toys.optflags) {
     dirtree_read("/sys/class", callback);
     dirtree_read("/sys/block", callback);
+  } else { // hotplug support
+    make_device(NULL);
   }
-
-  // hotplug support goes here
 }
-- 
2.1.4

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to