summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-12-05 22:26:11 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-12-05 22:26:11 +0000
commit90b12bd71bb9fc79a4640b9112c13ef529d0196a (patch)
tree523b3f4ee2969e7a729bab2ba749c4b924ae62af /doc
downloads6-90b12bd71bb9fc79a4640b9112c13ef529d0196a.tar.xz
Initial commit
Diffstat (limited to 'doc')
-rw-r--r--doc/fifodir.html123
-rw-r--r--doc/index.html291
-rw-r--r--doc/libftrig.html184
-rw-r--r--doc/libftrigr.html283
-rw-r--r--doc/libftrigw.html115
-rw-r--r--doc/libs6lock/index.html256
-rw-r--r--doc/libs6lock/s6lockd-helper.html52
-rw-r--r--doc/libs6lock/s6lockd.html73
-rw-r--r--doc/notifywhenup.html75
-rw-r--r--doc/s6-cleanfifodir.html42
-rw-r--r--doc/s6-envdir.html66
-rw-r--r--doc/s6-envuidgid.html64
-rw-r--r--doc/s6-fghack.html50
-rw-r--r--doc/s6-ftrig-listen.html73
-rw-r--r--doc/s6-ftrig-listen1.html88
-rw-r--r--doc/s6-ftrig-notify.html44
-rw-r--r--doc/s6-ftrig-wait.html51
-rw-r--r--doc/s6-ftrigrd.html73
-rw-r--r--doc/s6-log.html508
-rw-r--r--doc/s6-mkfifodir.html46
-rw-r--r--doc/s6-notifywhenup.html80
-rw-r--r--doc/s6-setlock.html65
-rw-r--r--doc/s6-setsid.html47
-rw-r--r--doc/s6-setuidgid.html49
-rw-r--r--doc/s6-softlimit.html54
-rw-r--r--doc/s6-supervise.html125
-rw-r--r--doc/s6-svc.html104
-rw-r--r--doc/s6-svok.html38
-rw-r--r--doc/s6-svscan-1.html374
-rw-r--r--doc/s6-svscan-not-1.html140
-rw-r--r--doc/s6-svscan.html176
-rw-r--r--doc/s6-svscanctl.html108
-rw-r--r--doc/s6-svstat.html45
-rw-r--r--doc/s6-svwait.html73
-rw-r--r--doc/s6-tai64n.html50
-rw-r--r--doc/s6-tai64nlocal.html73
-rw-r--r--doc/scandir.html145
-rw-r--r--doc/servicedir.html187
-rw-r--r--doc/systemd.html120
-rw-r--r--doc/ucspilogd.html94
-rw-r--r--doc/upgrade.html32
-rw-r--r--doc/why.html203
42 files changed, 4939 insertions, 0 deletions
diff --git a/doc/fifodir.html b/doc/fifodir.html
new file mode 100644
index 0000000..99805ed
--- /dev/null
+++ b/doc/fifodir.html
@@ -0,0 +1,123 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: fifodirs</title>
+ <meta name="Description" content="s6: fifodirs" />
+ <meta name="Keywords" content="s6 instant notification polling fifodir named pipe filesystem" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Fifodirs </h1>
+
+<p>
+ A <em>fifodir</em> is a rendez-vous point between the <em>notifier</em>
+of certain events and its <em>listeners</em>. It is implemented via a
+directory in the filesystem. No data is stored; it is appropriate to
+create fifodirs in a RAM filesystem.
+</p>
+
+<h2> Manipulating fifodirs </h2>
+
+<h3> C API </h3>
+
+<ul>
+ <li> You can create fifodirs via the
+<tt>ftrigw_fifodir_create()</tt> function in
+<a href="libftrigw.html">libftrig</a>. </li>
+ <li> You can send an event to a fifodir via the
+<tt>ftrigw_notify()</tt> function in
+<a href="libftrigw.html">libftrig</a>. </li>
+ <li> You can clean up a fifodir via the
+<tt>ftrigw_clean()</tt> function in
+<a href="libftrigw.html">libftrig</a>. </li>
+ <li> You can destroy fifodirs via the
+<tt>rm_rf()</tt> function in
+<a href="http://skarnet.org/software/skalibs/doc/libstddjb/djbunix.html">libstddjb</a>. </li>
+</ul>
+
+<h3> Unix API </h3>
+
+<ul>
+ <li> You can create fifodirs with the
+<a href="s6-mkfifodir.html">s6-mkfifodir</a> command. </li>
+ <li> You can send an event to a fifodir with the
+<a href="s6-ftrig-notify.html">s6-ftrig-notify</a> command. </li>
+ <li> You can clean up a fifodir with the
+<a href="s6-cleanfifodir.html">s6-cleanfifodir</a> command. </li>
+ <li> You can destroy fifodirs with the <tt>rm -rf</tt> command. </li>
+</ul>
+
+<h2> Internals and Unix permissions </h2>
+
+<ul>
+ <li> Notifiers and listeners agree on a fifodir. </li>
+ <li> The fifodir directory is created by the notifier. It must be writable
+by listeners. </li>
+ <li> To subscribe, a listener atomically creates a named pipe (FIFO) in this
+directory and listens to the reading end. This named pipe must be writable
+by the notifier. </li>
+ <li> To send an event to listeners, the notifier writes the event byte to
+all the named pipes in the directory. Credit for this idea goes to Stefan
+Karrmann. </li>
+ <li> To unsubscribe, a listener unlinks his named pipe from the directory. </li>
+</ul>
+
+<p>
+Fifodirs are created by, so they always originally have the same uid and gid as,
+their notifier. A notifier must be able to make his fifodir either publically
+accessible (anyone can subscribe) or restricted (only a given group can
+subscribe).
+</p>
+
+<p>
+ A publically accessible fifodir must have rights 1733:
+</p>
+
+<ul>
+ <li> Anyone can create a fifo in that fifodir </li>
+ <li> Only the notifier can see all the subscribers' fifos </li>
+ <li> A listener can only delete its own fifo </li>
+ <li> A notifier can delete any fifo for cleaning purposes </li>
+</ul>
+
+<p>
+ A restricted fifodir must have the gid <em>g</em> of the group of allowed
+listeners and have rights 3730. Unless the notifier is root, it
+must be in the group of allowed listeners to be able to create
+such a fifodir.
+</p>
+
+<ul>
+ <li> Only members of <em>g</em> can create a fifo in that fifodir </li>
+ <li> Only the notifier can see all the subscribers' fifos </li>
+ <li> Fifos are always created with gid <em>g</em> </li>
+ <li> A listener can only delete its own fifo </li>
+ <li> A notifier can delete any fifo for cleaning purposes </li>
+</ul>
+
+<p>
+ A named pipe in a fifodir must always belong to its listener and have
+rights 0622:
+</p>
+
+<ul>
+ <li> Only this listener can read on the fifo </li>
+ <li> Anyone who has reading rights on the fifodir (i.e. only the notifier)
+can write to the fifo </li>
+</ul>
+
+<p>
+ The <a href="libftrig.html">libftrig<a/> interface takes care of all
+the subtleties.
+</p>
+
+</body>
+</html>
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..048af4f
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,291 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6 - skarnet's small supervision suite</title>
+ <meta name="Description" content="s6 - skarnet's small supervision suite" />
+ <meta name="Keywords" content="s6 unix administration root pipe laurent bercot ska skarnet supervision djb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> s6 </h1>
+
+<h2> What is it&nbsp;? </h2>
+
+<p>
+ s6 is a small suite of programs for UNIX, designed to allow process supervision
+(a.k.a service supervision),
+in the line of <a href="http://cr.yp.to/daemontools.html">daemontools</a>
+and <a href="http://smarden.org/runit/">runit</a>.
+</p>
+
+<p>
+ The s6 documentation tries to be complete and self-contained; however,
+if you have never heard of process supervision before, you might be
+confused at first. See the <a href="#related">related resources</a> section
+below for pointers to more resources, and earlier approaches to process
+supervision that might help you understand the basics.
+</p>
+
+<hr />
+
+<ul>
+<li> <a href="why.html">Why another supervision suite?</a> Isn't <a href="http://smarden.org/runit/">runit</a> good enough?</li>
+<li> What is instant notification? What does the <a href="libftrig.html">libftrig</a> do exactly?</li>
+<li> How to run a s6-svscan-based supervision tree <a href="s6-svscan-not-1.html">without replacing init</a> </li>
+<li> How to <a href="s6-svscan-1.html">replace init</a> </li>
+</ul>
+
+<hr />
+
+<h2> Installation </h2>
+
+<h3> Requirements </h3>
+
+<ul>
+ <li> A POSIX-compliant system with a standard C development environment </li>
+ <li> GNU make, version 3.81 or later </li>
+ <li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version
+2.0.0.0 or later </li>
+ <li> <a href="http://skarnet.org/software/execline/">execline</a> version
+2.0.0.0 or later </li>
+</ul>
+
+<h3> Licensing </h3>
+
+<p>
+ s6 is free software. It is available under the
+<a href="http://opensource.org/licenses/ISC">ISC license</a>.
+</p>
+
+<h3> Download </h3>
+
+<ul>
+ <li> The current released version of s6 is <a href="s6-2.0.0.0.tar.gz">2.0.0.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>
+</ul>
+
+<h3> Compilation </h3>
+
+<ul>
+ <li> See the enclosed INSTALL file for installation details. </li>
+</ul>
+
+<h3> Upgrade notes </h3>
+
+<ul>
+ <li> <a href="upgrade.html">This page</a> lists the differences to be aware of between
+the previous versions of execline and the current one. </li>
+</ul>
+
+<hr />
+
+<h2> Reference </h2>
+
+<h3> Commands </h3>
+
+<p>
+ All these commands exit 111 if they encounter a temporary error or
+hardware error, and
+100 if they encounter a permanent error - such as a misuse. Short-lived
+commands exit 0 on success.
+</p>
+
+<h4> Supervision system </h4>
+
+<p>
+ <a href="s6-svscan.html">s6-svscan</a> and <a href="s6-supervise.html">s6-supervise</a>
+are the long-lived processes maintaining the supervision tree. Other programs are
+a user interface to control those processes and monitor service states.
+</p>
+
+<ul>
+<li><a href="s6-svscan.html">The <tt>s6-svscan</tt> program</a></li>
+<li><a href="s6-svscanctl.html">The <tt>s6-svscanctl</tt> program</a></li>
+<li><a href="s6-supervise.html">The <tt>s6-supervise</tt> program</a></li>
+<li><a href="s6-svc.html">The <tt>s6-svc</tt> program</a></li>
+<li><a href="s6-svok.html">The <tt>s6-svok</tt> program</a></li>
+<li><a href="s6-svstat.html">The <tt>s6-svstat</tt> program</a></li>
+<li><a href="s6-svwait.html">The <tt>s6-svwait</tt> program</a></li>
+</ul>
+
+<h4> Other daemontools-like utilities </h4>
+
+<p>
+ These programs are a rewrite of the corresponding utilities from
+<a href="http://cr.yp.to/daemontools.html">daemontools</a>, with
+a few extras. The
+<a href="s6-log.html">s6-log</a> program is important in itself: it's
+a powerful, scriptable, general-purpose filtering and logging tool
+that can be used to entirely replace syslogd. It has many more
+features than its <a href="http://cr.yp.to/daemontools/multilog.html">multilog</a>
+counterpart.
+</p>
+
+<ul>
+<li><a href="s6-envdir.html">The <tt>s6-envdir</tt> program</a></li>
+<li><a href="s6-envuidgid.html">The <tt>s6-envuidgid</tt> program</a></li>
+<li><a href="s6-fghack.html">The <tt>s6-fghack</tt> program</a></li>
+<li><a href="s6-log.html">The <tt>s6-log</tt> program</a></li>
+<li><a href="s6-setlock.html">The <tt>s6-setlock</tt> program</a></li>
+<li><a href="s6-setsid.html">The <tt>s6-setsid</tt> program</a></li>
+<li><a href="s6-setuidgid.html">The <tt>s6-setuidgid</tt> program</a></li>
+<li><a href="s6-softlimit.html">The <tt>s6-softlimit</tt> program</a></li>
+<li><a href="s6-tai64n.html">The <tt>s6-tai64n</tt> program</a></li>
+<li><a href="s6-tai64nlocal.html">The <tt>s6-tai64nlocal</tt> program</a></li>
+<li><a href="ucspilogd.html">The <tt>ucspilogd</tt> program</a></li>
+<li><a href="s6-notifywhenup.html">The <tt>s6-notifywhenup</tt> program</a> (NEW in 2.0.0.0)</li>
+</ul>
+
+<h4> Fifodir management, notification and subscription </h4>
+
+<p>
+These programs are a clean rewrite of the obsolete "pipe-tools" package; they
+are now based on a properly designed notification library.
+They provide a command-line interface to
+<a href="libftrig.html#notification">inter-process notification and
+synchronization</a>.
+</p>
+
+<ul>
+<li><a href="s6-mkfifodir.html">The <tt>s6-mkfifodir</tt> program</a></li>
+<li><a href="s6-cleanfifodir.html">The <tt>s6-cleanfifodir</tt> program</a></li>
+</ul>
+<p>
+</p>
+<ul>
+<li><a href="s6-ftrig-notify.html">The <tt>s6-ftrig-notify</tt> program</a></li>
+</ul>
+<p>
+</p>
+<ul>
+<li><a href="s6-ftrig-wait.html">The <tt>s6-ftrig-wait</tt> program</a></li>
+<li><a href="s6-ftrig-listen1.html">The <tt>s6-ftrig-listen1</tt> program</a></li>
+<li><a href="s6-ftrig-listen.html">The <tt>s6-ftrig-listen</tt> program</a></li>
+</ul>
+
+<h4> Internal commands </h4>
+
+<ul>
+<li><a href="s6-ftrigrd.html">The <tt>s6-ftrigrd</tt> internal program</a></li>
+<li><a href="libs6lock/s6-lockd.html">The <tt>s6lockd</tt> internal program</a></li>
+<li><a href="libs6lock/s6lockd-helper.html">The <tt>s6lockd-helper</tt> internal program</a></li>
+</ul>
+
+
+<h3> Libraries </h3>
+
+<ul>
+<li><a href="libftrigw.html">The <tt>ftrigw</tt> library interface</a></li>
+<li><a href="libftrigr.html">The <tt>ftrigr</tt> library interface</a></li>
+<li><a href="libs6lock/">The <tt>s6lock</tt> library interface</a></li>
+</ul>
+
+<h3> Definitions </h3>
+
+<ul>
+<li> What is a <a href="fifodir.html">fifodir</a></li>
+<li> What is a <a href="servicedir.html">service directory</a></li>
+<li> What is a <a href="scandir.html">scan directory</a></li>
+<li> Why are the <a href="libftrig.html">libftrigw and libftrigr</a> needed </li>
+</ul>
+
+<hr />
+
+<a name="related">
+<h2> Related resources </h2>
+</a>
+
+<h3> s6 discussion </h3>
+
+<ul>
+ <li> <tt>s6</tt> is discussed on the
+<a href="http://www.skarnet.org/lists.html#supervision">supervision</a> mailing-list. </li>
+ <li> <tt>s6</tt> has a
+<a href="http://freecode.com/projects/s6">freecode page</a>.
+ </li>
+</ul>
+
+<h3> Similar work </h3>
+
+<ul>
+ <li> <a href="http://cr.yp.to/daemontools.html">daemontools</a>, the pioneering
+process supervision software suite. </li>
+ <li> <a href="http://untroubled.org/daemontools-encore/">daemontools-encore</a>,
+a derived work from daemontools with enhancements. (Note that although s6 follows
+the same naming scheme, the same general design, and many of the same architecture
+choices as daemontools, it is still original work, sharing no code at all with
+daemontools.) </li>
+ <li> <a href="http://smarden.org/runit/">runit</a>, a slightly different
+approach to process supervision, with the same goals. </li>
+ <li> <a href="http://b0llix.net/perp/">perp</a>, yet another slightly different
+approach to process supervision, also with the same goals. </li>
+</ul>
+
+<h3> Other init systems </h3>
+
+<ul>
+ <li> Felix von Leitner's <a href="http://www.fefe.de/minit/">minit</a> is an
+init system for Linux, with process supervision capabilities. </li>
+ <li> <a href="http://freshmeat.net/projects/sysvinit/">sysvinit</a> is the
+traditional init system for Linux. </li>
+ <li> <a href="http://upstart.ubuntu.com/">Upstart</a> is a well-known init system
+for Linux, with complete service management, that comes with the Ubuntu
+distribution. It includes a coffee machine and the kitchen sink.</li>
+ <li> Because Upstart wasn't bloated or unreliable enough, someone came up with
+<a href="http://freedesktop.org/wiki/Software/systemd/">systemd</a>, yet
+another Linux init system, so contrary to all principles of good engineering
+it's just scary. </li>
+ <li> The various BSD flavors have their own style of
+<a href="http://www.freebsd.org/doc/handbook/boot-init.html">init</a>. </li>
+ <li> MacOS X has its own init spaghetti monster called
+<a href="http://en.wikipedia.org/wiki/Launchd">launchd</a>. </li>
+</ul>
+
+<p>
+All-in-one init systems generally feel complex and convoluted, and when most
+people find out about the process supervision approach to init systems, they
+usually find it much simpler.
+<a href="s6-svscan-1.html#stages">There is a good reason for this.</a>
+</p>
+
+
+<h2> Credits </h2>
+
+ s6 is one of the (late...) results of a long design discussion that
+happened in 2002-2003 on the
+<a href="http://www.skarnet.org/lists.html#supervision">supervision list</a>
+and the <a href="http://cr.yp.to/lists.html#log">log list</a>.
+The main contributors to the thread were
+<ul>
+ <li> <a href="http://dogmap.org/">Paul Jarc</a> </li>
+ <li> <a href="http://smarden.org/pape/">Gerrit Pape</a> </li>
+ <li> <a href="http://ino-waiting.gmxhome.de/">Clemens Fischer</a> </li>
+ <li> <a href="http://www.mathematik.uni-ulm.de/m5/sk/">Stefan Karrman</a> </li>
+ <li> and me. </li>
+</ul>
+
+<h2> Miscellaneous </h2>
+
+<h3> Why "s6"&nbsp;? </h3>
+
+<p>
+<strong>s</strong>karnet.org's <strong>s</strong>mall and <strong>s</strong>ecure
+<strong>s</strong>upervision <strong>s</strong>oftware <strong>s</strong>uite.
+</p>
+
+<p>
+ Also, s6 is a nice command name prefix to have: it identifies the origin of the
+software, and it's short. Expect more use of s6- in future skarnet.org software
+releases. And please avoid using that prefix for your own projects.
+</p>
+
+</body>
+</html>
diff --git a/doc/libftrig.html b/doc/libftrig.html
new file mode 100644
index 0000000..da4c25b
--- /dev/null
+++ b/doc/libftrig.html
@@ -0,0 +1,184 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: libftrig</title>
+ <meta name="Description" content="s6 libftrig" />
+ <meta name="Keywords" content="s6 libftrig" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> libftrig </h1>
+
+<p>
+<t>libftrig</t> is a portable Unix C programming interface allowing a
+process (the <em>subscriber</em> or <em>listener</em>) to be instantly
+notified when another process (the <em>notifier</em> or <em>writer</em>)
+signals an event.
+</p>
+
+<a name="notification">
+<h2> What is notification&nbsp;? </h2>
+</a>
+
+<h3> Notification vs. polling </h3>
+
+<p>
+ Process A is <em>notified</em> of an event E when it gets a instant
+notice that event E has happened; the notice may disrupt A's execution
+flow. Notification is the opposite of <em>polling</em>, where A has to
+periodically (every T milliseconds) check whether E happened and has no
+other way to be informed of it.
+</p>
+
+<p>
+ Polling is generally considered bad practice - and is inferior to
+notification in practically every case - for three reasons:
+</p>
+
+<ul>
+ <li> Reaction time. When event E happens, process A does not know it
+instantly. It will only learn of E, and be able to react to it, when
+it explicitly checks for E; and if E happened right after A performed
+the check, this can take as long as T milliseconds (the <em>polling
+period</em>). Polling processes have reaction delays due to the polling
+periods. </li>
+ <li> Resource consumption. Even if <em>no</em> event ever happens, process A
+will still wake up needlessly every T milliseconds. This might not seem like
+a problem, but it is a serious one in energy-critical environments. Polling
+processes use more CPU time than is necessary and are not energy-friendly. </li>
+ <li> Conflict between the two above reasons. The longer the polling period,
+the more energy-friendly the process, but the longer the reaction time. The
+shorter the polling period, the shorter the reaction time, but the more
+resource-consuming the process. A delicate balance has to be found, and
+acceptable behaviour is different in every case, so there's no general rule
+of optimization. </li>
+</ul>
+
+<p>
+ Notification, on the other hand, is generally optimal: reaction time is
+zero, and resource consumption is minimal - a process can sleep as soon as
+it's not handling an event, and only wake up when needed.
+</p>
+
+<p>
+ Of course, the problem of notification is that it's often more difficult
+to implement. Notification frameworks are generally more complex, involving
+lots of asynchronism; polling is widely used
+<a href="http://lib.store.yahoo.net/lib/demotivators/mediocritydemotivationalposter.jpg">because
+it's easy.</a>
+</p>
+
+<h3> Notifications and Unix </h3>
+
+<p>
+ Unix provides several frameworks so that a process B (or the kernel) can
+notify process A.
+</p>
+
+<ul>
+ <li> Signals. The simplest Unix notification mechanism. Sending events amounts
+to a <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html">kill()</a>
+call, and receiving events amounts to installing a signal handler (preferrably
+using a <a href="http://skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a>
+if mixing signals with an event loop). Unfortunately, Unix signals, even the more
+recent and powerful real-time Posix signals, have important limitations when it's
+about generic notification:
+ <ul>
+ <li> non-root processes can only send signals to a very restricted and
+implementation-dependent set of processes (roughly, processes with the same UID). This is a problem when
+designing secure programs that make use of the Unix privilege separation. </li>
+ <li> you need to know the PID of a process to send it signals. This is generally
+impractical; process management systems that do not use supervisor processes have
+to do exactly that, and they resort to unreliable, ugly hacks (.pid files) to track
+down process PIDs. </li>
+ </ul> </li>
+ <li> BSD-style IPCs, i.e. file descriptors to perform select()/poll() system
+calls on, in an <em>asynchronous event loop</em>. This mechanism is very widely used,
+and rightly so, because it's extremely generic and works in every ordinary situation;
+you have to be doing <a href="http://www.kegel.com/c10k.html">very specific stuff</a>
+to reach its limits. If process A is reading on
+fd <em>f</em>, it is notified everytime another process makes <em>f</em> readable -
+for instance by writing a byte to the other end if <em>f</em> is the reading end
+of a pipe. And indeed, this is how libftrig works internally; but libftrig is needed
+because direct use of BSD-style IPCs also has limitations.
+ <ul>
+ <li> Anonymous pipes are the simplest and most common BSD-style IPC. If there is a
+pipe from process B to process A, then B can notify A by writing to the pipe. The
+limitation is that A and B must have a common ancestor that created the pipe; two
+unrelated processes cannot communicate this way. </li>
+ <li> Sockets are a good many-to-one notification system: once a server is up, it
+can be notified by any client, and notify all its clients. The limitation of sockets
+is that the server must be up before the client, which prevents us from using them
+in a general notification scheme. </li>
+ </ul> </li>
+ <li> System V IPCs, i.e. message queues and semaphores. The interfaces to those IPCs
+are quite specific and can't mix with select/poll loops, that's why nobody in their
+right mind uses them. </li>
+</ul>
+
+<h3> What we want </h3>
+
+<p>
+ We need a general framework to:
+</p>
+
+<ul>
+ <li> Allow an event-generating process to broadcast notifications to every process
+that asked for one, without having to know their PIDs </li>
+ <li> Allow a process to subscribe to a "notification channel" and be instantly,
+asynchronously notified when an event occurs on this channel. </li>
+</ul>
+
+<p>
+ This requires a many-to-many approach that Unix does not provide natively, and
+that is what libftrig does.
+</p>
+
+<a name="bus">
+<h2> That's what a bus is for. D-Bus already does all this. </h2>
+</a>
+
+<p>
+ Yes, a bus is a good many-to-many notification mechanism indeed. However,
+a Unix bus can only be implemented via a daemon - you need a long-running
+process, i.e. a <em>service</em>, to implement a bus. And s6 is a
+<em>supervision suite</em>, i.e. a set of programs designed to manage
+services; we would like to be able to use notifications in the supervision
+suite, to be able to wait for a service to be up or down... <em>without</em>
+relying on a particular service to be up. libftrig provides a notification
+mechanism that <em>does not need</em> a bus service to be up, that's its
+main advantage over a bus.
+</p>
+
+<p>
+ If you are not concerned with supervision and can depend on a bus service,
+though, then yes, by all means, use a bus for your notification needs.
+There is a <a href="http://skarnet.org/software/skabus/">skabus</a>
+project in the making, which aims to be simpler, smaller and more
+maintainable than D-Bus.
+</p>
+
+<h2> How to use libftrig </h2>
+
+<p>
+ <tt>libftrig</tt> is really a part of <tt>libs6</tt>: all the functions
+are implemented in the <tt>libs6.a</tt> archive, or the <tt>libs6.so</tt>
+dynamic shared object. However, the interfaces are different for notifiers
+and listeners:
+</p>
+
+<ul>
+<li> Notifiers use the <a href="libftrigw.html">libftrigw</a> interface. </li>
+<li> Listeners use the <a href="libftrigr.html">libftrigr</a> interface. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libftrigr.html b/doc/libftrigr.html
new file mode 100644
index 0000000..27ffd61
--- /dev/null
+++ b/doc/libftrigr.html
@@ -0,0 +1,283 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the ftrigr library interface</title>
+ <meta name="Description" content="s6: the ftrigr library interface" />
+ <meta name="Keywords" content="s6 ftrig notification subscriber listener libftrigr ftrigr library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>ftrigr</tt> library interface </h1>
+
+<p>
+ The <tt>ftrigr</tt> library provides an API for listeners, i.e.
+programs that want to subscribe to fifodirs and be instantly
+notified when the proper sequence of events happens.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the s6 headers, as well as the skalibs headers,
+are visible in your header search path. </li>
+ <li> Use <tt>#include &lt;s6/ftrigr.h&gt;</tt> </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> Make sure the s6 libraries, as well as the skalibs libraries,
+are visible in your library search path. </li>
+ <li> Link against <tt>-ls6</tt> and <tt>-lskarnet</tt>. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ Check the <tt>s6/ftrigr.h</tt> header for the
+exact function prototypes.
+</p>
+
+<p>
+ Make sure your application is not disturbed by children it doesn't
+know it has. This means paying some attention to the SIGCHLD handler,
+if any, and to the way you perform <tt>waitpid()</tt>s. The best
+practice is to use a
+<a href="http://www.skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a>
+to handle SIGCHLD (as well as other signals the application needs to trap),
+and to <em>always</em> use <tt>wait_nohang()</tt> to reap children,
+simply ignoring pids you don't know.
+</p>
+
+<p>
+ If your (badly programmed) application has trouble handling unknown
+children, consider using a ftrigrd service.
+</p>
+
+<h3> A programming example </h3>
+
+<p>
+ The <tt>src/pipe-tools/s6-ftrig-listen1.c</tt> and
+<tt>src/supervision/s6-svwait.c</tt> files in the s6 package,
+for instance, illustrate how to use the ftrigr library.
+</p>
+
+
+<h3> Synchronous functions with a specified maximum execution time </h3>
+
+<ul>
+ <li> Synchronous functions take a <tt>tain_t const *</tt>
+(<em>deadline</em>) parameter and a <tt>tain_t *</tt> (<em>stamp</em>)
+parameter. Those are pointers to taia structures containing absolute times;
+the former represents a deadline (in most cases, this time will be in the
+future) and the latter must be an accurate enough timestamp. These
+structures can be filled using the <tt>tain_</tt> primitives declared in
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">skalibs/tai.h</a>. </li>
+ <li> ("Accurate enough" means that <strong>no blocking system call must have
+been made</strong> since the last time <em>stamp</em> was updated (by
+<tt>tain_now(&amp;stamp)</tt>). It's a good policy to always update
+<em>stamp</em> right after a (potentially) blocking system call like
+<tt>select()</tt>returns. And unless the application is extremely CPU-intensive
+(think calculus for physicists or astronomers) updating <em>stamp</em> more
+frequently is unnecessary.) </li>
+ <li> If such a synchronous function still hasn't returned when the deadline
+occurs, then it will immediately return a failure code and set errno to ETIMEDOUT.
+It is possible to pass null pointers to the function instead of pointers to
+taia structures, in which case the function will never timeout. </li>
+ <li> If a timeout occurs, the library does not guarantee proper interprocess
+communication later on; the application should either die, or at least close
+the communication channel and open a new one. </li>
+ <li> If any waiting occurred, the <em>stamp</em> structure is automatically
+updated by the called function, so it always represents an accurate enough estimation
+of the current time. This allows the programmer to call several such functions
+in a sequence without modifying the <em>deadline</em> and <em>stamp</em>
+parameters: then the whole sequence is bound in execution time. </li>
+ <li> This is a general safety mechanism implemented in
+<a href="http://skarnet.org/software/skalibs/libunixonacid/">libunixonacid</a>:
+in interprocess communication, purely synchronous primitives are dangerous
+because they make the calling process rely on proper behaviour of the called
+process. Giving synchronous primitives the ability to timeout allows developers
+to write reliable programs even when interacting with software they have no
+control on. </li>
+</ul>
+
+
+<h3> Starting and ending a session </h3>
+
+<pre>
+ftrigr_t a = FTRIGR_ZERO ;
+struct taia deadline, stamp ;
+
+taia_now(&amp;stamp) ;
+taia_addsec(&amp;deadline, &amp;stamp, 2)
+
+// char const *path = FTRIGR_IPCPATH ;
+// ftrigr_start(&amp;a, path, &amp;deadline, &amp;stamp) ;
+ftrigr_startf(&amp;a, &amp;deadline, &amp;stamp) ;
+</pre>
+
+<p>
+<tt>ftrigr_start</tt> starts a session with a ftrigrd service listening on
+<em>path</em>. <br />
+<tt>ftrigr_startf</tt> starts a session with a ftrigrd process as a child
+(which is the simplest usage). <br />
+<tt>a</tt> is a ftrigr_t structure that must be declared in the stack and
+initialized to FTRIGR_ZERO.
+<tt>stamp</tt> must be an accurate enough timestamp. <br />
+If the session initialization fails, the function returns 0 and errno is set;
+else the function returns 1.
+</p>
+<p>
+If the absolute time <tt>deadline</tt> is reached and the function
+has not returned yet, it immediately returns 0 with errno set to ETIMEDOUT.
+
+Only local interprocess communications are involved; unless your system is
+heavily overloaded, the function should return near-instantly. One or two
+seconds of delay between <tt>stamp</tt> and <tt>deadline</tt> should be
+enough: if the function takes more than that to return, then there is a
+problem with the underlying processes.
+</p>
+
+<p>
+ You can have more than one session open in parallel, by declaring
+several distinct <tt>ftrigr_t</tt> structures and calling
+<tt>ftrigr_startf</tt> (or <tt>ftrigr_start</tt>) more than once.
+However, this is useless, since one single session can handle
+virtually as many concurrent fifodirs as your application needs.
+</p>
+
+<pre>
+ftrigr_end(&amp;a) ;
+</pre>
+
+<p>
+<tt>ftrigr_end</tt> frees all the resources used by the session. The
+<tt>a</tt> structure is then reusable for another session.
+</p>
+
+<h3> Subscribing to a fifodir </h3>
+
+<pre>
+char const *path = "/var/lib/myservice/fifodir" ;
+char const *re = "a.*b|c*d" ;
+uint32 options = 0 ;
+
+uint16 id = ftrigr_subscribe (&amp;a, path, re, options, &amp;deadline, &amp;stamp) ;
+</pre>
+
+<p>
+<tt>ftrigr_subscribe</tt> instructs the
+<a href="s6-ftrigrd.html">s6-ftrigrd daemon</a>, related to the open
+session represented by the <tt>a</tt> structure, to subscribe to the
+<tt>path</tt> fifodir, and to notify the application when it receives
+a series of events that matches the <tt>re</tt> regexp.
+<tt>options</tt> can be 0 or FTRIGR_REPEAT. If it is 0, the daemon will
+automatically unsubscribe from <tt>path</tt> once <tt>re</tt> has been
+matched by a series of events. If it is FTRIGR_REPEAT, it will remain
+subscribed until told otherwise.
+</p>
+
+<p>
+ <tt>ftrigr_subscribe()</tt> returns 0 and sets errno in case of failure, or
+a nonzero 16-bit number identifying the subscription in case of success.
+</p>
+
+<p>
+<tt>ftrigr_subscribe</tt> should return near-instantly, but if
+<em>deadline</em> is reached, it will return 0 ETIMEDOUT. If
+<tt>ftrigr_subscribe</tt> returns successfully, then the
+s6-ftrigrd daemon is guaranteed to be listening on <tt>path</tt>,
+and events can be sent without the risk of a race condition.
+</p>
+
+<h3> Synchronously waiting for events </h3>
+
+<pre>
+uint16 list[1] ;
+unsigned int n = 1 ;
+char trigger ;
+list[0] = id ;
+
+// r = ftrigr_wait_and(&amp;a, list, n, &amp;deadline) ;
+r = ftrigr_wait_or(&amp;a, list, n, &amp;deadline, &amp;trigger) ;
+</pre>
+
+<p>
+ <tt>ftrigr_wait_and()</tt> waits for <em>all</em> the <tt>n</tt> fifodirs
+whose ids are listed in <tt>list</tt> to receive an event. It returns -1
+in case of error or timeout, or a non-negative integer in case of success. <br />
+ <tt>ftrigr_wait_or()</tt> waits for <em>one</em> of the <tt>n</tt> fifodirs
+whose ids are listed in <tt>list</tt> to receive an event. It returns -1
+in case of error or timeout; if it succeeds, the return value is the
+position in <tt>list</tt>, starting at 0, of the identifier that received
+an event; and <tt>trigger</tt> is set to the character that triggered that
+event, i.e. the last character of a sequence that matched the regular
+expression <tt>re</tt> used in the subscription.
+</p>
+
+<h3> Asynchronously waiting for events </h3>
+
+<p>
+<em> (from now on, the functions are listed with their prototypes instead
+of usage examples.) </em>
+</p>
+
+<pre>
+int ftrigr_fd (struct ftrigr const *a)
+</pre>
+
+<p>
+ Returns a file descriptor to select on for reading. Do not
+<tt>read()</tt> it though.
+</p>
+
+<pre>
+int ftrigr_update (ftrigr_ref a)
+</pre>
+
+<p>
+ Call this function whenever the fd checks readability: it will
+update <em>a</em>'s internal structures with information from the
+<a href="s6-ftrigrd.html">s6-ftrigrd</a> daemon. It returns -1 if an error
+occurs; in case of success, it returns the number of identifiers for
+which something happened.
+</p>
+
+<p>
+ When <tt>ftrigr_update</tt> returns,
+<tt>genalloc_s(uint16, &amp;a-&gt;list)</tt> points to an array of
+<tt>genalloc_len(uint16, &amp;a-&gt;list)</tt> 16-bit unsigned
+integers. Those integers are ids waiting to be passed to
+<tt>ftrigr_check</tt>.
+</p>
+
+<pre>
+int ftrigr_check (ftrigr_ref a, uint16 id, char *what)
+</pre>
+
+<p>
+ Checks whether an event happened to <em>id</em>. Use after a
+call to <tt>ftrigr_update()</tt>.
+</p>
+
+<ul>
+ <li> If an error occurred, returns -1 and sets errno. The error
+number may have been transmitted from
+<a href="s6-ftrigrd.html">s6-ftrigrd</a>. </li>
+ <li> If no notification happened yet, returns 0. </li>
+ <li> If something happened, writes the character that triggered the
+latest notification into <em>what</em> and returns the number of
+times that an event happened to this identifier since the last
+call to <tt>ftrigr_check()</tt>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libftrigw.html b/doc/libftrigw.html
new file mode 100644
index 0000000..d804976
--- /dev/null
+++ b/doc/libftrigw.html
@@ -0,0 +1,115 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the ftrigw library interface</title>
+ <meta name="Description" content="s6: the ftrigw library interface" />
+ <meta name="Keywords" content="s6 ftrig notification notifier writer libftrigw ftrigw library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>ftrigw</tt> library interface </h1>
+
+<p>
+ The <tt>ftrigw</tt> library provides an API for notifiers, i.e.
+programs that want to regularly announce what they're doing.
+</p>
+
+<p>
+ Notifiers should create a fifodir in a hardcoded place in the
+filesystem, and document its location. Listeners will then be
+able to subscribe to that fifodir, and receive the events.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the s6 headers, as well as the skalibs headers,
+are visible in your header search path. </li>
+ <li> Use <tt>#include &lt;s6/ftrigw.h&gt;</tt> </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> Make sure the s6 libraries, as well as the skalibs libraries,
+are visible in your library search path. </li>
+ <li> Link against <tt>-ls6</tt> and <tt>-lskarnet</tt>. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ Check the <tt>s6/ftrigw.h</tt> header for the
+exact function prototypes.
+</p>
+
+<h3> Creating a fifodir </h3>
+
+<pre>
+char const *path = "/var/lib/myservice/fifodir" ;
+int gid = -1 ;
+int forceperms = 0 ;
+int r = ftrigw_fifodir_make(path, gid, forceperms) ;
+</pre>
+
+<p>
+<tt>ftrigw_fifodir_make</tt> creates a fifodir at the <tt>path</tt> location.
+It returns 0, and sets errno, if an error occurs.
+It returns 1 if it succeeds. <br />
+If a fifodir, owned by the user, already exists at <tt>path</tt>, and
+<tt>forceperms</tt> is zero, then <tt>ftrigw_fifodir_make</tt> immediately
+returns a success. If <tt>forceperms</tt> is nonzero, then
+it tries to adjust <tt>path</tt>'s permissions before returning.
+</p>
+
+<p>
+If <tt>gid</tt> is negative, then <tt>path</tt> is created "public".
+Any listener will be able to subscribe to <tt>path</tt>.
+If <tt>gid</tt> is nonnegative, then <tt>path</tt> is created "private".
+Only processes belonging to group <tt>gid</tt> will be able to
+subscribe to <tt>path</tt>.
+</p>
+
+<h3> Sending an event </h3>
+
+<pre>
+char event = 'a' ;
+r = ftrigw_notify(path, event) ;
+</pre>
+
+<p>
+<tt>ftrigw_notify</tt> sends <tt>event</tt> to all the processes that are
+currently subscribed to <tt>path</tt>.
+It returns -1 if an error occurs, or the number of successfully notified
+processes.
+</p>
+
+<h3> Cleaning up </h3>
+
+<p>
+When stray KILL signals hit <a href="s6-ftrigrd.html">s6-ftrigrd</a> processes,
+1. it's a sign of incorrect system administration, 2. they can leave
+unused named pipes in the fifodir. It's the fifodir's owner's job, i.e.
+the notifier's job, to periodically do some housecleaning and take out
+the trash.
+</p>
+
+<pre>
+r = ftrigw_clean(path) ;
+</pre>
+
+<p>
+<tt>ftrigw_clean</tt> cleans <tt>path</tt>. It returns 0, and sets errno,
+if it encounters an error. It returns 1 if it succeeds.
+</p>
+
+</body>
+</html>
diff --git a/doc/libs6lock/index.html b/doc/libs6lock/index.html
new file mode 100644
index 0000000..3696b41
--- /dev/null
+++ b/doc/libs6lock/index.html
@@ -0,0 +1,256 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6lock library interface</title>
+ <meta name="Description" content="s6: the s6lock library interface" />
+ <meta name="Keywords" content="s6 timed lock s6lock libs6lock library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6lock</tt> library interface </h1>
+
+<h2> General information </h2>
+
+<p>
+ <tt>libs6lock</tt> is a C interface to timed locks. Unix natively provides
+locks, but the locking primitives are synchronous, so either they are
+unbounded in execution time or they require polling. libs6lock provides
+poll-free locks that can timeout during attempted acquisition.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the s6 headers, as well as the skalibs headers,
+are visible in your header search path. </li>
+ <li> Use <tt>#include &lt;s6/s6lock.h&gt;</tt> </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> Make sure the s6 libraries, as well as the skalibs libraries,
+are visible in your library search path. </li>
+ <li> Link against <tt>-ls6</tt>, <tt>-lskarnet</tt>,
+<tt>`cat $sysdeps/socket.lib`</tt>, and
+<tt>`cat $sysdeps/tainnow.lib`</tt>,
+if <tt>$sysdeps</tt> is your skalibs installation's sysdeps directory. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<ul>
+ <li> Check the <tt>s6/s6lock.h</tt> header
+for the prototypes. The functions documented here are
+often simplified macros, for instance relying on the STAMP global variable
+to hold the current time. Fully reentrant functions with more control
+options are usually available. </li>
+ <li> Given the nature of the s6lock library, it makes sense to use a
+<a href="http://skarnet.org/software/s6-networking/localservice.html">s6lockd service</a> concurrently
+accessed by several applications using such locks to gate shared
+resources. </li>
+ <li> If you're not using a s6lockd service,
+make sure your application is not disturbed by children it doesn't
+know it has. Using nonblocking waits, ignoring pids you don't know, and
+using a
+<a href="http://skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a>
+if your application is built around an event loop, are good programming
+practices. </li>
+</ul>
+
+<h3> Starting and ending a session </h3>
+
+<pre>
+s6lock_t a = S6LOCK_ZERO ;
+struct taia deadline ;
+
+taia_now_g() ;
+taia_addsec_g(&amp;deadline, 2)
+
+char const *path = S6LOCK_IPCPATH ;
+s6lock_start_g(&amp;a, path, &amp;deadline) ;
+// char const *lockdir = "/tmp/lock" ;
+// s6lock_startf_g(&amp;a, lockdir, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6lock_start_g</tt> starts a session by connecting to a s6lockd service
+listening on <em>path</em>. The working directory is set by the administrator
+of the service. <br />
+<tt>s6lock_startf_g</tt> starts a session with a s6lockd process as a child,
+using <em>lockdir</em> as its working directory.
+<br />
+<tt>a</tt> is a s6lock_t structure that must be declared in the stack and
+initialized to S6LOCK_ZERO.
+If the session initialization fails, the function returns 0 and errno is set;
+else the function returns 1.
+</p>
+<p>
+If the absolute time <tt>deadline</tt> is reached and the function
+has not returned yet, it immediately returns 0 with errno set to ETIMEDOUT.
+
+Only local interprocess communications are involved; unless your system is
+heavily overloaded, the function should return near-instantly. One or two
+seconds of delay between the current time and <tt>deadline</tt> should be
+enough: if the function takes more than that to return, then there is a
+problem with the underlying processes.
+</p>
+
+<p>
+ You can have more than one session open in parallel, by declaring
+several distinct <tt>s6lock_t</tt> structures and calling
+<tt>s6lock_startf_g</tt> (or <tt>s6lock_start_g</tt>) more than once.
+However, one single session can handle
+virtually as many concurrent locks as your application needs, so
+opening several sessions is only useful if you need to acquire locks
+in various distinct lock directories.
+</p>
+
+<pre>
+s6lock_end(&amp;a) ;
+</pre>
+
+<p>
+<tt>s6lock_end</tt> frees all the resources used by the session. The
+<tt>a</tt> structure is then reusable for another session.
+</p>
+
+<h3> Acquiring and releasing locks </h3>
+
+<pre>
+uint16 id ;
+char const *file = "lockfile" ;
+struct taia limit ;
+struct taia deadline ;
+
+int r = s6lock_acquire_sh_g (&amp;a, &amp;id, file, &amp;limit, &amp;deadline) ;
+/* int r = s6lock_acquire_ex_g (&amp;a, &amp;id, file, &amp;limit, &amp;deadline) ; */
+r = s6lock_release_g(&amp;a, id, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6lock_acquire_sh_g</tt> instructs the
+<a href="s6lockd.html">s6lockd daemon</a>, related to the open
+session represented by the <tt>a</tt> handle, to try and acquire a
+shared lock on the
+<em>file</em> file located under that daemon's working directory
+(typically <tt>/var/lock</tt>). <em>file</em> will be interpreted as
+relative to the daemon's working directory even if it starts with a
+slash; however, slashes in the middle of <em>file</em> are likely to
+result in an error.
+</p>
+
+<p>
+<em>limit</em> and <em>deadline</em> are two absolute dates.
+<em>deadline</em> is a deadline for the execution of the
+function: if by <em>deadline</em> the function has not returned,
+then it instantly returns 0 and sets errno to ETIMEDOUT. The
+function is normally near-instantaneous, so <em>deadline</em> can
+be very close in the future and serves only as a protection against
+malicious servers. <em>limit</em> is the acquisition deadline: if
+by <em>limit</em> the daemon still has not been able to acquire a lock
+on <em>file</em>, then it will report a timeout to the client.
+</p>
+
+<p>
+The function returns 1 in case of success, or 0 if an error occurs,
+with errno set to a suitable value. If it succeeds, then a 16-bit
+number is stored into *<em>id</em>; this number serves as an identifier
+for this lock.
+</p>
+
+<p>
+<tt>s6lock_acquire_ex_g</tt> works just like <tt>s6lock_acquire_sh_g</tt>,
+except that the daemon tries to acquire an exclusive lock.
+</p>
+
+<p>
+<tt>s6lock_release_g</tt> releases the lock identified by <em>id</em>.
+It normally returns 1. It can return 0 with errno set to a suitable
+value if it fails. <em>id</em> is not valid after the corresponding
+lock has been released. The function normally returns instantly, with
+<em>deadline</em> as a safeguard.
+</p>
+
+<h3> Asynchronously waiting for locks </h3>
+
+<p>
+<em> (from now on, the functions are listed with their prototypes instead
+of usage examples.) </em>
+</p>
+
+<pre>
+int s6lock_fd (s6lock_t const *a)
+</pre>
+
+<p>
+ Returns a file descriptor to select on for reading. Do not
+<tt>read()</tt> it though.
+</p>
+
+<pre>
+int s6lock_update (s6lock_t *a)
+</pre>
+
+<p>
+ Call this function whenever the fd checks readability: it will
+update <em>a</em>'s internal structures with information from the
+<a href="s6lockd.html">s6lockd</a> daemon. It returns -1 if an error
+occurs; in case of success, it returns the number of identifiers for
+which something happened.
+</p>
+
+<p>
+ When <tt>s6lock_update</tt> returns,
+<tt>genalloc_s(uint16, &amp;a-&gt;list)</tt> points to an array of
+<tt>genalloc_len(uint16, &amp;a-&gt;list)</tt> 16-bit unsigned
+integers. Those integers are ids waiting to be passed to
+<tt>s6lock_check</tt>.
+</p>
+
+<pre>
+int s6lock_check (s6lock_t *a, uint16 id, char *what)
+</pre>
+
+<p>
+ Checks whether the lock identified by <em>id</em> has
+been acquired. Use after a call to <tt>s6lock_update()</tt>.
+</p>
+
+<ul>
+ <li> If an error occurred, returns -1 and sets errno. The error
+number may have been transmitted from
+<a href="s6lockd.html">s6lockd</a>. </li>
+ <li> If the lock has not been acquired yet, returns 0. </li>
+ <li> If the lock has been acquired, returns 1. </li>
+</ul>
+
+<h3> Synchronously waiting for locks </h3>
+
+<p>
+<code> int s6lock_wait_or_g (s6lock_t *a, uint16 const *idlist, unsigned int n, struct taia const *deadline) </code> <br />
+Synchronously waits for <em>one</em> of the locks represented by the array pointed to
+by <em>idlist</em> of length <em>n</em> to be acquired. Returns -1 if it fails,
+or a nonnegative number on success, which is the index in <em>idlist</em> of the
+acquired lock's id. If no result has been obtained by <em>deadline</em>, the
+function returns -1 ETIMEDOUT.
+</p>
+
+<p>
+<code> int s6lock_wait_and_g (s6lock_t *a, uint16 const *idlist, unsigned int n, struct taia const *deadline) </code> <br />
+Synchronously waits for <em>all</em> of the locks represented by the array pointed to
+by <em>idlist</em> of length <em>n</em> to be acquired. Returns -1 if it fails and
+0 if it succeeds. If no result has been obtained by <em>deadline</em>, the
+function returns -1 ETIMEDOUT.
+</p>
+
+</body>
+</html>
diff --git a/doc/libs6lock/s6lockd-helper.html b/doc/libs6lock/s6lockd-helper.html
new file mode 100644
index 0000000..839dce4
--- /dev/null
+++ b/doc/libs6lock/s6lockd-helper.html
@@ -0,0 +1,52 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6lockd-helper internal program</title>
+ <meta name="Description" content="s6: the s6lockd-helper internal program" />
+ <meta name="Keywords" content="s6 s6lockd-helper lockd asynchronous timed lock daemon helper" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<a href="index.html">libs6lock</a><br />
+<a href="../">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a><p />
+
+<h1> The <tt>s6lockd-helper</tt> program </h1>
+
+<p>
+<tt>s6lockd-helper</tt> is a helper program for the s6lock daemon.
+It just acquires a lock and holds it until it is killed or told to
+exit by its parent daemon.
+</p>
+
+<h2> Interface </h2>
+
+<p>
+ s6lockd-helper is not meant to be invoked directly by the user:
+it will be spawned by the
+<a href="s6lockd.html">s6lockd</a> program.
+</p>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6lockd-helper blocks on lock acquisition until it succeeds. It then
+notifies its parent. It exits when its parent tells him to (i.e. when the
+client asks for lock release). During the lock acquisition phase, it can
+be killed if its parent detects a timeout. </li>
+ <li> One s6lockd-helper process per lock is the only way (apart from
+threads) to implement timed lock acquisition. This can lead to a lot of
+s6lockd-helper processes, but this is not a problem:
+ <ul>
+ <li> Processes are not a scarce resource. Today's schedulers work in O(1),
+i.e. a sleeping process takes no scheduling time at all. </li>
+ <li> s6lockd-helper is extremely tiny. Every instance should use up at
+most one or two pages of non-sharable memory. </li>
+ </ul> </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libs6lock/s6lockd.html b/doc/libs6lock/s6lockd.html
new file mode 100644
index 0000000..726d2f8
--- /dev/null
+++ b/doc/libs6lock/s6lockd.html
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6lockd internal program</title>
+ <meta name="Description" content="s6: the s6lockd internal program" />
+ <meta name="Keywords" content="s6 s6lockd lockd asynchronous timed lock daemon" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<a href="index.html">libs6lock</a><br />
+<a href="../">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a><p />
+
+<h1> The <tt>s6lockd</tt> program </h1>
+
+<p>
+<tt>s6lockd</tt> is the s6lock daemon. It is a program that manages
+a set of lock files in a given directory, and associated timeouts.
+</p>
+
+<h2> Interface </h2>
+
+<p>
+ s6lockd does not fork, does not background itself automatically,
+and does not use syslog. It is not meant to be run directly by the
+user: it will be spawned by the
+<a href="index.html">s6lock client library</a>.
+</p>
+
+<p>
+ There are 2 ways to use s6lockd:
+</p>
+
+<ol>
+ <li> Use the <tt>s6lock_startf()</tt> library call.
+A <tt>s6lockd</tt> child will then be spawned from your
+calling process, and automatically reaped when you call
+<tt>s6lock_end()</tt>. It requires care with applications that
+trap SIGCHLD. It also requires care with lock file permissions:
+a s6lockd instance might not be able
+to open a lock file created by a former instance run by another
+client with different permissions. </li>
+ <li> Use the <tt>s6lock_start()</tt> library call, together with a
+<a href="http://skarnet.org/software/s6-networking/localservice.html">s6lockd service</a>.
+For once, <em>this is the recommended setup</em>: s6lockd creates empty
+lock files, and having all s6lockd instances run under the same user
+simplifies permissions management considerably. </li>
+ </li>
+</ol>
+
+<p>
+When run as a service, s6lockd has no "standalone" mode: it is
+designed to work with a Unix
+domain superserver, like
+<a href="http://skarnet.org/software/s6-networking/s6-ipcserver.html">s6-ipcserver</a>.
+s6lockd follows the <a href="http://cr.yp.to/proto/ucspi.txt">UCSPI</a>
+interface, it can be directly executed from the superserver.
+</p>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> Unix does not natively provide a way to stop blocking on a lock
+acquisition after a timeout. To emulate such behaviour, s6lockd actually
+spawns a <a href="s6lockd-helper.html">s6lockd-helper</a> child per
+requested lock. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/notifywhenup.html b/doc/notifywhenup.html
new file mode 100644
index 0000000..40b0593
--- /dev/null
+++ b/doc/notifywhenup.html
@@ -0,0 +1,75 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: service startup notifications</title>
+ <meta name="Description" content="s6: service startup notifications" />
+ <meta name="Keywords" content="s6 ftrig notification notifier writer libftrigw ftrigw startup U up svwait s6-svwait" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Service startup notifications </h1>
+
+<p>
+ It is easy for a process supervision suite to know when a service that was <em>up</em>
+is now <em>down</em>: the long-lived process implementing the service is dead. The
+supervisor, running as the daemon's parent, is instantly notified via a SIGCHLD.
+When it happens, <a href="s6-supervise.html">s6-supervise</a> sends a 'd' event
+to its <tt>./event</tt> <a href="fifodir.html">fifodir</a>, so every subscriber
+knows that the service is down. All is well.
+</p>
+
+<p>
+ It is much trickier for a process supervision suite to know when a service
+that was <em>down</em> is now <em>up</em>. The supervisor forks and execs the
+daemon, and knows when the exec has succeeded; but after that point, it's all
+up to the daemon itself. Some daemons do a lot of initialization work before
+they're actually ready to serve, and it is impossible for the supervisor to
+know exactly <em>when</em> the service is really ready.
+<a href="s6-supervise.html">s6-supervise</a> sends a 'u' event to its
+<tt>./event</tt> <a href="fifodir.html">fifodir</a> when it successfully
+spawns the daemon, but any subscriber
+reacting to 'u' is subject to a race condition - the service provided by the
+daemon may not be ready yet.
+</p>
+
+<p>
+ Reliable startup notifications need support from the daemons themselves.
+Daemons should notify the outside world when the service they are providing
+is reliably up - because only they know when it is the case.
+</p>
+
+<p>
+ s6 provides two ways for daemons to perform startup notification.
+</p>
+
+<ol>
+ <li> Daemons can use the <tt>ftrigw_notify()</tt> function, provided in
+<a href="libftrigw.html">the ftrigw library</a>. This is extremely
+simple and efficient, but requires specific s6 support in the daemon. </li>
+ <li> Daemons can write something to a file descriptor of their choice,
+then close that file descriptor, when they're ready to serve. This is
+a generic mechanism that some daemons already implement, and does not
+require anything specific in the daemon's code. The administrator can
+then run the daemon under <a href="s6-notifywhenup.html">s6-notifywhenup</a>,
+which will properly catch the daemon's message and notify all the subscribers
+with a 'U' event, meaning that the service is now up with no possible race
+condition. </li>
+</ol>
+
+<p>
+ The second method should really be implemented in every long-running
+program providing a service. When it is not the case, it's impossible
+to provide race-free startup notifications, and subscribers should be
+content with the unreliable 'u' events provided by s6-supervise.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-cleanfifodir.html b/doc/s6-cleanfifodir.html
new file mode 100644
index 0000000..5724666
--- /dev/null
+++ b/doc/s6-cleanfifodir.html
@@ -0,0 +1,42 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-cleanfifodir program</title>
+ <meta name="Description" content="s6: the s6-cleanfifodir program" />
+ <meta name="Keywords" content="s6 command s6-cleanfifodir fifodir notification cleaning" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-cleanfifodir program </h1>
+
+<p>
+s6-cleanfifodir cleans up a <a href="fifodir.html">fifodir</a>.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-cleanfifodir <em>fifodir</em>
+</pre>
+
+<p>
+s6-cleanfifodir cleans up <em>fifodir</em>, that must belong to the current user.
+That means it removes all stale FIFOs in <em>fifodir</em>.
+</p>
+
+<p>
+ In normal use, it is not necessary to call s6-cleanfifodir. However, stale
+FIFOs can be left by <a href="s6-ftrigrd.html">s6-ftrigrd</a> processes that
+were violently killed, so it's good practice to regularly clean up fifodirs.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-envdir.html b/doc/s6-envdir.html
new file mode 100644
index 0000000..5ac92e2
--- /dev/null
+++ b/doc/s6-envdir.html
@@ -0,0 +1,66 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-envdir program</title>
+ <meta name="Description" content="s6: the s6-envdir program" />
+ <meta name="Keywords" content="s6 command s6-envdir dir environment modification" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-envdir program </h1>
+
+<p>
+s6-envdir changes its environment, then executes into another program.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-envdir [ -I | -i ] [ -n ] [ -f ] [ -c <em>nullis</em> ] <em>dir</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-envdir reads files in <em>dir</em>. For every file <em>f</em> in <em>dir</em>,
+that does not begin with a dot and does not contain the '=' character: </li>
+ <li> If <em>f</em> is empty, remove a variable named <em>f</em> from the environment, if any. </li>
+ <li> Else add a variable named <em>f</em> to the environment (or replace <em>f</em> if it
+already exists) with the first line of the contents of file <em>f</em> as value.
+Spaces and tabs at the end of this line are removed;
+null characters in this line are changed to newlines in the environment variable.</li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-i</tt>&nbsp;: strict. If <em>dir</em> does not exist, exit 111 with an
+error message. This is the default. </li>
+ <li> <tt>-I</tt>&nbsp;: loose. If <em>dir</em> does not exit, exec into
+<em>prog</em> without modifying the environment first. </li>
+ <li> <tt>-f</tt>&nbsp;: verbatim mode. All the file is given as the value of the
+environment variable, including newlines (except the last one if the <tt>-n</tt>
+option is not given). Null characters are still translated. </li>
+ <li> <tt>-n</tt>&nbsp;: do not chomp. If the <tt>-f</tt> option is given and the
+file ends with a newline, keep that last newline in the value. If the <tt>-f</tt>
+option is not given, keep the trailing blanks at the end of the first line (but
+not the ending newline). </li>
+ <li> <tt>-c</tt>&nbsp;<em>nullis</em>&nbsp;: replace null characters with the
+first character of <em>nullis</em> instead of a newline. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<p>
+ s6-envdir without options behaves exactly like
+<a href="http://cr.yp.to/daemontools/envdir.html">envdir</a>.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-envuidgid.html b/doc/s6-envuidgid.html
new file mode 100644
index 0000000..680e841
--- /dev/null
+++ b/doc/s6-envuidgid.html
@@ -0,0 +1,64 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-envuidgid program</title>
+ <meta name="Description" content="s6: the s6-envuidgid program" />
+ <meta name="Keywords" content="s6 command s6-envuidgid uid gid environment modification" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-envuidgid program </h1>
+
+<p>
+s6-envuidgid sets the UID, GID and GIDLIST environment variables,
+then executes into another program.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-envuidgid <em>account</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-envuidgid looks <em>account</em> up by name in the account database. </li>
+ <li> If <em>account</em> is unknown, it exits 1. </li>
+ <li> It sets the UID environment variable to <em>account</em>'s uid, and the GID
+environment variable to <em>account</em>'s gid. </li>
+ <li> It also sets the GIDLIST environment variable to a comma-separated list of
+supplementary group ids <em>account</em> is a member of according to the
+group database. (If <em>account</em> doesn't belong to any other group than its
+primary group, GIDLIST is still set, but empty.) </li>
+ <li> Then it executes into <em>prog...</em>. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<p>
+ s6-envuidgid behaves like
+<a href="http://cr.yp.to/daemontools/envuidgid.html">envuidgid</a>, except that:
+</p>
+
+<ul>
+ <li> it also handles supplementary groups </li>
+ <li> It exits 1 if <em>account</em> does not exist. </li>
+</ul>
+
+<p>
+ s6-envuidgid is useful when running a program that must start as root but can
+drop its privileges later. Such a program can read its new uid/gid/groups info
+from the UID, GID and GIDLIST environment variables. Superservers such as
+<a href="http://skarnet.org/software/s6-networking/s6-tcpserver4.html">s6-tcpserver4</a>
+make use of this.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-fghack.html b/doc/s6-fghack.html
new file mode 100644
index 0000000..ba3f351
--- /dev/null
+++ b/doc/s6-fghack.html
@@ -0,0 +1,50 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fghack program</title>
+ <meta name="Description" content="s6: the s6-fghack program" />
+ <meta name="Keywords" content="s6 command s6-fghack foreground program background hack anti-backgrounding tool" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-fghack program </h1>
+
+<p>
+s6-fghack is an anti-backgrounding tool.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fghack <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-fghack opens a lot of file descriptors (all writing to a single pipe). </li>
+ <li> Then it forks and executes <em>prog...</em>. </li>
+ <li> If something gets written on one of those descriptors, it's a bug in <em>prog</em>.
+s6-fghack then complains and exits 102. </li>
+ <li> Unless <em>prog...</em> goes out of its way to close descriptors it does know about,
+s6-fghack is able to detect when <em>prog...</em> exits. It exits with the same exit
+code (or 111 if <em>prog...</em> has crashed). </li>
+</ul>
+
+<h2> Notes </h2>
+
+<p>
+ s6-fghack is what it says: a hack. Ideally, you should never have to use it.
+It is only useful when you want to supervise a daemon that does not provide a
+"stay in the foreground" option; and even then, the right thing is to report
+this as a bug to the daemon author and have it fixed.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-ftrig-listen.html b/doc/s6-ftrig-listen.html
new file mode 100644
index 0000000..e1d2518
--- /dev/null
+++ b/doc/s6-ftrig-listen.html
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-ftrig-listen program</title>
+ <meta name="Description" content="s6: the s6-ftrig-listen program" />
+ <meta name="Keywords" content="s6 command s6-ftrig-listen fifodir notification event listener subscriber receive" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-ftrig-listen program </h1>
+
+<p>
+s6-ftrig-listen subscribes to several <a href="fifodir.html">fifodirs</a>, then
+spawns a program, then waits for pattern of events to occur on the fifodirs.
+</p>
+
+<h2> Interface </h2>
+
+<p>
+ In an <a href="http://skarnet.org/software/execline/execlineb.html">execlineb</a>
+script:
+</p>
+
+<pre>
+ s6-ftrig-listen [ -a | -o ] [ -t <em>timeout</em> ] { <em>fifodir1</em> <em>regexp1</em> <em>fifodir2</em> <em>regexp2</em> ... } <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-ftrig-listen subscribes to <em>fifodir1</em> with the regexp <em>regexp1</em>,
+to <em>fifodir2</em> with the regexp <em>regexp2</em>, and so on. </li>
+ <li> It then forks and exec <em>prog...</em> with all its arguments </li>
+ <li> It waits for the series of events received on <em>fifodir-i</em>
+to match <em>regexp-i</em>, The <em>regexp-i</em> must be
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
+regular expressions</a>. </li>
+ <li> When the series of read events matches the <em>regexp</em>s,
+s6-ftrig-listen exits 0. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-t <em>timeout</em></tt>&nbsp;: if the events on the <em>fifodir</em>s have not
+matched the <em>regexp</em>s after <em>timeout</em> milliseconds, print an error message on
+stderr and exit 1. By default, s6-ftrig-listen1 waits indefinitely for a matching series
+of events. </li>
+ <li> <tt>-a</tt>&nbsp;: and (conjunction). s6-ftrig-listen will only exit when <em>all</em>
+the <em>fifodir-i</em> have been notified with events matching the corresponding <em>regexp-i</em>.
+This is the default. </li>
+ <li> <tt>-o</tt>&nbsp;: one (disjunction). s6-ftrig-listen will exit as soon as <em>one</em>
+of the <em>fifodir-i</em> has been notified with events matching its <em>regexp-i</em>. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<p>
+ s6-ftrig-listen can be used outside of an execlineb script by using the
+internal argv syntax, but this syntax is an implementation detail and is
+not documented as stable. In a shell
+script, use <tt>execlineb -Pc 's6-ftrig-listen ...'</tt> to get the
+benefits of the execlineb brace syntax.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-ftrig-listen1.html b/doc/s6-ftrig-listen1.html
new file mode 100644
index 0000000..88e2c6a
--- /dev/null
+++ b/doc/s6-ftrig-listen1.html
@@ -0,0 +1,88 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-ftrig-listen1 program</title>
+ <meta name="Description" content="s6: the s6-ftrig-listen1 program" />
+ <meta name="Keywords" content="s6 command s6-ftrig-listen1 fifodir notification event listener subscriber receive" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-ftrig-listen1 program </h1>
+
+<p>
+s6-ftrig-listen1 subscribes to a <a href="fifodir.html">fifodir</a>, then
+spawns a program, then waits for a pattern of events to occur on the fifodir.
+</p>
+
+<p>
+s6-ftrig-listen1 acts just as <a href="s6-ftrig-wait.html">s6-ftrig-wait</a>,
+except it can make sure that the process sending the notifications is actually
+started <em>after</em> there is a listener for those events.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-ftrig-listen1 [ -t <em>timeout</em> ] <em>fifodir</em> <em>regexp</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-ftrig-listen1 subscribes to <em>fifodir</em> </li>
+ <li> It then forks and exec <em>prog...</em> with all its arguments </li>
+ <li> It waits for the series of events received on <em>fifodir</em>
+to match <em>regexp</em>. <em>regexp</em> must be an
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
+regular expression</a>. </li>
+ <li> When the series of read events matches <em>regexp</em>,
+s6-ftrig-listen1 exits 0. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-t <em>timeout</em></tt>&nbsp;: if the events on <em>fifodir</em> have not
+matched <em>regexp</em> after <em>timeout</em> milliseconds, print an error message on
+stderr and exit 1. By default, s6-ftrig-listen1 waits indefinitely for a matching series
+of events. </li>
+</ul>
+
+<h2> Usage example </h2>
+
+<p>
+ The following sequence of shell commands has a race condition:
+</p>
+
+<p> <em>In terminal 1:</em> </p>
+<pre>
+s6-mkfifodir /tmp/toto
+s6-ftrig-wait /tmp/toto "message"
+</pre>
+
+<p> <em>Then in terminal 2</em> </p>
+<pre>
+s6-ftrig-notify /tmp/toto message
+</pre>
+
+<p>
+ Depending on the operating system's scheduler, there is the possibility that
+the s6-ftrig-notify process starts sending "message" <em>before</em> the
+s6-ftrig-wait process has actually subscribed to <tt>/tmp/toto</tt>, in which
+case the notification will be missed. The following sequence of shell commands
+accomplishes the same goal in a reliable way, without the race condition:
+</p>
+
+<pre>
+s6-mkfifodir /tmp/toto
+s6-ftrig-listen1 /tmp/toto "message" s6-ftrig-notify /tmp/toto message
+</pre>
+
+</body>
+</html>
diff --git a/doc/s6-ftrig-notify.html b/doc/s6-ftrig-notify.html
new file mode 100644
index 0000000..fa1e8b5
--- /dev/null
+++ b/doc/s6-ftrig-notify.html
@@ -0,0 +1,44 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-ftrig-notify program</title>
+ <meta name="Description" content="s6: the s6-ftrig-notify program" />
+ <meta name="Keywords" content="s6 command s6-ftrig-notify fifodir notification event notifier send" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-ftrig-notify program </h1>
+
+<p>
+s6-ftrig-notify sends a series of events to a <a href="fifodir.html">fifodir</a>.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-ftrig-notify <em>fifodir</em> <em>message</em>
+</pre>
+
+<p>
+s6-ftrig-notify notifies all the current listeners in <em>fifodir</em>
+with all the characters in <em>message</em>, one by one.
+</p>
+
+<h2> Notes </h2>
+
+<p>
+s6-ftrig-notify cannot be used to send the null character (event 0x00).
+If you need to send the null character, use the C API:
+<a href="libftrigw.html">ftrigw_notify()</a>.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-ftrig-wait.html b/doc/s6-ftrig-wait.html
new file mode 100644
index 0000000..a833782
--- /dev/null
+++ b/doc/s6-ftrig-wait.html
@@ -0,0 +1,51 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-ftrig-wait program</title>
+ <meta name="Description" content="s6: the s6-ftrig-wait program" />
+ <meta name="Keywords" content="s6 command s6-ftrig-wait fifodir notification event listener subscriber receive" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-ftrig-wait program </h1>
+
+<p>
+s6-ftrig-listen1 subscribes to a <a href="fifodir.html">fifodir</a> and
+waits for a pattern of events to occur on this fifodir.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-ftrig-wait [ -t <em>timeout</em> ] <em>fifodir</em> <em>regexp</em>
+</pre>
+
+<ul>
+ <li> s6-ftrig-wait subscribes to <em>fifodir</em> </li>
+ <li> It waits for the series of events received on <em>fifodir</em>
+to match <em>regexp</em>. <em>regexp</em> must be an
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
+regular expression</a>. </li>
+ <li> When the series of read events matches <em>regexp</em>,
+s6-ftrig-wait exits 0. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-t <em>timeout</em></tt>&nbsp;: if the events on <em>fifodir</em> have not
+matched <em>regexp</em> after <em>timeout</em> milliseconds, print an error message on
+stderr and exit 1. By default, s6-ftrig-wait waits indefinitely for a matching series
+of events. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-ftrigrd.html b/doc/s6-ftrigrd.html
new file mode 100644
index 0000000..dbd611e
--- /dev/null
+++ b/doc/s6-ftrigrd.html
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-ftrigrd program</title>
+ <meta name="Description" content="s6: the s6-ftrigrd program" />
+ <meta name="Keywords" content="s6 command s6-ftrigrd program internal libexec fifodir regexp subscribe notification listener" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-ftrigrd program </h1>
+
+<p>
+s6-ftrigrd is a helper program that manages a set of subscriptions to fifodirs as well
+as regular expressions on events. It takes orders from its client program that controls
+it via the <a href="libftrigr.html">ftrigr library</a>, and notifies it when desired
+events happen.
+</p>
+
+<h2> Interface </h2>
+
+<p>
+ s6-ftrigrd is not meant to be called directly.
+</p>
+
+<ul>
+ <li> If the client program uses <tt>ftrigr_startf()</tt>, it spawns an instance of
+s6-ftrigrd as a child. s6-ftrigrd's stdin is a pipe reading from the client; its
+stdout is a pipe writing to the client; its stderr is the same as the client's; and
+there's an additional pipe from s6-ftrigrd to the client, used for asynchronous
+notifications. </li>
+ <li> If the client program uses <tt>ftrigr_start()</tt>, then it tries to connect
+to a Unix domain socket. A <em>ftrigrd service</em> should be listening to that
+socket, i.e. a Unix domain superserver such as
+<a href="http://www.skarnet.org/software/s6-networking/s6-ipcserver.html">s6-ipcserver</a>
+spawning a s6-ftrigrd program on every connection. Then a s6-ftrigrd instance is created
+for the client. </li>
+ <li> When the client uses <tt>ftrigr_end()</tt>, or closes s6-ftrigrd's stdin in
+any way, s6-ftrigrd exits 0. </li>
+</ul>
+
+<p>
+ s6-ftrigrd handles the grunt work of creating fifos in a
+<a href="fifodir.html">fifodir</a> for a subscriber. It also wakes up on every
+event, and compares the chain of events it received on a given fifodir with the
+client-provided regexp. If the chain of events matches the regexp, it notifies
+the client.
+</p>
+
+<h2> Notes </h2>
+
+<p>
+ The connection management between the client and s6-ftrigrd is entirely done
+by the <a href="http://www.skarnet.org/software/skalibs/libunixonacid/skaclient.html">skaclient</a>
+library.
+</p>
+
+<p>
+ s6-ftrigrd is entirely asynchronous. It stores unread notifications into heap
+memory; it can grow in size if there are a lot of events and the client fails
+to read them. To avoid uncontrolled growth, make sure your client calls
+<tt>ftrigr_update()</tt> as soon as <tt>ftrigr_fd()</tt> becomes readable.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-log.html b/doc/s6-log.html
new file mode 100644
index 0000000..0a525d6
--- /dev/null
+++ b/doc/s6-log.html
@@ -0,0 +1,508 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-log program</title>
+ <meta name="Description" content="s6: the s6-log program" />
+ <meta name="Keywords" content="s6 command s6-log log logger logging multilog" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-log program </h1>
+
+<p>
+s6-log is a reliable logging program with automated log rotation, similar to
+daemontools' <a href="http://cr.yp.to/daemontools/multilog.html">multilog</a>,
+with full POSIX regular expression support.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-log [ -q | -v ] [ -b ] [ -p ] [ -t ] [ -e ] <em>logging script</em>
+</pre>
+
+<p>
+s6-log reads and compiles <em>logging script</em> to an internal
+form. Then it reads its standard input, line by line, and performs actions
+on it, following the script it is given. It does its best to ensure there
+is <em>never any log loss</em>. It exits cleanly when stdin closes or when
+it receives SIGTERM.
+</p>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-b</tt>&nbsp;: blocking mode. With this option, s6-log stops
+reading its standard input while it has unflushed buffers. This ensures that
+every log line has been fully processed before reading the next one; this is also
+<a href="http://cr.yp.to/daemontools/multilog.html">multilog</a>'s behaviour.
+By default, s6-log keeps reading from stdin even if its buffers still
+contain data. <tt>-b</tt> is safer, but may slow down your service; the default
+is faster, but may lead to unbound memory use if you have a lot of output to
+write to a slow file system. </li>
+ <li> <tt>-p</tt>&nbsp;: protect. Do not exit on receipt of a SIGTERM; only
+exit when reading EOF on stdin. </li>
+ <li> <tt>-t</tt>&nbsp;: timestamp. Prepends every log line that is written to
+a logging directory with a
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">TAI64N</a>
+timestamp. </li>
+ <li> <tt>-e</tt>&nbsp;: timestamp alerts. Prepends every "alert" line with a
+TAI64N timestamp. </li>
+ <li> <tt>-q | -v</tt>&nbsp;: quiet | verbose. Decreases | increases s6-log's
+verbosity, i.e. which messages are sent to stderr. The default verbosity is 1.
+Currently supported verbosity levels:
+ <ul>
+ <li> 0: only write alerts and fatal errors </li>
+ <li> 1: write alerts, warnings and fatal errors </li>
+ </ul> </li>
+</ul>
+
+<h2> Logdirs </h2>
+
+<p>
+A <em>logdir</em> (<em>logging directory</em>) is a place where logs are
+stored. s6-log can be scripted to write into one or more logdirs.
+</p>
+
+<p>
+ A logdir may contain the following files:
+</p>
+
+<ul>
+ <li> <tt>lock</tt>: this file is locked by s6-log at start,
+to make sure only one instance is running at the same time. </li>
+ <li> <tt>current</tt>: the file where selected log lines are appended.
+If <tt>current</tt> has the executable-by-user flag, it means that no
+s6-log process is currently writing to it and the previous
+s6-log process managed to cleanly finalize it. If it does not,
+either a s6-log process is writing to it or the previous one
+has been interrupted without finalizing it. </li>
+ <li> <tt>state</tt>: last processor's output, see below. </li>
+ <li> <tt>previous</tt>: a rotation is happening in that logdir. </li>
+ <li> <tt>processed</tt>, <tt>newstate</tt>: a rotation is happening
+in that logdir and the processor script is running. </li>
+ <li> timestamped files: those files are @<em>timestamp</em>.s or
+@<em>timestamp</em>.u and are old log files that have been processed
+and rotated (if they're ending in .s) or that were the <tt>current</tt>
+file when s6-log got interrupted (if they're ending in .u), in which
+case they have not been processed. </li>
+</ul>
+
+<h3> Rotation </h3>
+
+<p>
+ In a logdir, selected lines are appended to the <tt>current</tt> file.
+When <tt>current</tt> becomes too big, a <em>rotation</em> happens.
+The <tt>current</tt> file will be possibly <em>processed</em>, then
+it will become an <em>archived</em> log file named
+@<em>timestamp</em>.s, where <em>timestamp</em>, a
+<a href="http://www.skarnet.org/software/skalibs/libstddjb/tai.html">TAI64N</a>
+timestamp, is the absolute time of the rotation. If there are too
+many archived log files in the logdir, the older ones are then
+suppressed. Logging then resumes, to a brand new <tt>current</tt>
+file.
+</p>
+
+<p>
+ You can use this mechanism to ensure that your logs never fill up
+the available disk space, for instance: something that neither
+syslogd, nor syslog-ng, nor rsyslog offers.
+</p>
+
+<h3> Processors </h3>
+
+<p>
+ A <em>processor</em> script can be set for every logdir. When a rotation
+occurs, <tt>current</tt> (which has then been renamed <tt>previous</tt>) is
+fed to <em>processor</em>'s stdin, and <em>processor</em>'s stdout is saved
+and archived. <em>processor</em> can also read the <tt>state</tt> file
+on its fd 4; what it writes to its fd 5 will be saved as the next
+<tt>state</tt> file, for the next rotation.
+</p>
+
+<p>
+ Processors should not background themselves: s6-log considers the
+processing done when its <em>processor</em> direct child dies.
+Processors should exit 0 on success and nonzero on failure; if a
+processor fails, s6-log will try it again after some
+<em>cooldown</em> time.
+</p>
+
+<p>
+ Processors make s6-log Turing-complete by allowing you to use any
+external program to handle log files that are going to be archived.
+</p>
+
+<h2> Logging script syntax </h2>
+
+<p>
+ When starting up, s6-log reads its arguments one by one; this
+argument sequence, or <em>directive sequence</em>, forms a
+<em>logging script</em> which tells s6-log what to log, where, and how.
+</p>
+
+<p>
+ Every directive can be a <em>selection</em> directive, a <em>control</em>
+directive or an <em>action</em> directive. A valid logging script always
+contains at least one action directive; every action directive can be
+preceded by zero or more selection or control directives. s6-log will exit 100
+if the script is invalid. If it can process the script but the last directive
+is not an action directive, s6-log will emit a warning.
+</p>
+
+<h3> Selection directives </h3>
+
+<p>
+ These directives tell s6-log whether to select or deselect lines it reads
+from stdin; actions will only happen on selected lines. By default, every
+line is selected.
+</p>
+
+<ul>
+ <li> <strong>+<em>regexp</em></strong>: select yet-unselected lines that match <em>regexp</em>, which must be a
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">POSIX
+Extended Regular Expression</a>. </li>
+ <li> <strong>-<em>regexp</em></strong>: deselect yet-selected lines that match <em>regexp</em>, which must be a
+POSIX Extended Regular Expression. </li>
+ <li> <strong>f</strong>: select exactly lines that have not yet been acted
+upon (i.e. that were always deselected when the script encountered an action
+directive). </li>
+</ul>
+
+<h3> Control directives </h3>
+
+<p>
+ These directives tune s6-log's behaviour for the next actions.
+</p>
+
+<ul>
+ <li> <strong>n<em>number</em></strong>: next logdirs will contain up to
+<em>number</em> archived log files. If there are more, the oldest archived
+log files will be suppressed, only the latest <em>number</em> will be kept.
+By default, <em>number</em> is 10. </li>
+ <li> <strong>s<em>filesize</em></strong>: next rotations will occur when
+<tt>current</tt> log files approach <em>filesize</em> bytes. By default,
+<em>filesize</em> is 99999; it cannot be set lower than 4096 or
+higher than 16777215. </li>
+ <li> <strong>S<em>totalsize</em></strong>: next logdirs will contain up
+to <em>totalsize</em> bytes of archived (and maybe processed) log files. If
+archived log files take more space than that, the older ones are suppressed
+until the total size fits. A <em>totalsize</em> of zero means no such limit;
+use <strong>n0</strong> instead if you don't want any archived log files. By
+default, <em>totalsize</em> is 0 (unlimited). </li>
+ <li> <strong>l<em>tolerance</em></strong>: next rotations will be triggered
+when the size of <tt>current</tt> goes higher than <em>filesize</em> minus
+<em>tolerance</em>. <em>tolerance</em> cannot be more than half of
+<em>filesize</em>. By default, <em>tolerance</em> is 2000. </li>
+ <li> <strong>r<em>cooldown</em></strong>: if an error occurs during operations
+on the next logdirs, retry every <em>cooldown</em> milliseconds. By default,
+<em>cooldown</em> is 2000; it's strongly discouraged to set it to a value
+under 50. </li>
+ <li> <strong>E<em>alertsize</em></strong>: only the first <em>alertsize</em>
+bytes of the selected lines will be used in the next alerts. An
+<em>alertsize</em> of 0 means no limit. By default, <em>alertsize</em> is
+200. </li>
+ <li> <strong>^<em>statussize</em></strong>: only the first <em>statussize</em>
+bytes of the selected lines will be used in the next status file updates.
+If a line is shorter than <em>statussize</em> bytes, the status file will be
+padded with newlines so it is always <em>statussize</em> bytes long. 0 means
+an unpadded, unlimited status file. By default, <em>statussize</em> is 1001. </li>
+ <li> <strong>!<em>processor</em></strong>: registers
+<tt>execlineb -Pc <em>processor</em></tt> as a processor for the next logdirs;
+<tt>execlineb</tt> must be found in s6-log's PATH.
+If <em>processor</em> is empty, no processor will be set for the next logdirs.
+By default, no processor is set. </li>
+</ul>
+
+<h3> Action directives </h3>
+
+<p>
+ These directives determine what s6-log actually <em>does</em> with the
+selected lines.
+</p>
+
+<ul>
+ <li> <strong>e</strong>: alert. s6-log will print "s6-log: alert: ",
+possibly prepended with a timestamp, followed by the first
+<em>alertsize</em> bytes of the line. </li>
+ <li> <strong>=<em>statusfile</em></strong>: status. s6-log will atomically
+update the <em>statusfile</em> file with the first <em>statussize</em>
+bytes of the line, and pad it with newlines. s6-log must have the right
+to write to <em>statusfile</em> and to <em>statusfile</em>'s directory. </li>
+ <li> <strong><em>dir</em></strong> (must start with '/' or '.'): logdir.
+s6-log will log the line into the logdir <em>dir</em>. s6-log must have
+the right to write to <em>dir</em>.</li>
+</ul>
+
+
+<h2> Signals </h2>
+
+<ul>
+ <li> SIGTERM: If s6-log has been run with the <tt>-p</tt> option, does nothing.
+Without this option, SIGTERM instructs s6-log to stop reading stdin after the
+next newline and exit after logging the last line. </li>
+ <li> SIGALRM: triggers a rotation on every logdir s6-log is monitoring,
+as if the <tt>current</tt> file in those logdirs had reached the size
+limit. </li>
+</ul>
+
+<h2> Examples </h2>
+
+<pre>
+ s6-log -bt n20 s1000000 /var/log/services/stuff
+</pre>
+
+<p>
+ Logs all of stdin, prepending every line with a timestamp, into the
+<tt>/var/log/services/stuff</tt> logdir, with a maximum archive of
+20 log files of 1 MB each; makes sure every line has been written
+before reading the next one.
+</p>
+
+<pre>
+ s6-log -t n30 E500 - +fatal: e - +^STAT =/var/log/foobard/status f s10000000 S15000000 !"gzip -nq9" /var/log/foobard
+</pre>
+
+<ul>
+ <li> Sends alerts to stderr with the 500 first bytes of lines containing "fatal:". </li>
+ <li> Maintains the <tt>/var/log/foobard/status</tt> file at 1001 bytes,
+updating it when it finds a log line starting with "STAT". </li>
+ <li> Logs all other lines to logdir <tt>/var/log/foobard</tt>. When <tt>current</tt>
+reaches at least 9998 kB (i.e. 10 MB filesise minus 2kB tolerance), pipe it
+through <tt>gzip -nq9</tt> and save the result into a timestamped archive file, with
+a maximum of 30 such files or a total of 15 MB of compressed archive files. </li>
+</ul>
+
+
+<h2> Why use execlineb to interpret the "processor" string ? </h2>
+
+<p>
+ Because it is <em>exactly</em> what
+<a href="http://skarnet.org/software/execline/execlineb.html">execlineb</a>
+is for.
+</p>
+
+<ul>
+ <li> Directly executing <em>processor</em> is not flexible enough. We want
+to be able to run a complete command line, with an executable name and its
+arguments. </li>
+ <li> We could interpret the <em>processor</em> string via <tt>/bin/sh</tt>.
+This is what <a href="http://cr.yp.to/daemontools/multilog.html">multilog</a>
+does. However, <tt>/bin/sh</tt>, despite being the traditional Unix interpreter,
+is overpowered for this. We don't need a complete shell script interpreter:
+most <em>processor</em> commands will be very simple, with only two or three
+words, and we only need a way to turn a string into an <em>argv</em>, i.e. a
+command line. </li>
+ <li> <a href="http://www.skarnet.org/software/execline/execlineb.html">execlineb</a>
+was designed just for this: to turn simple strings into command lines.
+It is a very fast and lightweight script launcher, that does not do any heavy
+startup initialization like <tt>/bin/sh</tt> does. It happens to be the perfect
+tool for the job. </li>
+ <li> Yes, I also did this on purpose so people have a reason to use the
+<a href="http://www.skarnet.org/software/execline/">execline</a> language. Do not
+look at me like that: it <em>really</em> is the perfect tool for the job. </li>
+</ul>
+
+<h2> Why have another logging mechanism ? </h2>
+
+<p>
+ Because the syslog mechanism and all its implementations (save one) suck.
+I'm not being judgmental; I'm just stating the obvious.
+</p>
+
+<a name="diesyslogdiedie"><h3> The syslog design is flawed from the start </h3></a>
+
+<p>
+<a href="http://blog.gerhards.net/2007/08/why-does-world-need-another-syslogd.html">When
+asked why he started rsyslog</a>, Rainer Gerhards came up with a lot of
+hand-waving and not a single word about technical points. There is a
+reason for that: rsyslog is forked from sysklogd! So, no matter how
+many bells and whistles are added to it, it still suffers from the same
+basic flaws.
+</p>
+
+<p>
+ The problem with syslogd does not come from such or such implementation.
+The problem comes from syslog's <em>design</em> in the first place.
+</p>
+
+<ul>
+ <li> syslog makes you send <em>all</em> your logs to the same place.
+The logs from a zillion processes are read by a single syslogd server.
+The server checks log lines against system-wide regular expressions
+to decide where to write them. This raises the following issues:
+ <ul>
+ <li> Unless the client explicitly mentions its name in every log
+line, there is no way for log readers to know what process generated a
+given line. Some syslogd implementations can log the pid of the client;
+big deal. </li>
+ <li> Log lines from every client have to run through the same regular
+expression matching. This requires huge regular expression sets, and an
+obvious performance impact, to do anything meaningful. And as a matter
+of fact, standard syslogd configurations don't do anything meaningful:
+they separate the logs into a few streams such as <tt>/var/log/messages</tt>,
+<tt>/var/log/auth.log</tt>, <tt>/var/log/daemon.log</tt> or
+<tt>/var/log/syslog</tt> with very vague semantics. All of syslogd's
+line processing power remains unused, because making real use of it would
+be too complex. </li>
+ </ul>
+ <li> syslogd logs to <em>files</em>. This is wrong, because files grow
+and disks fill up. Sure, there are utilities such as <tt>logrotate</tt>
+to perform cleaning up, but as long as logging and log rotation are
+kept separate, there is a race condition: a log file can grow and fill
+up a disk before a rotation occurs. I am all for separating tasks that
+can be separated, but there is no choice here: <em>logging and log
+rotation management must be done <strong>by the same tool</strong></em>.
+Only the Busybox implementation of syslogd does this, and that is a
+feature added by the Busybox developers who are aware of the problem
+but want to maintain compatibility with the historical syslogd.
+No other syslogd implementation I know of manages its log files: that's a
+flaw that no amount of external tools is going to fix. </li>
+ <li> syslogd is a complex process that runs as root. We all know what
+complex processes running as root mean: bugs turning into security holes. </li>
+ <li> syslog requires a syslogd service, and fails otherwise. A syslogd
+service may not be present, it may fail... or it may want to log stuff.
+Who's going to take care of syslogd's error messages ? </li>
+</ul>
+
+<p>
+ syslog is slow, it's unsafe, and it's incomplete. The only reason people
+use it is because it's historical, it exists, and there hasn't been any
+serious alternative yet, except maybe
+<a href="http://cr.yp.to/daemontools/multilog.html">multilog</a>, which
+s6-log improves upon.
+</p>
+
+<a name="loggingchain"><h3> A not-so-modest proposal: the logging chain </h3></a>
+
+<p>
+ Unix distributions already do this to some extent, but it's at best
+unclear where the logs go for any given program.
+</p>
+
+<ul>
+ <li> Every program, without exception, should send its logs (be it
+error messages, warning messages, or anything) to its <em>standard
+error descriptor</em>, i.e. fd 2. <em>This is why it's open for.</em> </li>
+ <li> When process 1 starts, the logging chain is rooted to the
+<em>machine console</em>: anything process 1 sends to its stderr
+appears, without modification, on the machine console, which should
+at any time remain the last resort place where logs are sent. </em>
+ <li> Process 1 should spawn and supervise a <em>catch-all logging
+mechanism</em> that handles logs from every service that does not
+take care of its own logging. Error messages from this logging
+mechanism naturally go to the machine console. </li>
+ <li> Process 1's own error messages can go to the machine console,
+or <a href="s6-svscan-1.html#log">dirty tricks can be used</a> so they
+go to the catch-all logging mechanism. </li>
+ <li> Services that are spawned by process 1 should come with their
+own logger service; the supervision mechanism offered by
+<a href="s6-svscan.html">s6-svscan</a> makes it easy. Error messages
+from the loggers themselves naturally go to the catch-all
+mechanism. </li>
+ <li> User login mechanisms such as <tt>getty</tt>, <tt>xdm</tt> or
+<tt>sshd</tt> are services: they should be started with their own
+loggers. Of course, when a user gets a terminal and a shell, the
+shell's stderr should be redirected to the terminal: interactive
+programs break the automatic logging chain and delegate responsibility
+to the user. </li>
+ <li> A syslogd service <em>may</em> exist, to catch logs sent via
+syslog() by legacy programs. But it is a normal service, and logs
+caught by this syslogd service are not part of the logging chain.
+ It is probably overkill to provide the syslogd service with its own
+logger; error messages from syslogd can default to the catch-all logger.
+ The s6 package, including the <a href="ucspilogd.html">ucspilogd</a> program,
+combined with the
+<a href="http://skarnet.org/software/s6-networking/">s6-networking</a>
+package, provides enough tools to easily implement
+a complete syslogd system, for a small fraction of the resource needs and
+the complexity of native syslogd implementations. </li>
+</ul>
+
+<p>
+ So, given a program, where are its logs sent&nbsp;?
+</p>
+
+<ul>
+ <li> Logs sent via syslog() will be handled by the syslogd service as
+usual. Smart administrators will make sure that those ones are as few as
+possible. The rest of this analysis is about logs sent to stderr. </li>
+ <li> If the program is descended from a user's interactive program,
+its logs are sent to the user's terminal or the user's choice redirection
+target. </li>
+ <li> If the program is descended from a logged service, its logs are
+naturally sent to the service's logger. </li>
+ <li> Else the logs are sent to the catch-all logger. </li>
+ <li> Only the catch-all logger's error messages, the kernel's fatal
+error messages, and maybe process 1's error messages, are sent to the
+system console. </li>
+</ul>
+
+<a name="#howtouse"><h3> What does s6-log have to do with all this ? </h3></a>
+
+<p>
+ In a <em>logging chain</em> situation, every service must have
+its own logger. To avoid syslogd's design mistakes, one logger process
+per service must be run. s6-log fits that role. Using s6-log as
+your one-stop logger offers the following benefits:
+</p>
+
+<ul>
+ <li> Every instance of s6-log can run as a different user, so it's
+easy to give different access rights to different logs. It is also
+more secure not to have any logger process running as root. </li>
+ <li> s6-log consumes very little memory per instance (unless it
+accumulates unflushed log lines, which you can avoid with the
+<tt>-b</tt> option). So, launching a lot of s6-log processes does
+not waste resources. </li>
+ <li> s6-log is vastly configurable via logging scripts; every instance
+is as powerful as a traditional syslogd. </li>
+ <li> s6-log can log to a RAM filesystem and thus is suitable as a
+catch-all logger. Clever tricks like Upstart's <em>logd</em> or daemontools'
+<a href="http://cr.yp.to/daemontools/readproctitle.html">readproctitle</a>
+are just that: tricks. s6-log gives a unified interface to all of
+your system's loggers. </li>
+</ul>
+
+
+<a name="#network"><h3> You're wrong about being as powerful as
+syslogd: s6-log does not do remote logging. </h3></a>
+
+<p>
+ You mean you want to send, <em>live</em>, every <em>log line</em>
+over the network via <em>UDP</em>&nbsp;? You can't be serious.
+</p>
+
+<p>
+ Do yourself a favor and use s6-log to write log lines to a logdir,
+with a processor script that sends files-being-archived to the
+network, possibly after compressing them. More reliability, less
+log lines lost, less network traffic, better engineering. If you
+have no disk to even write the <tt>current</tt> files to, write
+to a small RAM filesystem.
+</p>
+
+<p>
+ If you <em>have to</em> log stuff <em>live</em> via the network, you
+do not need any local logging software. You don't even need syslogd.
+Just filter your stderr via some <tt>grep</tt> that selects lines for
+you, then sends them to a network socket. A trivial shell script, or
+<a href="http://skarnet.org/software/execline/">execline</a>
+script, can do that for you.
+</p>
+
+<p>
+ Do not insist on using syslogd. It does nothing magical, and nothing
+that can't be done in a simpler way using simpler tools.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-mkfifodir.html b/doc/s6-mkfifodir.html
new file mode 100644
index 0000000..818a514
--- /dev/null
+++ b/doc/s6-mkfifodir.html
@@ -0,0 +1,46 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-mkfifodir program</title>
+ <meta name="Description" content="s6: the s6-mkfifodir program" />
+ <meta name="Keywords" content="s6 command s6-mkfifodir fifodir notification creation" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-mkfifodir program </h1>
+
+<p>
+s6-mkfifodir creates a <a href="fifodir.html">fifodir</a>.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-mkfifodir [ -f ] [ -g <em>gid</em> ] <em>fifodir</em>
+</pre>
+
+<p>
+s6-mkfifodir creates <em>fifodir</em>, belonging to the current user.
+</p>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-f</tt>&nbsp;: force permissions. If <em>fifodir</em> already exists,
+change its permissions according to the <tt>-g</tt> options. By default, if
+<em>fifodir</em> exists, s6-mkfifodir does nothing. </li>
+ <li> <tt>-g <em>gid</em></tt>&nbsp;: make <em>fifodir</em> only listenable
+by members of group <em>gid</em>. If this option is not given, the fifodir is
+made publically listenable. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-notifywhenup.html b/doc/s6-notifywhenup.html
new file mode 100644
index 0000000..ad7ef8e
--- /dev/null
+++ b/doc/s6-notifywhenup.html
@@ -0,0 +1,80 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-notifywhenup program</title>
+ <meta name="Description" content="s6: the s6-notifywhenup program" />
+ <meta name="Keywords" content="s6 command s6-notifywhenup fifodir notification event notifier send service daemon ready" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-notifywhenup program </h1>
+
+<p>
+s6-notifywhenup launches a daemon while listening to a file descriptor,
+and sends a 'U' event to a <a href="fifodir.html">fifodir</a> when it
+receives something on that file descriptor.
+</p>
+
+<p>
+<a href="notifywhenup.html">This page</a> explains why this program is
+needed.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-notifywhenup [ -d <em>fd</em> ] [ -e <em>fifodir</em> ] [ -f ] [ -t <em>timeout</em> ] <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-notifywhenup forks and executes <em>prog...</em> as the
+parent, with a pipe from <em>prog...</em>'s stdout to the child. </li>
+ <li> The child waits for EOF on the pipe. When it gets it, if there
+have been other characters written before the EOF, it sends a 'U'
+event to the <tt>./event</tt> fifodir. </li>
+ <li> The child exits 0. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-d&nbsp;<em>fd</em></tt>&nbsp;: listen to
+<em>prog</em>'s output on descriptor <em>fd</em>. The default is 1. </li>
+ <li> <tt>-e&nbsp;<em>fifodir</em></tt>&nbsp;: send a 'U' event to fifodir
+<em>fifodir</em>. Default is <tt>./event</tt>. </li>
+ <li> <tt>-f</tt>&nbsp;: simple fork. Normally, s6-notifywhenup doubleforks,
+in order to accommodate for a
+<em>prog</em> that does not expect to have a child and avoid a
+pending zombie. This option avoids the doublefork, but it should only be
+set if <em>prog</em> reaps even children it doesn't know it has. </li>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if no EOF has been received
+after <em>timeout</em> milliseconds, exit without sending the event.
+Default is 0, meaning infinite. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-notifywhenup executes <em>prog...</em> as the parent in order
+for <em>prog</em> to keep the same pid, which is vital for supervised
+processes. </li>
+ <li> s6-notifywhenup can be used, for instance, with
+<a href="http://skarnet.org/software/s6-networking/s6-tcpserver.html">s6-tcpserver</a>
+and its <tt>-1</tt> option, so that reliable startup notification is
+achieved. <tt>s6-notifywhenup -f s6-tcpserver -1 <em>args</em></tt> will
+send a 'U' event to <tt>./event</tt> when s6-tcpserver is actually
+listening to its network socket. </li>
+ <li> The <a href="s6-svwait.html">s6-svwait</a> program can be used
+to wait for 'U' events. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-setlock.html b/doc/s6-setlock.html
new file mode 100644
index 0000000..bab3e23
--- /dev/null
+++ b/doc/s6-setlock.html
@@ -0,0 +1,65 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-setlock program</title>
+ <meta name="Description" content="s6: the s6-setlock program" />
+ <meta name="Keywords" content="s6 command s6-setlock lock program" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-setlock program </h1>
+
+<p>
+s6-setlock takes a lock on a file, then executes into another program.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-setlock [ -n | -N | -t <em>timeout</em> ] [ -r | -w ] <em>file</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-setlock creates <em>file</em> if it does not exist and opens it for writing. </li>
+ <li> It locks <em>file</em>. If it cannot take the lock for any reason, it exits 1. </li>
+ <li> It executes into <em>prog...</em>. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-n</tt>&nbsp;: nonblocking lock. If s6-setlock cannot acquire the lock, it will
+exit 1 immediately. </li>
+ <li> <tt>-N</tt>&nbsp;: blocking lock. s6-setlock will wait until it can acquire the lock.
+This is the default. </li>
+ <li> <tt>-t&nbsp;<em>timeout</em>&nbsp;: timed lock. If s6-setlock cannot acquire
+the lock after <em>timeout</em> milliseconds, it will exit 1. </li>
+ <li> <tt>-r</tt>&nbsp;: shared lock. Other shared locks on the same file will not prevent
+the lock from being acquired (but an exclusive lock will). </li>
+ <li> <tt>-w</tt>&nbsp;: exclusive lock. This is the default. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-setlock leaks an open file descriptor into the <em>prog</em>
+execution. This is intended: the fd holds the lock, which is released
+when <em>prog</em> exits. <em>prog</em> must not touch fds it does not
+know about. </li>
+ <li> If the timed lock option is chosen, s6-setlock does not acquire the lock
+itself. Instead, it spawns a <a href="libs6lock/s6lockd-helper.html">s6lockd-helper</a>
+process that acquires the lock while s6-setlock controls the timeout; the
+s6lockd-helper process then holds the lock and lives as long as
+<em>prog</em>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-setsid.html b/doc/s6-setsid.html
new file mode 100644
index 0000000..2fe991b
--- /dev/null
+++ b/doc/s6-setsid.html
@@ -0,0 +1,47 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-setsid program</title>
+ <meta name="Description" content="s6: the s6-setsid program" />
+ <meta name="Keywords" content="s6 command s6-setsid session leader setting" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-setsid program </h1>
+
+<p>
+s6-setsid runs a program as session leader.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-setsid [ -I | -i ] <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-setsid creates a new session if it is not a session leader, and becomes
+session leader of this new session. </li>
+ <li> It then executes into <em>prog...</em>. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-i</tt>&nbsp;: strict. If s6-setsid is already a session leader, it will
+exit 111 with an error message. </li>
+ <li> <tt>-I</tt>&nbsp;: loose. If s6-setsid is already a session leader, it will
+print a warning message, but exec into <em>prog</em> nonetheless. This is the
+default. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-setuidgid.html b/doc/s6-setuidgid.html
new file mode 100644
index 0000000..f12ae04
--- /dev/null
+++ b/doc/s6-setuidgid.html
@@ -0,0 +1,49 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-setuidgid program</title>
+ <meta name="Description" content="s6: the s6-setuidgid program" />
+ <meta name="Keywords" content="s6 command s6-setuidgid uid gid groups privilege dropping loss user change su" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-setuidgid program </h1>
+
+<p>
+s6-setuidgid executes a program as another user.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-setuidgid <em>account</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> If <em>account</em> contains a colon, it is interpreted as <em>uid:gid</em>,
+else it is interpreted as a username and looked up by name in the account
+database. </li>
+ <li> If <em>account</em> is unknown, s6-setuidgid exits 1. </li>
+ <li> s6-setuidgid sets its (real and effective) uid and gid to those of <em>account</em>.
+It also sets the list of supplementary groups to the correct one for <em>account</em>
+according to the group database. </li>
+<li> Then it executes into <em>prog...</em>. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<p>
+ s6-setuidgid can only be run as root. Its main use is to drop root privileges before
+starting a daemon.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-softlimit.html b/doc/s6-softlimit.html
new file mode 100644
index 0000000..4b112f8
--- /dev/null
+++ b/doc/s6-softlimit.html
@@ -0,0 +1,54 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-softlimit program</title>
+ <meta name="Description" content="s6: the s6-softlimit program" />
+ <meta name="Keywords" content="s6 command s6-softlimit process limits" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-softlimit program </h1>
+
+<p>
+s6-softlimit changes its process limits, then executes into another program.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-softlimit [ -a <em>allmem</em> ] [ -c <em>core</em> ] [ -d <em>data</em> ] [ -f <em>fsize</em> ] [ -l <em>lock</em> ] [ -m <em>mem</em> ] [ -o <em>ofiles</em> ] [ -p <em>proc</em> ] [ -r <em>res</em> ] [ -s <em>stack</em> ] [ -t <em>cpusecs</em> ] <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-softlimit parses its options and sets process (soft) resource limits accordingly. </li>
+ <li> A value of '=' for any option means "set that limit to the hard limit". </li>
+ <li> Depending on your operating system, an option may do nothing. </li>
+ <li> When s6-softlimit has modified all the limits successfully, it executes into <em>prog...</em>. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-a&nbsp;<em>allmem</em></tt>&nbsp;: limit the total available memory to <em>allmem</em> bytes. </li>
+ <li> <tt>-c&nbsp;<em>core</em></tt>&nbsp;: limit the core file size to <em>core</em> bytes. </li>
+ <li> <tt>-d&nbsp;<em>data</em></tt>&nbsp;: limit the available heap memory to <em>data</em> bytes. </li>
+ <li> <tt>-f&nbsp;<em>fsize</em></tt>&nbsp;: limit the file size to <em>fsize</em> bytes. </li>
+ <li> <tt>-l&nbsp;<em>lock</em></tt>&nbsp;: limit the available locked memory to <em>lock</em> bytes. </li>
+ <li> <tt>-m&nbsp;<em>mem</em></tt>&nbsp;: limit all types of memory to <em>mem</em> bytes. </li>
+ <li> <tt>-o&nbsp;<em>ofiles</em></tt>&nbsp;: limit the number of open fds to <em>ofiles</em>. </li>
+ <li> <tt>-p&nbsp;<em>proc</em></tt>&nbsp;: limit the number of processes to <em>proc</em> (per user). </li>
+ <li> <tt>-r&nbsp;<em>allmem</em></tt>&nbsp;: limit the available physical memory to <em>res</em> bytes. </li>
+ <li> <tt>-s&nbsp;<em>stack</em></tt>&nbsp;: limit the available stack memory to <em>stack</em> bytes. </li>
+ <li> <tt>-t&nbsp;<em>cpusecs</em></tt>&nbsp;: limit the available CPU time to <em>cpusecs</em> seconds. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-supervise.html b/doc/s6-supervise.html
new file mode 100644
index 0000000..1c1551e
--- /dev/null
+++ b/doc/s6-supervise.html
@@ -0,0 +1,125 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-supervise program</title>
+ <meta name="Description" content="s6: the s6-supervise program" />
+ <meta name="Keywords" content="s6 command s6-supervise servicedir supervision supervise" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-supervise program </h1>
+
+<p>
+s6-supervise monitors a long-lived process (or <em>service</em>), making sure it
+stays alive, sending notifications to registered processes when it dies, and
+providing an interface to control its state. s6-supervise is designed to be the
+last non-leaf branch of a <em>supervision tree</em>, the supervised process
+being a leaf.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-supervise <em>servicedir</em>
+</pre>
+
+<ul>
+ <li> s6-supervise switches to the <em>servicedir</em>
+<a href="servicedir.html">service directory</a>. </li>
+ <li> It exits 100 if another s6-supervise process is already monitoring this service. </li>
+ <li> If the <tt>./event</tt> <a href="fifodir.html">fifodir</a> does not exist,
+s6-supervise creates it and allows public subscriptions to it.
+If it already exists, it uses it as is, without modifying the subscription rights. </li>
+ <li> It <a href="libftrigw.html">sends</a> a <tt>'s'</tt> event to <tt>./event</tt>. </li>
+ <li> If the default service state is up, s6-supervise spawns <tt>./run</tt>. </li>
+ <li> s6-supervise sends a <tt>'u'</tt> event to <tt>./event</tt> whenever it
+successfully spawns <tt>./run</tt>. </li>
+ <li> When <tt>./run</tt> dies, s6-supervise sends a <tt>'d'</tt> event to <tt>./event</tt>. </li>
+ <li> When <tt>./run</tt> dies, s6-supervise spawns <tt>./finish</tt> if it exists. </li>
+ <li> <tt>./finish</tt> must exit in less than 5 seconds. If it takes more than that,
+s6-supervise kills it. </li>
+ <li> When <tt>./finish</tt> dies, s6-supervise restarts <tt>./run</tt> unless it has been
+told not to. </li>
+ <li> There is a minimum 1-second delay between two <tt>./run</tt> spawns, to avoid busylooping
+if <tt>./run</tt> exits too quickly. </li>
+ <li> When killed or asked to exit, it waits for the service to go down one last time, then
+sends a <tt>'x'</tt> event to <tt>./event</tt> before exiting 0. </li>
+</ul>
+
+<h2> Signals </h2>
+
+<p>
+ s6-supervise reacts to the following signals:
+</p>
+
+<ul>
+ <li> SIGTERM: bring down the service and exit, as if a
+<a href="s6-svc.html">s6-svc -xd</a> command had been received </li>
+ <li> SIGHUP: exit as soon as the service stops, as if a
+<a href="s6-svc.html">s6-svc -x</a> command had been received </li>
+ <li> SIGQUIT: currently like SIGTERM, but this might change in the future </li>
+</ul>
+
+<h2> Usage notes </h2>
+
+<ul>
+ <li> s6-supervise is a long-lived process. It normally runs forever, from the system's
+boot scripts, until shutdown time; it should not be killed or told to exit. If you have
+no use for a service, just turn it off; the s6-supervise process does not hurt. </li>
+ <li> Even in boot scripts, s6-supervise should normally not be run directly. It's
+better to have a collection of <a href="servicedir.html">service directories</a> in a
+single <a href="scandir.html">scan directory</a>, and just run
+<a href="s6-svscan.html">s6-svscan</a> on that scan directory. s6-svscan will spawn
+the necessary s6-supervise processes, and will also take care of logged services. </li>
+ <li> You can use <a href="s6-svc.html">s6-svc</a> to send commands to the s6-supervise
+process; mostly to change the service state and send signals to the monitored
+process. </li>
+ <li> You can use <a href="s6-svok.html">s6-svok</a> to check whether s6-supervise
+is successfully running. </li>
+ <li> You can use <a href="s6-svstat.html">s6-svstat</a> to check the status of a
+service. </li>
+ <li> s6-supervise maintains internal information inside the <tt>./supervise</tt>
+subdirectory of <em>servicedir</em>. <em>servicedir</em> itself can be read-only,
+but both <em>servicedir</em><tt>/supervise</tt> and <em>servicedir</em><tt>/event</tt>
+need to be read-write. </li>
+ <li> The <tt>./finish</tt> script is not guaranteed to have stdin and
+stdout pointing to the same locations as the <tt>./run</tt> script. More
+precisely: the stdin and stdout will be preserved for <tt>./finish</tt>
+until s6-supervise is asked to exit, but the last <tt>./finish</tt>
+execution will have its stdin and stdout redirected to <tt>/dev/null</tt>.
+(This is to avoid maintaining open descriptors when a service is down, which
+would prevent its logger from exiting cleanly.) </li>
+</ul>
+
+<h2> Implementation notes </h2>
+
+<ul>
+ <li> s6-supervise tries its best to stay alive and running despite possible
+system call failures. It will write to its standard error everytime it encounters a
+problem. However, unlike <a href="s6-svscan.html">s6-svscan</a>, it will not go out
+of its way to stay alive; if it encounters an unsolvable situation, it will just
+die. </li>
+ <li> Unlike other "supervise" implementations, s6-supervise is a fully asynchronous
+state machine. That means that it can read and process commands at any time, even
+when the machine is in trouble (full process table, for instance). </li>
+ <li> s6-supervise <em>does not use malloc()</em>. That means it will <em>never leak
+memory</em>. <small>However, s6-supervise uses opendir(), and most opendir()
+implementations internally use heap memory - so unfortunately, it's impossible to
+guarantee that s6-supervise does not use heap memory at all.</small> </li>
+ <li> s6-supervise has been carefully designed so every instance maintains as little
+data as possible, so it uses a very small
+amount of non-sharable memory. It is not a problem to have several
+dozens of s6-supervise processes, even on constrained systems: resource consumption
+will be negligible. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-svc.html b/doc/s6-svc.html
new file mode 100644
index 0000000..72f0776
--- /dev/null
+++ b/doc/s6-svc.html
@@ -0,0 +1,104 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-svc program</title>
+ <meta name="Description" content="s6: the s6-svc program" />
+ <meta name="Keywords" content="s6 command s6-svc supervise command service" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-svc program </h1>
+
+<p>
+s6-svc sends commands to a running <a href="s6-supervise.html">s6-supervise</a>
+process. In other words, it's used to control a supervised process; among
+other benefits, it allows an administrator to send signals to daemons without
+knowing their PIDs, and without using horrible hacks such as .pid files.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-svc [ -abqhkti12fFpcoduxO ] <em>servicedir</em>
+</pre>
+
+<p>
+s6-svc sends the given series of commands to the
+<a href="s6-supervise.html">s6-supervise</a> process monitoring the
+<em>servicedir</em> directory, then exits 0. It exits 111 if it cannot send
+a command, or 100 if no s6-supervise process is running on <em>servicedir</em>.
+</p>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-a</tt>&nbsp;: send a SIGALRM to the supervised process </li>
+ <li> <tt>-b</tt>&nbsp;: send a SIGABRT to the supervised process </li>
+ <li> <tt>-q</tt>&nbsp;: send a SIGQUIT to the supervised process </li>
+ <li> <tt>-h</tt>&nbsp;: send a SIGHUP to the supervised process </li>
+ <li> <tt>-k</tt>&nbsp;: send a SIGKILL to the supervised process </li>
+ <li> <tt>-t</tt>&nbsp;: send a SIGTERM to the supervised process </li>
+ <li> <tt>-i</tt>&nbsp;: send a SIGINT to the supervised process </li>
+ <li> <tt>-1</tt>&nbsp;: send a SIGUSR1 to the supervised process </li>
+ <li> <tt>-2</tt>&nbsp;: send a SIGUSR2 to the supervised process </li>
+ <li> <tt>-p</tt>&nbsp;: send a SIGSTOP to the supervised process </li>
+ <li> <tt>-c</tt>&nbsp;: send a SIGCONT to the supervised process </li>
+ <li> <tt>-o</tt>&nbsp;: once. Equivalent to "-uO". </li>
+ <li> <tt>-d</tt>&nbsp;: down. If the supervised process is up, send it
+a SIGTERM and a SIGCONT. Do not restart it. </li>
+ <li> <tt>-u</tt>&nbsp;: up. If the supervised process is down, start it.
+Automatically restart it when it dies. </li>
+ <li> <tt>-x</tt>&nbsp;: exit. When the service is asked to be down and
+the supervised process dies, supervise will exit too. This command should
+normally never be used on a working system. </li>
+ <li> <tt>-O</tt>&nbsp;: Once at most. Do not restart the supervised process
+when it dies. If it is down when the command is received, do not even start
+it. </li>
+ <li> <tt>-f</tt>,&nbsp;<tt>-F</tt>&nbsp;: unused for now. </li>
+</ul>
+
+<h2> Usage examples </h2>
+
+<pre> s6-svc -h /service/httpd </pre>
+<p>
+ Send a SIGHUP to the process represented by the <tt>/service/httpd</tt>
+service directory. Traditionally, this makes web servers reload their
+configuration file.
+</p>
+
+<pre> s6-svc -t /service/sshd </pre>
+<p>
+ Kill (and automatically restart, if the wanted state of the service is up)
+the process represented by the <tt>/service/sshd</tt> service directory -
+typically the sshd server.
+</p>
+
+<pre> s6-svc -d /service/ftpd </pre>
+<p>
+ Take down the ftpd server.
+</p>
+
+<pre> s6-svc -a /service/httpd/log </pre>
+<p>
+ Send a SIGALRM to the logger process for the httpd server. If this logger
+process is <a href="s6-log.html">s6-log</a>, this triggers a log rotation.
+</p>
+
+<h2> Internals </h2>
+
+<p>
+s6-svc writes control commands into the <tt><em>servicedir</em>/supervise/control</tt>
+FIFO. A s6-supervise process running on <em>servicedir</em> will be listening to this FIFO,
+and will read and interpret those commands.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-svok.html b/doc/s6-svok.html
new file mode 100644
index 0000000..a43d253
--- /dev/null
+++ b/doc/s6-svok.html
@@ -0,0 +1,38 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-svok program</title>
+ <meta name="Description" content="s6: the s6-svok program" />
+ <meta name="Keywords" content="s6 command s6-svok servicedir checking supervision s6-supervise" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-svok program </h1>
+
+<p>
+s6-svok checks whether a <a href="servicedir.html">service directory</a> is
+currently supervised.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-svok <em>servicedir</em>
+</pre>
+
+<ul>
+<li> s6-svok checks whether a <a href="s6-supervise.html">s6-supervise</a>
+process is currently monitoring <em>fifodir</em>. </li>
+<li> It exits 0 if there is one, or 1 if there is none. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-svscan-1.html b/doc/s6-svscan-1.html
new file mode 100644
index 0000000..76bc31c
--- /dev/null
+++ b/doc/s6-svscan-1.html
@@ -0,0 +1,374 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: How to run s6-svscan as process 1</title>
+ <meta name="Description" content="s6: s6-svscan as init" />
+ <meta name="Keywords" content="s6 supervision svscan s6-svscan init process boot 1" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> How to run s6-svscan as process 1 </h1>
+
+<p>
+ It is possible to run s6-svscan as process 1, i.e. the <tt>init</tt>
+process. However, that does not mean you can directly <em>boot</em>
+on s6-svscan; that little program cannot do everything
+your stock init does. Replacing the <tt>init</tt> process requires a
+bit of understanding of what is going on.
+</p>
+
+<a name="stages">
+<h2> The three stages of init </h2>
+</a>
+
+<p>
+ The life of a Unix machine has three stages:
+</p>
+
+<ol>
+ <li> The <em>early initialization</em> phase. It starts when the
+kernel launches the first userland process, traditionally called <tt>init</tt>.
+During this phase, init is the only lasting process; its duty is to
+prepare the machine for the start of <em>other</em> long-lived processes,
+i.e. services. Work such as mounting filesystems, setting the system clock,
+etc. can be done at this point. This phase ends when process 1 launches
+its first services. </li>
+ <li> The <em>cruising</em> phase. This is the "normal", stable state of an
+up and running Unix machine. Early work is done, and init launches and
+maintains <em>services</em>, i.e. long-lived processes such as gettys,
+the ssh server, and so on. During this phase, init's duties are to reap
+orphaned zombies and to supervise services - also allowing the administrator
+to add or remove services. This phase ends when the administrator
+requires a shutdown. </li>
+ <li> The <em>shutdown</em> phase. Everything is cleaned up, services are
+stopped, filesystems are unmounted, the machine is getting ready to be
+halted. During this phase, everything but the shutdown procedure gets
+killed - the only surefire way to kill everything is <tt>kill -9 -1</tt>,
+and only process 1 can survive it and keep working: it's only logical
+that the shutdown procedure, or at least the shutdown procedure from
+the <tt>kill -9 -1</tt> on and until the final poweroff or reboot
+command, is performed by process 1. </li>
+</ol>
+
+<p>
+ As you can see, process 1's duties are <em>radically different</em> from
+one stage to the next, and init has the most work when the machine
+is booting or shutting down, which means a normally negligible fraction
+of the time it is up. The only common thing is that at no point is process
+1 allowed to exit.
+</p>
+
+<p>
+ Still, all common init systems insist that the same <tt>init</tt>
+executable must handle these three stages. From System V init to launchd,
+via busybox init, you name it - one init program from bootup to shutdown.
+No wonder those programs, even basic ones, seem complex to write and
+complex to understand!
+</p>
+
+<p>
+Even the <a href="http://smarden.org/runit/runit.8.html">runit</a>
+program, designed with supervision in mind, remains as process 1 all the
+time; at least runit makes things simple by clearly separating the three
+stages and delegating every stage's work to a different script that is
+<em>not</em> run as process 1. (This requires very careful handling of the
+<tt>kill -9 -1</tt> part of stage 3, though.)
+</p>
+
+<p>
+ One init to rule them all?
+<a href="http://en.wikipedia.org/wiki/Porgy_and_Bess">It ain't necessarily so!</a>
+</p>
+
+<a name="stage2">
+<h2> The role of s6-svscan </h2>
+</a>
+
+<p>
+ init does not have the right to die, but fortunately, <em>it has the right
+to <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html">execve()</a>!</em>
+During stage 2, why use precious RAM, or at best, swap space, to store data
+that are only relevant to stages 1 or 3? It only makes sense to have an
+init process that handles stage 1, then executes into an init process that
+handles stage 2, and when told to shutdown, this "stage 2" init executes into
+a "stage 3" init which just performs shutdown. Just as runit does with the
+<tt>/etc/runit/[123]</tt> scripts, but exec'ing the scripts as process 1
+instead of forking them.
+</p>
+
+<p>
+It becomes clear now that
+<a href="s6-svscan.html">s6-svscan</a> is perfectly suited to
+exactly fulfill process 1's role <strong>during stage 2</strong>.
+</p>
+
+<ul>
+ <li> It does not die </li>
+ <li> The reaper takes care of every zombie on the system </li>
+ <li> The scanner maintains services alive </li>
+ <li> It can be sent commands via the <a href="s6-svscanctl.html">s6-svscanctl</a>
+interface </li>
+ <li> It execs into a given script when told to </li>
+</ul>
+
+<p>
+ However, an init process for stage 1 and another one for stage 3 are still
+needed. Fortunately, those processes are very easy to design! The only
+difficulty here is that they're heavily system-dependent, so it's not possible
+to provide a stage 1 init and a stage 3 init that will work everywhere.
+s6 was designed to be as portable as possible, and it should run on virtually
+every Unix platform; but outside of stage 2 is where portability stops, and
+the s6 package can't help you there.
+</p>
+
+<p>
+ Here are some tips though.
+</p>
+
+<a name="stage1">
+<h2> How to design a stage 1 init </h2>
+</a>
+
+<h3> What stage 1 init must do </h3>
+
+<ul>
+ <li> Prepare an initial <a href="scandir.html">scan directory</a>, say in
+<tt>/service</tt>, with a few vital services, such as s6-svscan's own logger,
+and an early getty (in case debugging is needed). That implies mounting a
+read-write filesystem, creating it in RAM if needed, if the root filesystem
+is read-only. </li>
+ <li> Either perform all the one-time initialization, as stage 1
+<a href="http://smarden.org/runit/">runit</a> does; </li>
+ <li> or fork a process that will perform most of the one-time initialization
+once s6-svscan is in charge. </li>
+ <li> Be extremely simple and not fail, because recovery is almost impossible
+here. </li>
+</ul>
+
+<p>
+ Unlike the <tt>/etc/runit/1</tt> script, an init-stage1 script running as
+process 1 has nothing to back it up, and if it fails and dies, the machine
+crashes. Does that mean the runit approach is better? It's certainly safer,
+but not necessarily better, because init-stage1 can be made <em>extremely
+small</em>, to the point it is practically failproof, and if it fails, it
+means something is so wrong that you
+would have had to reboot the machine with <tt>init=/bin/sh</tt> anyway.
+</p>
+
+<p>
+ To make init-stage1 as small as possible, only this realization is needed:
+you do not need to perform all of the one-time initialization tasks before
+launching s6-svscan. Actually, once init-stage1 has made it possible for
+s6-svscan to run, it can fork a background "init-stage2" process and exec
+into s6-svscan immediately! The "init-stage2" process can then pursue the
+one-time initialization, with a big advantage over the "init-stage1"
+process: s6-svscan is running, as well as a few vital services, and if
+something bad happens, there's a getty for the administrator to log on.
+No need to play fancy tricks with <tt>/dev/console</tt> anymore! Yes,
+the theoretical separation in 3 stages is a bit more supple in practice:
+the "stage 2" process 1 can be already running when a part of the
+"stage 1" one-time tasks are still being run.
+</p>
+
+<p>
+ Of course, that means that the scan directory is still incomplete when
+s6-svscan first starts, because most services can't yet be run, for
+lack of mounted filesystems, network etc. The "init-stage2" one-time
+initialization script must populate the scan directory when it has made
+it possible for all wanted services to run, and trigger the scanner.
+Once all the one-time tasks are done, the scan directory is fully
+populated and the scanner has been triggered, the machine is fully
+operational and in stage 2, and the "init-stage2" script can die.
+</p>
+
+<h3> Is it possible to write stage 1 init in a scripting language? </h3>
+
+<p>
+ It is very possible, and I even recommend it. If you are using
+s6-svscan as stage 2 init, stage 1 init should be simple enough
+that it can be written in any scripting language you want, just
+as <tt>/etc/runit/1</tt> is if you're using runit. And since it
+should be so small, the performance impact will be negligible,
+while maintainability is enhanced. Definitely make your stage 1
+init a script.
+</p>
+
+<p>
+ Of course, most people will use the <em>shell</em> as scripting
+language; however, I advocate the use of
+<a href="http://www.skarnet.org/software/execline/">execline</a>
+for this, and not only for the obvious reasons. Piping s6-svscan's
+stderr to a logging service before said service is even up requires
+some <a href="#log">tricky fifo handling</a> that execline can do
+and the shell cannot.
+</p>
+
+<a name="stage3">
+<h2> How to design a stage 3 init </h2>
+</a>
+
+<p>
+ If you're using s6-svscan as stage 2 init on <tt>/service</tt>, then
+stage 3 init is naturally the <tt>/service/.s6-svscan/finish</tt> program.
+Of course, <tt>/service/.s6-svscan/finish</tt> can be a symbolic link
+to anything else; just make sure it points to something in the root
+filesystem (unless your program is an execline script, in which case
+it is not even necessary).
+</p>
+
+<h3> What stage 3 init must do </h3>
+
+<ul>
+ <li> Destroy the supervision tree and stop all services </li>
+ <li> Kill all processes <em>save itself</em>, first gently, then harshly </li>
+ <li> Unmount all the filesystems </li>
+ <li> Halt or reboot the machine, depending on what root asked for </li>
+</ul>
+
+<p>
+ This is also very simple; even simpler than stage 1.
+ The only tricky part is the <tt>kill -9 -1</tt> phase: you must make sure
+that <em>process 1</em> regains control and keeps running after it, because
+it will be the only process left alive. But since we're running stage 3
+init directly, it's almost automatic! this is an advantage of running
+the shutdown procedure as process 1, as opposed to, for instance,
+<tt>/etc/runit/3</tt>.
+</p>
+
+<h3> Is it possible to write stage 3 init in a scripting language? </h3>
+
+<p>
+ You'd have to be a masochist, or have extremely specific needs, not to
+do so.
+</p>
+
+<a name="log">
+<h2> How to log the supervision tree's messages </h2>
+</a>
+
+<p>
+ When the Unix kernel launches your (stage 1) init process, it does it
+with descriptors 0, 1 and 2 open and reading from or writing to
+<tt>/dev/console</tt>. This is okay for the early boot: you actually
+want early error messages to be displayed to the system console. But
+this is not okay for stage 2: the system console should only be used
+to display extremely serious error messages such as kernel errors, or
+errors from the logging system itself; everything else should be
+handled by the logging system, following the
+<a href="s6-log.html#loggingchain">logging chain</a> mechanism. The
+supervision tree's messages should go to the catch-all logger instead
+of the system console. (And the console should never be read, so no
+program should run with <tt>/dev/console</tt> as stdin, but this is easy
+enough to fix: s6-svscan will be started with stdin redirected from
+<tt>/dev/null</tt>.)
+</p>
+
+<p>
+ The catch-all logger is a service, and we want <em>every</em>
+service to run under the supervision tree. Chicken and egg problem:
+before starting s6-svscan, we must redirect s6-svscan's output to
+the input of a program that will only be started once s6-svscan is
+running and can start services.
+</p>
+
+<p>
+ There are several solutions to this problem, but the simplest one is
+to use a FIFO, a.k.a. named pipe. s6-svscan's stdout and stderr can
+be redirected to a named pipe before s6-svscan is run, and the
+catch-all logger service can be made to read from this named pipe.
+Only two minor problems remain:
+</p>
+
+<ul>
+ <li> If s6-svscan or s6-supervise writes to the FIFO before there is
+a reader, i.e. before the catch-all logging service is started, the
+write will fail (and a SIGPIPE will be emitted). This is not a real issue
+for an s6 installation because s6-svscan and s6-supervise ignore SIGPIPE,
+and they only write
+to their stderr if an error occurs; and if an error occurs before they are
+able to start the catch-all logger, this means that the system is seriously
+damaged (as if an error occurs during stage 1) and the only solution is
+to reboot with <tt>init=/bin/sh</tt> anyway. </li>
+ <li> Normal Unix semantics <em>do not allow</em> a writer to open a
+FIFO before there is a reader: if there is no reader when the FIFO is
+opened for writing, the <tt>open()</tt> system call <em>blocks</em>
+until a reader appears. This is obviously not what we want: we want
+to be able to <em>actually start</em> s6-svscan with its stdout and
+stderr pointing to the logging FIFO, even without a reader process,
+and we want it to run normally so it can start the logging service
+that will provide such a reader process. </li>
+</ul>
+
+<p>
+ This second point cannot be solved in a shell script, and that is why
+you are discouraged to write your stage 1 init script in the shell
+language: you cannot properly set up a FIFO output for s6-svscan without
+resorting to horrible and unreliable hacks involving a temporary background
+FIFO reader process.
+</p>
+
+<p>
+ Instead, you are encouraged to use the
+<a href="http://skarnet.org/software/execline/">execline</a> language -
+or, at least,
+the <a href="http://skarnet.org/software/execline/redirfd.html">redirfd</a>
+command, which is part of the execline distribution. The
+<a href="http://www.skarnet.org/software/execline/redirfd.html">redirfd</a>
+command does just the right amount of trickery with FIFOs for you to be
+able to properly redirect process 1's stdout and stderr to the logging FIFO
+without blocking: <tt>redirfd -w 1 /service/s6-svscan-log/fifo</tt> blocks
+if there's no process reading on <tt>/service/s6-svscan-log/fifo</tt>, but
+<tt>redirfd -wnb 1 /service/s6-svscan-log/fifo</tt> <em>does not</em>.
+</p>
+
+<p>
+ This trick with FIFOs can even be used to avoid potential race conditions
+in the one-time initialization script that runs in stage 2. If forked from
+init-stage1 right before executing s6-svscan, depending on the scheduler
+mood, this script may actually run a long way before s6-svscan is actually
+executed and running the initial services - and may do dangerous things,
+such as writing messages to the logging FIFO before there's a reader, and
+eating a SIGPIPE and dying without completing the initialization. To avoid
+that and be sure that s6-svscan really runs and initial services are really
+started before the stage 2 init script is allowed to continue, it is possible
+to redirect the child script's output (stdout and/or stderr) <em>once again</em>
+to the logging FIFO, but in the normal way without redirfd trickery, before
+it execs into the init-stage2 script. So, the child process blocks on the
+FIFO until a reader appears, while process 1 - which does not block - execs
+into s6-svscan and starts the logging service, which then opens the logging
+FIFO for reading and unblocks the child process, which then runs the
+initialization tasks with the guarantee that s6-svscan is running.
+</p>
+
+<p>
+ It really is simpler than it sounds. :-)
+</p>
+
+<h2> A working example </h2>
+
+<p>
+ This whole page may sound very theoretical, dry, wordy, and hard to
+grasp without a live example to try things on; unfortunately, s6 cannot provide
+live examples without becoming system-specific. However, it provides a whole
+set of script skeletons for you to edit and make your own working init.
+</p>
+
+<p>
+ The <tt>examples/ROOT</tt> subdirectory in the s6 distribution contains
+the relevant parts of a small root filesystem that works under Linux and follows
+all that has been explained here. In every directory, a <tt>README</tt> file
+has been added, to sum up what this directory does. You can copy those files
+and modify them to suit your needs; if you have the proper software installed,
+and the right configuration, some of them might even work verbatim.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-svscan-not-1.html b/doc/s6-svscan-not-1.html
new file mode 100644
index 0000000..613ba3d
--- /dev/null
+++ b/doc/s6-svscan-not-1.html
@@ -0,0 +1,140 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: How to run s6-svscan under another init process</title>
+ <meta name="Description" content="s6: s6-svscan as not-init" />
+ <meta name="Keywords" content="s6 supervision svscan s6-svscan init process boot" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> How to run s6-svscan under another init process </h1>
+
+<p>
+ You can have a reliable supervision tree even if s6-svscan is not your process 1.
+The supervision tree just has to be <em>rooted</em> in process 1: that means that
+your process 1 will have to supervise your s6-svscan process somehow. That way,
+if s6-svscan dies, it will be restarted, and your set of services will always
+be maintained.
+</p>
+
+<p>
+ Be aware, though, that pipes between services and loggers are maintained
+by the s6-svscan process; if this process dies, the pipes will be closed and
+some logs may be lost.
+</p>
+
+<a name="log">
+<h2> Logging the supervision tree's output </h2>
+</a>
+
+<p>
+ s6-svscan and the various s6-supervise processes might produce error or
+warning messages; those messages are written to s6-svscan's stderr (which
+is inherited by the s6-supervise processes). To log these messages:
+</p>
+
+<ul>
+ <li> You can use your init system's logging tools, and make your init
+system launch s6-svscan as is; its stderr should already be taken care
+of by the logging tools. </li>
+ <li> You can use a trick similar to the <a href="s6-svscan-1.html#log">process
+1 output logging trick</a> so the supervision tree's messages are logged via
+a service that's maintained by the supervision tree itself. Then your init
+system should not launch s6-svscan directly, but a wrapper script that performs
+the proper redirections. The
+<tt>examples/s6-svscanboot</tt> file in the s6 distribution gives an example of
+such a script. Make sure that your initial <a href="scandir.html">scan
+directory</a> contains a <a href="servicedir.html">service directory</a> for your
+initial logging service, that must read on the logging FIFO. </li>
+</ul>
+
+<p>
+ In the following examples, we'll assume that <tt>/command/s6-svscanboot</tt>
+is the name of the script you are using to start s6-svscan. Adjust this accordingly.
+</p>
+
+<a name="sysv">
+<h2> System V init </h2>
+</a>
+
+<p>
+ Put an appropriate line in your <tt>/etc/inittab</tt> file, then reload this
+config file with <tt>telinit q</tt>.
+</p>
+
+<h3> Example </h3>
+
+<pre> SV:123456:respawn:/command/s6-svscanboot </pre>
+
+
+<a name="upstart">
+<h2> Upstart </h2>
+</a>
+
+<p>
+ Put an appropriate configuration file in the <tt>/etc/init</tt> folder,
+for instance <tt>/etc/init/s6-svscan.conf</tt>, then start the service
+with <tt>start s6-svscan</tt>.
+</p>
+
+<h3>Example </h3>
+
+<pre># s6-svscan
+start on runlevel [2345]
+stop on runlevel [!2345]
+
+oom never
+respawn
+exec /command/s6-svscanboot
+</pre>
+
+<a name="systemd">
+<h2> systemd </h2>
+
+<p>
+ systemd has
+<a href="http://www.freedesktop.org/software/systemd/man/daemon.html">its
+own way</a> of supervising services. If you are a systemd user, chances
+are you do not need s6. If you are interested in using s6, I encourage
+you to also stop using systemd.
+</p>
+
+<p>
+
+</p>
+
+<a name="bsd">
+<h2> BSD init </h2>
+</a>
+
+<p>
+ Put an appropriate line in your <tt>/etc/ttys</tt> file, then reload this
+file with <tt>kill -s HUP 1</tt>.
+</p>
+
+<h3> Example </h3>
+
+<pre> sv /command/s6-svscanboot "" on </pre>
+
+<a name="launchd">
+<h2> MacOS X launchd </h2>
+</a>
+
+<p>
+ Like systemd, launchd comes with its own
+<a href="https://developer.apple.com/library/mac/documentation/macosx/conceptual/bpsystemstartup/chapters/CreatingLaunchdJobs.html">way
+of supervising services</a>; if you are a launchd user, you probably do
+not need s6.
+</p>
+
+
+</body>
+</html>
diff --git a/doc/s6-svscan.html b/doc/s6-svscan.html
new file mode 100644
index 0000000..4a7e800
--- /dev/null
+++ b/doc/s6-svscan.html
@@ -0,0 +1,176 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-svscan program</title>
+ <meta name="Description" content="s6: the s6-svscan program" />
+ <meta name="Keywords" content="s6 command s6-svscan scandir supervision supervise svscan monitoring collection" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">www.skarnet.org</a>
+</p>
+
+<h1> The s6-svscan program </h1>
+
+<p>
+s6-svscan starts and monitors a collection of <a href="s6-supervise.html">s6-supervise</a>
+processes, each of these processes monitoring a single service. It is designed to be either
+the root or a branch of a <em>supervision tree</em>.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-svscan [ -c max ] [ -t <em>rescan</em> ] [ <em>scandir</em> ]
+</pre>
+
+<ul>
+ <li> If given a <em>scandir</em> argument, s6-svscan switches to it. Else it uses
+its current directory as <a href="scandir.html">scan directory</a>. </li>
+ <li> It exits 100 if another s6-svscan process is already monitoring this
+<a href="scandir.html">scan directory</a>. </li>
+ <li> If the <tt>./.s6-svscan</tt> control directory does not exist,
+s6-svscan creates it. However, it is recommended to already have a <tt>.s6-svscan</tt>
+subdirectory in your scan directory, because s6-svscan may try and execute into the
+<tt>.s6-svscan/crash</tt> or <tt>.s6-svscan/finish</tt> files at some point - so those
+files should exist and be executable. </li>
+ <li> From this point on, s6-svscan never dies. It tries its best to keep
+control of what's happening. In case of a major system call failure, which means
+that the kernel or hardware is broken in some fashion, it executes into the
+<tt>.s6-svscan/crash</tt> program. (But if that execution fails, s6-svscan exits
+111.) </li>
+ <li> s6-svscan performs an initial <em>scan</em> of its scan directory. </li>
+ <li> s6-svscan then occasionally runs <em>scans</em> or <em>reaps</em>,
+see below. </li>
+ <li> s6-svscan runs until it is told to stop via <a href="s6-svscanctl.html">
+s6-svscanctl</a>, or a signal.
+Then it executes into the <tt>.s6-svscan/finish</tt> program. The program is
+given an argument that depends on the s6-svscanctl options that were used. </li>
+ <li> If that execution fails, s6-svscan falls back on a <tt>.s6-svscan/crash</tt>
+execution. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <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>
+ <li> The higher <em>max</em> is, the more stack memory s6-svscan will use,
+approximately 50 bytes per service. </li>
+ <li> s6-svscan uses 2 file descriptors per logged service. </li>
+ </ul>
+ It is the admin's responsibility to make sure that s6-svscan has enough available
+descriptors to function properly and does not exceed its stack limit. The default
+of 500 is safe and provides enough room for every reasonable system. </li>
+ <li> <tt>-t&nbsp;<em>rescan</em></tt>&nbsp;: perform a scan every <em>rescan</em>
+milliseconds. If <em>rescan</em> is 0, automatic scans are never performed after
+the first one and s6-svscan will only detect new services when told to via a
+<a href="s6-svscanctl.html">s6-svscanctl -a</a> command. The default <em>rescan</em>
+value is 5000, for compatibility with daemontools'
+<a href="http://cr.yp.to/daemontools/svscan.html">svscan</a>, which performs a
+scan (and a reap) every 5 seconds. It is <em>strongly</em> discouraged to set
+<em>rescan</em> to a positive value under 500. </li>
+</ul>
+
+<h2> Signals </h2>
+
+<p>
+ s6-svscan reacts to the following signals:
+</p>
+
+<ul>
+ <li> SIGCHLD&nbsp;: triggers the reaper. </li>
+ <li> SIGALRM&nbsp;: triggers the scanner. </li>
+ <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 -i</tt> command had been received. </li>
+</ul>
+
+<h2> The reaper </h2>
+
+<p>
+ Upon receipt of a SIGCHLD, or a <a href="s6-svscanctl.html">s6-svscanctl -z</a>
+command, s6-svscan runs a <em>reaper</em> routine.
+</p>
+
+<p>
+The reaper acknowledges (via some
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html">wait()</a>
+function), without blocking, every terminated child of s6-svscan, even ones it does not
+know it has. This is especially important when <a href="s6-svscan-1.html">s6-svscan is
+run as process 1</a>.
+</p>
+
+<p>
+ If the dead child is a <a href="s6-supervise.html">s6-supervise</a> process watched
+by s6-svscan, and the last scan flagged that process as active, then it is restarted
+one second later.
+</p>
+
+<h2> The scanner </h2>
+
+<p>
+ Every <em>rescan</em> milliseconds, or upon receipt of a SIGALRM or a
+<a href="s6-svscanctl.html">s6-svscanctl -a</a> command, s6-svscan runs a
+<em>scanner</em> routine.
+</p>
+
+<p>
+ The scanner scans the current directory for subdirectories (or symbolic links
+to directories), which must be <a href="servicedir.html">service directories</a>.
+It skips names starting with dots. It will not create services for more than
+<em>max</em> subdirectories.
+</p>
+
+<p>
+ For every new subdirectory <em>dir</em> it finds, the scanner spawns a
+<a href="s6-supervise.html">s6-supervise</a> process on it. If
+<em>dir</em><tt>/log</tt> exists, it spawns a s6-supervise process on
+both <em>dir</em> and <em>dir</em><tt>/log</tt>, and maintains a
+never-closing pipe from the service's stdout to the logger's stdin.
+This is <em>starting the service</em>, with or without a corresponding
+logger.
+Every service the scanner finds is flagged as "active".
+</p>
+
+<p>
+ The scanner remembers the services it found. If a service has been
+started in an earlier scan, but the current scan can't find the corresponding
+directory, the service is then flagged as inactive. No command is sent
+to stop inactive s6-supervise processes (unless the administrator
+uses <a href="s6-svscanctl.html">s6-svscanctl -n</a>), but inactive
+s6-supervise processes will not be restarted if they die.
+</p>
+
+<h2> Implementation notes </h2>
+
+<ul>
+ <li> s6-svscan is designed to run until the machine is shut down. It is
+also designed as a suitable candidate for
+<a href="s6-svscan-1.html">process 1</a>. So, it goes out of its way to
+stay alive, even in dire situations. When it encounters a fatal situation,
+something it really cannot handle, it executes into <tt>.s6-svscan/crash</tt>
+instead of dying; when it is told to exit, it executes into
+<tt>.s6-svscan/finish</tt>. Administrators should make sure to design
+appropriate <tt>crash</tt> and <tt>finish</tt> routines. </li>
+ <li> s6-svscan is a fully asynchronous state machine. It will read and
+process commands at any time, even when the computer is in trouble. </li>
+ <li> s6-svscan <em>does not use malloc()</em>. That means it will <em>never leak
+memory</em>. <small>However, s6-svscan uses opendir(), and most opendir()
+implementations internally use heap memory - so unfortunately, it's impossible
+to guarantee that s6-svscan does not use heap memory at all.</small> </li>
+ <li> When run with the <tt>-t0</tt> option, s6-svscan <em>never polls</em>,
+it only wakes up on notifications, just like s6-supervise. The s6 supervision
+tree can be used in energy-critical environments. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-svscanctl.html b/doc/s6-svscanctl.html
new file mode 100644
index 0000000..cc7ae99
--- /dev/null
+++ b/doc/s6-svscanctl.html
@@ -0,0 +1,108 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-svscanctl program</title>
+ <meta name="Description" content="s6: the s6-svscanctl program" />
+ <meta name="Keywords" content="s6 command s6-svscanctl svscan command service" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-svscanctl program </h1>
+
+<p>
+s6-svscanctl sends commands to a running <a href="s6-svscan.html">s6-svscan</a>
+process.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-svscanctl [ -phratszbnNiq0678 ] <em>svscandir</em>
+</pre>
+
+<p>
+s6-svscanctl sends the given series of commands to the
+<a href="s6-svscan.html">s6-svscan</a> process monitoring the
+<em>svscandir</em> directory, then exits 0. It exits 111 if it cannot send
+a command, or 100 if no s6-svscan process is running on <em>svscandir</em>.
+</p>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-p</tt>&nbsp;: poweroff mode. s6-svscan will exec into
+ <tt>./.s6-svscan/finish poweroff</tt> when it is told to terminate. </li>
+ <li> <tt>-h</tt>&nbsp;: Hangup. s6-svscan will send a SIGHUP to all the
+maintained s6-supervise processes, then run its finish procedure. </li>
+ <li> <tt>-r</tt>&nbsp;: reboot mode. s6-svscan will exec into
+ <tt>./.s6-svscan/finish reboot</tt> when it is told to terminate. This
+is s6-svscan's default mode.</li>
+ <li> <tt>-a</tt>&nbsp;: Alarm. s6-svscan will immediately perform a scan
+of <em>svscandir</em> to check for services. </li>
+ <li> <tt>-t</tt>&nbsp;: Terminate. s6-svscan will send a
+SIGTERM to all the s6-supervise processes supervising a service and a
+SIGHUP to all the s6-supervise processes supervising a logger, then run its
+finish procedure. </li>
+ <li> <tt>-s</tt>&nbsp;: halt mode. s6-svscan will exec into
+ <tt>./.s6-svscan/finish halt</tt> when it is told to terminate. </li>
+ <li> <tt>-z</tt>&nbsp;: destroy zombies. Immediately triggers s6-svscan's
+reaper mechanism. </li>
+ <li> <tt>-b</tt>&nbsp;: abort. s6-svscan will exec into its finishing
+procedure. It will not kill any of the maintained s6-supervise processes. </li>
+ <li> <tt>-n</tt>&nbsp;: nuke. s6-svscan will kill all the
+s6-supervise processes it has launched but that did not match a service
+directory last time <em>svscandir</em> was scanned, i.e. it prunes the
+supervision tree so that it matches exactly what was in <em>svscandir</em>
+at the time of the last scan. A SIGTERM is sent to the s6-supervise processes
+supervising services and a SIGHUP is sent to the s6-supervise processes
+supervising loggers. </li>
+ <li> <tt>-N</tt>&nbsp;: Really nuke. Does the same thing as <tt>-n</tt>,
+except that SIGTERM is sent to all the relevant s6-supervise processes, even
+if they are supervising loggers. That means that the logger processes will
+be killed with a SIGTERM instead of being allowed to exit at their own pace. </li>
+ <li> <tt>-i</tt>&nbsp;: Interrupt. Equivalent to <tt>-rt</tt>&nbsp;: s6-svscan
+will terminate in reboot mode. </li>
+ <li> <tt>-q</tt>&nbsp;: Quit. s6-svscan will send all its s6-supervise processes
+a SIGTERM, then exec into its finish procedure. </li>
+ <li> <tt>-0</tt>&nbsp;: Halt. Equivalent to <tt>-st</tt>&nbsp;: s6-svscan will
+terminate in halt mode. </li>
+ <li> <tt>-6</tt>&nbsp;: Reboot. Equivalent to <tt>-i</tt>. </li>
+ <li> <tt>-7</tt>&nbsp;: Poweroff. Equivalent to <tt>-pt</tt>: s6-svscan will
+terminate in poweroff mode. </li>
+ <li> <tt>-8</tt>&nbsp;: Other. s6-svscan will terminate in "other" mode. </li>
+</ul>
+
+<h2> Usage examples </h2>
+
+<pre> s6-svscanctl -an /service </pre>
+<p>
+ Updates the process supervision tree
+to exactly match the services listed in <tt>/service</tt>.
+</p>
+
+<pre> s6-svscanctl -6 /service </pre>
+<p>
+ Orders the s6-svscan process monitoring <tt>/service</tt> to exit in
+reboot mode: all the supervision tree at <tt>/service</tt> will be terminated,
+and s6-svscan will execute into the <tt>/service/.s6-svscan/finish</tt>
+script with the <tt>reboot</tt> argument.
+</p>
+
+<h2> Internals </h2>
+
+<p>
+s6-svscanctl writes control commands into the <tt><em>svscandir</em>/.s6-svscan/control</tt>
+FIFO. A s6-svscan process running on <em>svscandir</em> will be listening to this FIFO,
+and will read and interpret those commands.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-svstat.html b/doc/s6-svstat.html
new file mode 100644
index 0000000..75ee7e2
--- /dev/null
+++ b/doc/s6-svstat.html
@@ -0,0 +1,45 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-svstat program</title>
+ <meta name="Description" content="s6: the s6-svstat program" />
+ <meta name="Keywords" content="s6 command s6-svstat servicedir checking supervision s6-supervise" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-svstat program </h1>
+
+<p>
+s6-svstat prints a short, human-readable summary of the state of a supervised
+service.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-svstat <em>servicedir</em>
+</pre>
+
+<p>
+ s6-svstat gives the following information about the process being monitored
+at the <em>servicedir</em> <a href="servicedir.html">service directory</a>, then
+exits 0:
+</p>
+
+<ul>
+ <li> whether it is up or down </li>
+ <li> its pid, if it is up </li>
+ <li> what its default state is, if it is different from its current state </li>
+ <li> the number of seconds since it last changed states </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-svwait.html b/doc/s6-svwait.html
new file mode 100644
index 0000000..6e15704
--- /dev/null
+++ b/doc/s6-svwait.html
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-svwait program</title>
+ <meta name="Description" content="s6: the s6-svwait program" />
+ <meta name="Keywords" content="s6 command s6-svwait notification service waiting" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-svwait program </h1>
+
+<p>
+s6-svwait blocks until a collection of supervised services goes up, or down.
+</p>
+
+<p>
+s6-svwait only waits for notifications; it never polls.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-svwait [ -U | -u | -d ] [ -a | -o ] [ -t <em>timeout</em> ] <em>servicedir...</em>
+</pre>
+
+<p>
+s6-svwait monitors one or more <a href="servicedir.html">service
+directories</a> given as its arguments, waiting for a state (up or down) to
+happen. It exits 0 when the wanted condition becomes true.
+</p>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-u</tt>&nbsp;: up. s6-svwait will wait until the services are up, as
+reported by s6-supervise.
+This is the default; it is not reliable, but it does not depend on specific
+support in the service programs. See <a href="notifywhenup.html">this page</a>
+for details. </li>
+ <li> <tt>-U</tt>&nbsp;: really up. s6-svwait will wait until the services are
+up, as reported by the services themselves. This requires specific support in the
+service programs: see the explanation on <a href="notifywhenup.html">this page</a>. </li>
+ <li> <tt>-d</tt>&nbsp;: down. s6-svwait will wait until the services are down. </li>
+ <li> <tt>-o</tt>&nbsp;: or. s6-svwait will wait until <em>one</em> of the
+given services comes up or down. </li>
+ <li> <tt>-a</tt>&nbsp;: and. s6-svwait will wait until <em>all</em> of the
+given services come up or down. This is the default. </li>
+ <li> <tt>-t <em>timeout</em></tt>&nbsp;: if the requested events have not
+happened after <em>timeout</em> milliseconds, s6-svwait will print a message
+to stderr and exit 1. By default, <em>timeout</em> is 0, which means no time
+limit. </li>
+</ul>
+
+
+<h2> Internals </h2>
+
+<p>
+s6-svwait spawns a <a href="s6-ftrigrd.html">s6-ftrigrd</a> child to
+listen to notifications sent by <a href="s6-supervise.html">s6-supervise</a>.
+It also checks <tt>supervise/status</tt> files to get the current service
+states, so it is immune to race conditions.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-tai64n.html b/doc/s6-tai64n.html
new file mode 100644
index 0000000..8b7f5e0
--- /dev/null
+++ b/doc/s6-tai64n.html
@@ -0,0 +1,50 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-tai64n program</title>
+ <meta name="Description" content="s6: the s6-tai64n program" />
+ <meta name="Keywords" content="s6 command s6-tai64n filter timestamp TAI64 TAI64N" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-tai64n program </h1>
+
+<p>
+s6-tai64n acts as a filter, reading from stdin and writing to stdout.
+It prepends lines with a
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html#timestamp">TAI64N
+timestamp</a> and a space.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-tai64n
+</pre>
+
+<ul>
+ <li> s6-tai64n exits 0 when it sees the end of stdin. If there's an
+unfinished line, s6-tai64n processes it, adds a newline character to it,
+and writes it before exiting. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<p>
+ s6-tai64n does neither "line buffering" nor "block buffering". It does
+<em>optimal buffering</em>, i.e. it flushes its output buffer every time
+it risks blocking on input. Every filter should behave this way, whether
+its output is a tty or not: it's simpler and more efficient in every
+case.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-tai64nlocal.html b/doc/s6-tai64nlocal.html
new file mode 100644
index 0000000..f6d2280
--- /dev/null
+++ b/doc/s6-tai64nlocal.html
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-tai64nlocal program</title>
+ <meta name="Description" content="s6: the s6-tai64nlocal program" />
+ <meta name="Keywords" content="s6 command s6-tai64nlocal filter timestamp TAI64 TAI64N human-readable date time" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-tai64nlocal program </h1>
+
+<p>
+s6-tai64nlocal acts as a filter, reading from stdin and writing to stdout.
+For every line that begins with a
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html#timestamp">TAI64N
+timestamp</a>, it replaces this timestamp with a human-readable local date and
+time.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-tai64nlocal
+</pre>
+
+<ul>
+ <li> s6-tai64nlocal exits 0 when it sees the end of stdin. If there's an
+unfinished line, s6-tai64n processes it
+and writes it before exiting. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> The typical use case of s6-tai64nlocal is to read files that have
+been filtered through <a href="s6-tai64n.html">s6-tai64n</a>, or log files
+that have been produced by <a href="s6-log.html">s6-log</a> with the <tt>-t</tt>
+option. For instance, to read the latest httpd logs with human-readable
+timestamps, <tt>s6-tai64nlocal &lt; /var/log/httpd/current | less</tt> is a
+possible command. </li>
+ <li> s6-tai64nlocal does neither "line buffering" nor "block buffering". It does
+<em>optimal buffering</em>, i.e. it flushes its output buffer every time
+it risks blocking on input. </li>
+</ul>
+
+<h2> Troubleshooting </h2>
+
+<p>
+ If s6-tai64nlocal does not appear to give the correct local time:
+</p>
+
+<ul>
+ <li> Check the compilation options that were used for the
+<a href="http://skarnet.org/software/skalibs/">skalibs</a> libraries
+your s6-tai64nlocal program was linked against. In particular, check whether the
+<tt>--enable-tai-clock</tt> or <tt>--enable-right-tz</tt> configure options
+have been given. </li>
+ <li> Compare these flags and their meanings with your current timezone. In particular,
+check <tt>/etc/localtime</tt>, <tt>/etc/timezone</tt>, <tt>/etc/TZ</tt>, and the TZ
+environment variable. </li>
+ <li> Check that you have a correct and recent version of <tt>/etc/leapsecs.dat</tt>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/scandir.html b/doc/scandir.html
new file mode 100644
index 0000000..366bd08
--- /dev/null
+++ b/doc/scandir.html
@@ -0,0 +1,145 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: scan directories</title>
+ <meta name="Description" content="s6: scan directory" />
+ <meta name="Keywords" content="s6 scandir supervision svscan s6-svscan scan directory servicedir" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Scan directories </h1>
+
+<p>
+ A <em>scan directory</em> is a directory containing a list of
+<a href="servicedir.html">service directories</a>, or symbolic links
+pointing to service directories.
+</p>
+
+<p>
+ A scan directory represents a list of services that are supposed to
+be supervised. Running <a href="s6-svscan.html">s6-svscan</a> on this
+scan directory launches a <em>supervision tree</em>: every service
+listed in the scan directory will be supervised.
+</p>
+
+<p>
+ There is normally only one scan directory per system, although nothing
+prevents a system administrator from having more.
+<a href="http://cr.yp.to/daemontools.html">daemontools</a> traditionally
+uses <tt>/service</tt>, and <a href="http://smarden.org/runit/">runit</a>
+traditionally uses <tt>/etc/service</tt>. s6 does not care where your
+scan directory is, but I would advise <tt>/service</tt> for compatibility
+with daemontools. Depending on your installation, <tt>/service</tt> could
+be a symbolic link and point to a place either in a RAM filesystem or in
+<tt>/var</tt>.
+</p>
+
+<a name="where">
+<h2> Where and how to build a scan directory </h2>
+</a>
+
+<p>
+ Opinions and practices differ.
+</p>
+
+<p>
+ It is generally accepted that the place where you store all your
+service directories (your "service repository") should <em>not</em> be
+used as a scan directory - for a simple reason: you might want to have
+service directories for more services than what you want to start at
+any given time. In other words, your scan directory will be a <em>subset</em>
+of your service repository, so you cannot just run s6-svscan on every
+service you have a service directory for. So, the first thing is to
+separate your <em>service repository</em>, which is just a storage place
+for all the services you might want to manage someday, and your <em>scan
+directory</em>, which is a directory representing all the services that
+you are <em>currently</em> managing.
+</p>
+
+<h3> Service repository </h3>
+
+<p>
+ Where to store your service repository is purely a matter of personal
+preference. You just have to be aware that <a href="s6-supervise.html">
+s6-supervise</a> needs writable <tt>supervise</tt> and <tt>event</tt>
+subdirectories in a service directory it monitors.
+</p>
+
+<h3> Scan directory </h3>
+
+<p>
+ Where and how to build your scan directory depends heavily on your boot
+system - and on your personal preference too.
+</p>
+
+<p>
+ Standard <a href="http://cr.yp.to/daemontools.html">daemontools</a> and
+<a href="http://smarden.org/runit/">runit</a> installations like to have
+a fixed scan directory containing symlinks to service directories located
+in the service repository. In other words, the service repository contains
+the real <em>working copies</em> of the service directories. This works,
+as long as:
+</p>
+
+<ul>
+ <li> It is possible to create writable <tt>supervise</tt> and <tt>event</tt>
+subdirectories in every managed service directory. This can be achieved for
+instance via symlinks, or by having the service repository stored on a writable
+filesystem. </li>
+ <li> The scan program (<a href="s6-svscan.html">s6-svscan</a>,
+<a href="http://cr.yp.to/daemontools/svscan.html">svscan</a>,
+<a href="http://smarden.org/runit/runsvdir.8.html">runsvdir</a>...) is
+started late enough for all the necessary filesystems to be mounted. </li>
+</ul>
+
+<p>
+ My own recommendation would be to have working copies of the service
+directories <em>entirely separate</em> from the service repository. The
+service repository can be safely stored on the root filesystem, and the
+needed directories copied to a RAM filesystem at boot time. The scan
+directory can be either the place where the working copies are written,
+or another directory containing symlinks to those working copies. (The
+latter is useful if you are not using <tt>s6-svscan -t0</tt>: copying a
+directory is not atomic, but making a symlink is, so there is no risk
+of your scanner finding an incomplete directory.)
+</p>
+
+<p>
+ An example:
+</p>
+
+<ul>
+ <li> Have your service repository in <tt>/img/services</tt>, i.e. have
+service directories in <tt>/img/services/ftpd</tt>, <tt>/img/services/httpd</tt>,
+<tt>/img/services/sshd</tt>, etc. </li>
+ <li> When booting, make <tt>/tmp</tt> a RAM filesystem, and create the
+directories <tt>/tmp/services</tt> and <tt>/tmp/service</tt>. </li>
+ <li> Have s6-svscan run on <tt>/tmp/service</tt>, as early as possible in your
+boot sequence. This is possible whether you want to run s6-svscan
+<a href="s6-svscan-1.html">as process 1</a> or <a href="s6-svscan-not-1.html">not</a>. </li>
+ <li> During the boot sequence, populate <tt>/tmp/services</tt> with copies of the
+service directories you need: for instance,
+ <ul>
+ <li> <tt>cp -a /img/services/sshd /tmp/services/sshd</tt> </li>
+ <li> <tt>cp -a /img/services/ftpd /tmp/services/ftpd</tt> </li>
+ <li> etc. </li>
+ </ul> </li>
+ <li> When you are ready to start a service, make a symlink in the
+<tt>/tmp/service</tt> <em>scan directory</em> pointing to the working copy of
+the service directory you need in <tt>/tmp/services</tt>, then notify s6-svscan.
+For instance, to start ftpd and httpd together:
+<pre> ln -s ../services/ftpd /tmp/service
+ ln -s ../services/httpd /tmp/service
+ s6-svscanctl -a /tmp/service</pre> </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/servicedir.html b/doc/servicedir.html
new file mode 100644
index 0000000..b5c4d23
--- /dev/null
+++ b/doc/servicedir.html
@@ -0,0 +1,187 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: service directories</title>
+ <meta name="Description" content="s6: service directory" />
+ <meta name="Keywords" content="s6 supervision supervise service directory run finish servicedir" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Service directories </h1>
+
+<p>
+ A <em>service directory</em> is a directory containing all the information
+related to a <em>service</em>, i.e. a long-running process maintained and
+supervised by <a href="s6-supervise.html">s6-supervise</a>.
+</p>
+
+<p>
+ (Strictly speaking, a <em>service</em> is not always equivalent to a
+long-running process. Things like Ethernet interfaces fit the definition
+of <em>services</em> one may want to supervise; however, s6 does not
+provide <em>service supervision</em>; it provides <em>process supervision</em>,
+and it is impractical to use the s6 architecture as is to supervise
+services that are not equivalent to one long-running process. However,
+we still use the terms <em>service</em> and <em>service directory</em>
+for historical and compatibility reasons.)
+</p>
+
+<h2> Contents </h2>
+
+ A service directory <em>foo</em> may contain the following elements:
+
+<ul>
+ <li> An executable file named <tt>run</tt>. It can be any executable
+file (such as a binary file or a link to any other executable file),
+but most of the time it will be a script, called <em>run script</em>.
+This file is the most important one in your service directory: it
+contains the commands that will setup and run your <em>foo</em> service.
+It is forked and executed by <a href="s6-supervise.html">s6-supervise</a>
+every time the service must be started, i.e. normally when
+<a href="s6-supervise.html">s6-supervise</a> starts, and whenever
+the service goes down when it is supposed to be up. A run script
+should normally:
+ <ul>
+ <li> adjust redirections for stdin, stdout and stderr. For instance,
+if your service is logged, the run script should make sure that its
+stderr goes into the log pipe (which is on stdout by default), which
+is achieved by <tt><a href="http://skarnet.org/software/execline/fdmove.html">fdmove</a>
+-c 2 1</tt> in <a href="http://skarnet.org/software/execline/">execline</a>,
+and <tt>exec 2>&1</tt> in <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html">shell</a>.
+By default, in a normal supervision tree situation, a run script's stdin will
+be <tt>/dev/null</tt>, and its stdout and stderr will both be a pipe to a
+catch-all logging program. </li>
+<li> adjust the environment for your <em>foo</em> daemon. Normally the run script
+inherits its environment from <a href="s6-supervise.html">s6-supervise</a>,
+which normally inherits its environment from <a href="s6-svscan.html">s6-svscan</a>,
+which normally inherits a minimal environment from the boot scripts.
+Service-specific environment variables should be set in the run script. </li>
+ <li> adjust other parameters for the <em>foo</em> daemon, such as its
+uid and gid. Normally the supervision tree, i.e.
+<a href="s6-svscan.html">s6-svscan</a> and the various
+<a href="s6-supervise.html">s6-supervise</a> processes, is run as root, so
+run scripts are also run as root; however, for security purposes, services
+should not run as root if they don't need to. You can use the
+<a href="s6-setuidgid.html">s6-setuidgid</a> utility in <em>foo</em><tt>/run</tt>
+to lose privileges before executing into <em>foo</em>'s long-lived
+process; or the <a href="s6-envuidgid.html">s6-envuidgid</a> utility if
+your long-lived process needs root privileges at start time but can drop
+them afterwards. </li>
+ <li> execute into the long-lived process that is to be supervised by
+<a href="s6-supervise.html">s6-supervise</a>, i.e. the real <em>foo</em>
+daemon. That process must not "background itself": being run by a supervision
+tree already makes it a "background" task. </li>
+ </ul>
+ <li> An optional executable file named <tt>finish</tt>. Like <tt>run</tt>,
+it can be any executable file. This <em>finish script</em>, if present,
+is executed everytime the <tt>run</tt> script dies. Generally, its main
+purpose is to clean up non-volatile data such as the filesystem after the supervised
+process has been killed. If the <em>foo</em> service is supposed to be up,
+<em>foo</em><tt>/run</tt> is restarted
+after <em>foo</em><tt>/finish</tt> dies. A finish script must do its work and exit in less than
+3 seconds; if it takes more than that, it is killed. (The point is that the run
+script, not the finish script, should be running; the finish script should really
+be short-lived.) </li>
+ <li> A directory named <tt>supervise</tt>. It is automatically created by
+<a href="s6-supervise.html">s6-supervise</a> if it does not exist. This is where
+<a href="s6-supervise.html">s6-supervise</a> stores its information. The directory
+must be writable. </li>
+ <li> An optional, empty, regular file named <tt>down</tt>. If such a file exists,
+the default state of the service is considered down, not up: s6-supervise will not
+automatically start it until it receives a <tt>s6-svc -u</tt> command. If no
+<tt>down</tt> file exists, the default state of the service is up. </li>
+ <li> An optional, empty, regular file named <tt>nosetsid</tt>. If such a file exists,
+s6-supervise will not make the service a process group and session leader; the service
+will be run in the same process group as s6-supervise. If no <tt>nosetsid</tt> file
+exists, the service has its own process group and is started as a session leader. </li>
+ <li> A <a href="fifodir.html">fifodir</a> named <tt>event</tt>. It is automatically
+created by <a href="s6-supervise.html">s6-supervise</a> if it does not exist.
+<em>foo</em><tt>/event</tt>
+is the rendez-vous point for listeners, where <a href="s6-supervise.html">s6-supervise</a>
+will send notifications when the service goes up or down. </li>
+ <li> An optional service directory named <tt>log</tt>. If it exists and <em>foo</em>
+is in a <a href="scandir.html">scandir</a>, and <a href="s6-svscan.html">s6-svscan</a>
+runs on that scandir, then <em>two</em> services are monitored: <em>foo</em> and
+<em>foo</em><tt>/log</tt>. A pipe is open and maintained between <em>foo</em> and
+<em>foo</em><tt>/log</tt>, i.e. everything that <em>foo</em><tt>/run</tt>
+writes to its stdout will appear on <em>foo</em><tt>/log/run</tt>'s stdin. The <em>foo</em>
+service is said to be <em>logged</em>; the <em>foo</em><tt>/log</tt> service is called
+<em>foo</em>'s <em>logger</em>. A logger service cannot be logged: if
+<em>foo</em><tt>/log/log</tt> exists, nothing special happens. </li>
+</ul>
+
+<a name="where">
+ <h2> Where to store my service directories&nbsp;? </h2>
+</a>
+
+<p>
+ Service directories describe the way services are launched. Once they are
+designed, they have little reason to change on a given machine. They can
+theoretically reside on a read-only filesystem - for instance, the root
+filesystem, to avoid problems with mounting failures.
+</p>
+
+<p>
+ However, two subdirectories - namely <tt>supervise</tt> and <tt>event</tt> -
+of every service directory need to be writable. So it has to be a bit more
+complex. Here are a few possibilities.
+</p>
+
+<ul>
+ <li> The laziest option: you're not using <a href="s6-svscan.html">s6-svscan</a>
+as process 1, you're only using it to start a collection of services, and
+your booting process is already handled by another init system. Then you can
+just store your service directories and your <a href="scandir.html">scan
+directory</a> on some read-write filesystem such as <tt>/var</tt>; and you
+tell your init system to launch (and, if possible, maintain) s6-svscan on
+the scan directory after that filesystem is mounted. </li>
+ <li> The almost-as-lazy option: just have the service directories on the
+root filesystem. Then your service directory collection is for instance in
+<tt>/etc/services</tt> and you have a <tt>/service</tt>
+<a href="scandir.html">scan directory</a> containing symlinks to that
+collection. This is the easy setup, not requiring an external init system
+to mount your filesystems - however, it requires your root filesystem to be
+read-write, which is unacceptable if you are concerned with reliability - if
+you are, for instance, designing an embedded platform. </li>
+ <li> <a href="http://code.dogmap.org/">Some people</a> like to have
+their service directories in a read-only filesystem, with <tt>supervise</tt>
+symlinks pointing to various places in writable filesystems. This setup looks
+a bit complex to me: it requires careful handling of the writable
+filesystems, with not much room for error if the directory structure does not
+match the symlinks (which are then dangling). But it works. </li>
+ <li> Service directories are usually small; most daemons store their
+information elsewhere. Even a complete set of service directories often
+amounts to less than a megabyte of data - sometimes much less. Knowing this,
+it makes sense to have an image of your service directories in the
+(possibly read-only) root filesystem, and <em>copy it all</em>
+to a scan directory located on a RAM filesystem that is mounted at boot time.
+This is the setup I recommend. It has several advantages:
+ <ul>
+ <li> Your service directories reside on the root filesystem and are not
+modified during the lifetime of the system. If your root filesystem is
+read-only and you have a working set of service directories, you have the
+guarantee that a reboot will set your system in a working state. </li>
+ <li> Every boot system requires an early writeable filesystem, and many
+create it in RAM. You can take advantage of this to copy your service
+directories early and run s6-svscan early. </li>
+ <li> No dangling symlinks or potential problems with unmounted
+filesystems: this setup is robust. A simple <tt>/bin/cp -a</tt> or
+<tt>tar -x</tt> is all it takes to get a working service infrastructure. </li>
+ <li> You can make temporary modifications to your service directories
+without affecting the main ones, safely stored on the disk. Conversely,
+every boot ensures clean service directories - including freshly created
+<tt>supervise</tt> and <tt>event</tt> subdirectories. No stale files can
+make your system unstable. </li>
+ </ul> </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/systemd.html b/doc/systemd.html
new file mode 100644
index 0000000..49ba2aa
--- /dev/null
+++ b/doc/systemd.html
@@ -0,0 +1,120 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: a word about systemd</title>
+ <meta name="Description" content="s6: a word about systemd" />
+ <meta name="Keywords" content="s6 supervision init systemd" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> A word about systemd </h1>
+
+<p>
+ <a href="http://www.freedesktop.org/wiki/Software/systemd/">systemd</a>
+is becoming <i>de facto</i> a standard init system for Linux. But even
+this choice of words is treacherous, because systemd is much more than
+an init system. It's basically an integrated redesign of all the low-level
+userspace of a Linux system, with great plans to change how software is
+run and organized.
+
+<p>
+ Which is not a bad thing per se: Unix software can definitely benefit
+from improvements in this area, and the s6 suite, among other software,
+comes from the same assessment and ultimately has the same goal. But
+systemd suffers from a single conception flaw that sets it apart from
+the other initiatives, and that has both political and technical
+repercussions.
+</p>
+
+<p>
+<strong>
+ The single, overarching problem with systemd is that it attempts, in every
+possible way, to do <em>more</em> instead of <em>less</em>.
+</strong>
+</p>
+
+<h2> The political issue </h2>
+
+<p>
+ systemd attempts to cover <em>more</em> ground instead of <em>less</em>.
+In other words, rather than simply being an init system, it tries to be
+a complete overhaul of the way a Linux system is run, and tries to force
+other software to hook with it in order to be supported. This goes very
+much against:
+</p>
+
+<ul>
+ <li> The Unix philosophy, which is to do one job and do it well; </li>
+ <li> The <a href="http://www.catb.org/esr/writings/cathedral-bazaar/">bazaar</a>
+approach that has made the free software ecosystem what it is today; </li>
+ <li> Cross-platform compatibility. BSD is not dead, Solaris is not dead,
+but systemd ignores Unix. It even ignores Linux to some extent: the systemd
+authors had the guts to ask for specific kernel interfaces! </li>
+</ul>
+
+<p>
+ The reason why systemd has become so prevalent is not that it has been
+accepted by the community. It's that it has manpower. It is backed up by
+open source software companies that can provide much more manpower than
+developers like myself working on free software on their own time. The
+distribution model of systemd, made of lobbying and bullying, is much more
+akin to the distribution model of Microsoft Windows than the one of GNU/Linux.
+</p>
+
+<p>
+ Which says something.
+</p>
+
+<h2> The technical issue </h2>
+
+<p>
+ Software that does <em>more</em> instead of <em>less</em> is, simply put,
+badly designed software. Trying to come up with an all-encompassing solution
+is always a sign of developer hubris and inexperience, and never a sign of
+good engineering. Ever. Remember sendmail, BIND, INN, and, definitely a better
+analogy, the early days of Microsoft Windows&nbsp;? Yes, systemd is in
+exactly the same league. It's as if we had learned <em>nothing</em> from the
+mistakes of the past 20 years. Technically as well as politically, systemd
+is actually very close to Windows; is that the future we want for Linux
+machines&nbsp?
+</p>
+
+<p>
+ Doing more instead of less is bad, and it's especially true in the case of
+system software, i.e. low-level software that
+aims to make the machine work and that application software depends upon.
+The goal of an operating system is to make it possible to run <em>applications</em>,
+and system software should always partake in that goal. <strong>System software
+should stay the heck out of the way</strong>, and systemd is big, loud and
+obnoxious. Embedded devices are common, and will become even more common in
+the future; that is a market that systemd will have trouble breaking into, because
+it's a lot more complex than embedded devices need. And that, too, says something:
+if a software suite is too complex for an embedded device, maybe it's just too
+complex, period.
+</p>
+
+<h2> Links </h2>
+
+<ul>
+ <li> <a href="http://freedesktop.org/wiki/Software/systemd/">systemd's home page</a> </li>
+ <li> <a href="http://uselessd.darknedgy.net/ProSystemdAntiSystemd/">An analysis of
+the vacuity of most Internet arguments about systemd</a>, by the author of
+<a href="http://uselessd.darknedgy.net/">uselessd</a>. </li>
+ <li> <a href="http://boycottsystemd.org">boycottsystemd.org</a>, summarizing
+political arguments against systemd </li>
+ <li> <a href="http://ewontfix.com/14/">Technical arguments against systemd</a>,
+by Rich Felker, main author of <a href="http://musl-libc.org/">musl</a> </li>
+ <li> <a href="http://judecnelson.blogspot.fr/2014/09/systemd-biggest-fallacies.html">A
+list of fallacies about systemd, with debunk</a> </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/ucspilogd.html b/doc/ucspilogd.html
new file mode 100644
index 0000000..1b06335
--- /dev/null
+++ b/doc/ucspilogd.html
@@ -0,0 +1,94 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the ucspilogd program</title>
+ <meta name="Description" content="s6: the ucspilogd program" />
+ <meta name="Keywords" content="s6 command ucspilogd log logging UCSPI" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>ucspilogd</tt> program </h1>
+
+<p>
+ <tt>ucspilogd</tt> acts as a filter, converting syslog facility
+numbers and alert levels into names.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ ucspilogd [ <em>var</em> ... ]
+</pre>
+
+<ul>
+ <li> ucspilogd reads a stream of syslog-like messages on stdin.
+Those messages can be newline-terminated or null-terminated. </li>
+ <li> For every line it reads: if it has been given <em>var</em>
+arguments, it writes the value of every <em>var</em> environment
+variable, followed by a colon and a space. </li>
+ <li> If the line begins with a syslog facility number and/or
+alert level in the syslog format, it converts them into a
+human-readable name in the syslogd fashion. </li>
+ <li> It then writes the processed line to stdout. </li>
+</ul>
+
+<h2> Common use </h2>
+
+<p>
+ You can emulate the whole <em>syslogd</em> behaviour by combining the following
+components:
+</p>
+
+<ul>
+ <li> A Unix stream super-server such as
+<a href="http://skarnet.org/software/s6-networking/s6-ipcserver.html">s6-ipcserver</a>
+listening to the Unix domain socket <tt>/dev/log</tt>, to connect to
+the kernel log-reading interface. </li>
+ <li> <tt>ucspilogd</tt> running under that super-server, to read the
+logs and perform adequate transformations. </li>
+ <li> A logger such as
+<a href="s6-log.html">s6-log</a>
+to store the logs into the filesystem. </li>
+ <li> A supervision mechanism such as s6,
+to ensure ease of use and reliability of the whole chain. </li>
+</ul>
+
+<p>
+ The resulting suite of programs is still smaller, and way more reliable,
+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
+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>
+language.
+</p>
+
+<h2> Using <tt>ucspilogd</tt> as a <em>klogd</em> replacement </h2>
+
+<p>
+ Certain Unix kernels offer a nice interface to the kernel logs.
+For instance, the Linux kernel provides the <tt>/proc/kmsg</tt> fake
+file, that can be opened and read like a normal file, excepts that
+it gives the kernel logs when they are available and blocks otherwise.
+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
+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>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
new file mode 100644
index 0000000..1a35178
--- /dev/null
+++ b/doc/upgrade.html
@@ -0,0 +1,32 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>How to upgrade s6</title>
+ <meta name="Description" content="How to upgrade s6" />
+ <meta name="Keywords" content="s6 installation upgrade" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> How to upgrade s6 </h1>
+
+<h2> to 2.0.0.0 </h2>
+
+<ul>
+ <li> The build system has completely changed. It is now a standard
+<tt>./configure &amp;&amp; make &amp;&amp; sudo make install</tt>
+build system. See the enclosed INSTALL file for details. </li>
+ <li> slashpackage is not activated by default. </li>
+ <li> shared libraries are not used by default. </li>
+ <li> skalibs dependency bumped to 2.0.0.0 </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/why.html b/doc/why.html
new file mode 100644
index 0000000..1901259
--- /dev/null
+++ b/doc/why.html
@@ -0,0 +1,203 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: why another supervision suite</title>
+ <meta name="Description" content="s6: why another supervision suite" />
+ <meta name="Keywords" content="s6 supervision daemontools runit perp service svscan supervise" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Why another supervision suite ? </h1>
+
+<p>
+ Supervision suites are becoming quite common. Today, we already have:
+</p>
+
+<ul>
+ <li> Good (?) old System V init, which can be made to supervise services if you perform <tt>/etc/inittab</tt> voodoo.
+BSD init can also be used the same way with the <tt>/etc/ttys</tt> file, but for some reason, nobody among BSD
+developers is using <tt>/etc/ttys</tt> to this purpose, so I won't consider BSD init here. </li>
+ <li> <a href="http://cr.yp.to/daemontools.html">daemontools</a>, the pioneer </li>
+ <li> <a href="http://untroubled.org/daemontools-encore/">daemontools-encore</a>, Bruce Guenter's upgrade to daemontools </li>
+ <li> <a href="http://smarden.org/runit/">runit</a>, Gerrit Pape's suite, well-integrated with Debian </li>
+ <li> <a href="http://b0llix.net/perp/">perp</a>, Wayne Marshall's take on supervision </li>
+ <li> Integrated init systems providing a lot of features, process supervision being one of them.
+For instance, <a href="http://upstart.ubuntu.com/">Upstart</a>, MacOS X's
+<a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man8/launchd.8.html">launchd</a>,
+and Fedora's <a href="http://freedesktop.org/wiki/Software/systemd">systemd</a>. </li>
+</ul>
+
+<p>
+ Why is s6 needed ? What does it do differently ? Here are the criteria I used.
+</p>
+
+
+<h2> Supervision suites should not wake up unless notified. </h2>
+
+<ul>
+ <li> System V init fails the test: it wakes up every 5 seconds, for the reason that
+<tt>/dev/initctl</tt> might have changed.
+<a href="http://demotivate.me/mediafiles/full/4162010103911AM_picard-no-facepalm.jpg"><tt>m(</tt></a> </li>
+ <li> daemontools fails the test: it wakes up every 5 seconds to check for new services. </li>
+ <li> daemontools-encore does the same. </li>
+ <li> the current version of runit fails the test: it wakes up every 14 seconds. But this is a workaround for a bug in some Linux kernels;
+there is no design flaw in runit that prevents it from passing the test. </li>
+ <li> perp works. </li>
+ <li> Upstart works. I have no idea what other integrated init systems do: it's much too difficult to strace them
+to see exactly where they're spending their time, and when it is possible, the trace output is so big that it's
+hard to extract any valuable information from it. </li>
+ <li> s6 works. By default, s6-svscan wakes up every 5 seconds, to emulate
+<a href="http://cr.yp.to/daemontools/svscan.html">svscan</a> behaviour; but it
+can be told not to do so. (<tt>s6-svscan -t0</tt>) </li>
+</ul>
+
+
+<h2> Supervision suites should provide a program that can run as process 1. </h2>
+
+<ul>
+ <li> System V init <em>is</em> process 1, so no problem here. </li>
+ <li> Integrated init systems, by definition, provide a process 1. </li>
+ <li> daemontools was not designed to take over init, although
+<a href="http://code.dogmap.org./svscan-1/">it can be made to work</a> with
+enough hacking skills. Same thing with daemontools-encore. </li>
+ <li> runit provides an <em>init</em> functionality, but the mechanism is
+separate from the supervision itself; the <tt>runit</tt> process, not the
+<tt>runsvdir</tt> process, runs as process 1. This lengthens the supervision
+chain. </li>
+ <li> perp was not designed to run as process 1. It probably could be made to work too
+without too much trouble. </li>
+ <li> s6-svscan was designed from the start to be run as process 1, although it
+does not have to. </li>
+</ul>
+
+
+<h2> Supervision suites should be bug-free, lightweight and easy to understand. </h2>
+
+<ul>
+ <li> daemontools, daemontools-encore, runit and perp all qualify. All of this is excellent quality
+code, <a href="http://skarnet.org/software/skalibs/djblegacy.html">unsurprisingly</a>. </li>
+ <li> System V init is understandable, and reasonably lightweight; but it is still
+too big for what it does - poorly. The <tt>/etc/inittab</tt> file needs to be parsed;
+that parser has to be in process 1. There is support in process 1 for the whole
+"runlevel" concept, which is a primitive form of service management. The same
+executable handles all 3 stages of the machine's lifetime and does not separate
+them properly. All in all, System V init does its job, but is showing its age
+and nowadays we know much better designs. </li>
+ <li> This is where integrated init systems fail, hard. By wanting to organize
+the way a the machine is operated - so, machine state management - in the
+<em>same package</em> as the init and process supervision system, they add
+incredible complexity where it does not belong.
+ <ul>
+ <li> Upstart uses <tt>ptrace</tt> to watch its children fork(), and links
+process 1 against libdbus. This is insane.
+Process 1 should be <em>absolutely stable</em>, it should be guaranteed
+to never crash, so the whole of its source code should be under control. At
+Upstart's level of complexity, those goals are outright impossible to achieve,
+so this approach is flawed by design. </li>
+ <li> launchd suffers from the same kind of problem. Regardless of how
+things are actually implemented inside (which I have no idea about), services
+running under launchd must be configured
+<a href="https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html">using
+XML</a>. That means there is an XML parser in process 1.
+<a href="https://software.intel.com/sites/default/files/race.jpg">What
+could possibly go wrong&nbsp;?</a> </li>
+ <li> systemd is much, much worse than the other ones, and a real danger
+for the future of GNU/Linux. I have a <a href="systemd.html">special page</a>
+dedicated to it. </li>
+ </ul>
+ What those systems fail to recognize is that process supervision, rooted in
+process 1, is a good thing, and machine management is also a good thing, but
+<strong>those are two different functions</strong>, and a good init system
+needs, and <strong>should</strong>, only provide process supervision, in
+order to keep such a crucial piece of code as easy to maintain as possible.
+Machine management can be added <em>on top of</em> a process supervision
+suite, in a different package, and it has nothing to do with process 1. </li>
+ <li> s6, which has been designed with embedded environments in mind, tries
+harder than anyone to pass this. It tries so hard that <tt>s6-svscan</tt>
+and <tt>s6-supervise</tt>, the two long-running programs that make the
+supervision chain, <em>do not even allocate heap memory</em>, and their main
+program source files are less than 500 lines long. </li>
+</ul>
+
+
+<h2> Supervision suites should provide a basis for high-level service management. </h2>
+
+<ul>
+ <li> Neither System V init, daemontools, runit or perp
+provides any hooks to wait for a service to go up or down. runit provides a
+waiting mechanism, but it's based on polling, and the <tt>./check</tt> script
+has to be manually written for every service. </li>
+ <li> daemontools-encore qualifies: the <em>notify script</em> can be used for
+inter-service communication. But it's just a hook: all the real notification
+work has to be done by the notify script itself, no notification framework is
+provided. </li>
+ <li> Integrated init systems provide high-level service management
+themselves. Again, this is not good design: service management has nothing
+to do with init or process supervision, and should be implemented on top
+of it, not as a part of it. </li>
+ <li> s6 comes with <a href="libftrig.html">libftrig</a>, an event notification
+library, and command-line tools based on this library, thus providing a simple
+API for future service management tools to build upon. </li>
+</ul>
+
+
+<h2> Artistic considerations </h2>
+
+<ul>
+ <li> <tt>s6-svscan</tt> and <tt>s6-supervise</tt> are <em>entirely asynchronous</em>.
+Even during trouble (full process table, for instance), they'll remain reactive
+and instantly respond to commands they may receive. <tt>s6-supervise</tt> has
+even been implemented as a full deterministic finite automaton, to ensure it
+always does the right thing under any circumstance. Other supervision suites
+do not achieve that for now. </li>
+ <li> daemontools' <a href="http://cr.yp.to/daemontools/svscan.html">svscan</a>
+maintains an open pipe between a daemon and its logger, so even if the daemon,
+the logger, <em>and</em> both
+<a href="http://cr.yp.to/daemontools/supervise.html">supervise</a> processes
+die, the pipe is still the same so <em>no logs are lost, ever</em>, unless
+svscan itself dies. </li>
+ <li> runit has only one supervisor, <a href="http://smarden.org/runit/runsv.8.html">runsv</a>,
+for both a daemon and its logger. The pipe is maintained by <tt>runsv</tt>.
+If the <tt>runsv</tt> process dies, the pipe disappears and logs are lost.
+So, runit does not offer as strong a guarantee as daemontools. </li>
+ <li> perp has only one process, <a href="http://b0llix.net/perp/site.cgi?page=perpd.8">perpd</a>,
+acting both as a "daemon and logger supervisor" (like <tt>runsv</tt>) and as a
+"service directory scanner" (like <tt>runsvdir</tt>). It maintains the pipes
+between the daemons and their respective loggers. If perpd dies, everything
+is lost. Since perpd cannot be run as process 1, this is a possible SPOF for
+a perp installation; however, perpd is well-written and has virtually no risk of
+dying, especially compared to process 1 behemoths provided by integrated
+init systems. </li>
+ <li> Besides, the <tt>runsv</tt> model, which has to handle both a daemon
+and its logger, is more complex than the <tt>supervise</tt> model (which
+only has to handle a daemon). Consequently, the <tt>runsvdir</tt> model is
+simpler than the <tt>svscan</tt> model, but there is only one <tt>svscan</tt>
+instance when there are several <tt>runsv</tt>s and <tt>supervise</tt>s.
+The <tt>perpd</tt> model is obviously the most complex; while very understandable,
+<tt>perpd</tt> is unarguably harder to maintain than the other two. </li>
+ <li> So, to achieve maximum simplicity and code reuse, and minimal memory
+footprint, s6's design is close to daemontools' one.
+And when <a href="s6-svscan-1.html">s6-svscan is run as process 1</a>,
+pipes between daemons and loggers are never lost. </li>
+</ul>
+
+
+<h2> Conclusion </h2>
+
+<p>
+ All in all, I believe that s6 offers the best overall implementation of a
+supervision suite <em>as it should be designed</em>. At worst, it's just another
+take on daemontools with a <a href="http://skarnet.org/software/skalibs/">reliable
+base library</a> and a few nifty features.
+</p>
+
+</body>
+</html>