[RFC] mdev: support reading events from stdin, add features to mdev -s
Denys Vlasenko
vda.linux at googlemail.com
Wed Apr 15 16:46:08 UTC 2015
On Mon, Apr 13, 2015 at 7:15 PM, Isaac Dunham <ibid.ag at gmail.com> wrote:
> Here's a patch series to add mdev -i and make mdev -s a little more
> featureful, so rules like this one:
> $MODALIAS=.* root:root 660 @modprobe "$MODALIAS"
> will work even with coldplug.
>
> mdev -i reads hotplug events from stdin, in a format proposed by Laurent Bercot
> wherein each "line" is terminated with '\0' (rather than '\n') and each event
> is terminated by an additional '\0'.
> Internally, each event is loaded into the environment (without copying) at
> the start of handle_event(), then the environment is cleared before
> handle_event() returns.
> This is done instead of using a new key lookup method because helper
> scripts rely extensively on environment variables; if we did not load
> the events into the environment at some point, autoloading modules and
> other important features would no longer work.
>
> The new mdev -s (FEATURE_MDEV_NEWSCAN) uses the same codepath as mdev -i
> instead of calling make_device() directly.
>
> Both mdev -i and the new mdev -s are compile-time options, separately
> selectable.
How about the following applet, which would listen to netlink and spawn a helper
for every new message?
So far not tested with "mdev".
# ndev --help
BusyBox v1.24.0.git (2015-04-15 18:31:44 CEST) multi-call binary.
Usage: ndev [PROG [ARGS]]
ndev runs PROG for every netlink notification.
PROG's environment contains data passed from the kernel.
Typical usage:
ndev mdev & - daemon for dynamic device node creation
ndev - print notifications to stdout
# ndev
change@/devices/platform/regulatory.0
ACTION=change
DEVPATH=/devices/platform/regulatory.0
SUBSYSTEM=platform
COUNTRY=CZ
MODALIAS=platform:regulatory
SEQNUM=4678
change@/devices/platform/regulatory.0
ACTION=change
DEVPATH=/devices/platform/regulatory.0
SUBSYSTEM=platform
COUNTRY=00
MODALIAS=platform:regulatory
SEQNUM=4679
^C
diff -d -urpN busybox.1/util-linux/ndev.c busybox.2/util-linux/ndev.c
--- busybox.1/util-linux/ndev.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox.2/util-linux/ndev.c 2015-04-15 18:27:58.607840699 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2014 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//config:config NDEV
+//config: bool "ndev"
+//config: default y
+//config: select PLATFORM_LINUX
+//config: help
+//config: ndev is a netlink listener for kernel uevent notifications
+//config: sent via netlink. It is usually used for dynamic
device creation.
+
+//applet:IF_NDEV(APPLET(ndev, BB_DIR_SBIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_NDEV) += ndev.o
+
+//usage:#define ndev_trivial_usage
+//usage: "[PROG [ARGS]]"
+//usage:#define ndev_full_usage "\n\n"
+//usage: "ndev runs PROG for every netlink notification.\n"
+//usage: "PROG's environment contains data passed from the kernel.\n"
+//usage: "Typical usage:\n"
+//usage: "\n"
+//usage: "ndev mdev & - daemon for dynamical device node creation\n"
+//usage: "ndev - print notifications to stdout\n"
+
+#include "libbb.h"
+#include <linux/netlink.h>
+
+#define BUFFER_SIZE 16*1024
+
+int ndev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ndev_main(int argc UNUSED_PARAM, char **argv)
+{
+ struct sockaddr_nl sa;
+ struct pollfd pfd;
+
+ argv++;
+
+ // Subscribe for UEVENT kernel messages
+ close(STDIN_FILENO);
+ // opened socket will be STDIN_FILENO fd
+ xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+ sa.nl_family = AF_NETLINK;
+ sa.nl_pad = 0;
+ sa.nl_pid = getpid();
+ sa.nl_groups = 1 << 0;
+ xbind(STDIN_FILENO, (struct sockaddr *) &sa, sizeof(sa));
+
+ pfd.fd = STDIN_FILENO;
+ pfd.events = POLLIN;
+
+ for (;;) {
+ char *netbuf;
+ char *s;
+ char **env;
+ ssize_t len;
+ int idx;
+
+ /* In many cases, a system can sit for DAYS waiting
+ * for a new uevent notification to come in.
+ * We use mmap so that the buffer is not allocated
+ * until kernel actually starts filling it.
+ */
+ netbuf = mmap(NULL, BUFFER_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON,
+ /* ignored: */ -1, 0);
+ if (netbuf == MAP_FAILED)
+ bb_perror_msg_and_die("mmap");
+
+ // Here we block. Possibly for a very long time.
+ len = safe_read(STDIN_FILENO, netbuf, BUFFER_SIZE - 1);
+ if (len < 0)
+ bb_perror_msg_and_die("read");
+ netbuf[len] = '\0';
+
+ // Each netlink message starts with "ACTION@/path",
+ // followed by environment variables.
+ if (!argv[0])
+ putchar('\n');
+ env = NULL;
+ idx = 0;
+ s = netbuf;
+ while (len > 0) {
+ char *p;
+
+ if (!argv[0])
+ puts(s);
+
+ p = (char*)endofname(s);
+ if (*p == '@') {
+ // This is "ACTION@/path", ignore
+ } else if (*p == '=') {
+ env = xrealloc_vector(env, 2, idx);
+ env[idx++] = s;
+ }
+ p += strlen(p) + 1;
+ len -= p - s;
+ s = p;
+ }
+
+ idx = 0;
+ while (env && env[idx])
+ putenv(env[idx++]);
+ if (argv[0])
+ spawn_and_wait(argv);
+ idx = 0;
+ while (env && env[idx])
+ bb_unsetenv(env[idx++]);
+ free(env);
+ munmap(netbuf, BUFFER_SIZE);
+ }
+
+ return 0;
+}
(sorry for formatting, I'm using gmail web interface...)
More information about the busybox
mailing list