diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2017-04-14 11:09:40 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2017-04-14 11:09:40 +0000 |
commit | 6cdac30aed3d1199cbcde2c10e61691af9fc77e3 (patch) | |
tree | be782d5f890637e929b7b0f1ad39a5f33e6be394 | |
parent | 30bb26f896777144eb20a620440a97fa5c2be50f (diff) | |
download | s6-linux-utils-6cdac30aed3d1199cbcde2c10e61691af9fc77e3.tar.xz |
Change s6-uevent-listener API: don't spawn, write events to stdout
-rw-r--r-- | INSTALL | 2 | ||||
-rw-r--r-- | doc/index.html | 5 | ||||
-rw-r--r-- | doc/s6-uevent-listener.html | 42 | ||||
-rw-r--r-- | doc/upgrade.html | 6 | ||||
-rw-r--r-- | package/deps.mak | 1 | ||||
-rw-r--r-- | package/info | 2 | ||||
-rw-r--r-- | src/minutils/s6-uevent-listener.c | 75 |
7 files changed, 55 insertions, 78 deletions
@@ -9,7 +9,7 @@ Build Instructions - skalibs version 2.5.0.0 or later: http://skarnet.org/software/skalibs/ This software is Linux-specific. It will run on a Linux kernel, -version 2.6.32 or later. +version 3.5 or later. * Standard usage diff --git a/doc/index.html b/doc/index.html index 6627d5b..2e7897d 100644 --- a/doc/index.html +++ b/doc/index.html @@ -30,7 +30,8 @@ <h3> Requirements </h3> <ul> - <li> A Linux-based system with a standard C development environment </li> + <li> A Linux-based system with a standard C development environment. +The Linux kernel must be 3.5 or later. </li> <li> GNU make, version 3.81 or later </li> <li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version 2.5.0.0 or later. It's a build-time requirement. It's also a run-time @@ -49,7 +50,7 @@ library. </li> <ul> <li> The current released version of s6-linux-utils is -<a href="s6-linux-utils-2.3.0.0.tar.gz">2.3.0.0</a>. </li> +<a href="s6-linux-utils-2.4.0.0.tar.gz">2.4.0.0</a>. </li> <li> Alternatively, you can checkout a copy of the <a href="http://git.skarnet.org/cgi-bin/cgit.cgi/s6-linux-utils/">s6-linux-utils git repository</a>: diff --git a/doc/s6-uevent-listener.html b/doc/s6-uevent-listener.html index 4db31d8..b1908a1 100644 --- a/doc/s6-uevent-listener.html +++ b/doc/s6-uevent-listener.html @@ -19,27 +19,29 @@ <h1> The <tt>s6-uevent-listener</tt> program </h1> <p> -<tt>s6-uevent-listener</tt> spawns a long-lived helper program. -It then listens to the netlink interface for uevents (also called -"hotplug" or "udev" events), and passes those events to the -helper program's standard input, using a simple format. +<tt>s6-uevent-listener</tt> listens to the netlink interface for uevents +(also called "hotplug" or "udev" events), and writes those uevents to +its standard output, using a simple format. </p> <h2> Interface </h2> <pre> - s6-uevent-listener [ -v <em>verbosity</em> ] [ -b kbufsz ] <em>prog...</em> + s6-uevent-listener [ -v <em>verbosity</em> ] [ -b kbufsz ] </pre> <ul> - <li> s6-uevent-listener spawns <em>prog...</em> with a pipe writing to -<em>prog</em>' stdin. </li> <li> s6-uevent-listener binds to the netlink interface and listens for hotplug events, as the <em>udev</em> program does. </li> - <li> It transmits event information to <em>prog</em> via the pipe. </li> - <li> s6-uevent-listener, like <em>prog</em>, is a long-lived program. + <li> It writes event information to its stdout. The output contains +null characters, so a terminal will not display them correctly. To +properly use s6-uevent-listener, it should be piped into a handler +program such as +<a href="s6-uevent-spawner.html">s6-uevent-spawner</a> or +<a href="mdevd.html">mdevd</a>. </li> + <li> s6-uevent-listener is a long-lived program. When it receives a SIGTERM, it stops listening; it will -exit as soon as it has flushed its event queue to <em>prog</em>. </li> +exit as soon as it has flushed its event queue to stdout. </li> </ul> <h2> Options </h2> @@ -58,8 +60,6 @@ the large side). </li> <h2> Protocol </h2> <ul> - <li> <em>prog</em> should read a series of events on its stdin, and exit -on EOF. </li> <li> An event is a series of null-terminated strings as they are sent by the kernel to the netlink; s6-uevent-listener adds a final empty string (i.e. an additional null character) to mark the end of the series. </li> @@ -90,11 +90,19 @@ as <a href="http://skarnet.org/software/s6/">s6</a>. </li> <li> If you are running s6-uevent-listener, <em>prog...</em> should be the only program handling uevents, which means that <tt>/proc/sys/kernel/hotplug</tt> should be empty. </li> - <li> If you want the serialization benefit of the netlink, but still -want to spawn a program such as <a href="http://busybox.net/">busybox</a>'s -or <a href="http://landley.net/toybox/">toybox</a>'s <tt>mdev</tt>, use -<tt><a href="s6-uevent-spawner.html">s6-uevent-spawner</a> mdev</tt> as -s6-uevent-listener's <em>prog</em>. </li> + <li> Examples of valid uses of s6-uevent-listener: + <ul> + <li> <tt>s6-uevent-listener | s6-uevent-spawner mdev</tt> </li> + <li> <tt>s6-uevent-listener | mdevd</tt> </li> + <li> Those examples can be made safer by using a supervision system: +under <a href="http://skarnet.org/software/s6/">s6</a> or +<a href="http://skarnet.org/software/s6-rc/">s6-rc</a>, write a service +pipeline where <tt>s6-uevent-listener</tt> is a producer and +<tt>s6-uevent-spawner mdev</tt> or <tt>mdevd</tt> is a consumer. This +setup has the advantage, among others, that you can restart the netlink +listener and the event handler separately. </li> + </ul> + </li> </ul> </body> diff --git a/doc/upgrade.html b/doc/upgrade.html index f5c14b0..91a143a 100644 --- a/doc/upgrade.html +++ b/doc/upgrade.html @@ -18,6 +18,12 @@ <h1> What has changed in s6-linux-utils </h1> +<h2> in 2.4.0.0 </h2> + +<ul> + <li> Linux dependency bumped to 3.5. </li> +</ul> + <h2> in 2.3.0.0 </h2> <ul> diff --git a/package/deps.mak b/package/deps.mak index 74e1ff2..7aaf8d0 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -2,6 +2,7 @@ # This file has been generated by tools/gen-deps.sh # +src/minutils/mdevd.o src/minutils/mdevd.lo: src/minutils/mdevd.c src/minutils/s6-chroot.o src/minutils/s6-chroot.lo: src/minutils/s6-chroot.c src/minutils/s6-devd.o src/minutils/s6-devd.lo: src/minutils/s6-devd.c src/include/s6-linux-utils/config.h src/minutils/s6-fillurandompool.o src/minutils/s6-fillurandompool.lo: src/minutils/s6-fillurandompool.c diff --git a/package/info b/package/info index f39d9e7..65df44f 100644 --- a/package/info +++ b/package/info @@ -1,4 +1,4 @@ package=s6-linux-utils -version=2.3.0.0 +version=2.4.0.0 category=admin package_macro_name=S6_LINUX_UTILS diff --git a/src/minutils/s6-uevent-listener.c b/src/minutils/s6-uevent-listener.c index 29fbc38..e882821 100644 --- a/src/minutils/s6-uevent-listener.c +++ b/src/minutils/s6-uevent-listener.c @@ -9,32 +9,28 @@ #include <errno.h> #include <signal.h> #include <sys/socket.h> -#include <sys/wait.h> #include <linux/netlink.h> #include <skalibs/types.h> #include <skalibs/allreadwrite.h> #include <skalibs/siovec.h> #include <skalibs/buffer.h> #include <skalibs/sgetopt.h> +#include <skalibs/error.h> #include <skalibs/strerr2.h> #include <skalibs/iopause.h> #include <skalibs/djbunix.h> #include <skalibs/sig.h> #include <skalibs/selfpipe.h> -#define USAGE "s6-uevent-listener [ -v verbosity ] [ -b kbufsz ] helperprogram..." +#define USAGE "s6-uevent-listener [ -v verbosity ] [ -b kbufsz ]" #define dieusage() strerr_dieusage(100, USAGE) #define dienomem() strerr_diefu1sys(111, "build string") ; #define MAXNLSIZE 4096 -#define BUFSIZE 8191 -static char buf1[BUFSIZE + 1] ; -static buffer b1 = BUFFER_INIT(&buffer_write, 1, buf1, BUFSIZE + 1) ; static unsigned int cont = 1, verbosity = 1 ; -static pid_t pid ; -static inline int fd_recvmsg (int fd, struct msghdr *hdr) +static inline ssize_t fd_recvmsg (int fd, struct msghdr *hdr) { ssize_t r ; do r = recvmsg(fd, hdr, MSG_DONTWAIT) ; @@ -64,26 +60,6 @@ static inline void handle_signals (void) cont = 0 ; fd_close(0) ; break ; - case SIGCHLD : - { - char fmt[UINT_FMT] ; - int wstat ; - int r = wait_pid_nohang(pid, &wstat) ; - if (r < 0) - if (errno != ECHILD) strerr_diefu1sys(111, "wait_pid_nohang") ; - else break ; - else if (!r) break ; - if (WIFSIGNALED(wstat)) - { - fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ; - strerr_dief2x(1, "child crashed with signal ", fmt) ; - } - else - { - fmt[uint_fmt(fmt, WEXITSTATUS(wstat))] = 0 ; - strerr_dief2x(1, "child exited ", fmt) ; - } - } default : strerr_dief1x(101, "internal error: inconsistent signal state. Please submit a bug-report.") ; } @@ -92,7 +68,8 @@ static inline void handle_signals (void) static inline void handle_stdout (void) { - if (!buffer_flush(&b1)) strerr_diefu1sys(111, "flush stdout") ; + if (!buffer_flush(buffer_1) && !error_isagain(errno)) + strerr_diefu1sys(111, "flush stdout") ; } static inline void handle_netlink (void) @@ -110,7 +87,7 @@ static inline void handle_netlink (void) .msg_flags = 0 } ; ssize_t r ; - buffer_wpeek(&b1, v) ; + buffer_wpeek(buffer_1, v) ; siovec_trunc(v, 2, siovec_len(v, 2) - 1) ; r = sanitize_read(fd_recvmsg(0, &msg)) ; if (r < 0) @@ -131,14 +108,14 @@ static inline void handle_netlink (void) { if (verbosity >= 3) { - char fmt[UINT_FMT] ; - fmt[uint_fmt(fmt, nl.nl_pid)] = 0 ; + char fmt[PID_FMT] ; + fmt[pid_fmt(fmt, nl.nl_pid)] = 0 ; strerr_warnw3x("netlink message", " from userspace process ", fmt) ; } return ; } - buffer_wseek(&b1, r) ; - buffer_putnoflush(&b1, "", 1) ; + buffer_wseek(buffer_1, r) ; + buffer_putnoflush(buffer_1, "", 1) ; } @@ -161,45 +138,29 @@ int main (int argc, char const *const *argv, char const *const *envp) } } argc -= l.ind ; argv += l.ind ; - if (!argc) strerr_dieusage(100, USAGE) ; if (!netlink_init_stdin(kbufsz)) strerr_diefu1sys(111, "init netlink") ; } x[0].fd = selfpipe_init() ; if (x[0].fd < 0) strerr_diefu1sys(111, "init selfpipe") ; if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; - { - sigset_t set ; - sigemptyset(&set) ; - sigaddset(&set, SIGTERM) ; - sigaddset(&set, SIGCHLD) ; - if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; - } - - { - int fd ; - pid = child_spawn1_pipe(argv[0], argv, envp, &fd, 0) ; - if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; - if (fd_move(1, fd) < 0) strerr_diefu1sys(111, "move pipe to stdout") ; - if (ndelay_on(1) < 0) strerr_diefu1sys(111, "make stdout nonblocking") ; - } + if (selfpipe_trap(SIGTERM) < 0) strerr_diefu1sys(111, "trap SIGTERM") ; if (verbosity >= 2) strerr_warni1x("starting") ; while (cont || buffer_len(buffer_1)) { int r ; - x[1].events = buffer_len(&b1) ? IOPAUSE_WRITE : 0 ; - x[2].events = buffer_available(&b1) >= MAXNLSIZE + 1 ? IOPAUSE_READ : 0 ; + x[1].events = buffer_len(buffer_1) ? IOPAUSE_WRITE : 0 ; + x[2].events = buffer_available(buffer_1) >= MAXNLSIZE + 1 ? IOPAUSE_READ : 0 ; r = iopause(x, 2 + cont, 0, 0) ; if (r < 0) strerr_diefu1sys(111, "iopause") ; if (!r) continue ; - if (x[0].revents & IOPAUSE_EXCEPT) - strerr_diefu1x(111, "iopause: trouble with selfpipe") ; - if (x[0].revents & IOPAUSE_READ) - handle_signals() ; - if (x[1].revents & IOPAUSE_WRITE) - handle_stdout() ; + for (r = 0 ; r < 2 ; r++) + if (x[r].revents & IOPAUSE_EXCEPT) + x[r].revents |= IOPAUSE_READ | IOPAUSE_WRITE ; + if (x[0].revents & IOPAUSE_READ) handle_signals() ; + if (x[1].revents & IOPAUSE_WRITE) handle_stdout() ; if (cont && x[2].events & IOPAUSE_READ && x[2].revents & IOPAUSE_READ) handle_netlink() ; } |