diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | INSTALL | 4 | ||||
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | doc/index.html | 6 | ||||
-rw-r--r-- | doc/mdevd-coldplug.html | 17 | ||||
-rw-r--r-- | doc/upgrade.html | 10 | ||||
-rw-r--r-- | package/deps.mak | 18 | ||||
-rw-r--r-- | package/info | 2 | ||||
-rw-r--r-- | src/mdevd/deps-exe/mdevd | 1 | ||||
-rw-r--r-- | src/mdevd/deps-exe/mdevd-coldplug | 1 | ||||
-rw-r--r-- | src/mdevd/deps-lib/mdevd | 3 | ||||
-rw-r--r-- | src/mdevd/mdevd-coldplug.c | 61 | ||||
-rw-r--r-- | src/mdevd/mdevd-internal.h | 24 | ||||
-rw-r--r-- | src/mdevd/mdevd.c | 140 | ||||
-rw-r--r-- | src/mdevd/mdevd_netlink_init.c | 31 | ||||
-rw-r--r-- | src/mdevd/mdevd_uevent_getvar.c | 16 | ||||
-rw-r--r-- | src/mdevd/mdevd_uevent_read.c | 87 |
17 files changed, 283 insertions, 149 deletions
@@ -1,8 +1,7 @@ *.o -*.a +/*.a.xyzzy *.lo -*.so -*.so.* +/*.so.xyzzy /config.mak /src/include/mdevd/config.h /mdevd @@ -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. @@ -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>&</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> <em>verbosity</em> : 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> <em>slashsys</em> : assume the sysfs pseudo-filesystem is mounted on <em>slashsys</em>. Default is <tt>/sys</tt>. </li> + <li> <tt>-O</tt> <em>nlgroup</em> : 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> <em>kbufsz</em> : 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 ; +} |