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