about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/index.html2
-rw-r--r--doc/libs6/index.html2
-rw-r--r--doc/s6-svscan.html58
-rw-r--r--doc/ucspilogd.html4
-rw-r--r--doc/upgrade.html7
-rwxr-xr-xexamples/ROOT/etc/s6-init/crash13
-rwxr-xr-xexamples/ROOT/etc/s6-init/init-stage12
-rwxr-xr-xexamples/ROOT/etc/s6-init/init-stage220
-rwxr-xr-xexamples/ROOT/etc/s6-init/init-stage32
-rwxr-xr-xexamples/ROOT/etc/s6-init/network-config5
-rw-r--r--examples/ROOT/etc/s6-rc/README9
-rw-r--r--examples/ROOT/img/README11
-rw-r--r--examples/ROOT/img/services-local/README5
-rw-r--r--examples/ROOT/img/services-network/README5
-rw-r--r--examples/ROOT/img/services-network/dns-cache/README2
-rw-r--r--examples/ROOT/img/services-network/dns-cache/env/CACHESIZE1
-rw-r--r--examples/ROOT/img/services-network/dns-cache/env/IP1
-rw-r--r--examples/ROOT/img/services-network/dns-cache/env/IPSEND1
-rw-r--r--examples/ROOT/img/services-network/dns-cache/env/ROOT1
-rw-r--r--examples/ROOT/img/services-network/dns-cache/log/README3
-rwxr-xr-xexamples/ROOT/img/services-network/dns-cache/log/run4
-rw-r--r--examples/ROOT/img/services-network/dns-cache/root/ip/127.0.0.10
-rw-r--r--examples/ROOT/img/services-network/dns-cache/root/servers/@13
-rwxr-xr-xexamples/ROOT/img/services-network/dns-cache/run12
-rw-r--r--examples/ROOT/img/services-network/fifodir-cleanup/README2
-rwxr-xr-xexamples/ROOT/img/services-network/fifodir-cleanup/run14
-rw-r--r--examples/ROOT/img/services-network/ntpclient/README9
-rw-r--r--examples/ROOT/img/services-network/ntpclient/log/README3
-rwxr-xr-xexamples/ROOT/img/services-network/ntpclient/log/run4
-rwxr-xr-xexamples/ROOT/img/services-network/ntpclient/run19
-rw-r--r--examples/ROOT/img/services-network/sshd/README5
-rw-r--r--examples/ROOT/img/services-network/sshd/log/README1
-rwxr-xr-xexamples/ROOT/img/services-network/sshd/log/run4
-rw-r--r--examples/ROOT/img/services-network/sshd/notification-fd1
-rw-r--r--examples/ROOT/img/services-network/sshd/rules/ip4/0.0.0.0_0/deny0
-rw-r--r--examples/ROOT/img/services-network/sshd/rules/ip4/127.0.0.1_32/allow0
-rwxr-xr-xexamples/ROOT/img/services-network/sshd/run6
-rw-r--r--examples/ROOT/img/tmpfs/service/.s6-svscan/README11
-rwxr-xr-xexamples/ROOT/img/tmpfs/service/.s6-svscan/SIGINT3
-rwxr-xr-xexamples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR13
-rwxr-xr-xexamples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR23
-rwxr-xr-x[l---------]examples/ROOT/img/tmpfs/service/.s6-svscan/crash14
l---------examples/ROOT/run1
-rw-r--r--examples/klogd-linux/README (renamed from examples/ROOT/img/services-local/klogd-linux/README)2
-rw-r--r--examples/klogd-linux/log/README (renamed from examples/ROOT/img/services-local/klogd-linux/log/README)0
-rwxr-xr-xexamples/klogd-linux/log/run (renamed from examples/ROOT/img/services-local/klogd-linux/log/run)0
-rwxr-xr-xexamples/klogd-linux/run (renamed from examples/ROOT/img/services-local/klogd-linux/run)0
-rw-r--r--examples/syslogd-linux/README (renamed from examples/ROOT/img/services-local/syslogd-linux/README)2
-rw-r--r--examples/syslogd-linux/log/README (renamed from examples/ROOT/img/services-local/syslogd-linux/log/README)0
-rw-r--r--examples/syslogd-linux/log/env/LOGSCRIPT (renamed from examples/ROOT/img/services-local/syslogd-linux/log/env/LOGSCRIPT)0
-rwxr-xr-xexamples/syslogd-linux/log/run (renamed from examples/ROOT/img/services-local/syslogd-linux/log/run)0
-rw-r--r--examples/syslogd-linux/notification-fd (renamed from examples/ROOT/img/services-local/syslogd-linux/notification-fd)0
-rwxr-xr-xexamples/syslogd-linux/run (renamed from examples/ROOT/img/services-local/syslogd-linux/run)0
-rw-r--r--package/info2
-rw-r--r--src/supervision/s6-svscan.c49
55 files changed, 161 insertions, 180 deletions
diff --git a/doc/index.html b/doc/index.html
index 50018e7..48ec334 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -101,7 +101,7 @@ library. </li>
 <h3> Download </h3>
 
 <ul>
- <li> The current released version of s6 is <a href="s6-2.2.1.1.tar.gz">2.2.1.1</a>. </li>
+ <li> The current released version of s6 is <a href="s6-2.2.2.0.tar.gz">2.2.2.0</a>. </li>
  <li> Alternatively, you can checkout a copy of the s6 git repository:
 <pre> git clone git://git.skarnet.org/s6 </pre> </li>
  <li> There's also a
diff --git a/doc/libs6/index.html b/doc/libs6/index.html
index b70bda3..348dfed 100644
--- a/doc/libs6/index.html
+++ b/doc/libs6/index.html
@@ -54,7 +54,7 @@ stands for your skalibs sysdeps directory. </li>
 <p>
  The <tt>s6/s6.h</tt> header is actually a
 concatenation of other headers:
-the libs6net is separated into several modules, each of them with its
+the libs6 is separated into several modules, each of them with its
 own header.
 </p>
 
diff --git a/doc/s6-svscan.html b/doc/s6-svscan.html
index a0a6790..6c4d8d9 100644
--- a/doc/s6-svscan.html
+++ b/doc/s6-svscan.html
@@ -27,7 +27,7 @@ the root or a branch of a <em>supervision tree</em>.
 <h2> Interface </h2>
 
 <pre>
-     s6-svscan [ -c max ] [ -t <em>rescan</em> ] [ <em>scandir</em> ]
+     s6-svscan [ -S | -s ] [ -c max ] [ -t <em>rescan</em> ] [ <em>scandir</em> ]
 </pre>
 
 <ul>
@@ -59,6 +59,9 @@ execution. </li>
 <h2> Options </h2>
 
 <ul>
+ <li> <tt>-S&nbsp;</tt>&nbsp;: do not divert signals. This is the default for now;
+it may change in a future version of s6. </li>
+ <li> <tt>-s&nbsp;</tt>&nbsp;: divert signals - see below. </li>
  <li> <tt>-c&nbsp;<em>max</em></tt>&nbsp;: maintain services for up to <em>max</em>
 service directories. Default is 500. Lower limit is 2. There is no upper limit, but:
  <ul>
@@ -82,20 +85,67 @@ scan (and a reap) every 5 seconds. It is <em>strongly</em> discouraged to set
 <h2> Signals </h2>
 
 <p>
- s6-svscan reacts to the following signals:
+ s6-svscan always reacts to the following signals:
 </p>
 
 <ul>
  <li> SIGCHLD&nbsp;: triggers the reaper. </li>
  <li> SIGALRM&nbsp;: triggers the scanner. </li>
+ <li> SIGABRT&nbsp;: acts as if a <tt>s6-svscanctl -b</tt> command had been received. </li>
+</ul>
+
+<p>
+ By default, it also reacts to the following signals:
+</p>
+
+<ul>
  <li> SIGTERM&nbsp;: acts as if a <tt>s6-svscanctl -t</tt> command had been received. </li>
  <li> SIGHUP&nbsp;: acts as if a <tt>s6-svscanctl -h</tt> command had been received. </li>
  <li> SIGQUIT&nbsp;: acts as if a <tt>s6-svscanctl -q</tt> command had been received. </li>
- <li> SIGABRT&nbsp;: acts as if a <tt>s6-svscanctl -b</tt> command had been received. </li>
  <li> SIGINT&nbsp;: acts as if a <tt>s6-svscanctl -6</tt> command had been received. </li>
- <li> SIGUSR1&nbsp;: acts as if a <tt>s6-svscanctl -7</tt> command had been received. </li>
 </ul>
 
+<p>
+ But if the <tt>-s</tt> option was given, then instead of those default actions,
+s6-svscan uses configurable handlers: it forks and executes a program every time
+it receives one of the following signals.
+</p>
+
+<ul>
+ <li> SIGTERM&nbsp;: fork and execute <tt>.s6-svscan/SIGTERM</tt> </li>
+ <li> SIGHUP&nbsp;: fork and execute <tt>.s6-svscan/SIGHUP</tt> </li>
+ <li> SIGQUIT&nbsp;: fork and execute <tt>.s6-svscan/SIGQUIT</tt> </li>
+ <li> SIGINT&nbsp;: fork and execute <tt>.s6-svscan/SIGINT</tt> </li>
+ <li> SIGUSR1&nbsp;: fork and execute <tt>.s6-svscan/SIGUSR1</tt> </li>
+ <li> SIGUSR2&nbsp;: fork and execute <tt>.s6-svscan/SIGUSR2</tt> </li>
+</ul>
+
+<p>
+ If an action cannot be taken (the relevant file doesn't exist, or isn't
+executable, or any kind of error happens), s6-svscan prints a warning
+message to its standard error but does nothing else with the signal.
+</p>
+
+<p>
+ The <tt>-s</tt> mechanism is useful, for instance, when s6-svscan is running as
+process 1 and needs to trap signals such as SIGINT (sent on some systems by
+a Ctrl-Alt-Del press) in order to perform some specific work instead of
+executing into <tt>.s6-svscan/finish</tt> on the spot.
+</p>
+
+<p>
+ s6-svscan will not exit its loop on its own when it receives a signal such as
+SIGINT and the <tt>-s</tt> option has been given. To make it exit its loop,
+invoke a <a href="s6-svscanctl.html">s6-svscanctl</a> command from the signal
+handling script. For instance, a <tt>.s6-svscan/SIGINT</tt> script could look
+like this:
+</p>
+
+<pre>  #!/command/execlineb -P
+  foreground { shutdown-the-services }
+  s6-svscanctl -i .
+</pre>
+
 <h2> The reaper </h2>
 
 <p>
diff --git a/doc/ucspilogd.html b/doc/ucspilogd.html
index 29b1975..856e257 100644
--- a/doc/ucspilogd.html
+++ b/doc/ucspilogd.html
@@ -79,7 +79,7 @@ than a standard <em>syslogd</em>.
 </p>
 
 <p>
- In the <tt>examples/ROOT/img/services-local/syslogd-linux</tt> subdirectory of the s6 package, you will
+ In the <tt>examples/syslogd-linux</tt> subdirectory of the s6 package, you will
 find a suitable ucspilogd <a href="servicedir.html">service directory</a>.
 The run scripts are written in the
 <a href="http://skarnet.org/software/execline/">execline</a>
@@ -97,7 +97,7 @@ You can use <tt>ucspilogd</tt> to process data from those interfaces.
 </p>
 
 <p>
- The <tt>examples/ROOT/img/services-local/klogd-linux</tt> subdirectory of the s6 package
+ The <tt>examples/klogd-linux</tt> subdirectory of the s6 package
 is a <a href="servicedir.html">service directory</a> providing such a <em>klogd</em> service
 for Linux, using the <tt>/proc/kmsg</tt> interface.
 </p>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index a68b1a7..91c088e 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -18,6 +18,13 @@
 
 <h1> What has changed in s6 </h1>
 
+<h2> in 2.2.2.0 </h2>
+
+<ul>
+ <li> <a href="s6-svscan.html">s6-svscan</a> now supports the <tt>-s</tt>
+option for configurable signal management. </li>
+</ul>
+
 <h2> in 2.2.1.1 </h2>
 
 <ul>
diff --git a/examples/ROOT/etc/s6-init/crash b/examples/ROOT/etc/s6-init/crash
deleted file mode 100755
index 501e316..0000000
--- a/examples/ROOT/etc/s6-init/crash
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/command/execlineb -P
-
-# This file is run when an unrecoverable error happens
-# to s6-svscan. Edit it to suit your needs.
-
-cd /
-redirfd -r 0 /dev/console
-redirfd -w 1 /dev/console
-fdmove -c 2 1
-
-foreground { s6-echo "s6-svscan panicked! Dropping to a root shell.\n" }
-
-/bin/sh -i
diff --git a/examples/ROOT/etc/s6-init/init-stage1 b/examples/ROOT/etc/s6-init/init-stage1
index a06b015..810948b 100755
--- a/examples/ROOT/etc/s6-init/init-stage1
+++ b/examples/ROOT/etc/s6-init/init-stage1
@@ -56,4 +56,4 @@ background
 unexport !
 
 # Start stage 2.
-s6-svscan -t0 /service
+s6-svscan -st0 /service
diff --git a/examples/ROOT/etc/s6-init/init-stage2 b/examples/ROOT/etc/s6-init/init-stage2
index 58ac98d..86f31a5 100755
--- a/examples/ROOT/etc/s6-init/init-stage2
+++ b/examples/ROOT/etc/s6-init/init-stage2
@@ -4,7 +4,6 @@
 # starts. It should perform all the remaining one-time initialization
 # tasks.
 
-
 if -nt
 {
 
@@ -12,22 +11,9 @@ if -nt
 # NOT on /dev/console !
   if { s6-echo "* init-stage2 starting." }
 
-# Call your one-time early initialization scripts (before bringing
-# the network up) here:
-# set the hostname, mount filesystems, adjust sysctls, etc.
-# if { s6-mount -wt devpts -o noexec,nosuid,gid=0,mode=0600 devpts /dev/pts }
-# if { s6-mount -wt ext4 /dev/sda3 /mnt/rwfs }
-
-# Start the local services
-  if { s6-hiercopy /img/services-local /service }
-  if { s6-svscanctl -a /service }
-
-# Bring up the network
-  if { /etc/s6-init/network-config }
-
-# Start the late services
-  if { s6-hiercopy /img/services-network /service }
-  if { s6-svscanctl -a /service }
+# Call your service manager commands here to run the boot scripts.
+  if { s6-rc-init /service }
+  if { s6-rc -u change normal-state }
 
 # We're done and the machine is fully operational.
   s6-echo "* init-stage2 completed."
diff --git a/examples/ROOT/etc/s6-init/init-stage3 b/examples/ROOT/etc/s6-init/init-stage3
index 66b3062..ff28372 100755
--- a/examples/ROOT/etc/s6-init/init-stage3
+++ b/examples/ROOT/etc/s6-init/init-stage3
@@ -13,7 +13,7 @@ foreground { s6-echo "Syncing disks." }
 foreground { s6-sync }
 
 
-# Even if s6-svscan properly brought all the services down
+# Even if s6-rc and s6-svscan properly brought all the services down
 # before exec'ing into this script, users might have launched
 # background nohup processes, so we have to kill everything.
 
diff --git a/examples/ROOT/etc/s6-init/network-config b/examples/ROOT/etc/s6-init/network-config
deleted file mode 100755
index 2f9e3cd..0000000
--- a/examples/ROOT/etc/s6-init/network-config
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/command/execlineb -P
-
-# if { ifconfig lo 127.0.0.1 netmask 255.0.0.0 }
-
-# Configure your network interfaces and routing here.
diff --git a/examples/ROOT/etc/s6-rc/README b/examples/ROOT/etc/s6-rc/README
new file mode 100644
index 0000000..959f280
--- /dev/null
+++ b/examples/ROOT/etc/s6-rc/README
@@ -0,0 +1,9 @@
+ If you are using s6-rc as your service manager, this directory should
+be the place where you store your compiled service databases.
+
+ The /etc/s6-init/init-stage2 script invokes s6-rc which expects to
+find its data here by default.
+
+ The /run/service/.s6-svscan/SIG{INT,USR1,USR2} scripts invoke
+s6-rc to bring down all the managed services before shutting down
+s6-svscan.
diff --git a/examples/ROOT/img/README b/examples/ROOT/img/README
index 8181be3..185a3e6 100644
--- a/examples/ROOT/img/README
+++ b/examples/ROOT/img/README
@@ -1,9 +1,4 @@
-This directory is read-only. It contains the service
-repository (actually one list of services that do not
-need the network and one list of services that can only
-be started after the network is up), and an image of the
+This directory is read-only. It contains an image of the
 tmpfs that it copied as-is at boot-time (during stage 1
-init).
-This directory is only used at boot-time, it is never
-written to (the service directories are copied as-is
-to /service during stage 2 init).
+init). It is only used at boot-time, it is never
+written to.
diff --git a/examples/ROOT/img/services-local/README b/examples/ROOT/img/services-local/README
deleted file mode 100644
index 9e4c027..0000000
--- a/examples/ROOT/img/services-local/README
+++ /dev/null
@@ -1,5 +0,0 @@
-This is the service repository for services that should be started
-early, typically before the network goes up.
-"klogd" and "syslogd" services should be present as soon as possible,
-because other services might need them. However, since they need
-a writable disk filesystem, they can't be run as early as a getty.
diff --git a/examples/ROOT/img/services-network/README b/examples/ROOT/img/services-network/README
deleted file mode 100644
index 9f4ab38..0000000
--- a/examples/ROOT/img/services-network/README
+++ /dev/null
@@ -1,5 +0,0 @@
-This is the service repository for all the late services,
-i.e. those that do not need to be started before the network
-is up.
-Only a few examples are provided here; you can make your own
-service directories depending on your needs.
diff --git a/examples/ROOT/img/services-network/dns-cache/README b/examples/ROOT/img/services-network/dns-cache/README
deleted file mode 100644
index 8fc5c28..0000000
--- a/examples/ROOT/img/services-network/dns-cache/README
+++ /dev/null
@@ -1,2 +0,0 @@
-Service directory for a DNS caching resolver service,
-implemented via djbdns's dnscache running on 127.0.0.1
diff --git a/examples/ROOT/img/services-network/dns-cache/env/CACHESIZE b/examples/ROOT/img/services-network/dns-cache/env/CACHESIZE
deleted file mode 100644
index 6820bf1..0000000
--- a/examples/ROOT/img/services-network/dns-cache/env/CACHESIZE
+++ /dev/null
@@ -1 +0,0 @@
-1048576
diff --git a/examples/ROOT/img/services-network/dns-cache/env/IP b/examples/ROOT/img/services-network/dns-cache/env/IP
deleted file mode 100644
index 7b9ad53..0000000
--- a/examples/ROOT/img/services-network/dns-cache/env/IP
+++ /dev/null
@@ -1 +0,0 @@
-127.0.0.1
diff --git a/examples/ROOT/img/services-network/dns-cache/env/IPSEND b/examples/ROOT/img/services-network/dns-cache/env/IPSEND
deleted file mode 100644
index d690dc0..0000000
--- a/examples/ROOT/img/services-network/dns-cache/env/IPSEND
+++ /dev/null
@@ -1 +0,0 @@
-0.0.0.0
diff --git a/examples/ROOT/img/services-network/dns-cache/env/ROOT b/examples/ROOT/img/services-network/dns-cache/env/ROOT
deleted file mode 100644
index 0a89945..0000000
--- a/examples/ROOT/img/services-network/dns-cache/env/ROOT
+++ /dev/null
@@ -1 +0,0 @@
-/service/dns-cache/root
diff --git a/examples/ROOT/img/services-network/dns-cache/log/README b/examples/ROOT/img/services-network/dns-cache/log/README
deleted file mode 100644
index 55676f1..0000000
--- a/examples/ROOT/img/services-network/dns-cache/log/README
+++ /dev/null
@@ -1,3 +0,0 @@
-Logger service for the dns-cache service.
-djbdns's dnscache produces a lot of output, so
-you may want to add log filters.
diff --git a/examples/ROOT/img/services-network/dns-cache/log/run b/examples/ROOT/img/services-network/dns-cache/log/run
deleted file mode 100755
index 4177eaa..0000000
--- a/examples/ROOT/img/services-network/dns-cache/log/run
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/command/execlineb -P
-s6-setuidgid dnslog
-exec -c
-s6-log t s1000000 n20 /var/log/dns-cache
diff --git a/examples/ROOT/img/services-network/dns-cache/root/ip/127.0.0.1 b/examples/ROOT/img/services-network/dns-cache/root/ip/127.0.0.1
deleted file mode 100644
index e69de29..0000000
--- a/examples/ROOT/img/services-network/dns-cache/root/ip/127.0.0.1
+++ /dev/null
diff --git a/examples/ROOT/img/services-network/dns-cache/root/servers/@ b/examples/ROOT/img/services-network/dns-cache/root/servers/@
deleted file mode 100644
index ca40b38..0000000
--- a/examples/ROOT/img/services-network/dns-cache/root/servers/@
+++ /dev/null
@@ -1,13 +0,0 @@
-198.41.0.4
-192.228.79.201
-192.33.4.12
-128.8.10.90
-192.203.230.10
-192.5.5.241
-192.112.36.4
-128.63.2.53
-192.36.148.17
-192.58.128.30
-193.0.14.129
-199.7.83.42
-202.12.27.33
diff --git a/examples/ROOT/img/services-network/dns-cache/run b/examples/ROOT/img/services-network/dns-cache/run
deleted file mode 100755
index af92aae..0000000
--- a/examples/ROOT/img/services-network/dns-cache/run
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/command/execlineb -P
-fdmove -c 2 1
-s6-envuidgid dnscache
-s6-envdir env
-s6-softlimit -m 2000000
-pipeline -d
-{
-  redirfd -r 0 /dev/urandom
-  s6-head -c 128
-}
-unexport !
-dnscache
diff --git a/examples/ROOT/img/services-network/fifodir-cleanup/README b/examples/ROOT/img/services-network/fifodir-cleanup/README
deleted file mode 100644
index 2c41ea2..0000000
--- a/examples/ROOT/img/services-network/fifodir-cleanup/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This service cleans up the fifodirs for all the services in
-/service once a day.
diff --git a/examples/ROOT/img/services-network/fifodir-cleanup/run b/examples/ROOT/img/services-network/fifodir-cleanup/run
deleted file mode 100755
index 9928d84..0000000
--- a/examples/ROOT/img/services-network/fifodir-cleanup/run
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/command/execlineb -P
-fdmove -c 2 1
-if
-{
-  forbacktickx -p -0 i { s6-ls -0 /service }
-  import i unexport i
-  foreground
-  {
-    if { s6-test -d /service/${i}/log }
-    s6-cleanfifodir /service/${i}/log/event
-  }
-  s6-cleanfifodir /service/${i}/event
-}
-s6-sleep 86400
diff --git a/examples/ROOT/img/services-network/ntpclient/README b/examples/ROOT/img/services-network/ntpclient/README
deleted file mode 100644
index c4fc357..0000000
--- a/examples/ROOT/img/services-network/ntpclient/README
+++ /dev/null
@@ -1,9 +0,0 @@
-This service updates the system clock via NTP every 4 hours.
-If you're not in France, change 0.fr.pool.ntp.org to a NTP
-server pool more fitting your location.
-See www.ntp.pool.org for details.
-
-Do yourself a favor and don't rely on NTP internally.
-Just synchronize your main time server via this NTP client
-to the outside world, and use a saner and simpler protocol
-like TAICLOCK in your internal, fast-speed network.
diff --git a/examples/ROOT/img/services-network/ntpclient/log/README b/examples/ROOT/img/services-network/ntpclient/log/README
deleted file mode 100644
index e4c7a37..0000000
--- a/examples/ROOT/img/services-network/ntpclient/log/README
+++ /dev/null
@@ -1,3 +0,0 @@
-Yes, the output of the ntpclient service is logged to
-the /var/log/ntpclient logdir.
-Make sure it has the correct Unix credentials and permissions!
diff --git a/examples/ROOT/img/services-network/ntpclient/log/run b/examples/ROOT/img/services-network/ntpclient/log/run
deleted file mode 100755
index 80d7b5b..0000000
--- a/examples/ROOT/img/services-network/ntpclient/log/run
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/command/execlineb -P
-s6-setuidgid ntplog
-exec -c
-s6-log t /var/log/ntpclient
diff --git a/examples/ROOT/img/services-network/ntpclient/run b/examples/ROOT/img/services-network/ntpclient/run
deleted file mode 100755
index 7ade064..0000000
--- a/examples/ROOT/img/services-network/ntpclient/run
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/command/execlineb -P
-
-fdmove -c 2 1
-if
-{
-  pipeline
-  {
-    s6-setuidgid ntp
-    backtick -n NTPSERVERIP
-    {
-      pipeline { s6-dnsip4 -t 16000 0.fr.pool.ntp.org. }
-      s6-head -n 1
-    }
-    s6-sntpclock -v $NTPSERVERIP
-  }
-  s6-clockadd
-}
-s6-setuidgid nobody
-s6-sleep 14400
diff --git a/examples/ROOT/img/services-network/sshd/README b/examples/ROOT/img/services-network/sshd/README
deleted file mode 100644
index 2d55a5e..0000000
--- a/examples/ROOT/img/services-network/sshd/README
+++ /dev/null
@@ -1,5 +0,0 @@
-Service directory for a sshd server over IPv4,
-implemented via s6-networking and dropbear.
-The rules subdirectory implements access control; in
-this example, only 127.0.0.1 is allowed to connect
-(which isn't exactly useful for a SSH server).
diff --git a/examples/ROOT/img/services-network/sshd/log/README b/examples/ROOT/img/services-network/sshd/log/README
deleted file mode 100644
index 392ede8..0000000
--- a/examples/ROOT/img/services-network/sshd/log/README
+++ /dev/null
@@ -1 +0,0 @@
-Logging service for sshd.
diff --git a/examples/ROOT/img/services-network/sshd/log/run b/examples/ROOT/img/services-network/sshd/log/run
deleted file mode 100755
index d07f180..0000000
--- a/examples/ROOT/img/services-network/sshd/log/run
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/command/execlineb -P
-s6-setuidgid log
-exec -c
-s6-log t s1000000 n20 /var/log/sshd
diff --git a/examples/ROOT/img/services-network/sshd/notification-fd b/examples/ROOT/img/services-network/sshd/notification-fd
deleted file mode 100644
index 00750ed..0000000
--- a/examples/ROOT/img/services-network/sshd/notification-fd
+++ /dev/null
@@ -1 +0,0 @@
-3
diff --git a/examples/ROOT/img/services-network/sshd/rules/ip4/0.0.0.0_0/deny b/examples/ROOT/img/services-network/sshd/rules/ip4/0.0.0.0_0/deny
deleted file mode 100644
index e69de29..0000000
--- a/examples/ROOT/img/services-network/sshd/rules/ip4/0.0.0.0_0/deny
+++ /dev/null
diff --git a/examples/ROOT/img/services-network/sshd/rules/ip4/127.0.0.1_32/allow b/examples/ROOT/img/services-network/sshd/rules/ip4/127.0.0.1_32/allow
deleted file mode 100644
index e69de29..0000000
--- a/examples/ROOT/img/services-network/sshd/rules/ip4/127.0.0.1_32/allow
+++ /dev/null
diff --git a/examples/ROOT/img/services-network/sshd/run b/examples/ROOT/img/services-network/sshd/run
deleted file mode 100755
index 3a35a11..0000000
--- a/examples/ROOT/img/services-network/sshd/run
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/command/execlineb -P
-fdmove -c 2 1
-fdmove 1 3
-s6-tcpserver4 -1 -- 0.0.0.0 22
-s6-tcpserver-access -vvDRl0 -t 5000 -i rules
-dropbear -iEg
diff --git a/examples/ROOT/img/tmpfs/service/.s6-svscan/README b/examples/ROOT/img/tmpfs/service/.s6-svscan/README
index 6500cc6..f61dc8d 100644
--- a/examples/ROOT/img/tmpfs/service/.s6-svscan/README
+++ b/examples/ROOT/img/tmpfs/service/.s6-svscan/README
@@ -1,2 +1,9 @@
-This is the image of the control directory of the s6-svscan process.
-Notice how the symlinks point to ever-existing scripts.
+This is the image of the control directory of the s6-svscan process
+running as pid 1.
+"crash" is run if s6-svscan fails.
+"finish" is run when s6-svscan exits its loop.
+
+ The "SIG*" files are run as children of s6-svscan when it receives
+the corresponding signal. SIGINT, SIGUSR1 and SIGUSR2 will all
+trigger "s6-rc -da change" (the service manager will shut down all
+the services), then s6-svscan will be told to exit its loop.
diff --git a/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGINT b/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGINT
new file mode 100755
index 0000000..f0ff213
--- /dev/null
+++ b/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGINT
@@ -0,0 +1,3 @@
+#!/command/execlineb -P
+foreground { s6-rc -da change }
+s6-svscanctl -6 .
diff --git a/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR1 b/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR1
new file mode 100755
index 0000000..cb4a4ef
--- /dev/null
+++ b/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR1
@@ -0,0 +1,3 @@
+#!/command/execlineb -P
+foreground { s6-rc -da change }
+s6-svscanctl -0 .
diff --git a/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR2 b/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR2
new file mode 100755
index 0000000..e5932be
--- /dev/null
+++ b/examples/ROOT/img/tmpfs/service/.s6-svscan/SIGUSR2
@@ -0,0 +1,3 @@
+#!/command/execlineb -P
+foreground { s6-rc -da change }
+s6-svscanctl -7 .
diff --git a/examples/ROOT/img/tmpfs/service/.s6-svscan/crash b/examples/ROOT/img/tmpfs/service/.s6-svscan/crash
index 262c196..501e316 120000..100755
--- a/examples/ROOT/img/tmpfs/service/.s6-svscan/crash
+++ b/examples/ROOT/img/tmpfs/service/.s6-svscan/crash
@@ -1 +1,13 @@
-/etc/s6-init/crash
\ No newline at end of file
+#!/command/execlineb -P
+
+# This file is run when an unrecoverable error happens
+# to s6-svscan. Edit it to suit your needs.
+
+cd /
+redirfd -r 0 /dev/console
+redirfd -w 1 /dev/console
+fdmove -c 2 1
+
+foreground { s6-echo "s6-svscan panicked! Dropping to a root shell.\n" }
+
+/bin/sh -i
diff --git a/examples/ROOT/run b/examples/ROOT/run
new file mode 120000
index 0000000..cc11a99
--- /dev/null
+++ b/examples/ROOT/run
@@ -0,0 +1 @@
+mnt/tmpfs
\ No newline at end of file
diff --git a/examples/ROOT/img/services-local/klogd-linux/README b/examples/klogd-linux/README
index ec95a00..712cfa3 100644
--- a/examples/ROOT/img/services-local/klogd-linux/README
+++ b/examples/klogd-linux/README
@@ -1,3 +1,5 @@
+This is an example of a service directory for process supervision by s6.
+
 This klogd emulation is only valid under Linux.
 The service only processes logs from /proc/kmsg and
 sends them to stdout, i.e. its own logger.
diff --git a/examples/ROOT/img/services-local/klogd-linux/log/README b/examples/klogd-linux/log/README
index 6b51a4a..6b51a4a 100644
--- a/examples/ROOT/img/services-local/klogd-linux/log/README
+++ b/examples/klogd-linux/log/README
diff --git a/examples/ROOT/img/services-local/klogd-linux/log/run b/examples/klogd-linux/log/run
index d9659e7..d9659e7 100755
--- a/examples/ROOT/img/services-local/klogd-linux/log/run
+++ b/examples/klogd-linux/log/run
diff --git a/examples/ROOT/img/services-local/klogd-linux/run b/examples/klogd-linux/run
index 453b55b..453b55b 100755
--- a/examples/ROOT/img/services-local/klogd-linux/run
+++ b/examples/klogd-linux/run
diff --git a/examples/ROOT/img/services-local/syslogd-linux/README b/examples/syslogd-linux/README
index a3c3ba4..675715b 100644
--- a/examples/ROOT/img/services-local/syslogd-linux/README
+++ b/examples/syslogd-linux/README
@@ -1,3 +1,5 @@
+This is an example of a service directory for process supervision by s6.
+
 This syslogd emulation works on any Unix where syslog() is
 implemented via a connection on the /dev/log Unix-domain socket.
 It needs a Unix superserver (see s6-networking, ucspi-unix or
diff --git a/examples/ROOT/img/services-local/syslogd-linux/log/README b/examples/syslogd-linux/log/README
index 9d4968e..9d4968e 100644
--- a/examples/ROOT/img/services-local/syslogd-linux/log/README
+++ b/examples/syslogd-linux/log/README
diff --git a/examples/ROOT/img/services-local/syslogd-linux/log/env/LOGSCRIPT b/examples/syslogd-linux/log/env/LOGSCRIPT
index e7a1eb7..e7a1eb7 100644
--- a/examples/ROOT/img/services-local/syslogd-linux/log/env/LOGSCRIPT
+++ b/examples/syslogd-linux/log/env/LOGSCRIPT
diff --git a/examples/ROOT/img/services-local/syslogd-linux/log/run b/examples/syslogd-linux/log/run
index 56de271..56de271 100755
--- a/examples/ROOT/img/services-local/syslogd-linux/log/run
+++ b/examples/syslogd-linux/log/run
diff --git a/examples/ROOT/img/services-local/syslogd-linux/notification-fd b/examples/syslogd-linux/notification-fd
index 00750ed..00750ed 100644
--- a/examples/ROOT/img/services-local/syslogd-linux/notification-fd
+++ b/examples/syslogd-linux/notification-fd
diff --git a/examples/ROOT/img/services-local/syslogd-linux/run b/examples/syslogd-linux/run
index de33c2c..de33c2c 100755
--- a/examples/ROOT/img/services-local/syslogd-linux/run
+++ b/examples/syslogd-linux/run
diff --git a/package/info b/package/info
index 3f4a486..457b4bc 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
 package=s6
-version=2.2.1.1
+version=2.2.2.0
 category=admin
 package_macro_name=S6
diff --git a/src/supervision/s6-svscan.c b/src/supervision/s6-svscan.c
index 8153186..29b0429 100644
--- a/src/supervision/s6-svscan.c
+++ b/src/supervision/s6-svscan.c
@@ -21,11 +21,12 @@
 #include <s6/config.h>
 #include <s6/s6-supervise.h>
 
-#define USAGE "s6-svscan [ -c maxservices ] [ -t timeout ] [ dir ]"
+#define USAGE "s6-svscan [ -S | -s ] [ -c maxservices ] [ -t timeout ] [ dir ]"
 
-#define SHUTDOWN_PROG S6_SVSCAN_CTLDIR "/shutdown"
 #define FINISH_PROG S6_SVSCAN_CTLDIR "/finish"
 #define CRASH_PROG S6_SVSCAN_CTLDIR "/crash"
+#define SIGNAL_PROG S6_SVSCAN_CTLDIR "/SIG"
+#define SIGNAL_PROG_LEN (sizeof(SIGNAL_PROG) - 1)
 
 #define DIR_RETRY_TIMEOUT 3
 #define CHECK_RETRY_TIMEOUT 4
@@ -126,12 +127,38 @@ static void handle_signals (void)
       case 0 : return ;
       case SIGCHLD : wantreap = 1 ; break ;
       case SIGALRM : wantscan = 1 ; break ;
+      case SIGABRT : cont = 0 ; break ;
       case SIGTERM : term() ; break ;
       case SIGHUP : hup() ; break ;
       case SIGQUIT : quit() ; break ;
-      case SIGABRT : cont = 0 ; break ;
       case SIGINT : intr() ; break ;
-      case SIGUSR1 : usr1() ; break ;
+    }
+  }
+}
+
+static void handle_diverted_signals (void)
+{
+  for (;;)
+  {
+    register int sig = selfpipe_read() ;
+    switch (sig)
+    {
+      case -1 : panic("selfpipe_read") ;
+      case 0 : return ;
+      case SIGCHLD : wantreap = 1 ; break ;
+      case SIGALRM : wantscan = 1 ; break ;
+      case SIGABRT : cont = 0 ; break ;
+      default :
+      {
+        char const *name = sig_name(sig) ;
+        unsigned int len = str_len(name) ;
+        char fn[SIGNAL_PROG_LEN + len + 1] ;
+        char const *const newargv[2] = { fn, 0 } ;
+        byte_copy(fn, SIGNAL_PROG_LEN, SIGNAL_PROG) ;
+        byte_copy(fn + SIGNAL_PROG_LEN, len + 1, name) ;
+        if (!child_spawn0(newargv[0], newargv, (char const **)environ))
+          strerr_warnwu2sys("spawn ", newargv[0]) ;
+      }
     }
   }
 }
@@ -422,16 +449,19 @@ static void scan (void)
 int main (int argc, char const *const *argv)
 {
   iopause_fd x[2] = { { -1, IOPAUSE_READ, 0 }, { -1, IOPAUSE_READ, 0 } } ;
+  int divertsignals = 0 ;
   PROG = "s6-svscan" ;
   {
     subgetopt_t l = SUBGETOPT_ZERO ;
     unsigned int t = 5000 ;
     for (;;)
     {
-      register int opt = subgetopt_r(argc, argv, "t:c:", &l) ;
+      register int opt = subgetopt_r(argc, argv, "Sst:c:", &l) ;
       if (opt == -1) break ;
       switch (opt)
       {
+        case 'S' : divertsignals = 0 ; break ;
+        case 's' : divertsignals = 1 ; break ;
         case 't' : if (uint0_scan(l.arg, &t)) break ;
         case 'c' : if (uint0_scan(l.arg, &max)) break ;
         default : strerr_dieusage(100, USAGE) ;
@@ -465,7 +495,11 @@ int main (int argc, char const *const *argv)
     sigaddset(&set, SIGQUIT) ;
     sigaddset(&set, SIGABRT) ;
     sigaddset(&set, SIGINT) ;
-    sigaddset(&set, SIGUSR1) ;
+    if (divertsignals)
+    {
+      sigaddset(&set, SIGUSR1) ;
+      sigaddset(&set, SIGUSR2) ;
+    }
     if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ;
   }
 
@@ -497,7 +531,8 @@ int main (int argc, char const *const *argv)
           errno = EIO ;
           panic("check internal pipes") ;
         }
-        if (x[0].revents & IOPAUSE_READ) handle_signals() ;
+        if (x[0].revents & IOPAUSE_READ)
+          divertsignals ? handle_diverted_signals() : handle_signals() ;
         if (x[1].revents & IOPAUSE_READ) handle_control(x[1].fd) ;
       }
     }