aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2025-04-08 06:39:59 +0000
committerLaurent Bercot <ska@appnovation.com>2025-04-08 06:39:59 +0000
commitea26c3662b37b92f6acd2330a81dfd2b72082e8a (patch)
tree98f8e729867503e93bff1a961b05d117f53768ee
parent94f626f54548bc6134267c2063a6f6df43b4858f (diff)
downloadmdevd-ea26c3662b37b92f6acd2330a81dfd2b72082e8a.tar.gz
Add intake option
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--doc/mdevd.html16
-rw-r--r--src/mdevd/mdevd.c24
2 files changed, 30 insertions, 10 deletions
diff --git a/doc/mdevd.html b/doc/mdevd.html
index 983dbb5..ca39b02 100644
--- a/doc/mdevd.html
+++ b/doc/mdevd.html
@@ -49,7 +49,7 @@ to running mdevd over mdev. </li>
<h2> Interface </h2>
<pre>
- mdevd [ -v <em>verbosity</em> ] [ -D <em>notif</em> ] [ -o <em>outputfd</em> ] [ -O <em>nlgroups</em> ] [ -b <em>kbufsz</em> ] [ -f <em>conffile</em> ] [ -n ] [ -s <em>slashsys</em> ] [ -d <em>slashdev</em> ] [ -F <em>fwbase</em> ] [ -C ]
+ mdevd [ -v <em>verbosity</em> ] [ -D <em>notif</em> ] [ -I <em>intake</em> ] [ -o <em>outputfd</em> ] [ -I <em>intake</em> ] [ -O <em>nlgroups</em> ] [ -b <em>kbufsz</em> ] [ -f <em>conffile</em> ] [ -n ] [ -s <em>slashsys</em> ] [ -d <em>slashdev</em> ] [ -F <em>fwbase</em> ] [ -C ]
</pre>
<ul>
@@ -104,11 +104,19 @@ character. The uevent is terminated by an additional null character.
If for any reason, at any point, mdevd fails to write to <em>outputfd</em>,
it stops writing, until it is restarted. (This is to preserve mdevd's memory
stability guarantee.) By default, the uevents are not written anywhere. </li>
+ <li> <tt>-I</tt>&nbsp;<em>intake</em>&nbsp;: read the uevents from the netlink
+groups identified by the mask <em>intake</em>. The default is <strong>1</strong>,
+meaning the netlink group where the kernel sends its events, and it should not
+be changed unless you have a very particular and rare setting (namely, a chain
+of device managers reading events and rebroadcasting them to other netlink
+groups). </li>
<li> <tt>-O</tt>&nbsp;<em>nlgroups</em>&nbsp;: after mdevd has handled the
uevents, rebroadcast them to the netlink groups identified by the mask
-<em>nlgroups</em>. Bit 0 of <em>nlgroups</em> is always ignored (because
-netlink group 1 is the one used by the kernel to send the original uevents and
-that mdevd listens to, and we don't want to loopback on it). </li>
+<em>nlgroups</em>. If the bit 0 or the bits specified in <em>intake</em>
+(see above) are set in <em>nlgroups</em>, a warning is printed and these
+bits are ignored, in order to avoid causing a loop. (Yes, you can still
+cause a loop by chaining two separate instances of mdevd. mdevd will protect
+you against accidents, not against intentional stupidity.) </li>
<li> <tt>-b</tt>&nbsp;<em>kbufsz</em>&nbsp;: try and reserve a kernel buffer of
<em>kbufsz</em> bytes for the netlink queue. Too large a buffer wastes kernel memory;
too small a buffer risks losing events. The default is <strong>512288</strong>,
diff --git a/src/mdevd/mdevd.c b/src/mdevd/mdevd.c
index bbef872..6b82874 100644
--- a/src/mdevd/mdevd.c
+++ b/src/mdevd/mdevd.c
@@ -43,7 +43,7 @@
#include <mdevd/config.h>
#include "mdevd-internal.h"
-#define USAGE "mdevd [ -v verbosity ] [ -D notif ] [ -o outputfd ] [ -O nlgroups ] [ -b kbufsz ] [ -f conffile ] [ -n ] [ -s slashsys ] [ -d slashdev ] [ -F fwbase ] [ -C ]"
+#define USAGE "mdevd [ -v verbosity ] [ -D notif ] [ -I intake ] [ -o outputfd ] [ -O nlgroups ] [ -b kbufsz ] [ -f conffile ] [ -n ] [ -s slashsys ] [ -d slashdev ] [ -F fwbase ] [ -C ]"
#define dieusage() strerr_dieusage(100, USAGE)
#define CONFBUFSIZE 8192
@@ -186,7 +186,7 @@ static int makesubdirs (char const *path)
static inline int rebc_init (unsigned int groups, unsigned int kbufsz)
{
- struct sockaddr_nl nl = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_groups = groups & ~1U, .nl_pid = 0 } ;
+ struct sockaddr_nl nl = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_groups = groups, .nl_pid = 0 } ;
int fd = socket_internal(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT, O_CLOEXEC) ;
if (fd == -1) return -1 ;
if (connect(fd, (struct sockaddr *)&nl, sizeof nl) == -1) goto err ;
@@ -907,6 +907,7 @@ int main (int argc, char const *const *argv)
unsigned int kbufsz = 512288 ;
char const *slashdev = "/dev" ;
int docoldplug = 0 ;
+ unsigned int intake = 1 ;
unsigned int outputfd = 0 ;
unsigned int rebc = 0 ;
PROG = "mdevd" ;
@@ -914,13 +915,14 @@ int main (int argc, char const *const *argv)
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "nv:D:o:O:b:f:s:d:F:C", &l) ;
+ int opt = subgetopt_r(argc, argv, "nv:D:I:o:O:b:f:s:d:F:C", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'n' : dryrun = 1 ; break ;
case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
case 'D' : if (!uint0_scan(l.arg, &notif)) dieusage() ; break ;
+ case 'I' : if (!uint0_scan(l.arg, &intake)) dieusage() ; break ;
case 'o' : if (!uint0_scan(l.arg, &outputfd)) dieusage() ; break ;
case 'O' : if (!uint0_scan(l.arg, &rebc)) dieusage() ; break ;
case 'b' : if (!uint0_scan(l.arg, &kbufsz)) dieusage() ; break ;
@@ -947,6 +949,16 @@ int main (int argc, char const *const *argv)
if (notif < 3) strerr_dief1x(100, "notification fd must be 3 or more") ;
if (fcntl(notif, F_GETFD) < 0) strerr_dief1sys(100, "invalid notification fd") ;
}
+ {
+ unsigned int loop = rebc & (intake | 1) ;
+ if (loop)
+ {
+ char fmt[UINT_FMT] ;
+ fmt[uint_fmt(fmt, loop)] = 0 ;
+ strerr_warnw3x("ignoring rebroadcast request on nlgroups ", fmt, " to avoid loops") ;
+ rebc &= ~loop ;
+ }
+ }
if (outputfd)
{
if (outputfd < 3) strerr_dief1x(100, "output fd must be 3 or more") ;
@@ -961,8 +973,7 @@ int main (int argc, char const *const *argv)
root_maj = major(st.st_dev) ;
root_min = minor(st.st_dev) ;
}
-
- x[1].fd = mdevd_netlink_init(1, kbufsz) ;
+ x[1].fd = mdevd_netlink_init(intake, kbufsz) ;
if (x[1].fd < 0) strerr_diefu1sys(111, "init netlink") ;
if (rebc)
{
@@ -973,7 +984,8 @@ int main (int argc, char const *const *argv)
x[0].fd = selfpipe_init() ;
if (x[0].fd < 0) strerr_diefu1sys(111, "init selfpipe") ;
- if (!sig_altignore(SIGPIPE)) strerr_diefu1sys(111, "ignore SIGPIPE") ;
+ if (!sig_altignore(SIGPIPE))
+ strerr_diefu1sys(111, "ignore SIGPIPE") ;
{
sigset_t set ;
sigemptyset(&set) ;