summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--INSTALL4
-rw-r--r--NEWS6
-rw-r--r--doc/index.html6
-rw-r--r--doc/mdevd-coldplug.html17
-rw-r--r--doc/upgrade.html10
-rw-r--r--package/deps.mak18
-rw-r--r--package/info2
-rw-r--r--src/mdevd/deps-exe/mdevd1
-rw-r--r--src/mdevd/deps-exe/mdevd-coldplug1
-rw-r--r--src/mdevd/deps-lib/mdevd3
-rw-r--r--src/mdevd/mdevd-coldplug.c61
-rw-r--r--src/mdevd/mdevd-internal.h24
-rw-r--r--src/mdevd/mdevd.c140
-rw-r--r--src/mdevd/mdevd_netlink_init.c31
-rw-r--r--src/mdevd/mdevd_uevent_getvar.c16
-rw-r--r--src/mdevd/mdevd_uevent_read.c87
17 files changed, 283 insertions, 149 deletions
diff --git a/.gitignore b/.gitignore
index 147e421..e11a6fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,7 @@
*.o
-*.a
+/*.a.xyzzy
*.lo
-*.so
-*.so.*
+/*.so.xyzzy
/config.mak
/src/include/mdevd/config.h
/mdevd
diff --git a/INSTALL b/INSTALL
index 8e4fc04..422d895 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,8 +6,8 @@ Build Instructions
- A Linux-based system with a standard C development environment
- GNU make version 3.81 or later
- - skalibs version 2.12.0.0 or later: https://skarnet.org/software/skalibs/
- - optional: execline version 2.9.0.0 or later: https://skarnet.org/software/execline/
+ - skalibs version 2.12.0.1 or later: https://skarnet.org/software/skalibs/
+ - optional: execline version 2.9.0.1 or later: https://skarnet.org/software/execline/
This software is Linux-specific. It will run on a Linux kernel,
version 2.6.10 or later.
diff --git a/NEWS b/NEWS
index 028923a..f382c60 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,11 @@
Changelog for mdevd.
+In 0.1.6.0
+----------
+
+ - mdevd-coldplug can now be synchronous with the -O option.
+
+
In 0.1.5.2
----------
diff --git a/doc/index.html b/doc/index.html
index e51e85c..c6261c4 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -99,7 +99,7 @@ and does not pull in any unnecessary code. </li>
The Linux kernel must be 2.6.10 or later. </li>
<li> GNU make, version 3.81 or later </li>
<li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version
-2.12.0.0 or later. It's a build-time requirement. It's also a run-time
+2.12.0.1 or later. It's a build-time requirement. It's also a run-time
requirement if you link against the shared version of the skalibs
library. </li>
<li> Optionally: <a href="//skarnet.org/software/execline/">nsss</a>
@@ -108,7 +108,7 @@ you use the <tt>--enable-nsss</tt> option to configure; but you would
only do that if you're replacing nsswitch on your whole system, and most
people are not. </li>
<li> Optionally: <a href="//skarnet.org/software/execline/">execline</a>
-version 2.9.0.0 or later. It's a only a run-time requirement, and only
+version 2.9.0.1 or later. It's a only a run-time requirement, and only
if your <tt>mdev.conf</tt> file contains <tt>+</tt>, <tt>-</tt> or
<tt>&amp;</tt> command directives. </li>
</ul>
@@ -124,7 +124,7 @@ if your <tt>mdev.conf</tt> file contains <tt>+</tt>, <tt>-</tt> or
<ul>
<li> The current released version of mdevd is
-<a href="mdevd-0.1.5.2.tar.gz">0.1.5.2</a>. </li>
+<a href="mdevd-0.1.6.0.tar.gz">0.1.6.0</a>. </li>
<li> Alternatively, you can checkout a copy of the
<a href="//git.skarnet.org/cgi-bin/cgit.cgi/mdevd/">mdevd
git repository</a>:
diff --git a/doc/mdevd-coldplug.html b/doc/mdevd-coldplug.html
index 027c849..36654eb 100644
--- a/doc/mdevd-coldplug.html
+++ b/doc/mdevd-coldplug.html
@@ -28,7 +28,7 @@ for all these devices.
<h2> Interface </h2>
<pre>
- mdevd-coldplug [ -s <em>slashsys</em> ]
+ mdevd-coldplug [ -v <em>verbosity</em> ] [ -s <em>slashsys</em> ] [ -O <em>nlgroup</em> ] [ -b <em>kbufsize</em> ]
</pre>
<ul>
@@ -43,8 +43,23 @@ at this point, it will pick up the series of events. </li>
<h2> Options </h2>
<ul>
+ <li> <tt>-v</tt>&nbsp;<em>verbosity</em>&nbsp;: be more or less verbose.
+Default verbosity is 1. 0 will only print fatal error messages, 3 or more
+is seriously verbose debugging. </li>
<li> <tt>-s</tt>&nbsp;<em>slashsys</em>&nbsp;: assume the sysfs
pseudo-filesystem is mounted on <em>slashsys</em>. Default is <tt>/sys</tt>. </li>
+ <li> <tt>-O</tt>&nbsp;<em>nlgroup</em>&nbsp;: synchronous coldplug.
+<tt>mdevd-coldplug</tt> will not exit until the last uevent it triggers
+has been handled by <a href="mdevd.html">mdevd</a>. <em>nlgroup</em>
+needs to be a netlink group that <a href="mdevd.html">mdevd</a> is
+rebroadcasting handled events to. Note that this option can only work
+if <a href="mdevd.html">mdevd</a> is running with a similar <tt>-O</tt>
+option with a compatible value; else, <tt>mdevd-coldplug</tt> will wait
+forever. </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. The default is 500 kB;
+if you're getting "No buffer space available" errors, try increasing this number.
+This option is only meaningful when paired with the <tt>-O</tt> option. </li>
</ul>
<h2> Exit codes </h2>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 5ae8dd3..28485ee 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -18,6 +18,15 @@
<h1> What has changed in mdevd </h1>
+<h2> in 0.1.6.0 </h2>
+
+<ul>
+ <li> <a href="//skarnet.org/software/skalibs/">skalibs</a>
+dependency bumped to 2.12.0.1. </li>
+ <li> <a href="//skarnet.org/software/execline/">execline</a>
+optional dependency bumped to 2.9.0.1. </li>
+</ul>
+
<h2> in 0.1.5.2 </h2>
<ul>
@@ -27,7 +36,6 @@ dependency bumped to 2.12.0.0. </li>
optional dependency bumped to 2.9.0.0. </li>
</ul>
-
<h2> in 0.1.5.1 </h2>
<ul>
diff --git a/package/deps.mak b/package/deps.mak
index a6e8248..7820c93 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -2,10 +2,20 @@
# This file has been generated by tools/gen-deps.sh
#
-src/mdevd/mdevd-coldplug.o src/mdevd/mdevd-coldplug.lo: src/mdevd/mdevd-coldplug.c
-src/mdevd/mdevd.o src/mdevd/mdevd.lo: src/mdevd/mdevd.c src/include/mdevd/config.h
+src/mdevd/mdevd-coldplug.o src/mdevd/mdevd-coldplug.lo: src/mdevd/mdevd-coldplug.c src/mdevd/mdevd-internal.h
+src/mdevd/mdevd.o src/mdevd/mdevd.lo: src/mdevd/mdevd.c src/mdevd/mdevd-internal.h src/include/mdevd/config.h
+src/mdevd/mdevd_netlink_init.o src/mdevd/mdevd_netlink_init.lo: src/mdevd/mdevd_netlink_init.c
+src/mdevd/mdevd_uevent_getvar.o src/mdevd/mdevd_uevent_getvar.lo: src/mdevd/mdevd_uevent_getvar.c src/mdevd/mdevd-internal.h
+src/mdevd/mdevd_uevent_read.o src/mdevd/mdevd_uevent_read.lo: src/mdevd/mdevd_uevent_read.c src/mdevd/mdevd-internal.h
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+libmdevd.a.xyzzy: src/mdevd/mdevd_netlink_init.o src/mdevd/mdevd_uevent_read.o src/mdevd/mdevd_uevent_getvar.o
+else
+libmdevd.a.xyzzy: src/mdevd/mdevd_netlink_init.lo src/mdevd/mdevd_uevent_read.lo src/mdevd/mdevd_uevent_getvar.lo
+endif
+libmdevd.so.xyzzy: EXTRA_LIBS :=
+libmdevd.so.xyzzy: src/mdevd/mdevd_netlink_init.lo src/mdevd/mdevd_uevent_read.lo src/mdevd/mdevd_uevent_getvar.lo
mdevd: EXTRA_LIBS := -lskarnet ${MAYBEPTHREAD_LIB}
-mdevd: src/mdevd/mdevd.o ${LIBNSSS}
+mdevd: src/mdevd/mdevd.o libmdevd.a.xyzzy ${LIBNSSS}
mdevd-coldplug: EXTRA_LIBS := -lskarnet
-mdevd-coldplug: src/mdevd/mdevd-coldplug.o
+mdevd-coldplug: src/mdevd/mdevd-coldplug.o libmdevd.a.xyzzy
diff --git a/package/info b/package/info
index 2c62800..d2a6a5d 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
package=mdevd
-version=0.1.5.2
+version=0.1.6.0
category=admin
package_macro_name=MDEVD
diff --git a/src/mdevd/deps-exe/mdevd b/src/mdevd/deps-exe/mdevd
index ee4ed0b..a410ca2 100644
--- a/src/mdevd/deps-exe/mdevd
+++ b/src/mdevd/deps-exe/mdevd
@@ -1,3 +1,4 @@
+libmdevd.a.xyzzy
${LIBNSSS}
-lskarnet
${MAYBEPTHREAD_LIB}
diff --git a/src/mdevd/deps-exe/mdevd-coldplug b/src/mdevd/deps-exe/mdevd-coldplug
index e7187fe..31063b4 100644
--- a/src/mdevd/deps-exe/mdevd-coldplug
+++ b/src/mdevd/deps-exe/mdevd-coldplug
@@ -1 +1,2 @@
+libmdevd.a.xyzzy
-lskarnet
diff --git a/src/mdevd/deps-lib/mdevd b/src/mdevd/deps-lib/mdevd
new file mode 100644
index 0000000..1e9efc3
--- /dev/null
+++ b/src/mdevd/deps-lib/mdevd
@@ -0,0 +1,3 @@
+mdevd_netlink_init.o
+mdevd_uevent_read.o
+mdevd_uevent_getvar.o
diff --git a/src/mdevd/mdevd-coldplug.c b/src/mdevd/mdevd-coldplug.c
index 596001c..2be7be0 100644
--- a/src/mdevd/mdevd-coldplug.c
+++ b/src/mdevd/mdevd-coldplug.c
@@ -5,23 +5,35 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <limits.h>
+
#include <skalibs/sgetopt.h>
+#include <skalibs/types.h>
#include <skalibs/strerr2.h>
#include <skalibs/direntry.h>
+#include <skalibs/djbunix.h>
+
+#include "mdevd-internal.h"
-#define USAGE "mdevd-coldplug [ -s slashsys ]"
+#define USAGE "mdevd-coldplug [ -v verbosity ] [ -s slashsys ] [ -O nlgroup ] [ -b kbufsize ]"
#define dieusage() strerr_dieusage(100, USAGE)
-static void scan_subdir (int fdat, char const *pathat, char const *list)
+static char subsystem[PATH_MAX] = "" ;
+static char mdev[PATH_MAX] = "" ;
+
+static int scan_subdir (int fdat, char const *pathat, char const *list)
{
+ int r = 0 ;
DIR *dir ;
+ direntry *d = 0 ;
+ direntry *lastd ;
int fdlist = openat(fdat, list, O_RDONLY | O_DIRECTORY) ;
if (fdlist < 0) strerr_diefu4sys(111, "open ", pathat, "/", list) ;
dir = fdopendir(fdlist) ;
if (!dir) strerr_diefu4sys(111, "fdopendir ", pathat, "/", list) ;
for (;;)
{
- direntry *d ;
+ lastd = d ;
errno = 0 ;
d = readdir(dir) ;
if (!d) break ;
@@ -37,10 +49,13 @@ static void scan_subdir (int fdat, char const *pathat, char const *list)
if (write(fd, "add\n", 4) < 4)
strerr_warnwu6sys("write to ", pathat, "/", list, "/", fn) ;
close(fd) ;
+ r = 1 ;
}
}
if (errno) strerr_diefu4sys(111, "readdir ", pathat, "/", list) ;
+ if (r) strncpy(mdev, lastd->d_name, PATH_MAX) ;
dir_close(dir) ;
+ return r ;
}
static int scan_dir (char const *path, int add_devices)
@@ -63,9 +78,11 @@ static int scan_dir (char const *path, int add_devices)
char fn[dlen + 9] ;
memcpy(fn, d->d_name, dlen) ;
memcpy(fn + dlen, "/devices", 9) ;
- scan_subdir(fdpath, path, fn) ;
+ if (scan_subdir(fdpath, path, fn))
+ strncpy(subsystem, d->d_name, PATH_MAX) ;
}
- else scan_subdir(fdpath, path, d->d_name) ;
+ else if (scan_subdir(fdpath, path, d->d_name))
+ strncpy(subsystem, d->d_name, PATH_MAX) ;
}
if (errno) strerr_diefu2sys(111, "readdir ", path) ;
dir_close(dir) ;
@@ -76,22 +93,40 @@ static int scan_dir (char const *path, int add_devices)
int main (int argc, char const *const *argv, char const *const *envp)
{
char const *slashsys = "/sys" ;
+ unsigned int verbosity = 1 ;
+ unsigned int nlgroup = 0 ;
+ unsigned int kbufsz = 512288 ;
+ int nlfd = -1 ;
PROG = "mdevd-coldplug" ;
{
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "s:", &l) ;
+ int opt = subgetopt_r(argc, argv, "v:s:O:b:", &l) ;
if (opt == -1) break ;
switch (opt)
{
+ case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
case 's' : slashsys = l.arg ; break ;
+ case 'O' : if (!uint0_scan(l.arg, &nlgroup)) dieusage() ; break ;
+ case 'b' : if (!uint0_scan(l.arg, &kbufsz)) dieusage() ; break ;
default : dieusage() ;
}
}
argc -= l.ind ; argv += l.ind ;
}
+ nlgroup &= ~1 ;
+ if (nlgroup)
+ {
+ nlfd = mdevd_netlink_init(nlgroup, kbufsz) ;
+ if (nlfd == -1)
+ strerr_diefu1sys(111, "init netlink") ;
+ if (ndelay_off(nlfd) == -1)
+ strerr_diefu1sys(111, "make netlink socket non-blocking") ;
+ }
+
+ /* Trigger the uevents */
{
size_t slashsyslen = strlen(slashsys) ;
char fn[slashsyslen + 11] ;
@@ -105,5 +140,19 @@ int main (int argc, char const *const *argv, char const *const *envp)
if (!scan_dir(fn, 1)) strerr_diefu2sys(111, "open ", fn) ;
}
}
+
+ /* Wait for the last triggered uevent to be processed */
+ if (nlgroup && subsystem[0] && mdev[0])
+ {
+ struct uevent_s event ;
+ for (;;) if (mdevd_uevent_read(nlfd, &event, verbosity))
+ {
+ char *x = mdevd_uevent_getvar(&event, "SUBSYSTEM") ;
+ if (strcmp(x, subsystem)) continue ;
+ x = mdevd_uevent_getvar(&event, "MDEV") ;
+ if (!strcmp(x, mdev)) break ;
+ }
+ }
+
return 0 ;
}
diff --git a/src/mdevd/mdevd-internal.h b/src/mdevd/mdevd-internal.h
new file mode 100644
index 0000000..cc98a6d
--- /dev/null
+++ b/src/mdevd/mdevd-internal.h
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#ifndef MDEVD_INTERNAL_H
+#define MDEVD_INTERNAL_H
+
+#define UEVENT_MAX_VARS 63
+#define UEVENT_MAX_SIZE 8192
+
+#include <limits.h>
+
+struct uevent_s
+{
+ unsigned short len ;
+ unsigned short varn ;
+ unsigned short vars[UEVENT_MAX_VARS + 1] ;
+ char buf[UEVENT_MAX_SIZE + PATH_MAX + 5] ;
+} ;
+#define UEVENT_ZERO { .len = 0, .varn = 0 }
+
+extern int mdevd_netlink_init (unsigned int, unsigned int) ;
+extern int mdevd_uevent_read (int, struct uevent_s *, unsigned int) ;
+extern char *mdevd_uevent_getvar (struct uevent_s *, char const *) ;
+
+#endif
diff --git a/src/mdevd/mdevd.c b/src/mdevd/mdevd.c
index bc663a4..2bc6e08 100644
--- a/src/mdevd/mdevd.c
+++ b/src/mdevd/mdevd.c
@@ -40,6 +40,7 @@
#include <skalibs/unix-transactional.h>
#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 dieusage() strerr_dieusage(100, USAGE)
@@ -123,15 +124,6 @@ static scriptelem const scriptelem_catchall =
.envmatchs = 0
} ;
-struct uevent_s
-{
- unsigned short len ;
- unsigned short varn ;
- unsigned short vars[UEVENT_MAX_VARS + 1] ;
- char buf[UEVENT_MAX_SIZE + PATH_MAX + 5] ;
-} ;
-#define UEVENT_ZERO { .len = 0, .varn = 0 }
-
typedef struct udata_s udata, *udata_ref ;
struct udata_s
{
@@ -188,34 +180,6 @@ static int makesubdirs (char *path)
}
- /* Netlink isolation layer */
-
-static inline ssize_t fd_recvmsg (int fd, struct msghdr *hdr)
-{
- ssize_t r ;
- do r = recvmsg(fd, hdr, MSG_DONTWAIT) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-static inline int netlink_init (unsigned int kbufsz)
-{
- struct sockaddr_nl nl = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_groups = 1, .nl_pid = 0 } ;
- int fd = socket_internal(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT, O_NONBLOCK|O_CLOEXEC) ;
- if (fd < 0) return -1 ;
- if (bind(fd, (struct sockaddr *)&nl, sizeof(struct sockaddr_nl)) < 0) goto err ;
- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &kbufsz, sizeof(unsigned int)) < 0)
- {
- if (errno != EPERM
- || setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &kbufsz, sizeof(unsigned int)) < 0) goto err ;
- }
- return fd ;
-
- err:
- fd_close(fd) ;
- return -1 ;
-}
-
static inline int rebc_init (unsigned int groups)
{
struct sockaddr_nl nl = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_groups = groups & ~1U, .nl_pid = 0 } ;
@@ -229,76 +193,6 @@ static inline int rebc_init (unsigned int groups)
return fd ;
}
-static inline size_t netlink_read (int fd, char *s)
-{
- struct sockaddr_nl nl;
- struct iovec v = { .iov_base = s, .iov_len = UEVENT_MAX_SIZE } ;
- struct msghdr msg =
- {
- .msg_name = &nl,
- .msg_namelen = sizeof(struct sockaddr_nl),
- .msg_iov = &v,
- .msg_iovlen = 1,
- .msg_control = 0,
- .msg_controllen = 0,
- .msg_flags = 0
- } ;
- ssize_t r = sanitize_read(fd_recvmsg(fd, &msg)) ;
- if (r < 0)
- {
- if (errno == EPIPE)
- {
- if (verbosity >= 2) strerr_warnw1x("received EOF on netlink") ;
- cont = 0 ;
- return 0 ;
- }
- else strerr_diefu1sys(111, "receive netlink message") ;
- }
- if (!r) return 0 ;
- if (msg.msg_flags & MSG_TRUNC)
- strerr_diefu1x(111, "buffer too small for netlink message") ;
- if (nl.nl_pid)
- {
- if (verbosity >= 3)
- {
- char fmt[PID_FMT] ;
- fmt[pid_fmt(fmt, nl.nl_pid)] = 0 ;
- strerr_warnw2x("received netlink message from userspace process ", fmt) ;
- }
- return 0 ;
- }
- if (s[r-1])
- {
- if (verbosity) strerr_warnw2x("received invalid event: ", "improperly terminated") ;
- return 0 ;
- }
- if (!strstr(s, "@/"))
- {
- if (verbosity) strerr_warnw2x("received invalid event: ", "bad initial summary") ;
- return 0 ;
- }
- return r ;
-}
-
-static inline int uevent_read (int fd, struct uevent_s *event)
-{
- unsigned short len = 0 ;
- event->len = netlink_read(fd, event->buf) ;
- if (!event->len) return 0 ;
- event->varn = 0 ;
- while (len < event->len)
- {
- if (event->varn >= UEVENT_MAX_VARS)
- {
- if (verbosity) strerr_warnw2x("received invalid event: ", "too many variables") ;
- return 0 ;
- }
- event->vars[event->varn++] = len ;
- len += strlen(event->buf + len) + 1 ;
- }
- return 1 ;
-}
-
/* mdev.conf parsing. See PARSING.txt for details. */
@@ -623,16 +517,6 @@ static inline void load_firmware (char const *fw, char const *sysdevpath)
/* uevent management */
-static char *event_getvar (struct uevent_s *event, char const *var)
-{
- size_t varlen = strlen(var) ;
- unsigned short i = 1 ;
- for (; i < event->varn ; i++)
- if (!strncmp(var, event->buf + event->vars[i], varlen) && event->buf[event->vars[i] + varlen] == '=')
- break ;
- return i < event->varn ? event->buf + event->vars[i] + varlen + 1 : 0 ;
-}
-
static inline unsigned char format_cclass (char c)
{
static unsigned char const classtable[58] = "0333333333333333333333333333333333333133333333332222222222" ;
@@ -694,7 +578,7 @@ static inline int run_scriptelem (struct uevent_s *event, scriptelem const *elem
unsigned short i = 0 ;
for (; i < elem->envmatchlen ; i++)
{
- char const *x = event_getvar(event, storage + envmatch[elem->envmatchs + i].var) ;
+ char const *x = mdevd_uevent_getvar(event, storage + envmatch[elem->envmatchs + i].var) ;
if (!x) return 0 ;
if (regexec(&envmatch[elem->envmatchs + i].re, x, 0, 0, 0)) return 0 ;
}
@@ -799,7 +683,7 @@ static inline int run_scriptelem (struct uevent_s *event, scriptelem const *elem
if (elem->cmdtype == ACTION_ANY || ud->action == elem->cmdtype)
{
- if (!event_getvar(event, "MDEV"))
+ if (!mdevd_uevent_getvar(event, "MDEV"))
{
event->vars[event->varn++] = event->len ;
memcpy(event->buf + event->len, "MDEV=", 5) ;
@@ -852,14 +736,14 @@ static inline int act_on_event (struct uevent_s *event, char *sysdevpath, size_t
{
ssize_t hasmajmin = 0 ;
unsigned int mmaj, mmin ;
- char const *x = event_getvar(event, "MAJOR") ;
+ char const *x = mdevd_uevent_getvar(event, "MAJOR") ;
ud->devtype = S_IFCHR ;
ud->action = action ;
if (action == ACTION_ADD)
{
if (x && uint0_scan(x, &mmaj))
{
- x = event_getvar(event, "MINOR") ;
+ x = mdevd_uevent_getvar(event, "MINOR") ;
if (x && uint0_scan(x, &mmin)) hasmajmin = 1 ;
}
if (!hasmajmin)
@@ -883,7 +767,7 @@ static inline int act_on_event (struct uevent_s *event, char *sysdevpath, size_t
ud->mmaj = hasmajmin > 0 ? mmaj : -1 ;
ud->mmin = hasmajmin > 0 ? mmin : -1 ;
- ud->devname = event_getvar(event, "DEVNAME") ;
+ ud->devname = mdevd_uevent_getvar(event, "DEVNAME") ;
if (!ud->devname)
{
ssize_t r ;
@@ -910,7 +794,7 @@ static inline int act_on_event (struct uevent_s *event, char *sysdevpath, size_t
if (strstr(sysdevpath, "/block/")) ud->devtype = S_IFBLK ;
else
{
- x = event_getvar(event, "SUBSYSTEM") ;
+ x = mdevd_uevent_getvar(event, "SUBSYSTEM") ;
if (x && str_start(x, "block")) ud->devtype = S_IFBLK ;
}
ud->i = 0 ;
@@ -920,12 +804,12 @@ static inline int act_on_event (struct uevent_s *event, char *sysdevpath, size_t
static inline int on_event (struct uevent_s *event, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
{
unsigned int action ;
- char const *x = event_getvar(event, "ACTION") ;
+ char const *x = mdevd_uevent_getvar(event, "ACTION") ;
if (!x) return 1 ;
if (!strcmp(x, "add")) action = ACTION_ADD ;
else if (!strcmp(x, "remove")) action = ACTION_REMOVE ;
else action = ACTION_ANY ;
- x = event_getvar(event, "DEVPATH") ;
+ x = mdevd_uevent_getvar(event, "DEVPATH") ;
if (!x) return 1 ;
{
int done = 1 ;
@@ -934,7 +818,7 @@ static inline int on_event (struct uevent_s *event, scriptelem const *script, un
char sysdevpath[devpathlen + slashsyslen + 8] ; /* act_on_event needs the extra storage */
memcpy(sysdevpath, slashsys, slashsyslen) ;
memcpy(sysdevpath + slashsyslen, x, devpathlen + 1) ;
- x = event_getvar(event, "FIRMWARE") ;
+ x = mdevd_uevent_getvar(event, "FIRMWARE") ;
if (action == ACTION_ADD || !x) done = act_on_event(event, sysdevpath, slashsyslen + devpathlen, action, script, scriptlen, storage, envmatch, ud) ;
if (action == ACTION_ADD && x) load_firmware(x, sysdevpath) ;
return done ;
@@ -978,7 +862,7 @@ static inline int handle_signals (struct uevent_s *event, scriptelem const *scri
static inline int handle_event (int fd, struct uevent_s *event, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
{
- if (!uevent_read(fd, event) || event->varn <= 1) return 0 ;
+ if (!mdevd_uevent_read(fd, event, verbosity) || event->varn <= 1) return 0 ;
return on_event(event, script, scriptlen, storage, envmatch, ud) ;
}
@@ -1066,7 +950,7 @@ int main (int argc, char const *const *argv)
root_min = minor(st.st_dev) ;
}
- x[1].fd = netlink_init(kbufsz) ;
+ x[1].fd = mdevd_netlink_init(1, kbufsz) ;
if (x[1].fd < 0) strerr_diefu1sys(111, "init netlink") ;
if (rebc)
{
diff --git a/src/mdevd/mdevd_netlink_init.c b/src/mdevd/mdevd_netlink_init.c
new file mode 100644
index 0000000..264240b
--- /dev/null
+++ b/src/mdevd/mdevd_netlink_init.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <skalibs/socket.h>
+#include <skalibs/djbunix.h>
+
+int mdevd_netlink_init (unsigned int group, unsigned int kbufsz)
+{
+ struct sockaddr_nl nl = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_groups = group, .nl_pid = 0 } ;
+ int fd = socket_internal(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT, O_NONBLOCK|O_CLOEXEC) ;
+ if (fd < 0) return -1 ;
+ if (bind(fd, (struct sockaddr *)&nl, sizeof(struct sockaddr_nl)) < 0) goto err ;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &kbufsz, sizeof(unsigned int)) < 0)
+ {
+ if (errno != EPERM
+ || setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &kbufsz, sizeof(unsigned int)) < 0) goto err ;
+ }
+ return fd ;
+
+ err:
+ fd_close(fd) ;
+ return -1 ;
+}
diff --git a/src/mdevd/mdevd_uevent_getvar.c b/src/mdevd/mdevd_uevent_getvar.c
new file mode 100644
index 0000000..8eb8583
--- /dev/null
+++ b/src/mdevd/mdevd_uevent_getvar.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <string.h>
+
+#include "mdevd-internal.h"
+
+char *mdevd_uevent_getvar (struct uevent_s *event, char const *var)
+{
+ size_t varlen = strlen(var) ;
+ unsigned short i = 1 ;
+ for (; i < event->varn ; i++)
+ if (!strncmp(var, event->buf + event->vars[i], varlen) && event->buf[event->vars[i] + varlen] == '=')
+ break ;
+ return i < event->varn ? event->buf + event->vars[i] + varlen + 1 : 0 ;
+}
+
diff --git a/src/mdevd/mdevd_uevent_read.c b/src/mdevd/mdevd_uevent_read.c
new file mode 100644
index 0000000..2cb4245
--- /dev/null
+++ b/src/mdevd/mdevd_uevent_read.c
@@ -0,0 +1,87 @@
+/* ISC license. */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <skalibs/types.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/strerr2.h>
+
+#include "mdevd-internal.h"
+
+static inline ssize_t fd_recvmsg (int fd, struct msghdr *hdr)
+{
+ ssize_t r ;
+ do r = recvmsg(fd, hdr, MSG_DONTWAIT) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+static inline size_t netlink_read (int fd, char *s, unsigned int verbosity)
+{
+ struct sockaddr_nl nl;
+ struct iovec v = { .iov_base = s, .iov_len = UEVENT_MAX_SIZE } ;
+ struct msghdr msg =
+ {
+ .msg_name = &nl,
+ .msg_namelen = sizeof(struct sockaddr_nl),
+ .msg_iov = &v,
+ .msg_iovlen = 1,
+ .msg_control = 0,
+ .msg_controllen = 0,
+ .msg_flags = 0
+ } ;
+ ssize_t r = sanitize_read(fd_recvmsg(fd, &msg)) ;
+ if (r < 0)
+ strerr_diefu1sys(111, "receive netlink message") ;
+ if (!r) return 0 ;
+ if (msg.msg_flags & MSG_TRUNC)
+ strerr_diefu1x(111, "buffer too small for netlink message") ;
+ if (nl.nl_pid)
+ {
+ if (verbosity >= 3)
+ {
+ char fmt[PID_FMT] ;
+ fmt[pid_fmt(fmt, nl.nl_pid)] = 0 ;
+ strerr_warnw2x("received netlink message from userspace process ", fmt) ;
+ }
+ return 0 ;
+ }
+ if (s[r-1])
+ {
+ if (verbosity) strerr_warnw2x("received invalid event: ", "improperly terminated") ;
+ return 0 ;
+ }
+ if (!strstr(s, "@/"))
+ {
+ if (verbosity) strerr_warnw2x("received invalid event: ", "bad initial summary") ;
+ return 0 ;
+ }
+ return r ;
+}
+
+int mdevd_uevent_read (int fd, struct uevent_s *event, unsigned int verbosity)
+{
+ unsigned short len = 0 ;
+ event->len = netlink_read(fd, event->buf, verbosity) ;
+ if (!event->len) return 0 ;
+ event->varn = 0 ;
+ while (len < event->len)
+ {
+ if (event->varn >= UEVENT_MAX_VARS)
+ {
+ if (verbosity) strerr_warnw2x("received invalid event: ", "too many variables") ;
+ return 0 ;
+ }
+ event->vars[event->varn++] = len ;
+ len += strlen(event->buf + len) + 1 ;
+ }
+ return 1 ;
+}