summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2022-07-24 00:28:32 +0000
committerLaurent Bercot <ska@appnovation.com>2022-07-24 00:28:32 +0000
commit8ad0f7f39526ee0d8f52f44f5434dfd518f8897a (patch)
tree41b3da33258b25b56ab85973b91e4e98dd833ae8 /src
parentd9f63961ec01dc02131ad0967734ae1a058b27b8 (diff)
downloadmdevd-8ad0f7f39526ee0d8f52f44f5434dfd518f8897a.tar.xz
Add "settle" functionality to mdevd-colplug
- Still untested. - Also prepare for 0.1.6.0. - Includes a refactor of several functions in mdevd, moved into an internal libmdevd that is also used by mdevd-coldplug. Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src')
-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
9 files changed, 230 insertions, 134 deletions
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 ;
+}