summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2015-01-26 22:26:57 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2015-01-26 22:26:57 +0000
commit8bffa1c19fd05f4f04dad4b5b98f85b94f23113c (patch)
treef4e25c3cdb7118db02a06c85b7862107a2074ba4
parent49cb17940e403431566dc7b5a312624f14eb25d0 (diff)
downloads6-8bffa1c19fd05f4f04dad4b5b98f85b94f23113c.tar.xz
- added s6-fdholder-delete(c)
- small s6-fdholder-* fixes - s6-fdholder documentation (in review) - s6_svstatus_* bugfix (thanks Olivier Brunel)
-rw-r--r--doc/index.html104
-rw-r--r--doc/libs6/ftrigr.html3
-rw-r--r--doc/libs6/index.html6
-rw-r--r--doc/libs6/s6-fdholder.html207
-rw-r--r--doc/s6-fdholder-daemon.html147
-rw-r--r--doc/s6-fdholder-delete.html71
-rw-r--r--doc/s6-fdholder-deletec.html63
-rw-r--r--doc/s6-fdholder-errorcodes.html72
-rw-r--r--doc/s6-fdholder-getdump.html92
-rw-r--r--doc/s6-fdholder-getdumpc.html91
-rw-r--r--doc/s6-fdholder-list.html51
-rw-r--r--doc/s6-fdholder-listc.html68
-rw-r--r--doc/s6-fdholder-retrieve.html98
-rw-r--r--doc/s6-fdholder-retrievec.html68
-rw-r--r--doc/s6-fdholder-setdump.html66
-rw-r--r--doc/s6-fdholder-setdumpc.html62
-rw-r--r--doc/s6-fdholder-store.html80
-rw-r--r--doc/s6-fdholder-storec.html68
-rw-r--r--doc/s6-fdholder-transferdump.html58
-rw-r--r--doc/s6-fdholder-transferdumpc.html82
-rw-r--r--doc/s6-fdholderd.html318
-rw-r--r--doc/s6-ipcserver.html25
-rw-r--r--doc/s6-notifywhenup.html4
-rw-r--r--doc/s6-svlisten.html4
-rw-r--r--doc/s6-svlisten1.html2
-rw-r--r--package/deps.mak4
-rw-r--r--package/modes2
-rw-r--r--package/targets.mak2
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-delete1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-deletec4
-rw-r--r--src/fdholder/s6-fdholder-delete.c51
-rw-r--r--src/fdholder/s6-fdholder-deletec.c42
-rw-r--r--src/fdholder/s6-fdholder-getdumpc.c8
-rw-r--r--src/fdholder/s6-fdholder-listc.c2
-rw-r--r--src/fdholder/s6-fdholder-retrievec.c2
-rw-r--r--src/fdholder/s6-fdholder-setdumpc.c2
-rw-r--r--src/fdholder/s6-fdholder-storec.c2
-rw-r--r--src/fdholder/s6-fdholder-transferdumpc.c4
-rw-r--r--src/fdholder/s6-fdholderd.c8
-rw-r--r--src/include/s6/s6-fdholder.h2
-rw-r--r--src/libs6/s6_svstatus_read.c4
-rw-r--r--src/libs6/s6_svstatus_write.c4
42 files changed, 1987 insertions, 67 deletions
diff --git a/doc/index.html b/doc/index.html
index 57d1ef1..7fcf79a 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -22,10 +22,36 @@
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>.
+and <a href="http://smarden.org/runit/">runit</a>, as well as various
+operations on processes and daemons. It is meant to be a toolbox for
+low-level process and service administration, providing different sets of
+independent tools that can be used within or without the framework, and
+that can be assembled together to achieve powerful functionality with
+a very small amount of code.
</p>
<p>
+ Examples of things you can do by assembling together several programs
+provided by s6:
+</p>
+
+<ul>
+ <li> <a href="http://en.wikipedia.org/wiki/Syslog">syslogd</a> functionality,
+using much less resources than the traditional syslogd. </li>
+ <li> Reliable service readiness notification, which is the basis for
+service dependency management. </li>
+ <li> Controlled privileged gain as with
+<a href="http://en.wikipedia.org/wiki/Sudo">sudo</a>, without using
+any suid programs. </li>
+ <li> The useful parts of
+<a href="http://0pointer.de/blog/projects/socket-activation.html">socket
+activation</a><sup><a href="#fn1" id="r1">[1]</a></sup>
+without having to change application code or link servers
+against any specific library, and without having to switch to any
+specific init system. </li>
+</ul>
+
+<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
@@ -51,11 +77,14 @@ supervision that might help you understand the basics.
<ul>
<li> A POSIX-compliant system with a standard C development environment </li>
- <li> GNU make, version 4.0 or later </li>
+ <li> GNU make, version 4.0 or later. Please be aware that s6 will not build
+with an earlier version. </li>
<li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version
-2.2.1.0 or later </li>
+2.2.1.0 or later. It's a build-time requirement. It's also a run-time
+requirement if you link against the shared version of the skalibs
+library. </li>
<li> <a href="http://skarnet.org/software/execline/">execline</a> version
-2.0.1.1 or later </li>
+2.0.1.1 or later. It's a build-time and run-time requirement. </li>
</ul>
<h3> Licensing </h3>
@@ -120,32 +149,24 @@ a user interface to control those processes and monitor service states.
<li><a href="s6-notifywhenup.html">The <tt>s6-notifywhenup</tt> program</a> </li>
</ul>
-<h4> Other daemontools-like utilities </h4>
+<h4> 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.
+a few extras.
</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-applyuidgid.html">The <tt>s6-applyuidgid</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>
</ul>
<h4> Fifodir management, notification and subscription </h4>
@@ -174,6 +195,11 @@ synchronization</a>.
<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>
+<p>
+</p>
+<ul>
+<li><a href="s6-ftrigrd.html">The <tt>s6-ftrigrd</tt> internal program</a></li>
+</ul>
<h4> Local service management and access control </h4>
@@ -203,14 +229,44 @@ synchronization</a>.
<li><a href="s6-sudod.html">The <tt>s6-sudod</tt> program</a></li>
</ul>
-<h4> Internal commands </h4>
+<h4> Logging </h4>
<ul>
-<li><a href="s6-ftrigrd.html">The <tt>s6-ftrigrd</tt> internal program</a></li>
-<li><a href="libs6/s6lockd.html">The <tt>s6lockd</tt> internal program</a></li>
+<li><a href="s6-log.html">The <tt>s6-log</tt> program</a></li>
+<li><a href="ucspilogd.html">The <tt>ucspilogd</tt> program</a></li>
+</ul>
+
+<h4> Timed lock acquisition </h4>
+
+<ul>
+<li><a href="s6-setlock.html">The <tt>s6-setlock</tt> program</a></li>
+<li><a href="libs6/s6lockd.html">The <tt>s6lockd</tt> program</a></li>
<li><a href="libs6/s6lockd-helper.html">The <tt>s6lockd-helper</tt> internal program</a></li>
</ul>
+<h4> fd-holding, a.k.a. the sensible part of socket activation </h4>
+
+<ul>
+<li><a href="s6-fdholder-daemon.html">The <tt>s6-fdholder-daemon</tt> program</a></li>
+<li><a href="s6-fdholderd.html">The <tt>s6-fdholderd</tt> program</a></li>
+</ul>
+<p></p>
+<ul>
+<li><a href="s6-fdholder-store.html">The <tt>s6-fdholder-store</tt> program</a></li>
+<li><a href="s6-fdholder-storec.html">The <tt>s6-fdholder-storec</tt> program</a></li>
+<li><a href="s6-fdholder-retrieve.html">The <tt>s6-fdholder-retrieve</tt> program</a></li>
+<li><a href="s6-fdholder-retrievec.html">The <tt>s6-fdholder-retrievec</tt> program</a></li>
+<li><a href="s6-fdholder-delete.html">The <tt>s6-fdholder-delete</tt> program</a></li>
+<li><a href="s6-fdholder-deletec.html">The <tt>s6-fdholder-deletec</tt> program</a></li>
+<li><a href="s6-fdholder-list.html">The <tt>s6-fdholder-list</tt> program</a></li>
+<li><a href="s6-fdholder-listc.html">The <tt>s6-fdholder-listc</tt> program</a></li>
+<li><a href="s6-fdholder-getdump.html">The <tt>s6-fdholder-getdump</tt> program</a></li>
+<li><a href="s6-fdholder-getdumpc.html">The <tt>s6-fdholder-getdumpc</tt> program</a></li>
+<li><a href="s6-fdholder-setdump.html">The <tt>s6-fdholder-setdump</tt> program</a></li>
+<li><a href="s6-fdholder-setdumpc.html">The <tt>s6-fdholder-setdumpc</tt> program</a></li>
+<li><a href="s6-fdholder-transferdump.html">The <tt>s6-fdholder-transferdump</tt> program</a></li>
+<li><a href="s6-fdholder-transferdumpc.html">The <tt>s6-fdholder-transferdumpc</tt> program</a></li>
+</ul>
<h3> Libraries </h3>
@@ -220,6 +276,7 @@ synchronization</a>.
<li><a href="libs6/ftrigr.html">The <tt>ftrigr</tt> library interface</a></li>
<li><a href="libs6/s6lock.html">The <tt>s6lock</tt> library interface</a></li>
<li><a href="libs6/accessrules.html">The <tt>accessrules</tt> library interface</a></li>
+<li><a href="libs6/s6-fdholder.html">The <tt>s6-fdholder</tt> library interface</a></li>
</ul>
<h3> Definitions </h3>
@@ -259,6 +316,10 @@ daemontools.) </li>
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>
+ <li> <a href="http://homepage.ntlworld.com/jonathan.deboynepollard/Softwares/nosh.html">nosh</a>
+is another suite of system-level utilities with similarities in the design
+and approach. It is written in C++, though, and is coded in quite a
+different way than the previous items on this list. </li>
</ul>
<h3> Other init systems </h3>
@@ -302,5 +363,14 @@ 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>
+<h3> Footnotes </h3>
+
+<section>
+ <p id="fn1"><a href="#r1"><sup>[1]</sup></a>
+ Take everything you read on that link with two or three salt shakers.
+(This is true for anything written by the author of that document.)
+ </p>
+</section>
+
</body>
</html>
diff --git a/doc/libs6/ftrigr.html b/doc/libs6/ftrigr.html
index 2c9bf88..0a83534 100644
--- a/doc/libs6/ftrigr.html
+++ b/doc/libs6/ftrigr.html
@@ -55,8 +55,9 @@ children, consider using a ftrigrd service.
for instance, illustrate how to use the ftrigr library.
</p>
-
+<a name="synctimed">
<h3> Synchronous functions with a specified maximum execution time </h3>
+</a>
<ul>
<li> Synchronous functions take a <tt>tain_t const *</tt>
diff --git a/doc/libs6/index.html b/doc/libs6/index.html
index 9fe7e65..aa7b78a 100644
--- a/doc/libs6/index.html
+++ b/doc/libs6/index.html
@@ -4,7 +4,7 @@
<meta http-equiv="Content-Language" content="en" />
<title>s6: the s6 library interface</title>
<meta name="Description" content="s6: the s6 library interface" />
- <meta name="Keywords" content="s6 s6 libs6 library libs6net" />
+ <meta name="Keywords" content="s6 s6 libs6 library" />
<!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
</head>
<body>
@@ -66,6 +66,10 @@ functions to subscribe to fifodirs and be notified of events. </li>
functions to manage fifodirs and send notifications to them. </li>
<li> The <a href="s6lock.html">s6/s6lock.h</a> header provides
functions to acquire locks with a timeout. </li>
+ <li> The <a href="s6-fdholder.html">s6/s6-fdholder.h</a> header provides
+functions to communicate with a
+<a href="../s6-fdholderd.html">s6-fdholderd</a> server and exchange
+file descriptors with it. </li>
</ul>
</body>
diff --git a/doc/libs6/s6-fdholder.html b/doc/libs6/s6-fdholder.html
new file mode 100644
index 0000000..79c4725
--- /dev/null
+++ b/doc/libs6/s6-fdholder.html
@@ -0,0 +1,207 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder library interface</title>
+ <meta name="Description" content="s6: the s6-fdholder library interface" />
+ <meta name="Keywords" content="s6 fdholder file descriptor fd holding fd-passing library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6</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>s6-fdholder</tt> library interface </h1>
+
+<p>
+ The <tt>s6-fdholder</tt> library provides an API for clients
+wanting to communicate with a
+<a href="../s6-fdholderd.html">s6-fdholderd</a> daemon.
+</p>
+
+<h2> Programming </h2>
+
+<p>
+ Check the <tt>s6/s6-fdholder.h</tt> header for the
+exact function prototypes.
+</p>
+
+<h3> A programming example </h3>
+
+<p>
+ The <tt>src/fdholder/s6-fdholder-*c.c</tt> files in the s6 package,
+for instance, illustrate how to use the s6-fdholder library.
+</p>
+
+
+<h3> Synchronous functions with a specified maximum execution time </h3>
+
+<p>
+ The explanation given
+<a href="ftrigr.html#synctimed">there</a> applies here too: the
+functions documented in this page are synchronous, but can return
+early if the deadline is reached, in which case the connection to the
+server should be closed immediately because no protocol consistency is
+guaranteed.
+</p>
+
+<p>
+ The <a href="../s6-fdholderd.html">s6-fdholderd</a> server should be
+very quick to answer queries, so this mechanism is provided as a simple
+security against programming errors - for instance, connecting to the
+wrong daemon.
+</p>
+
+<h3> Starting and ending a session </h3>
+
+<pre>
+s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+int fd = 6 ;
+
+tain_now_g() ;
+
+s6_fdholder_init(&amp;a, fd) ;
+(...)
+s6_fdholder_free(&a) ;
+</pre>
+
+<p>
+<tt>s6_fdholder_init</tt> assumes that <em>fd</em> is a socket already
+connected to a s6-fdholderd daemon. The <em>a</em> structure must be
+initialized to <tt>S6_FDHOLDER_ZERO</tt> before use.
+</p>
+
+<p>
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">tain_now_g()</a>
+initializes a global variable that keeps track of the current time, for
+use with later functions.
+</p>
+
+<p>
+<tt>s6_fdholder_free</tt> frees the resources occupied by <em>a</em>.
+It does not, however, close <em>fd</em>. You should manually close it
+to end the connection to the server. Note that if your program has been
+started by <a href="../s6-ipcclient.html">s6-ipcclient</a>, both fds 6
+and 7 are open (and refer to the same socket), so you should close both.
+</p>
+
+<h3> Storing a fd </h3>
+
+<pre>
+int r ;
+int fd ;
+tain_t limit = TAIN_INFINITE ;
+char const *id = "my_identifier" ;
+r = s6_fdholder_store_g(&amp;a, fd, id, &amp;limit, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6_fdholder_store</tt> (and its variant <tt>s6_fdholder_store_g</tt>
+that uses the global timestamp variable) attempts to store a copy of
+descriptor <em>fd</em> into s6-fdholderd, using identifier <em>id</em>,
+with an expiration date of <em>limit</em>. In this example, <em>limit</em>
+is TAIN_INFINITE, which means no expiration date. The operation should
+return before <em>deadline</em>, else it will automatically return
+0 ETIMEDOUT. The result is 1 on success and 0 on failure, with an
+<a href="../s6-fdholder-errorcodes.html">appropriate</a> errno code.
+</p>
+
+<h3> Deleting a fd </h3>
+
+<pre>
+fd = s6_fdholder_delete_g(&amp;a, id, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6_fdholder_delete</tt> attempts to delete the file descriptor
+identified by <em>id</em>. It returns 1 on success and 0 on failure,
+with an
+<a href="../s6-fdholder-errorcodes.html">appropriate</a> errno code.
+</p>
+
+<h3> Retrieving a fd </h3>
+
+<pre>
+fd = s6_fdholder_retrieve_g(&amp;a, id, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6_fdholder_retrieve</tt> attempts to retrieve the file descriptor
+identified by <em>id</em>. It returns a valid fd number on success, and
+-1 on failure, with an
+<a href="../s6-fdholder-errorcodes.html">appropriate</a> errno code.
+</p>
+
+<p>
+ <tt>s6_fdholder_retrieve_delete()</tt> performs a retrieval and a
+deletion at the same time, if the client is authorized to do so.
+</p>
+
+<h3> Listing the identifiers held by the server </h3>
+
+<pre>
+stralloc list = STRALLOC_ZERO ;
+int n ;
+n = s6_fdholder_list_g(&amp;a, &amp;list, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6_fdholder_list</tt> gets the list of all identifiers currently
+held by the server. It stores it into the
+<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>
+<em>list</em>, as a series of null-terminated strings, one after the other.
+There are <em>n</em> such strings. The function returns <em>n</em> on
+success, or -1 on failure, with an
+<a href="../s6-fdholder-errorcodes.html">appropriate</a> errno code.
+</p>
+
+
+<h3> Reading a dump </h3>
+
+<pre>
+genalloc dump = GENALLOC_ZERO ;
+r = s6_fdholder_getdump_g(&amp;a, &amp;dump, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6_fdholder_getdump</tt> attempts to retrieve the whole set of
+descriptors from the server.
+It returns 1 on success, and 0 on failure, with an
+<a href="../s6-fdholder-errorcodes.html">appropriate</a> errno code.
+The set is stored into the
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+<em>dump</em>, which is to be interpreted as a stralloc containing an array
+of <tt>s6_fdholder_fd_t</tt>.
+</p>
+
+<p>
+<tt>genalloc_s(s6_fdholder_fd_t, &amp;dump)</tt> is a pointer to this array, and
+<tt>genalloc_len(s6_fdholder_fd_t, &amp;dump)</tt> is the number of elements
+in the array. A <tt>s6_fdholder_fd_t</tt> contains at least a descriptor
+number, an identifier, and an expiration date, see the
+<tt>s6/s6-fdholder.h</tt> header file.
+</p>
+
+<h3> Writing a dump </h3>
+
+<pre>
+unsigned int dumplen ;
+s6_fdholder_fd_t const *dumparray ;
+r = s6_fdholder_setdump_g(&amp;a, &amp;dumparray, dumplen, &amp;deadline) ;
+</pre>
+
+<p>
+<tt>s6_fdholder_setdump</tt> attempts to send a set of descriptors to the
+server. The descriptors are contained in the array <em>dumparray</em> of
+length <em>dumplen</em>. The function
+returns 1 on success, and 0 on failure, with an
+<a href="../s6-fdholder-errorcodes.html">appropriate</a> errno code.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-daemon.html b/doc/s6-fdholder-daemon.html
new file mode 100644
index 0000000..90adea0
--- /dev/null
+++ b/doc/s6-fdholder-daemon.html
@@ -0,0 +1,147 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-daemon program</title>
+ <meta name="Description" content="s6: the s6-fdholder-daemon program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd unix socket activation server daemon" />
+ <!-- <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>s6-fdholder-daemon</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-daemon</tt> is a fd-holding <em>daemon</em>, i.e. a
+long-lived program.
+It listens on a Unix domain socket, then
+accepts client connections;
+it stores file descriptors on behalf of clients, along with an identifier
+for every file descriptor stored, and possibly an expiration date (after
+which the file descriptor will be forgotten). It also allows clients to
+retrieve a file descriptor by its identifier.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-daemon [ -1 ] [ -v <em>verbosity</em> ] [ -d | -D ] [ -c <em>maxconn</em> ] [ -n <em>maxfds</em> ] [ -b <em>backlog</em> ] [ -G <em>gidlist</em> ] [ -g <em>gid</em> ] [ -u <em>uid</em> ] [ -U ] [ -t <em>clienttimeout</em> ] [ -T <em>lameducktimeout</em> ] [ -i <em>rulesdir</em> | -x <em>rulesfile</em> ] <em>path</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-daemon parses the options and arguments it is given, and
+builds a new command line with them. It then executes into that new
+command line. </li>
+ <li> The first program s6-fdholder-daemon executes into is
+<a href="s6-ipcserver-socketbinder.html">s6-ipcserver-socketbinder</a>.
+It will create and bind a Unix domain socket to <em>path</em>, then
+execute into the rest of the command line. </li>
+ <li> If a privilege-dropping operation has been requested, the
+program that s6-ipcserver-socketbinder executes into is
+<a href="s6-applyuidgid.html">s6-applyuidgid</a>.
+It will drop the root privileges, then execute into the rest of the
+command line. </li>
+ <li> The last program in the chain is
+<a href="s6-fdholderd.html">s6-fdholderd</a>. It is executed into
+by s6-applyuidgid, or directly by s6-ipcserver-socketbinder if no
+privilege-dropping operation has been requested. s6-fdholderd is
+the long-lived process, the daemon itself, performing fd holding and
+accepting connections from clients. </li>
+</ul>
+
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-1</tt>&nbsp;: write <em>path</em>, followed by a newline,
+to stdout, before
+closing it, right after binding and listening to the Unix socket.
+If stdout is suitably redirected, this can be used by monitoring
+programs to check when the server is ready to accept connections. </li>
+ <li> <tt>-v&nbsp;<em>verbosity</em></tt>&nbsp;: be quiet, normally
+verbose, or more verbose, depending on if <em>verbosity</em> is 0,
+1, or more. The default is 1. </li>
+ <li> <tt>-d</tt>&nbsp;: allow instant rebinding to the same path
+even if it has been used not long ago - this is the SO_REUSEADDR flag to
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">setsockopt()</a>
+and is generally used with server programs. This is the default. Note that
+<em>path</em> will be deleted if it already exists at program start time. </li>
+ <li> <tt>-D</tt>&nbsp;: disallow instant rebinding to the same path. </li>
+ <li> <tt>-c&nbsp;<em>maxconn</em></tt>&nbsp;: accept at most
+<em>maxconn</em> concurrent client connections. Default is 16. It is
+impossible to set it higher than the value of the S6_FDHOLDER_MAX macro,
+which is 256. Client connections to this server are short-lived, so this
+number needs not be too high. Every client connection eats up
+one available file descriptor, so it is best for <em>maxconn</em> to be
+as small as possible. </li>
+ <li> <tt>-n&nbsp;<em>maxfds</em></tt>&nbsp;: store at most
+<em>maxfds</em> file descriptors. Default is 1000.
+It is impossible to set it higher than the number of files that can
+be opened by the s6-fdholder-daemon process minus a few descriptors
+needed for correct <a href="s6-fdholderd.html">s6-fdholderd</a>
+operation. Before running s6-fdholder-daemon, make sure to
+<a href="s6-softlimit.html">properly adjust</a> the
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_resource.h.html">number
+of openable files</a> of the current process. </li>
+ <li> <tt>-b&nbsp;<em>backlog</em></tt>&nbsp;: set a maximum of
+<em>backlog</em> backlog connections on the socket. Extra
+connection attempts will rejected by the kernel. </li>
+ <li> <tt>-G&nbsp;<em>gidlist</em></tt>&nbsp;: change s6-fdholder-daemon's
+supplementary group list to <em>gidlist</em> after binding the socket.
+This is only valid when run as root. <em>gidlist</em> must be a
+comma-separated list of numerical group IDs. </li>
+ <li> <tt>-g&nbsp;<em>gid</em></tt>&nbsp;: change s6-fdholder-daemon's groupid
+to <em>gid</em> after binding the socket. This is only valid when run
+as root. </li>
+ <li> <tt>-u&nbsp;<em>uid</em></tt>&nbsp;: change s6-fdholder-daemon's userid
+to <em>uid</em> after binding the socket. This is only valid when run
+as root. </li>
+ <li> <tt>-U</tt>&nbsp;: change s6-fdholder-daemon's user id, group id and
+supplementary group list
+according to the values of the UID, GID and GIDLIST environment variables
+after binding the socket. This is only valid when run as root.
+This can be used with the
+<a href="s6-envuidgid.html">s6-envuidgid</a>
+program to easily script a service that binds to a privileged socket
+then drops its privileges to those of a named non-root account. </li>
+ <li> <tt>-t&nbsp;<em>clienttimeout</em></tt>&nbsp;: disconnect a client
+if it's in the middle of an operation and it has not written or read any
+data in <em>clienttimeout</em> milliseconds. By default, <em>clienttimeout</em>
+is 0, which means infinite. </li>
+ <li> <tt>-T&nbsp;<em>lameducktimeout</em></tt>&nbsp;: give clients
+<em>lameducktimeout</em> milliseconds to finish their current operation
+before exiting after s6-fdholderd has received a SIGTERM. By default,
+<em>lameducktimeout</em> is 0, which means infinite. </li>
+ <li> <tt>-x&nbsp;<em>rulesfile</em></tt>&nbsp;: read access rights
+configuration from CDB file <em>rulesfile</em>. </li>
+ <li> <tt>-i&nbsp;<em>rulesdir</em></tt>&nbsp;: read access rights
+configuration from the filesystem in directory <em>rulesdir</em>. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-fdholder-daemon does not interpret its options itself. It just
+dispatches them to the appropriate program on the command line that
+it builds. </li>
+ <li> From the user's point of view, s6-fdholder-daemon behaves like a
+long-lived process, even if the long-lived process itself is called
+<a href="s6-fdholderd.html">s6-fdholderd</a>. Every operational detail
+of s6-fdholderd applies to s6-fdholder-daemon as well; in particular,
+make sure to properly
+<a href="s6-fdholderd.html#configuration">configure the clients'
+access rights</a>. </li>
+ <li> s6-fdholder-daemon is meant to be used in a s6 run script, as
+a supervised local service. It does not fork itself or write to syslog.
+However, it can be run under any infrastructure, including other
+supervision infrastructures, OpenRC, systemd, or SysV scripts. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-delete.html b/doc/s6-fdholder-delete.html
new file mode 100644
index 0000000..a0fa6dd
--- /dev/null
+++ b/doc/s6-fdholder-delete.html
@@ -0,0 +1,71 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-delete program</title>
+ <meta name="Description" content="s6: the s6-fdholder-delete program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd delete deletion unix socket activation" />
+ <!-- <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>s6-fdholder-delete</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-delete</tt> connects to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> listening on a
+Unix domain socket, and deletes a file descriptor from the
+daemon storage.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-delete [ -t <em>timeout</em> ] <em>path</em> <em>id</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-delete executes into <tt><a href="s6-ipcclient.html">s6-ipcclient</a> <em>path</em>
+<a href="s6-fdholder-deletec.html">s6-fdholder-deletec</a> <em>id</em> </tt>.
+It does nothing else: it is just a convenience program.
+The <a href="s6-ipcclient.html">s6-ipcclient</a> program connects
+to a Unix socket at <em>path</em>, and the
+<a href="s6-fdholder-deletec.html">s6-fdholder-deletec</a> program
+sends instruction to the server. </li>
+ <li> It should be used to connect to a
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon, which will receive
+the instruction to close and remove the file descriptor identified
+by <em>id</em>. </li>
+ <li> It then exits 0. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors (connecting to the
+wrong socket, for instance). </li>
+</ul>
+
+<h2> Usage example </h2>
+
+<pre>
+ s6-fdholder-delete /service/fdholderd/s MYSOCKET
+</pre>
+
+<p>
+ will tell a
+s6-fdholderd daemon listening on the <tt>/service/fdholderd/s</tt>
+socket to close the filedescriptor identified as MYSOCKET.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-deletec.html b/doc/s6-fdholder-deletec.html
new file mode 100644
index 0000000..526de30
--- /dev/null
+++ b/doc/s6-fdholder-deletec.html
@@ -0,0 +1,63 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-deletec program</title>
+ <meta name="Description" content="s6: the s6-fdholder-deletec program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd delete deletion unix socket activation" />
+ <!-- <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>s6-fdholder-deletec</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-deletec</tt> talks to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> on its open
+descriptors 6 and 7, and tells it to close a file descriptor
+it's currently holding.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-deletec [ -t <em>timeout</em> ] <em>id</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-deletec expects to talk to a listening
+<a href="s6-fdholderd.html">s6-fdholderd</a> program on its descriptors 6 and 7. </li>
+ <li> It tells the server to close the file descriptor that has been
+stored with identifier <em>id</em>. </li>
+ <li> It then exits 0, or 1 if the server returned an error. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+<li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li>s6-fdholder-deletec is the "internal" version of
+<a href="s6-fdholder-delete.html">s6-fdholder-delete</a>. It simply
+expects to be run as a UCSPI client, i.e. talking to the server
+over descriptors 6 and 7, instead of connecting to the server
+itself. </li>
+ <li> The error messages for the s6-fdholder suite are explained
+<a href="s6-fdholder-errorcodes.html">here</a>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-errorcodes.html b/doc/s6-fdholder-errorcodes.html
new file mode 100644
index 0000000..8e41365
--- /dev/null
+++ b/doc/s6-fdholder-errorcodes.html
@@ -0,0 +1,72 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder error codes</title>
+ <meta name="Description" content="s6: the s6-fdholder error codes" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd unix socket activation" />
+ <!-- <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>s6-fdholder</tt> error codes </h1>
+
+<p>
+ The following error messages (and corresponding
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html">errno codes</a>)
+can be returned by the
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon to its various clients.
+This page explains why they occur.
+</p>
+
+<ul>
+ <li> <tt>Protocol error</tt> (EPROTO) or <tt>Protocol wrong type
+for socket</tt> (EPROTOTYPE): the client connected to the wrong
+kind of server and they cannot communicate. This is generally a
+programming error. It can also
+signal a bug in the s6-fdholder tools, but protocol bugs have
+usually been wiped out before a s6 release. </li>
+ <li> <tt>Broken pipe</tt> (EPIPE): the client was not authorized to
+connect to the server, which closed the connection. You need to
+<a href="s6-fdholderd.html#configuration">configure the access
+rights to the server</a>. </li>
+ <li> <tt>Operation not permitted</tt> (EPERM): even though the
+client was authorized to connect to the server, the specific
+operation it wanted to perform was denied. You need to
+<a href="s6-fdholderd.html#configuration">configure the access
+rights to the server</a>. </li>
+ <li> <tt>Too many open files in system</tt> (ENFILE): the client
+attempted to store more file descriptors than the server can hold.
+Or, the client attempted to retrieve more file descriptors than it
+can hold. You should check the <tt>-n</tt> option to
+<a href="s6-fdholderd.html">s6-fdholderd</a>, as well as the
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_resource.h.html">RLIMIT_NOFILE</a>
+resource limits used by the client and the server, and adjust them
+accordingly. </li>
+ <li> <tt>Resource busy</tt> (EBUSY): the client attempted to store
+a descriptor under an identifier that is already used. </li>
+ <li> <tt>Filename too long</tt> (ENAMETOOLONG): the identifier
+provided by the client was too long. </li>
+ <li> <tt>No such file or directory</tt> (ENOENT): the identifier
+provided by the client was not found in the server database. </li>
+ <li> <tt>Bad file descriptor</tt> (EBADF): the client attempted
+to transmit a closed, or otherwise unsuitable for fd-passing,
+file descriptor. </li>
+ <li> <tt>Operation timed out</tt> (ETIMEDOUT): the client, or the
+server, took too long to perform the wanted operation. This is most
+probably a programming error, because both client and server should
+have a very fast reaction time. Check that the client is connecting
+to the right server, and check <tt>-t</tt> options to both client and
+server (the argument is interpreted as milliseconds!). </li>
+ <li> Other errors indicate a transient error such as lack of memory,
+hardware failure, etc. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-getdump.html b/doc/s6-fdholder-getdump.html
new file mode 100644
index 0000000..a339b71
--- /dev/null
+++ b/doc/s6-fdholder-getdump.html
@@ -0,0 +1,92 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-getdump program</title>
+ <meta name="Description" content="s6: the s6-fdholder-getdump program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd dump retrieval unix socket activation" />
+ <!-- <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>s6-fdholder-getdump</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-getdump</tt> connects to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> listening on a
+Unix domain socket, and retrieves its entire state: file descriptors with
+their identifiers and expiration dates. It then executes a program with
+those file descriptors still open, and the state stored in the
+environment.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-getdump [ -t <em>timeout</em> ] <em>path</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-getdump executes into <tt><a href="s6-ipcclient.html">s6-ipcclient</a> <em>path</em>
+<a href="s6-fdholder-getdumpc.html">s6-fdholder-getdumpc</a> <em>prog...</em></tt>.
+It does nothing else: it is just a convenience program.
+The <a href="s6-ipcclient.html">s6-ipcclient</a> program connects
+to a Unix socket at <em>path</em>, and the
+<a href="s6-fdholder-getdumpc.html">s6-fdholder-getdumpc</a> program
+gets the server's state over the socket. </li>
+ <li> It executes into <em>prog...</em> with as many more open
+file descriptors as there were in the daemon, and information about those
+file descriptors in the environment. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors (connecting to the
+wrong socket, for instance). </li>
+</ul>
+
+<h2> Usage example </h2>
+
+<pre>
+ s6-fdholder-getdump /service/fdholderd/s s6-fdholder-setdump /service/fdholderd-2/s
+</pre>
+
+<p>
+will get the state of the s6-fdholderd daemon listening on the <tt>/service/fdholderd/s</tt>
+socket, and transmit it to the other s6-fdholderd daemon listening on the
+<tt>/service/fdholderd-2/s</tt> socket. Note that in this precise case,
+the <a href="s6-fdholder-transferdump.html">s6-fdholder-transferdump</a>
+program does the same thing more efficiently.
+</p>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-fdholder-getdump really executes into <tt>s6-ipcclient
+s6-fdholder-getdumpc
+<a href="http://skarnet.org/software/execline/fdclose.html">fdclose</a>
+6 fdclose 7 <em>prog...</em></tt>, so that <em>prog...</em> does not
+have a connection with the fd-holding daemon anymore. If you want to
+keep the server connection open for <em>prog...</em>, use
+<tt>s6-ipcclient s6-fdholder-getdumpc</tt> manually. </li>
+ <li> The exact format of the environment given to <em>prog...</em>
+is described in the
+<a href="s6-fdholder-getdumpc.html">s6-fdholder-getdumpc</a> page. </li>
+ <li> Getting the whole state of a s6-fdholderd daemon requires specific
+privileges. Make sure you properly
+<a href="s6-fdholderd.html#configuration">configure the s6-fdholderd
+access rights</a> so your client can perform that operation. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-getdumpc.html b/doc/s6-fdholder-getdumpc.html
new file mode 100644
index 0000000..acaf31a
--- /dev/null
+++ b/doc/s6-fdholder-getdumpc.html
@@ -0,0 +1,91 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-getdumpc program</title>
+ <meta name="Description" content="s6: the s6-fdholder-getdumpc program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd retrieval unix socket activation" />
+ <!-- <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>s6-fdholder-getdumpc</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-getdumpc</tt> talks to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> on its open
+descriptors 6 and 7, and retrieves its whole state,
+then executes a program with as many more file descriptors open
+as were given by the daemon, plus a modified environment to
+describe the retrieved state.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-retrievec [ -t <em>timeout</em> ] <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-retrievec expects to talk to a listening
+<a href="s6-fdholderd.html">s6-fdholderd</a> program on its descriptors 6 and 7. </li>
+ <li> It retrieves a copy of the whole set of file descriptors
+stored in that daemon, including their identifiers and expiration dates. </li>
+ <li> It then executes into <em>prog...</em> with the additional descriptors
+and environment. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors. </li>
+</ul>
+
+<h2> Environment format </h2>
+
+<p>
+ <em>prog...</em> is executed with the following environment variables
+set:
+</p>
+
+<ul>
+ <li> <tt>S6_FD#</tt>&nbsp;: contains the number <em>n</em> of file
+descriptors retrieved from the server. </li>
+ <li> Then, for every <em>i</em> between 0 and <em>n</em>-1 inclusive:
+ <ul>
+ <li> <tt>S6_FD_<em>i</em></tt>&nbsp;: contains the number of the <em>i</em>th
+open file descriptor. </li>
+ <li> <tt>S6_FDID_<em>i</em></tt>&nbsp;: contains the identifier of the
+<em>i</em>th open file descriptor. </li>
+ <li> <tt>S6_FDLIMIT_<em>i</em></tt>&nbsp;: contains the expiration date of
+the <em>i</em>th open file descriptor, if applicable. That date is stored in
+<a href="http://cr.yp.to/libtai/tai64.html#tai64n">external TAI64N
+format</a>. </li>
+If the file descriptor is not supposed to expire, that environment variable
+is not defined. </li>
+ </ul> </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-fdholder-getdumpc is the "internal" version of
+<a href="s6-fdholder-getdump.html">s6-fdholder-getdump</a>. It simply
+expects to be run as a UCSPI client, i.e. talking to the server
+over descriptors 6 and 7, instead of connecting to the server
+itself. </li>
+ <li> The error messages for the s6-fdholder suite are explained
+<a href="s6-fdholder-errorcodes.html">here</a>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-list.html b/doc/s6-fdholder-list.html
new file mode 100644
index 0000000..8b92506
--- /dev/null
+++ b/doc/s6-fdholder-list.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-fdholder-list program</title>
+ <meta name="Description" content="s6: the s6-fdholder-list program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd list unix socket activation" />
+ <!-- <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>s6-fdholder-list</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-list</tt> lists the descriptors currently held by a
+<a href="s6-fdholderd.html">fd-holding daemon</a>.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-list [ -t <em>timeout</em> ] <em>path</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-list executes into <tt><a href="s6-ipcclient.html">s6-ipcclient</a> <em>path</em>
+<a href="s6-fdholder-listc.html">s6-fdholder-listc</a> <em>id</em></tt>. It does nothing else: it is just a
+convenience program. The <a href="s6-ipcclient.html">s6-ipcclient</a> program connects
+to a Unix socket at <em>path</em>, and the
+<a href="s6-fdholder-listc.html">s6-fdholder-listc</a> program transmits
+the instruction over the socket, and gets and prints the result. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+<li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors (connecting to the
+wrong socket, for instance). </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-listc.html b/doc/s6-fdholder-listc.html
new file mode 100644
index 0000000..47a2ec8
--- /dev/null
+++ b/doc/s6-fdholder-listc.html
@@ -0,0 +1,68 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-listc program</title>
+ <meta name="Description" content="s6: the s6-fdholder-listc program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd list unix socket activation" />
+ <!-- <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>s6-fdholder-listc</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-listc</tt> talks to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> on its open
+descriptors 6 and 7. It prints on stdout the list of identifiers
+of all the fd currently held by the daemon, one per line.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-listc [ -t <em>timeout</em> ]
+</pre>
+
+<ul>
+ <li> s6-fdholder-listc expects to talk to a listening
+<a href="s6-fdholderd.html">s6-fdholderd</a> program on its descriptors 6 and 7. </li>
+ <li> It gets the list of identifiers corresponding to the currently held
+file descriptors. It prints that list to stdout, one per line.
+ <li> It then exits 0, or 1 if the server returned an error. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+<li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li>s6-fdholder-listc is the "internal" version of
+<a href="s6-fdholder-list.html">s6-fdholder-list</a>. It simply
+expects to be run as a UCSPI client, i.e. talking to the server
+over descriptors 6 and 7, instead of connecting to the server
+itself. </li>
+ <li> The error messages for the s6-fdholder suite are explained
+<a href="s6-fdholder-errorcodes.html">here</a>. </li>
+ <li> The list of identifiers is printed one per line; special
+characters - such as newline - are quoted. The output can be
+unquoted, for instance, by
+<tt><a href="http://skarnet.org/software/s6-portable-utils/s6-unquote-filter.html">s6-unquote-filter</a>
+-d ""</tt>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-retrieve.html b/doc/s6-fdholder-retrieve.html
new file mode 100644
index 0000000..5231051
--- /dev/null
+++ b/doc/s6-fdholder-retrieve.html
@@ -0,0 +1,98 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-retrieve program</title>
+ <meta name="Description" content="s6: the s6-fdholder-retrieve program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd retrieval unix socket activation" />
+ <!-- <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>s6-fdholder-retrieve</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-retrieve</tt> connects to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> listening on a
+Unix domain socket, and retrieves a file descriptor from that
+daemon, then executes a program with that file descriptor as the
+program's standard input.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-retrieve [ -D ] [ -t <em>timeout</em> ] <em>path</em> <em>id</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-retrieve executes into <tt><a href="s6-ipcclient.html">s6-ipcclient</a> <em>path</em>
+<a href="s6-fdholder-retrievec.html">s6-fdholder-retrievec</a> <em>id</em> <em>prog...</em></tt>.
+It does nothing else: it is just a convenience program.
+The <a href="s6-ipcclient.html">s6-ipcclient</a> program connects
+to a Unix socket at <em>path</em>, and the
+<a href="s6-fdholder-retrievec.html">s6-fdholder-retrievec</a> program
+gets the file descriptor identified by <em>id</em> over the socket. </li>
+ <li> It should be used to connect to a
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon, which will pass the
+file descriptor to the client over the <em>path</em> socket. </li>
+ <li> It executes into <em>prog...</em> with the retrieved file
+descriptor as <em>prog...</em>'s standard input. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-D</tt>&nbsp;: delete the file descriptor from the server's
+storage after retrieval. This option requires writing rights over the
+given identifier as well as reading rights: check the server's
+<a href="s6-fdholderd.html#configuration">configuration</a>. </li>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors (connecting to the
+wrong socket, for instance). </li>
+</ul>
+
+<h2> Usage example </h2>
+
+<pre>
+ s6-fdholder-store /service/fdholderd/s MYSOCKET s6-ipcserverd cat
+</pre>
+
+<p>
+ will retrieve a file descriptor stored under the MYSOCKET identifier in
+the s6-fdholderd daemon listening on the <tt>/service/fdholderd/s</tt>
+socket, and execute into <tt>s6-ipcserverd cat</tt> with that file
+descriptor as stdin. In this case, if MYSOCKET referred to a Unix domain
+socket, <a href="s6-ipcserverd.html">s6-ipcserverd</a> will then accept
+client connections on it and spawn a <tt>cat</tt> program for every
+connection.
+</p>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-fdholder-retrieve really executes into <tt>s6-ipcclient
+s6-fdholder-retrievec
+<a href="http://skarnet.org/software/execline/fdclose.html">fdclose</a>
+6 fdclose 7 <em>prog...</em></tt>, so that <em>prog...</em> does not
+have a connection with the fd-holding daemon anymore. If you want to
+keep the server connection open for <em>prog...</em>, use
+<tt>s6-ipcclient s6-fdholder-retrievec</tt> manually. </li>
+ <li> To execute <em>prog</em> with the newly retrieved file descriptor
+as number <em>n</em> while preserving stdin, use the following construct:
+<tt>fdmove <em>n</em> 0 s6-fdholder-retrieve <em>path</em> <em>id</em>
+<a href="http://skarnet.org/software/execline/fdswap.html">fdswap</a>
+0 <em>n</em> <em>prog...</em></tt>. Be aware that <em>n</em>
+cannot be 6 or 7, internally used by s6-fdholder-retrieve. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-retrievec.html b/doc/s6-fdholder-retrievec.html
new file mode 100644
index 0000000..5724ee0
--- /dev/null
+++ b/doc/s6-fdholder-retrievec.html
@@ -0,0 +1,68 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-retrievec program</title>
+ <meta name="Description" content="s6: the s6-fdholder-retrievec program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd retrieval unix socket activation" />
+ <!-- <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>s6-fdholder-retrievec</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-retrievec</tt> talks to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> on its open
+descriptors 6 and 7, and retrieves a file descriptor from it,
+then executes a program.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-retrievec [ -D ] [ -t <em>timeout</em> ] <em>id</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-retrievec expects to talk to a listening
+<a href="s6-fdholderd.html">s6-fdholderd</a> program on its descriptors 6 and 7. </li>
+ <li> It attempts to retrieve a copy of the file descriptor that has been
+stored into that daemon under identifier <em>id</em>.
+ <li> It then executes into <em>prog...</em>, with the retrieved
+file descriptor as standard input. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-D</tt>&nbsp;: delete the file descriptor from the server's
+storage after retrieval. This option requires writing rights over the
+given identifier as well as reading rights: check the server's
+<a href="s6-fdholderd.html#configuration">configuration</a>. </li>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li>s6-fdholder-retrievec is the "internal" version of
+<a href="s6-fdholder-retrieve.html">s6-fdholder-retrieve</a>. It simply
+expects to be run as a UCSPI client, i.e. talking to the server
+over descriptors 6 and 7, instead of connecting to the server
+itself. </li>
+ <li> The error messages for the s6-fdholder suite are explained
+<a href="s6-fdholder-errorcodes.html">here</a>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-setdump.html b/doc/s6-fdholder-setdump.html
new file mode 100644
index 0000000..b5661e2
--- /dev/null
+++ b/doc/s6-fdholder-setdump.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-fdholder-setdump program</title>
+ <meta name="Description" content="s6: the s6-fdholder-setdump program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd dump storage unix socket activation" />
+ <!-- <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>s6-fdholder-setdump</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-setdump</tt> connects to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> listening on a
+Unix domain socket, and dumps a set of file descriptors into
+that daemon.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-setdump [ -t <em>timeout</em> ] <em>path</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-setdump executes into <tt><a href="s6-ipcclient.html">s6-ipcclient</a> <em>path</em>
+<a href="s6-fdholder-setdumpc.html">s6-fdholder-setdumpc</a> <em>id</em></tt>. It does nothing else: it is just a
+convenience program. The <a href="s6-ipcclient.html">s6-ipcclient</a> program connects
+to a Unix socket at <em>path</em>, and the
+<a href="s6-fdholder-setdumpc.html">s6-fdholder-setdumpc</a> program transmits the
+file descriptors over the socket. </li>
+ <li> It should be used to connect to a
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon, which will store the set of
+file descriptors. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+<li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors (connecting to the
+wrong socket, for instance). </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> The file descriptors to transmit to the server should of course be
+already open in the s6-fdholder-setdump program; also, s6-fdholder-setdump
+should have certain environment variables that describe that set of file
+descriptors. The format of the environment is the same as the one set by
+<a href="s6-fdholder-getdumpc.html">s6-fdholder-getdumpc</a>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-setdumpc.html b/doc/s6-fdholder-setdumpc.html
new file mode 100644
index 0000000..126dcf0
--- /dev/null
+++ b/doc/s6-fdholder-setdumpc.html
@@ -0,0 +1,62 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-setdumpc program</title>
+ <meta name="Description" content="s6: the s6-fdholder-setdumpc program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd dump storage unix socket activation" />
+ <!-- <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>s6-fdholder-setdumpc</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-setdumpc</tt> talks to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> on its open
+descriptors 6 and 7, and transmits it a set of file descriptors
+together with a list of identifiers and expiration dates found
+in its environment.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-setdumpc [ -t <em>timeout</em> ]
+</pre>
+
+<ul>
+ <li> s6-fdholder-storec expects to talk to a listening
+<a href="s6-fdholderd.html">s6-fdholderd</a> program on its descriptors 6 and 7. </li>
+ <li> It attempts to pass a complete state - i.e. a set of file descriptors
+with identifiers and expiration dates - to s6-fdholderd. </li>
+ <li> It then exits 0, or 1 if the server returned an error. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+<li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> The error messages for the s6-fdholder suite are explained
+<a href="s6-fdholder-errorcodes.html">here</a>. </li>
+ <li> The format of the environment variables where s6-fdholder-setdumpc
+gets its information from is the same as the one set by
+<a href="s6-fdholder-getdumpc.html">s6-fdholder-getdumpc</a>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-store.html b/doc/s6-fdholder-store.html
new file mode 100644
index 0000000..c67927d
--- /dev/null
+++ b/doc/s6-fdholder-store.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-fdholder-store program</title>
+ <meta name="Description" content="s6: the s6-fdholder-store program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd storage unix socket activation" />
+ <!-- <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>s6-fdholder-store</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-store</tt> connects to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> listening on a
+Unix domain socket, and gives it a copy of one of its open file
+descriptors for the daemon to hold.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-store [ -d <em>fd</em> ] [ -T fdtimeout ] [ -t <em>timeout</em> ] <em>path</em> <em>id</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-store executes into <tt><a href="s6-ipcclient.html">s6-ipcclient</a> <em>path</em>
+<a href="s6-fdholder-storec.html">s6-fdholder-storec</a> <em>id</em></tt>. It does nothing else: it is just a
+convenience program. The <a href="s6-ipcclient.html">s6-ipcclient</a> program connects
+to a Unix socket at <em>path</em>, and the
+<a href="s6-fdholder-storec.html">s6-fdholder-storec</a> program transmits the desired
+file descriptor over the socket. </li>
+ <li> It should be used to connect to a
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon, which will store the
+file descriptor given by the user. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-d&nbsp;<em>fd</em></tt>&nbsp;: store descriptor number <em>fd</em>.
+By default, <em>fd</em> is 0 (i.e. the program's stdin will be stored).
+s6-fdholder-store replaces its stdin with <em>fd</em> before executing into
+<tt>s6-ipcclient <a href="s6-fdholder-storec.html">s6-fdholder-storec</a></tt>. </li>
+ <li> <tt>-T&nbsp;<em>fdtimeout</em></tt>&nbsp;: the descriptor is stored with
+an expiration time of <em>fdtimeout</em> milliseconds, which means the
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon will close and get rid of
+the descriptor after that time. By default, <em>fdtimeout</em> is 0, which
+means infinite - no expiration time. </li>
+<li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors (connecting to the
+wrong socket, for instance). </li>
+</ul>
+
+<h2> Usage example </h2>
+
+<pre>
+ <a href="s6-ipcserver-socketbinder.html">s6-ipcserver-socketbinder</a> /tmp/mysocket s6-fdholder-store /service/fdholderd/s MYSOCKET
+</pre>
+
+<p>
+ will open a Unix domain socket, bind it to <tt>/tmp/mysocket</tt> and
+listen to incoming connections, then give it to a
+<a href="s6-fdholderd.html">s6-fdholderd</a> instance listening on
+<tt>/service/fdholderd/s</tt>, with no expiration date, with the
+"MYSOCKET" identifier. Another program will be able to retrieve the
+socket later, using <a href="s6-fdholder-retrieve.html">s6-fdholder-retrieve</a>.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-storec.html b/doc/s6-fdholder-storec.html
new file mode 100644
index 0000000..08180e4
--- /dev/null
+++ b/doc/s6-fdholder-storec.html
@@ -0,0 +1,68 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-storec program</title>
+ <meta name="Description" content="s6: the s6-fdholder-storec program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd storage unix socket activation" />
+ <!-- <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>s6-fdholder-storec</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-storec</tt> talks to a
+<a href="s6-fdholderd.html">fd-holding daemon</a> on its open
+descriptors 6 and 7, and passes it a copy of its standard
+input.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-storec [ -T fdtimeout ] [ -t <em>timeout</em> ] <em>id</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-storec expects to talk to a listening
+<a href="s6-fdholderd.html">s6-fdholderd</a> program on its descriptors 6 and 7. </li>
+ <li> It attempts to pass a copy of its fd 0 (standard input) to s6-fdholderd,
+with identifier <em>id</em>. </li>
+ <li> It then exits 0, or 1 if the server returned an error. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-T&nbsp;<em>fdtimeout</em></tt>&nbsp;: the descriptor is stored with
+an expiration time of <em>fdtimeout</em> milliseconds, which means the
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon will close and get rid of
+the descriptor after that time. By default, <em>fdtimeout</em> is 0, which
+means infinite - no expiration time. </li>
+<li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the operation cannot be
+processed in <em>timeout</em> milliseconds, then fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li>s6-fdholder-storec is the "internal" version of
+<a href="s6-fdholder-store.html">s6-fdholder-store</a>. It simply
+expects to be run as a UCSPI client, i.e. talking to the server
+over descriptors 6 and 7, instead of connecting to the server
+itself. </li>
+ <li> The error messages for the s6-fdholder suite are explained
+<a href="s6-fdholder-errorcodes.html">here</a>. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-transferdump.html b/doc/s6-fdholder-transferdump.html
new file mode 100644
index 0000000..714ea03
--- /dev/null
+++ b/doc/s6-fdholder-transferdump.html
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-transferdump program</title>
+ <meta name="Description" content="s6: the s6-fdholder-transferdump program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd dump transfer unix socket activation" />
+ <!-- <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>s6-fdholder-transferdump</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-transferdump</tt> connects to two separate
+<a href="s6-fdholderd.html">fd-holding daemons</a> and
+transfers the content of the first one to the second one.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-transferdump [ -t <em>timeoutfrom:timeoutto</em> ] <em>pathfrom</em> <em>pathto</em>
+</pre>
+
+<ul>
+ <li> s6-fdholder-transferdump executes into a more complex command line
+involving two
+<a href="s6-ipcclient.html">s6-ipcclient</a> invocations and ending with
+<a href="s6-fdholder-transferdumpc.html">s6-fdholder-transferdumpc</a>. It
+is just a convenience program: the real transfer is performed by
+<a href="s6-fdholder-transferdumpc.html">s6-fdholder-transferdumpc</a>. </li>
+ <li> The file descriptor transfer will occur from the
+<a href="s6-fdholderd.html">s6-fdholderd</a> daemon listening on
+<em>pathfrom</em> to the one listening on <em>pathto</em>. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+<li> <tt>-t&nbsp;<em>timeoutfrom</em>:<em>timeoutto</em></tt>&nbsp;:
+if the operations cannot be
+processed in <em>timeoutfrom</em> (for the connection to <em>pathfrom</em>)
+or <em>timeoutto</em> (for the connection to <em>pathto</em>) milliseconds,
+then fail with an error message.
+Communications with the servers should be near-instant, so this option is
+only here to protect users against programming errors (connecting to the
+wrong socket, for instance). </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholder-transferdumpc.html b/doc/s6-fdholder-transferdumpc.html
new file mode 100644
index 0000000..7bd6aa0
--- /dev/null
+++ b/doc/s6-fdholder-transferdumpc.html
@@ -0,0 +1,82 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholder-transferdumpc program</title>
+ <meta name="Description" content="s6: the s6-fdholder-transferdumpc program" />
+ <meta name="Keywords" content="s6 s6-fdholder fd-holding fd-holder fd dump transfer unix socket activation" />
+ <!-- <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>s6-fdholder-transferdumpc</tt> program </h1>
+
+<p>
+<tt>s6-fdholder-transferdumpc</tt> talks to two
+<a href="s6-fdholderd.html">fd-holding daemons</a>: the source of the
+transfer on its
+standard input, and the destination of the transfer on its standard output,
+both being
+open Unix domain sockets. It retrieves the entire storage state of
+the source daemon and dumps it into the destination daemon.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholder-transferdumpc [ -t <em>timeoutfrom</em> ] [ -T timeoutto ]
+</pre>
+
+<ul>
+ <li> s6-fdholder-transferdumpc expects to talk to a listening
+<a href="s6-fdholderd.html">s6-fdholderd</a> program on its descriptor 0 and
+to another one on its descriptor 1. </li>
+ <li> It gets the entire set of file descriptors from the first
+server, with their identifiers and possibly expiration dates. </li>
+ <li> It stores that set into the second server. The set is
+<em>added</em> to the second server, which keeps the descriptors
+it was already holding. </li>
+ <li> It then exits 0, or 1 if a server returned an error. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+<li> <tt>-t&nbsp;<em>timeoutfrom</em></tt>&nbsp;: if the set-retrieving
+operation cannot be processed in <em>timeoutfrom</em> milliseconds, then
+fail with an error message.
+Communications with the server should be near-instant, so this option is
+only here to protect users against programming errors. </li>
+<li> <tt>-T&nbsp;<em>timeoutto</em></tt>&nbsp;: same thing with the
+set-storing operation. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-fdholder-transferdumpc is the "internal" version of
+<a href="s6-fdholder-transferdump.html">s6-fdholder-transferdump</a>. It simply
+expects to be run with file descriptors already open to both
+servers; <a href="s6-fdholder-transferdump.html">s6-fdholder-transferdump</a>
+takes care of all the plumbing. </li>
+ <li> The error messages for the s6-fdholder suite are explained
+<a href="s6-fdholder-errorcodes.html">here</a>. </li>
+ <li> Dumping the entire state of <a href="s6-fdholderd.html">s6-fdholderd</a>
+requires special authorizations. Make sure the s6-fdholderd instances are
+<a href="s6-fdholderd.html#configuration">configured</a> to accept
+dump-getting and dump-setting requests from your client. </li>
+ <li> The point of the
+<a href="s6-fdholder-transferdump.html">s6-fdholder-transferdump</a> and
+s6-fdholder-transferdumpc programs is to move a set of fds from one
+daemon to another, for instance in the event that the first one has to
+to shut down for an upgrade. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-fdholderd.html b/doc/s6-fdholderd.html
new file mode 100644
index 0000000..0977101
--- /dev/null
+++ b/doc/s6-fdholderd.html
@@ -0,0 +1,318 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6: the s6-fdholderd program</title>
+ <meta name="Description" content="s6: the s6-fdholderd program" />
+ <meta name="Keywords" content="s6 s6-fdholderd fd-holding fd-holder fd unix socket activation server daemon" />
+ <!-- <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>s6-fdholderd</tt> program </h1>
+
+<p>
+<tt>s6-fdholderd</tt> is the serving part of the
+<a href="s6-fdholder-daemon.html">s6-fdholder-daemon</a>
+fd-holding server.
+It assumes that its stdin is a bound and listening Unix
+domain socket, and
+it accepts connections from clients connecting to it, and stores and
+retrieves file descriptors on their behalf.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-fdholderd [ -1 ] [ -v verbosity ] [ -c <em>maxconn</em> ] [ -n <em>maxfds</em> ] [ -i <em>rulesdir</em> | -x <em>rulesfile</em> ]
+</pre>
+
+<ul>
+ <li> s6-fdholderd accepts connections from clients to an already
+bound and listening SOCK_STREAM Unix domain socket which is its
+standard input. </li>
+ <li> Depending on the verbosity level, it logs what it does to stderr. </li>
+ <li> It runs until killed by a signal. Depending on the received
+signal, it may kill its children before exiting. </li>
+ <li> Client connections are short-lived. Clients generally perform
+one operation, then disconnect. </li>
+ <li> Possible operations include:
+ <ul>
+ <li> <a href="s6-fdholder-storec.html">Storing a file descriptor</a> </li>
+ <li> <a href="s6-fdholder-retrievec.html">Retrieving a file descriptor</a> </li>
+ <li> <a href="s6-fdholder-deletec.html">Deleting a file descriptor</a> </li>
+ <li> <a href="s6-fdholder-listc.html">Listing stored file descriptor
+identifiers</a> </li>
+ <li> <a href="s6-fdholder-getdumpc.html">Getting the whole server state</a> </li>
+ <li> <a href="s6-fdholder-setdumpc.html">Setting the whole server state</a>,
+or more accurately adding a set of file descriptors to the already existing
+state </li>
+ </ul> </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-1</tt>&nbsp;: write a newline to stdout, and close stdout,
+right before entering the client-accepting loop.
+If stdout is suitably redirected, this can be used by monitoring
+programs to check when the server is accepting connections.
+The <a href="s6-notifywhenup.html">s6-notifywhenup</a>
+program can be used before the s6-ipcserver
+invocation to notify listeners when the server is ready. </li>
+ <li> <tt>-v&nbsp;<em>verbosity</em></tt>&nbsp;: be more or less
+verbose. <em>verbosity</em> can be 0 (quiet), 1 (normal), or 2 or more
+(verbose). </li>
+ <li> <tt>-c&nbsp;<em>maxconn</em></tt>&nbsp;: accept at most
+<em>maxconn</em> concurrent connections. Default is 16. It is
+impossible to set it higher than the value of the S6_FDHOLDER_MAX macro,
+i.e. 256. Client connections to this server are short-lived, so this
+number needs not be too high. Every client connection eats up
+one available file descriptor, so it is best for <em>maxconn</em> to be
+as small as possible. </li>
+ <li> <tt>-n&nbsp;<em>maxfds</em></tt>&nbsp;: store at most
+<em>maxfds</em> file descriptors. Default is 1000.
+It is impossible to set it higher than the number of files that can
+be opened by the s6-fdholderd process, minus a few descriptors
+needed for correct operation. Before running s6-fdholderd, make sure to
+<a href="s6-softlimit.html">properly adjust</a> the
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_resource.h.html">number
+of openable files</a> of the current process. </li>
+ <li> <tt>-t&nbsp;<em>clienttimeout</em></tt>&nbsp;: disconnect a client
+if it's in the middle of an operation and it has not written or read any
+data in <em>clienttimeout</em> milliseconds. By default, <em>clienttimeout</em>
+is 0, which means infinite. </li>
+ <li> <tt>-T&nbsp;<em>lameducktimeout</em></tt>&nbsp;: give clients
+<em>lameducktimeout</em> milliseconds to finish their current operation
+before exiting after receiving a SIGTERM. By default, <em>lameducktimeout</em>
+is 0, which means infinite. </li>
+ <li> <tt>-x&nbsp;<em>rulesfile</em></tt>&nbsp;: read access rights
+configuration from
+<a href="http://en.wikipedia.org/wiki/Cdb_%28software%29">CDB</a>
+file <em>rulesfile</em>. </li>
+ <li> <tt>-i&nbsp;<em>rulesdir</em></tt>&nbsp;: read access rights
+configuration from the filesystem in directory <em>rulesdir</em>. </li>
+</ul>
+
+<h2> Signals </h2>
+
+<ul>
+ <li> SIGTERM: enter lameduck mode, then exit when no more operation
+is pending. </li>
+ <li> SIGHUP: reopen <em>rulesfile</em>, if s6-fdholderd has been run
+with the <tt>-x</tt> option. It is not necessary to send s6-fdholderd
+a SIGHUP when the <tt>-i</tt> option is used instead: configuration
+changes in the filesystem are automatically picked up. </li>
+</ul>
+
+<h2> Identifiers </h2>
+
+<ul>
+ <li> Every file descriptor is stored in the s6-fdholderd daemon via the
+<a href="s6-fdholder-storec.html">s6-fdholder-storec</a> program, with
+an <em>identifier</em>. That identifier is a zero-terminated character
+string, containing 1 to 255 characters. </li>
+ <li> Any non-null character can be used in an identifier. Non-printable or
+special characters will be quoted when printed by
+<a href="s6-fdholder-listc.html">s6-fdholder-listc</a>. However, it is
+recommended to only use reasonable characters in identifiers: clients
+should be able to know at a glance what file descriptor is represented by
+an identifier. Identifiers have no special meaning to the server. </li>
+ <li> A good convention is to use <tt>unix:/<em>path</em>/<em>to</em>/<em>socket</em></tt> for
+Unix domain sockets and <tt><em>protocol</em>:<em>ip</em>:</em><em>port</em></tt>
+for INET domain sockets. </li>
+ <li> An identifier is chosen by the storing client, within the limits of
+what the server authorizes it to use. </li>
+ <li> The retrieving client must know the exact identifier corresponding to
+a descriptor to be able to retrieve that descriptor. It must also be
+authorized by the server. </li>
+ <li> When an identifier is in use, it cannot be used again to store another
+descriptor. However, once the descriptor has been deleted or has expired,
+it is possible to reuse the same identifier. </li>
+</ul>
+
+<a name="configuration">
+<h2> Configuration </h2>
+</a>
+
+<p>
+ Before running s6-fdholderd (or its wrapper
+<a href="s6-fdholder-daemon.html">s6-fdholder-daemon</a>), it is necessary
+to configure it. This is done by a series of rules, or <em>ruleset</em>,
+stored in either a <em>rulesfile</em> in the
+<a href="http://en.wikipedia.org/wiki/Cdb_%28software%29">CDB</a> format,
+or in a <em>rulesdir</em>, i.e. a directory in the filesystem following a
+certain format. s6-fdholderd will refuse to run if neither the <tt>-i</tt>
+nor the <tt>-x</tt> option have been provided.
+</p>
+
+<p>
+ Rulesets can be converted between the <em>rulesdir</em> and
+<em>rulesfile</em> formats with the
+<a href="s6-accessrules-cdb-from-fs.html">s6-accessrules-cdb-from-fs</a> and
+<a href="s6-accessrules-fs-from-cdb.html">s6-accessrules-fs-from-cdb</a>
+conversion tools.
+</p>
+
+<h3> Rules format </h3>
+
+<p>
+ The rules file, or rules directory, follows the
+<a href="libs6/accessrules.html">s6 accessrules format</a> for uid and
+gid checking. For every connecting client, s6-fdholderd matches the uid
+and gid of the client against the provided ruleset, and determines what
+the client is authorized to do.
+</p>
+
+<p>
+ By default, no client is allowed to do anything - not even
+connect to the server. Even <tt>root</tt>, the super-user, will be denied
+access. That's why
+it is essential to create a sensible ruleset prior to running the server
+in order to do anything useful.
+</p>
+
+<p>
+ The various rights that a client can have are the following (using a
+rulesdir as an example, but a rulesfile works the same way):
+</p>
+
+<ul>
+ <li> Connect to the server. This is a prerequisite for
+doing anything. It will allow a client to perform "public" operations,
+ones that do not require specific access rights other than connecting:
+for instance, listing all identifiers. This right is given if an
+<tt>allow</tt> file is found in one of the subdirectories checked by
+<a href="libs6/accessrules.html#uidgid">s6_accessrules_keycheck_uidgid</a>.
+For instance, to allow everyone to connect, touch
+<tt><em>rulesdir</em>/uid/default/allow</tt>. </li>
+</ul>
+
+<p>
+ The other rights are defined in the "environment" part of the ruleset:
+</p>
+
+<ul>
+ <li> File descriptor storage rights. This will be checked for storage and
+deletion of individual file descriptors. This right is given if a non-empty
+file named <tt>S6_FDHOLDER_STORE_REGEX</tt> is found is the <tt>env/</tt>
+subdirectory of one of the subdirectories checked by
+<a href="libs6/accessrules.html#uidgid">s6_accessrules_keycheck_uidgid</a>.
+This file should contain a single line, which will be interpreted as an
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
+regular expression</a> by s6-fdholderd; the regular expression describes the
+set of identifiers that the client is allowed to use to store file
+descriptors. For instance, <tt>^unix:/tmp/</tt> indicates that a client
+that matches this rule will be allowed to store or delete file descriptors
+using any identifier starting with <tt>unix:/tmp/</tt>. </li>
+ <li> File descriptor retrieval rights. This will be checked for retrieval
+of individual file descriptors. This right is given if a non-empty
+file named <tt>S6_FDHOLDER_RETRIEVE_REGEX</tt> is found is the <tt>env/</tt>
+subdirectory of one of the subdirectories checked by
+<a href="libs6/accessrules.html#uidgid">s6_accessrules_keycheck_uidgid</a>.
+This file should contain a single line, which will be interpreted as an
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
+regular expression</a> by s6-fdholderd; the regular expression describes the
+set of identifiers that the client is allowed to use to retrieve file
+descriptors. For instance, <tt>^unix:/tmp/</tt> indicates that a client
+that matches this rule will be allowed to retrieve file descriptors that are
+identified by strings starting with <tt>unix:/tmp/</tt>. </li>
+ <li> Dump reading rights. This will be checked for clients wanting to
+copy the whole state of the server. This right is given if a non-empty
+file named <tt>S6_FDHOLDER_GETDUMP</tt> is found is the <tt>env/</tt>
+subdirectory of one of the subdirectories checked by
+<a href="libs6/accessrules.html#uidgid">s6_accessrules_keycheck_uidgid</a>.
+This is very powerful: you should only give this right to <tt>root</tt>,
+or to a dedicated uid that is only used to perform dump transfers. </li>
+ <li> Dump writing rights. This will be checked for clients wanting to
+copy an entire set of file descriptors into the server.
+This right is given if a non-empty
+file named <tt>S6_FDHOLDER_SETDUMP</tt> is found is the <tt>env/</tt>
+subdirectory of one of the subdirectories checked by
+<a href="libs6/accessrules.html#uidgid">s6_accessrules_keycheck_uidgid</a>.
+This is very powerful: you should only give this right to <tt>root</tt>, or
+to a dedicated uid that is only used to perform dump transfers. </li>
+</ul>
+
+<h3> Configuration examples </h3>
+
+<p>
+ Assuming you want to run a s6-fdholderd daemon in the
+<tt>/service/fdholder</tt> directory with the <tt>-i rules</tt> option,
+you should:
+</p>
+
+<ul>
+ <li> Prepare the rules directory: <tt>mkdir /service/fdholder/rules ;
+cd /service/fdholder/rules ; mkdir uid gid</tt> </li>
+ <li> Allow a few users, or everyone, to connect. To allow root to
+connect: <tt>mkdir uid/0 ; touch uid/0/allow</tt>. To allow everyone
+to connect: <tt>mkdir uid/default ; touch uid/default/allow</tt>. </li>
+</ul>
+
+<p>
+ Depending on your policy, you should now give certain rights to
+certain users or groups. For instance:
+</p>
+
+<ul>
+ <li> To allow user number 50 to perform dump transfers from and to
+this server: <tt>mkdir -p uid/50/env ; touch uid/50/allow ;
+echo &gt; uid/50/env/S6_FDHOLDER_GETDUMP ; echo &gt;
+uid/50/env/S6_FDHOLDER_SETDUMP</tt> </li>
+ <li> To allow user number 72 to store a descriptor under the name
+<tt>foobar</tt> and <em>only</em> this name: <tt>mkdir -p uid/72/env ;
+touch uid/72/allow ; echo '^foobar$' &gt;
+uid/72/env/S6_FDHOLDER_STORE_REGEX</tt> </li>
+ <li> To allow users having 23 as their primary group number to retrieve file
+descriptors with an identifier containing <tt>foo</tt>, then one
+character, then <tt>bar</tt>:
+<tt>mkdir -p gid/23/env ; touch gid/23/allow ; echo foo.bar &gt;
+gid/23/env/S6_FDHOLDER_RETRIEVE_REGEX</tt> </li>
+ <li> To allow everyone to dump entire states into the server:
+<tt>mkdir -p uid/default/env ; touch uid/default/allow ;
+echo &gt; uid/default/env/S6_FDHOLDER_SETDUMP</tt>.
+<strong>Never do this!</strong> </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> s6-fdholderd is meant to be execve'd into by a program that gets
+the listening socket. That program is normally
+<a href="s6-ipcserver-socketbinder.html">s6-ipcserver-socketbinder</a>,
+which creates the socket itself; but it can be a different one if the
+socket is to be obtained by another means, for instance if it has
+been retrieved from another fd-holding daemon. </li>
+ <li> s6-fdholderd will store any open file descriptor, without
+discriminating on its type. However, it makes more sense to store certain
+file descriptor types than others: for instance, Unix domain or INET domain
+sockets, or named pipes, are good candidates for fd-holding. On the other
+hand, it makes little sense to fd-hold regular files, and if done anyway,
+the results can be surprising, because the read/write file offset is
+stored with the descriptor, and no automatic rewind is performed by the
+daemon. </li>
+ <li> Anyone that is allowed to connect is allowed to read the whole list
+of identifiers. This is intentional: identifiers should be public and
+well-known, and the security of the system should not depend on a client
+not knowing what identifier a certain descriptor is stored under. If you
+need to hold descriptors that only a few programs are supposed to access,
+you can always run a separate s6-fdholderd instance in a private directory
+with a configuration tailored to your needs
+- and you can even make the name of the listening socket private.
+s6-fdholderd is lightweight, you can start as many instances as you need,
+and you can run them as long as you need then kill them with SIGTERM.
+ <li> s6-fdholderd pre-allocates its storage at start, in the stack. It
+uses a small amount of heap memory for communication with a client, but frees
+it as soon as the client disconnects. It should never run out of memory in
+normal usage, even if used intensively. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-ipcserver.html b/doc/s6-ipcserver.html
index 855fe4b..54fe040 100644
--- a/doc/s6-ipcserver.html
+++ b/doc/s6-ipcserver.html
@@ -128,31 +128,6 @@ program to easily script a service that binds to a privileged socket
then drops its privileges to those of a named non-root account. </li>
</ul>
-<h2> Implementation </h2>
-
-<ul>
- <li> s6-ipcserver parses the options and arguments it is given, and
-builds a new command line with them. It then executes into that new
-command line. </li>
- <li> The first program s6-ipcserver executes into is
-<a href="s6-ipcserver-socketbinder.html">s6-ipcserver-socketbinder</a>.
-It will create and bind a Unix domain socket to <em>path</em>, then
-execute into the rest of the command line. </li>
- <li> If a privilege-dropping operation has been requested, the
-program that s6-ipcserver-socketbinder executes into is
-<a href="s6-applyuidgid.html">s6-applyuidgid</a>.
-It will drop the root privileges, then execute into the rest of the
-command line. </li>
- <li> The next program in the chain is
-<a href="s6-ipcserverd.html">s6-ipcserverd</a>. It is executed into
-by s6-applyuidgid, or directly by s6-ipcserver-socketbinder if no
-privilege-dropping operation has been requested. s6-ipcserverd is
-the long-lived process, the "daemon" itself, accepting connections
-from clients. </li>
- <li> For every client, s6-ipcserverd will spawn an instance of
-<em>prog...</em>, the remainder of the command line. </li>
-</ul>
-
<h2> Notes </h2>
<ul>
diff --git a/doc/s6-notifywhenup.html b/doc/s6-notifywhenup.html
index 10fa6d8..ee5a99e 100644
--- a/doc/s6-notifywhenup.html
+++ b/doc/s6-notifywhenup.html
@@ -74,7 +74,9 @@ achieved. <tt>s6-notifywhenup -f s6-ipcserver -1 <em>args</em></tt> will
send a 'U' event to <tt>./event</tt> when s6-ipcserver is actually
listening to its socket. </li>
<li> The <a href="s6-svwait.html">s6-svwait</a> program can be used
-to wait for 'U' events. </li>
+to wait for 'U' events, as well as the
+<a href="s6-svlisten1.html">s6-svlisten1</a> and
+<a href="s6-svlisten.html">s6-svlisten</a> programs. </li>
<li> The <tt>supervise/ready</tt> file, when created, contains at least
the absolute time when s6-notifywhenup detected service readiness. The
format and contents of this file are subject to change. </li>
diff --git a/doc/s6-svlisten.html b/doc/s6-svlisten.html
index eeb0a91..1561394 100644
--- a/doc/s6-svlisten.html
+++ b/doc/s6-svlisten.html
@@ -51,7 +51,7 @@ their state changes. </li>
<li> It spawns <em>prog...</em> as a child right after getting the
initial state of all the monitored services. </li>
<li> It then blocks until the wanted state happens, then exits 0. </li>
-</p>
+</ul>
<h2> Options </h2>
@@ -91,7 +91,7 @@ sequentially. </li>
For that, it uses an encoding provided by
<a href="http://skarnet.org/software/execline/">execline</a>, so it's best
to only use it in execline scripts (only the execline syntax is guaranteed
-to not change). There is a variant of s6-svlisten that does not use execline
+not to change). There is a variant of s6-svlisten that does not use execline
syntax, but only handles one service directory:
<a href="s6-svlisten1.html">s6-svlisten1</a>. </li>
</ul>
diff --git a/doc/s6-svlisten1.html b/doc/s6-svlisten1.html
index f6565ed..77eda9a 100644
--- a/doc/s6-svlisten1.html
+++ b/doc/s6-svlisten1.html
@@ -39,7 +39,7 @@ state changes. </li>
<li> It spawns <em>prog...</em> as a child right after getting the
initial state of the service. </li>
<li> It then blocks until the wanted state happens, then exits 0. </li>
-</p>
+</ul>
<h2> Options </h2>
diff --git a/package/deps.mak b/package/deps.mak
index b7163fa..d93bfb3 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -169,6 +169,10 @@ ucspilogd: private EXTRA_LIBS :=
ucspilogd: src/daemontools-extras/ucspilogd.o -lskarnet
s6-fdholder-daemon: private EXTRA_LIBS :=
s6-fdholder-daemon: src/fdholder/s6-fdholder-daemon.o -lskarnet
+s6-fdholder-delete: private EXTRA_LIBS :=
+s6-fdholder-delete: src/fdholder/s6-fdholder-delete.o -lskarnet
+s6-fdholder-deletec: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB}
+s6-fdholder-deletec: src/fdholder/s6-fdholder-deletec.o ${LIBS6} -lskarnet
s6-fdholder-getdump: private EXTRA_LIBS :=
s6-fdholder-getdump: src/fdholder/s6-fdholder-getdump.o -lskarnet
s6-fdholder-getdumpc: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB}
diff --git a/package/modes b/package/modes
index a635703..9692b1a 100644
--- a/package/modes
+++ b/package/modes
@@ -43,6 +43,8 @@ s6-sudoc 0755
s6-sudod 0755
s6-fdholder-daemon 0755
s6-fdholderd 0755
+s6-fdholder-delete 0755
+s6-fdholder-deletec 0755
s6-fdholder-store 0755
s6-fdholder-storec 0755
s6-fdholder-retrieve 0755
diff --git a/package/targets.mak b/package/targets.mak
index ecd6fe4..277617a 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -41,6 +41,8 @@ s6-sudoc \
s6-sudod \
s6-fdholder-daemon \
s6-fdholderd \
+s6-fdholder-delete \
+s6-fdholder-deletec \
s6-fdholder-store \
s6-fdholder-storec \
s6-fdholder-retrieve \
diff --git a/src/fdholder/deps-exe/s6-fdholder-delete b/src/fdholder/deps-exe/s6-fdholder-delete
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-delete
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-deletec b/src/fdholder/deps-exe/s6-fdholder-deletec
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-deletec
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/s6-fdholder-delete.c b/src/fdholder/s6-fdholder-delete.c
new file mode 100644
index 0000000..7742148
--- /dev/null
+++ b/src/fdholder/s6-fdholder-delete.c
@@ -0,0 +1,51 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-delete [ -t timeout ] socket id"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ char const *newargv[10] ;
+ unsigned int timeout = 0 ;
+ unsigned int m = 0 ;
+ char fmtt[UINT_FMT] ;
+ PROG = "s6-fdholder-delete" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+ if (argc < 2) dieusage() ;
+
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[0] ;
+ newargv[m++] = S6_BINPREFIX "s6-fdholder-deletec" ;
+ if (timeout)
+ {
+ fmtt[uint_fmt(fmtt, timeout)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtt ;
+ }
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[1] ;
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+}
diff --git a/src/fdholder/s6-fdholder-deletec.c b/src/fdholder/s6-fdholder-deletec.c
new file mode 100644
index 0000000..ce26635
--- /dev/null
+++ b/src/fdholder/s6-fdholder-deletec.c
@@ -0,0 +1,42 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholder-deletec [ -t timeout ] id"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+ tain_t deadline ;
+ PROG = "s6-fdholder-deletec" ;
+ {
+ unsigned int t = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ }
+ if (!argc) dieusage() ;
+
+ s6_fdholder_init(&a, 6) ;
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+ if (!s6_fdholder_delete_g(&a, argv[0], &deadline))
+ strerr_diefu1sys(1, "delete fd") ;
+ return 0 ;
+}
diff --git a/src/fdholder/s6-fdholder-getdumpc.c b/src/fdholder/s6-fdholder-getdumpc.c
index ff7fd9d..85c288c 100644
--- a/src/fdholder/s6-fdholder-getdumpc.c
+++ b/src/fdholder/s6-fdholder-getdumpc.c
@@ -41,7 +41,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
tain_now_g() ;
tain_add_g(&deadline, &deadline) ;
if (!s6_fdholder_getdump_g(&a, &dump, &deadline))
- strerr_diefu1sys(111, "get dump") ;
+ strerr_diefu1sys(1, "get dump") ;
s6_fdholder_free(&a) ;
tain_half(&halfinfinite, &tain_infinite_relative) ;
tain_add_g(&halfinfinite, &halfinfinite) ;
@@ -67,14 +67,14 @@ int main (int argc, char const *const *argv, char const *const *envp)
modifs[pos++] = '=' ;
byte_copy(modifs + pos, len, p->id) ;
pos += len ;
+ byte_copy(modifs + pos, 11, "S6_FDLIMIT_") ; pos += 11 ;
+ pos += uint_fmt(modifs + pos, i) ;
if (tain_less(&p->limit, &halfinfinite))
{
- byte_copy(modifs + pos, 11, "S6_FDLIMIT_") ; pos += 11 ;
- pos += uint_fmt(modifs + pos, i) ;
modifs[pos++] = '=' ;
pos += timestamp_fmt(modifs + pos, &p->limit) ;
- modifs[pos++] = 0 ;
}
+ modifs[pos++] = 0 ;
}
pathexec_r(argv, envp, env_len(envp), modifs, pos) ;
}
diff --git a/src/fdholder/s6-fdholder-listc.c b/src/fdholder/s6-fdholder-listc.c
index fefb676..6bd2104 100644
--- a/src/fdholder/s6-fdholder-listc.c
+++ b/src/fdholder/s6-fdholder-listc.c
@@ -43,7 +43,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
tain_now_g() ;
tain_add_g(&deadline, &deadline) ;
n = s6_fdholder_list_g(&a, &sa, &deadline) ;
- if (n < 0) strerr_diefu1sys(111, "get fd list") ;
+ if (n < 0) strerr_diefu1sys(1, "get fd list") ;
while (n--)
{
register unsigned int len = str_len(sa.s + pos) ;
diff --git a/src/fdholder/s6-fdholder-retrievec.c b/src/fdholder/s6-fdholder-retrievec.c
index 2aea31e..8b86bc4 100644
--- a/src/fdholder/s6-fdholder-retrievec.c
+++ b/src/fdholder/s6-fdholder-retrievec.c
@@ -41,7 +41,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
tain_now_g() ;
tain_add_g(&deadline, &deadline) ;
fd = s6_fdholder_retrieve_maybe_delete_g(&a, argv[0], dodelete, &deadline) ;
- if (fd < 0) strerr_diefu2sys(111, "retrieve fd for id ", argv[0]) ;
+ if (fd < 0) strerr_diefu2sys(1, "retrieve fd for id ", argv[0]) ;
else if (!fd)
{
if (uncoe(0) < 0) strerr_diefu1sys(111, "uncoe stdin") ;
diff --git a/src/fdholder/s6-fdholder-setdumpc.c b/src/fdholder/s6-fdholder-setdumpc.c
index 8a74dba..9e253d9 100644
--- a/src/fdholder/s6-fdholder-setdumpc.c
+++ b/src/fdholder/s6-fdholder-setdumpc.c
@@ -70,7 +70,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
else if (!timestamp_scan(x, &dump[i].limit)) strerr_dieinvalid(100, s) ;
}
if (!s6_fdholder_setdump_g(&a, dump, dumplen, &deadline))
- strerr_diefu1sys(111, "set dump") ;
+ strerr_diefu1sys(1, "set dump") ;
}
return 0 ;
}
diff --git a/src/fdholder/s6-fdholder-storec.c b/src/fdholder/s6-fdholder-storec.c
index 57257da..eeb0ed8 100644
--- a/src/fdholder/s6-fdholder-storec.c
+++ b/src/fdholder/s6-fdholder-storec.c
@@ -41,6 +41,6 @@ int main (int argc, char const *const *argv, char const *const *envp)
tain_add_g(&deadline, &deadline) ;
tain_add_g(&limit, &limit) ;
if (!s6_fdholder_store_g(&a, 0, argv[0], &limit, &deadline))
- strerr_diefu1sys(111, "store fd") ;
+ strerr_diefu1sys(1, "store fd") ;
return 0 ;
}
diff --git a/src/fdholder/s6-fdholder-transferdumpc.c b/src/fdholder/s6-fdholder-transferdumpc.c
index e0ed069..b5be170 100644
--- a/src/fdholder/s6-fdholder-transferdumpc.c
+++ b/src/fdholder/s6-fdholder-transferdumpc.c
@@ -41,11 +41,11 @@ int main (int argc, char const *const *argv, char const *const *envp)
tain_now_g() ;
tain_add_g(&deadline, &deadline) ;
if (!s6_fdholder_getdump_g(&a, &dump, &deadline))
- strerr_diefu1sys(111, "get dump") ;
+ strerr_diefu1sys(1, "get dump") ;
s6_fdholder_free(&a) ;
s6_fdholder_init(&a, 1) ;
tain_add_g(&deadline, &totto) ;
if (!s6_fdholder_setdump_g(&a, genalloc_s(s6_fdholder_fd_t, &dump), genalloc_len(s6_fdholder_fd_t, &dump), &deadline))
- strerr_diefu1sys(111, "set dump") ;
+ strerr_diefu1sys(1, "set dump") ;
return 0 ;
}
diff --git a/src/fdholder/s6-fdholderd.c b/src/fdholder/s6-fdholderd.c
index 0404165..218e338 100644
--- a/src/fdholder/s6-fdholderd.c
+++ b/src/fdholder/s6-fdholderd.c
@@ -243,7 +243,7 @@ static int do_store (unsigned int cc, unixmessage_t const *m)
if (numfds >= maxfds)
{
unixmessage_drop(m) ;
- return answer(c, ENOSPC) ;
+ return answer(c, ENFILE) ;
}
if (avltreen_search(fds_by_id, m->s + TAIN_PACK + 1, &pp))
{
@@ -639,7 +639,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
{
int spfd ;
int flag1 = 0 ;
- unsigned int maxconn = 40 ;
+ unsigned int maxconn = 16 ;
PROG = "s6-fdholderd" ;
{
@@ -760,7 +760,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
if (!r)
{
- if (!cont && !tain_future(&lameduckdeadline)) return 1 ;
+ if (!cont && !tain_future(&lameduckdeadline)) break ;
for (;;)
{
if (!avltreeb_min(&fdmap_deadline, &i)) break ;
@@ -793,6 +793,6 @@ int main (int argc, char const *const *argv, char const *const *envp)
else client_add(&i, fd, &rre, &wre, flags) ;
}
}
+ return (~!numfds | (!!numconn << 1)) ;
}
- return 0 ;
}
diff --git a/src/include/s6/s6-fdholder.h b/src/include/s6/s6-fdholder.h
index d15b869..af0f6c5 100644
--- a/src/include/s6/s6-fdholder.h
+++ b/src/include/s6/s6-fdholder.h
@@ -10,7 +10,7 @@
#include <skalibs/unixconnection.h>
#define S6_FDHOLDER_ID_SIZE 255
-#define S6_FDHOLDER_MAX 16
+#define S6_FDHOLDER_MAX 256
typedef struct s6_fdholder_s s6_fdholder_t, *s6_fdholder_t_ref ;
struct s6_fdholder_s
diff --git a/src/libs6/s6_svstatus_read.c b/src/libs6/s6_svstatus_read.c
index 59a31a5..334dc47 100644
--- a/src/libs6/s6_svstatus_read.c
+++ b/src/libs6/s6_svstatus_read.c
@@ -8,9 +8,9 @@ int s6_svstatus_read (char const *dir, s6_svstatus_t *status)
{
unsigned int n = str_len(dir) ;
char pack[S6_SVSTATUS_SIZE] ;
- char tmp[n + 2 + sizeof(S6_SVSTATUS_FILENAME)] ;
+ char tmp[n + 1 + sizeof(S6_SVSTATUS_FILENAME)] ;
byte_copy(tmp, n, dir) ;
- byte_copy(tmp + n, 2 + sizeof(S6_SVSTATUS_FILENAME), "/" S6_SVSTATUS_FILENAME) ;
+ byte_copy(tmp + n, 1 + sizeof(S6_SVSTATUS_FILENAME), "/" S6_SVSTATUS_FILENAME) ;
if (openreadnclose(tmp, pack, S6_SVSTATUS_SIZE) < S6_SVSTATUS_SIZE) return 0 ;
s6_svstatus_unpack(pack, status) ;
return 1 ;
diff --git a/src/libs6/s6_svstatus_write.c b/src/libs6/s6_svstatus_write.c
index 2cc8a7b..e07d744 100644
--- a/src/libs6/s6_svstatus_write.c
+++ b/src/libs6/s6_svstatus_write.c
@@ -8,9 +8,9 @@ int s6_svstatus_write (char const *dir, s6_svstatus_t const *status)
{
unsigned int n = str_len(dir) ;
char pack[S6_SVSTATUS_SIZE] ;
- char tmp[n + 2 + sizeof(S6_SVSTATUS_FILENAME)] ;
+ char tmp[n + 1 + sizeof(S6_SVSTATUS_FILENAME)] ;
byte_copy(tmp, n, dir) ;
- byte_copy(tmp + n, 2 + sizeof(S6_SVSTATUS_FILENAME), "/" S6_SVSTATUS_FILENAME) ;
+ byte_copy(tmp + n, 1 + sizeof(S6_SVSTATUS_FILENAME), "/" S6_SVSTATUS_FILENAME) ;
s6_svstatus_pack(pack, status) ;
return openwritenclose_suffix(tmp, pack, S6_SVSTATUS_SIZE, ".new") ;
}