about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2017-04-14 11:09:40 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2017-04-14 11:09:40 +0000
commit6cdac30aed3d1199cbcde2c10e61691af9fc77e3 (patch)
treebe782d5f890637e929b7b0f1ad39a5f33e6be394
parent30bb26f896777144eb20a620440a97fa5c2be50f (diff)
downloads6-linux-utils-6cdac30aed3d1199cbcde2c10e61691af9fc77e3.tar.gz
s6-linux-utils-6cdac30aed3d1199cbcde2c10e61691af9fc77e3.tar.xz
s6-linux-utils-6cdac30aed3d1199cbcde2c10e61691af9fc77e3.zip
Change s6-uevent-listener API: don't spawn, write events to stdout
-rw-r--r--INSTALL2
-rw-r--r--doc/index.html5
-rw-r--r--doc/s6-uevent-listener.html42
-rw-r--r--doc/upgrade.html6
-rw-r--r--package/deps.mak1
-rw-r--r--package/info2
-rw-r--r--src/minutils/s6-uevent-listener.c75
7 files changed, 55 insertions, 78 deletions
diff --git a/INSTALL b/INSTALL
index 656bbc8..2b310a8 100644
--- a/INSTALL
+++ b/INSTALL
@@ -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() ;
   }