s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

commit a3cdeecf0033919e3b5a79c17c19b5ac98719256
parent bd34de9054cec794d96b0fde1eee9100e1d34215
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Mon, 20 Jul 2015 20:20:54 +0000

 - Add timeout-finish support and "down-readiness"
 - LOTS of refactoring to make this work
 - Remove s6-notifywhenup
 - s6-supervise now rocks the casbah
 - rc for 2.2.0.0

Diffstat:
MINSTALL | 2+-
Mdoc/index.html | 6++----
Mdoc/notifywhenup.html | 6+++---
Ddoc/s6-notifywhenup.html | 111-------------------------------------------------------------------------------
Mdoc/s6-sudod.html | 13++++++++-----
Mdoc/s6-supervise.html | 22++++++++++++----------
Mdoc/s6-svc.html | 28++++++++++++++++++----------
Mdoc/s6-svlisten.html | 8++++++--
Mdoc/s6-svlisten1.html | 5++++-
Mdoc/s6-svstat.html | 6+++++-
Mdoc/s6-svwait.html | 10+++++++---
Mdoc/servicedir.html | 6++++++
Mdoc/upgrade.html | 21+++++++++++++++++++++
Mpackage/deps.mak | 25++++++++++++++-----------
Mpackage/info | 2+-
Mpackage/modes | 1-
Mpackage/targets.mak | 1-
Msrc/include/s6/s6-supervise.h | 23++++++++++++++---------
Msrc/libs6/deps-lib/s6 | 1+
Asrc/libs6/s6_svc_writectl.c | 16++++++++++++++++
Msrc/libs6/s6_svstatus_pack.c | 15++++++++++-----
Msrc/libs6/s6_svstatus_unpack.c | 37++++++++++++++-----------------------
Dsrc/supervision/deps-exe/s6-notifywhenup | 3---
Msrc/supervision/deps-exe/s6-svlisten | 2++
Msrc/supervision/deps-exe/s6-svlisten1 | 2++
Msrc/supervision/deps-exe/s6-svwait | 1+
Dsrc/supervision/s6-notifywhenup.c | 99-------------------------------------------------------------------------------
Msrc/supervision/s6-supervise.c | 155++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/supervision/s6-svc.c | 27+++++++++++++--------------
Msrc/supervision/s6-svlisten.c | 114+++++++++++--------------------------------------------------------------------
Asrc/supervision/s6-svlisten.h | 29+++++++++++++++++++++++++++++
Msrc/supervision/s6-svlisten1.c | 102++++++++++++++------------------------------------------------------------------
Msrc/supervision/s6-svscanctl.c | 12+++---------
Msrc/supervision/s6-svstat.c | 31+++++++++----------------------
Msrc/supervision/s6-svwait.c | 92++++++++++++-------------------------------------------------------------------
Asrc/supervision/s6_svlisten_loop.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/supervision/s6_svlisten_signal_handler.c | 29+++++++++++++++++++++++++++++
37 files changed, 454 insertions(+), 687 deletions(-)

diff --git a/INSTALL b/INSTALL @@ -6,7 +6,7 @@ Build Instructions - A POSIX-compliant C development environment - GNU make version 4.0 or later - - skalibs version 2.3.5.1 or later: http://skarnet.org/software/skalibs/ + - skalibs version 2.3.6.0 or later: http://skarnet.org/software/skalibs/ - execline version 2.1.2.2 or later: http://skarnet.org/software/execline/ This software will run on any operating system that implements diff --git a/doc/index.html b/doc/index.html @@ -84,7 +84,7 @@ with s6</a> </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.3.5.1 or later. It's a build-time requirement. It's also a run-time +2.3.6.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 @@ -101,7 +101,7 @@ library. </li> <h3> Download </h3> <ul> - <li> The current released version of s6 is <a href="s6-2.1.6.0.tar.gz">2.1.6.0</a>. </li> + <li> The current released version of s6 is <a href="s6-2.2.0.0.tar.gz">2.2.0.0</a>. </li> <li> Alternatively, you can checkout a copy of the s6 git repository: <pre> git clone git://git.skarnet.org/s6 </pre> </li> <li> There's also a @@ -153,8 +153,6 @@ a user interface to control those processes and monitor service states. <li><a href="s6-svwait.html">The <tt>s6-svwait</tt> program</a></li> <li><a href="s6-svlisten1.html">The <tt>s6-svlisten1</tt> program</a></li> <li><a href="s6-svlisten.html">The <tt>s6-svlisten</tt> program</a></li> -<li><a href="s6-notifywhenup.html">The <tt>s6-notifywhenup</tt> program</a> -<strong>(deprecated)</strong></li> </ul> <h4> Daemontools-like utilities </h4> diff --git a/doc/notifywhenup.html b/doc/notifywhenup.html @@ -67,16 +67,16 @@ a generic mechanism that some daemons already implement. <a href="servicedir.html">service directory</a> for the daemon contains a valid <tt>notification-fd</tt> file, the daemon's supervisor, i.e. the <a href="s6-supervise.html">s6-supervise</a> program, will properly catch -the daemon's message, update a state file (<tt>supervise/ready</tt>), then +the daemon's message, update the status file (<tt>supervise/status</tt>), then notify all the subscribers -with a 'U' event, meaning that the service is now up and ready. +with a <tt>'U'</tt> event, meaning that the service is now up and ready. </p> <p> This method should really be implemented in every long-running program providing a service. When it is not the case, it's impossible to provide reliable startup notifications, and subscribers should then -be content with the unreliable 'u' events provided by s6-supervise. +be content with the unreliable <tt>'u'</tt> events provided by s6-supervise. </p> </body> diff --git a/doc/s6-notifywhenup.html b/doc/s6-notifywhenup.html @@ -1,111 +0,0 @@ -<html> - <head> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> - <meta http-equiv="Content-Language" content="en" /> - <title>s6: the s6-notifywhenup program</title> - <meta name="Description" content="s6: the s6-notifywhenup program" /> - <meta name="Keywords" content="s6 command s6-notifywhenup fifodir notification event notifier send service daemon ready" /> - <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> - </head> -<body> - -<p> -<a href="index.html">s6</a><br /> -<a href="http://skarnet.org/software/">Software</a><br /> -<a href="http://skarnet.org/">skarnet.org</a> -</p> - -<h1> The s6-notifywhenup program </h1> - -<em> -<p> -Starting with s6-2.1.4.0, the s6-notifywhenup program has been deprecated, -because there was still a case (albeit extremely rare) where a race -condition would occur and readiness would be improperly advertised. -Readiness notification for a service can now be achieved via a -<tt>notification-fd</tt> file in the -<a href="servicedir.html">service directory</a>, containing the -number of the descriptor the service will write its readiness -notification newline to. The notification will directly be picked by -<a href="s6-supervise.html">s6-supervise</a>. <br /> -</p> - -<p> - Quick upgrade recipe: for every service using s6-notifywhenup, -replace the s6-notifywhenup invocation in your run script with -<tt>fdmove 1 3</tt>, then perform <tt>echo 3 &gt; notification-fd</tt>. -Done! -</p> -</em> - -<p> -s6-notifywhenup launches a daemon while listening to a file descriptor, -and sends a 'U' event to a <a href="fifodir.html">fifodir</a> when it -receives something on that file descriptor. -</p> - -<p> -<a href="notifywhenup.html">This page</a> explains why this program is -needed. -</p> - -<h2> Interface </h2> - -<pre> - s6-notifywhenup [ -d <em>fd</em> ] [ -e <em>fifodir</em> ] [ -f ] [ -X ] [ -t <em>timeout</em> ] <em>prog...</em> -</pre> - -<ul> - <li> s6-notifywhenup forks and executes <em>prog...</em> as the -parent, with a pipe from <em>prog...</em>'s stdout to the child. </li> - <li> The child waits for a newline (<tt>\n</tt>) to be written -on the pipe. When it gets it, it creates a -<tt>./supervise/ready</tt> file then sends a 'U' event to the -<tt>./event</tt> fifodir. </li> - <li> The child exits 0. </li> -</ul> - -<h2> Options </h2> - -<ul> - <li> <tt>-d&nbsp;<em>fd</em></tt>&nbsp;: listen to -<em>prog</em>'s output on descriptor <em>fd</em>. The default is 1. </li> - <li> <tt>-e&nbsp;<em>fifodir</em></tt>&nbsp;: send a 'U' event to fifodir -<em>fifodir</em>. Default is <tt>./event</tt>. </li> - <li> <tt>-f</tt>&nbsp;: simple fork. Normally, s6-notifywhenup doubleforks, -in order to accommodate for a -<em>prog</em> that does not expect to have a child and avoid a -pending zombie. This option avoids the doublefork, but it should only be -set if <em>prog</em> reaps even children it doesn't know it has. </li> - <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if no EOF has been received -after <em>timeout</em> milliseconds, exit without sending the event. -Default is 0, meaning infinite. </li> - <li> <tt>-X</tt>&nbsp;: fake readiness. s6-notifywhenup will actually send -the newline itself before executing <em>prog</em>. This option should in -principle never be used. </li> -</ul> - -<h2> Notes </h2> - -<ul> - <li> s6-notifywhenup executes <em>prog...</em> as the parent in order -for <em>prog</em> to keep the same pid, which is vital for supervised -processes. </li> - <li> s6-notifywhenup can be used, for instance, with -<a href="s6-ipcserver.html">s6-ipcserver</a> -and its <tt>-1</tt> option, so that reliable startup notification is -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, 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> -</ul> - -</body> -</html> diff --git a/doc/s6-sudod.html b/doc/s6-sudod.html @@ -91,8 +91,8 @@ will set up a privileged program: <pre> #!/command/execlineb -P fdmove -c 2 1 +fdmove 1 3 s6-envuidgid serveruser -s6-notifywhenup -f s6-ipcserver -U -1 -- serversocket s6-ipcserver-access -v2 -l0 -i rules -- exec -c @@ -106,12 +106,15 @@ sargv executes the script. </li> <li> <a href="http://skarnet.org/software/execline/fdmove.html">fdmove</a> makes sure the script's error messages are sent to the service's logger. </li> + <li> <a href="http://skarnet.org/software/execline/fdmove.html">fdmove</a> +redirects the script's stdout to file descriptor 3. This is useful if +the service directory contains a <tt>notification-fd</tt> file containing +<tt>3</tt>, so the daemon can perform +<a href="notifywhenup.html">readiness notification</a> by writing a +newline to its stdout. (The +<tt>-1</tt> option to s6-ipcserver tells it to do this.) </li> <li> <a href="s6-envuidgid.html">s6-envuidgid</a> sets the UID, GID and GIDLIST environment variables for s6-ipcserver to interpret. </li> - <li> <a href="s6-notifywhenup.html">s6-notifywhenup</a> primes the -service for readiness notification (and the -<tt>-1</tt> option to s6-ipcserver tells the daemon to actually -notify when it's ready). </li> <li> <a href="s6-ipcserver.html">s6-ipcserver</a> binds to <em>serversocket</em>, drops its privileges to those of <em>serveruser</em>, and announces its readiness. Then, for every client connecting to <em>serversocket</em>: diff --git a/doc/s6-supervise.html b/doc/s6-supervise.html @@ -44,15 +44,18 @@ If it already exists, it uses it as is, without modifying the subscription right <li> If the default service state is up, s6-supervise spawns <tt>./run</tt>. </li> <li> s6-supervise sends a <tt>'u'</tt> event to <tt>./event</tt> whenever it successfully spawns <tt>./run</tt>. </li> - <li> When <tt>./run</tt> dies, s6-supervise sends a <tt>'d'</tt> event to <tt>./event</tt>. </li> - <li> When <tt>./run</tt> dies, s6-supervise spawns <tt>./finish</tt> if it exists. + <li> When <tt>./run</tt> dies, s6-supervise sends a <tt>'d'</tt> event to <tt>./event</tt>. +It then spawns <tt>./finish</tt> if it exists. <tt>./finish</tt> will have <tt>./run</tt>'s exit code as first argument, or 256 if <tt>./run</tt> was signaled; it will have the number of the signal that killed <tt>./run</tt> as second argument, or an undefined number if <tt>./run</tt> was not signaled. </li> - <li> <tt>./finish</tt> must exit in less than 5 seconds. If it takes more than that, -s6-supervise kills it with a SIGKILL. </li> - <li> When <tt>./finish</tt> dies, s6-supervise restarts <tt>./run</tt> unless it has been -told not to. </li> + <li> By default, <tt>./finish</tt> must exit in less than 5 seconds. If it takes more than that, +s6-supervise kills it with a SIGKILL. This can be configured via the +<tt>./timeout-finish</tt> file, see the description in the +<a href="servicedir.html">service directory page</a>. </li> + <li> When <tt>./finish</tt> dies (or is killed), +s6-supervise sends a <tt>'D'</tt> event to <tt>./event</tt>. Then +it restarts <tt>./run</tt> unless it has been told not to. </li> <li> There is a minimum 1-second delay between two <tt>./run</tt> spawns, to avoid busylooping if <tt>./run</tt> exits too quickly. </li> <li> When killed or asked to exit, it waits for the service to go down one last time, then @@ -78,10 +81,9 @@ what they do, are listed on the <tt>notification-fd</tt> file when the service is started, or restarted, s6-supervise creates and listens to an additional pipe from the service for <a href="notifywhenup.html">readiness notification</a>. When the -notification occurs, s6-supervise creates a <tt>./supervise/ready</tt> -file containing the absolute time when readiness occurred, then sends -a <tt>'U'</tt> event to <tt>./event</tt>. The <tt>./supervise/ready</tt> -file is deleted on service death. +notification occurs, s6-supervise updates the <tt>./supervise/status</tt> +file accordingly, then sends +a <tt>'U'</tt> event to <tt>./event</tt>. </p> <p> diff --git a/doc/s6-svc.html b/doc/s6-svc.html @@ -28,7 +28,7 @@ knowing their PIDs, and without using horrible hacks such as .pid files. <h2> Interface </h2> <pre> - s6-svc [ -D | -U ] [ -T <em>timeout</em> ] [ -abqhkti12pcoduxO ] <em>servicedir</em> + s6-svc [ -wu | -wU | -wd | -wD ] [ -T <em>timeout</em> ] [ -abqhkti12pcoduxO ] <em>servicedir</em> </pre> <p> @@ -75,13 +75,20 @@ it. </li> (in milliseconds) after which s6-svc will exit 1 with an error message if the service still hasn't reached the desired state. By default, the timeout is 0, which means that s6-svc will block indefinitely. </li> - <li> <tt>-D</tt>&nbsp;: s6-svc will not exit until the service is down. </li> - <li> <tt>-U</tt>&nbsp;: s6-svc will not exit until the service is up and + <li> <tt>-wd</tt>&nbsp;: s6-svc will not exit until the service is down, +i.e. until the <tt>run</tt> process has died. </li> + <li> <tt>-wD</tt>&nbsp;: s6-svc will not exit until the service is down +<em>and</em> ready to be brought up, i.e. a possible <tt>finish</tt> script has +exited. </li> + <li> <tt>-wu</tt>&nbsp;: s6-svc will not exit until the service is up, +i.e. there is a process running the <tt>run</tt> executable. </li> + <li> <tt>-wU</tt>&nbsp;: s6-svc will not exit until the service is up <em>and</em> <a href="notifywhenup.html">ready</a> as notified by the daemon itself. If the <a href="servicedir.html">service directory</a> does not contain a <tt>notification-fd</tt> file to tell <a href="s6-supervise.html">s6-supervise</a> to accept readiness -notification, s6-svc will print a warning and ignore the command. </li> +notification, s6-svc will print a warning and act as if the <tt>-wu</tt> +option had been given instead. </li> </ul> <h2> Usage examples </h2> @@ -100,12 +107,13 @@ the process represented by the <tt>/service/sshd</tt> service directory - typically the sshd server. </p> -<pre> s6-svc -Dd /service/ftpd </pre> +<pre> s6-svc -wD -d /service/ftpd </pre> <p> - Take down the ftpd server and block until the process is really down. + Take down the ftpd server and block until the process is down and +the finish script has completed. </p> -<pre> s6-svc -Uu -T 5000 /service/ftpd </pre> +<pre> s6-svc -wU -T 5000 -u /service/ftpd </pre> <p> Bring up the ftpd server and block until it has sent notification that it is ready. Exit 1 if it is still not ready after 5 seconds. @@ -123,10 +131,10 @@ process is <a href="s6-log.html">s6-log</a>, this triggers a log rotation. <li> s6-svc writes control commands into the <tt><em>servicedir</em>/supervise/control</tt> FIFO. A s6-supervise process running on <em>servicedir</em> will be listening to this FIFO, and will read and interpret those commands. </li> - <li> When invoked with the <tt>-D</tt> or <tt>-U</tt> option, s6-svc executes into + <li> When invoked with one of the <tt>-w</tt> options, s6-svc executes into <a href="s6-svlisten1.html">s6-svlisten1</a>, which will listen to service state -changes and spawn another s6-svc instance (without the <tt>-D</tt> or <tt>-U</tt> -option) that will send the commands to the service. Any error message written during +changes and spawn another s6-svc instance (without the <tt>-w</tt> option) +that will send the commands to the service. Any error message written during the waiting period will mention it is being written by s6-svlisten1; this is normal. </li> </ul> diff --git a/doc/s6-svlisten.html b/doc/s6-svlisten.html @@ -34,7 +34,7 @@ a collection of supervised services, and blocks until they all go up, or down. </p> <pre> - s6-svlisten [ -U | -u | -d ] [ -a | -o ] [ -t <em>timeout</em> ] { <em>servicedir</em> <em>servicedir...</em> } <em>prog...</em> + s6-svlisten [ -U | -u | -D | -d ] [ -a | -o ] [ -t <em>timeout</em> ] { <em>servicedir</em> <em>servicedir...</em> } <em>prog...</em> </pre> <p> @@ -42,7 +42,7 @@ a collection of supervised services, and blocks until they all go up, or down. </p> <pre> - s6-svlisten [ -U | -u | -d ] [ -a | -o ] [ -t <em>timeout</em> ] <em>servicedir</em> <em>servicedir...</em> "" <em>prog...</em> + s6-svlisten [ -U | -u | -D | -d ] [ -a | -o ] [ -t <em>timeout</em> ] <em>servicedir</em> <em>servicedir...</em> "" <em>prog...</em> </pre> <ul> @@ -69,6 +69,10 @@ specific support in the service programs, and the use of the <a href="servicedir.html">service directory</a>. See the explanation on <a href="notifywhenup.html">this page</a>. </li> <li> <tt>-d</tt>&nbsp;: down. s6-svlisten will wait until the services are down. </li> + <li> <tt>-D</tt>&nbsp;: really down. s6-svlisten will wait until the +services are down and the cleanup scripts in <tt><em>servicedir</em>/finish</tt> +for every <em>servicedir</em> +have finished executing (or have timed out and been killed). </li> <li> <tt>-o</tt>&nbsp;: or. s6-svlisten will wait until <em>one</em> of the given services comes up or down. </li> <li> <tt>-a</tt>&nbsp;: and. s6-svlisten will wait until <em>all</em> of the diff --git a/doc/s6-svlisten1.html b/doc/s6-svlisten1.html @@ -30,7 +30,7 @@ supervised service, and blocks until said service goes up, or down. <h2> Interface </h2> <pre> - s6-svlisten [ -U | -u | -d ] [ -t <em>timeout</em> ] <em>servicedir</em> <em>prog...</em> + s6-svlisten [ -U | -u | -D | -d ] [ -t <em>timeout</em> ] <em>servicedir</em> <em>prog...</em> </pre> <ul> @@ -57,6 +57,9 @@ specific support in the service programs, and the use of the <a href="servicedir.html">service directory</a>. See the explanation on <a href="notifywhenup.html">this page</a>. </li> <li> <tt>-d</tt>&nbsp;: down. s6-svlisten1 will wait until the service is down. </li> + <li> <tt>-D</tt>&nbsp;: really down. s6-svlisten1 will wait until the +service is down and the cleanup script in <tt><em>servicedir</em>/finish</tt> +has finished executing (or has timed out and been killed). </li> <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if the requested event has not happened after <em>timeout</em> milliseconds, s6-svlisten1 will print a message to stderr and exit 1. By default, <em>timeout</em> is 0, which means no time diff --git a/doc/s6-svstat.html b/doc/s6-svstat.html @@ -46,7 +46,11 @@ signal, if it is down </li> kernel's scheduler picks up s6-supervise </li> <li> whether the service is <a href="notifywhenup.html">ready</a>, as notified by the daemon itself, and -if it is, the number of seconds that it has been. </li> +if it is, the number of seconds that it has been. +A service reported as down and ready simply means that it is ready +to be brought up. A service is down and not ready when it is in the +cleanup phase, i.e. the <tt>./finish</tt> script is still being executed. </li> + </li> </ul> <h2> Options </h2> diff --git a/doc/s6-svwait.html b/doc/s6-svwait.html @@ -29,7 +29,7 @@ s6-svwait only waits for notifications; it never polls. <h2> Interface </h2> <pre> - s6-svwait [ -U | -u | -d ] [ -a | -o ] [ -t <em>timeout</em> ] <em>servicedir...</em> + s6-svwait [ -U | -u | -D | -d ] [ -a | -o ] [ -t <em>timeout</em> ] <em>servicedir...</em> </pre> <p> @@ -53,6 +53,11 @@ specific support in the service programs, and the use of the <a href="servicedir.html">service directory</a>. See the explanation on <a href="notifywhenup.html">this page</a>. </li> <li> <tt>-d</tt>&nbsp;: down. s6-svwait will wait until the services are down. </li> + <li> <tt>-D</tt>&nbsp;: really down. s6-svwait will wait until the +services are down and the cleanup scripts in +<tt><em>servicedir</em>/finish</tt> +for every <em>servicedir</em> +have finished executing (or have timed out and been killed). </li> <li> <tt>-o</tt>&nbsp;: or. s6-svwait will wait until <em>one</em> of the given services comes up or down. </li> <li> <tt>-a</tt>&nbsp;: and. s6-svwait will wait until <em>all</em> of the @@ -80,8 +85,7 @@ s6-supervise has not been started yet. </li> <p> s6-svwait spawns a <a href="libs6/s6-ftrigrd.html">s6-ftrigrd</a> child to listen to notifications sent by <a href="s6-supervise.html">s6-supervise</a>. -It also checks <tt>supervise/status</tt> files, as well as the -<tt>supervise/ready</tt> files if necessary, to get the current service +It also checks <tt>supervise/status</tt> files to get the current service states, so it is immune to race conditions. </p> diff --git a/doc/servicedir.html b/doc/servicedir.html @@ -117,6 +117,12 @@ notification from the service and broadcast readiness, i.e. any <a href="s6-svlisten1.html">s6-svlisten1 -U</a> or <a href="s6-svlisten.html">s6-svlisten -U</a> processes will be triggered. </li> + <li> An optional regular file named <tt>timeout-finish</tt>. If such a file +exists, it must only contain an unsigned integer, which is the number of +milliseconds after which the <tt>./finish</tt> script, if it exists, will +be killed with a SIGKILL. The default is 5000: finish scripts are killed +if they're still alive after 5 seconds. A value of 0 allows finish scripts +to run forever. </li> <li> A <a href="fifodir.html">fifodir</a> named <tt>event</tt>. It is automatically created by <a href="s6-supervise.html">s6-supervise</a> if it does not exist. <em>foo</em><tt>/event</tt> diff --git a/doc/upgrade.html b/doc/upgrade.html @@ -18,6 +18,27 @@ <h1> What has changed in s6 </h1> +<h2> in 2.2.0.0 </h2> + +<ul> + <li> skalibs dependency bumped to 2.3.6.0. </li> + <li> The internals of <a href="s6-supervise.html">s6-supervise</a> have +changed; the <tt>supervise/status</tt> file ABI has changed and is not +compatible with the daemontools/runit <tt>supervise/status</tt> files +anymore. (This should not impact anything.) </li> + <li> <a href="s6-supervise.html">s6-supervise</a> features a +configurable timeout for <tt>./finish</tt> scripts, via the +<a href="servicedir.html"><tt>./timeout-finish</tt></a> file. </li> + <li> <a href="s6-svwait.html">s6-svwait</a>, +<a href="s6-svlisten1.html">s6-svlisten1</a> and +<a href="s6-svlisten.html">s6-svlisten</a> can now wait for a <tt>'D'</tt> +event, which means the <tt>./finish</tt> script has terminated. </li> + <li> The deprecated <tt>s6-notifywhenup</tt> program has been +removed. </li> + <li> The syntax for synchronous <a href="s6-svc.html">s6-svc</a> +waiting has changed. </li> +</ul> + <h2> in 2.1.6.0 </h2> <ul> diff --git a/package/deps.mak b/package/deps.mak @@ -5,6 +5,7 @@ src/include/s6/ftrigr.h: src/include/s6/config.h src/include/s6/s6.h: src/include/s6/accessrules.h src/include/s6/ftrigr.h src/include/s6/ftrigw.h src/include/s6/s6-supervise.h src/include/s6/s6lock.h src/include/s6/s6lock.h: src/include/s6/config.h +src/supervision/s6-svlisten.h: src/include/s6/ftrigr.h src/conn-tools/s6-accessrules-cdb-from-fs.o src/conn-tools/s6-accessrules-cdb-from-fs.lo: src/conn-tools/s6-accessrules-cdb-from-fs.c src/conn-tools/s6-accessrules-fs-from-cdb.o src/conn-tools/s6-accessrules-fs-from-cdb.lo: src/conn-tools/s6-accessrules-fs-from-cdb.c src/conn-tools/s6-connlimit.o src/conn-tools/s6-connlimit.lo: src/conn-tools/s6-connlimit.c @@ -30,6 +31,8 @@ src/daemontools-extras/s6-tai64n.o src/daemontools-extras/s6-tai64n.lo: src/daem src/daemontools-extras/s6-tai64nlocal.o src/daemontools-extras/s6-tai64nlocal.lo: src/daemontools-extras/s6-tai64nlocal.c src/daemontools-extras/ucspilogd.o src/daemontools-extras/ucspilogd.lo: src/daemontools-extras/ucspilogd.c src/fdholder/s6-fdholder-daemon.o src/fdholder/s6-fdholder-daemon.lo: src/fdholder/s6-fdholder-daemon.c src/include/s6/config.h +src/fdholder/s6-fdholder-delete.o src/fdholder/s6-fdholder-delete.lo: src/fdholder/s6-fdholder-delete.c src/include/s6/config.h +src/fdholder/s6-fdholder-deletec.o src/fdholder/s6-fdholder-deletec.lo: src/fdholder/s6-fdholder-deletec.c src/include/s6/s6-fdholder.h src/fdholder/s6-fdholder-getdump.o src/fdholder/s6-fdholder-getdump.lo: src/fdholder/s6-fdholder-getdump.c src/include/s6/config.h src/fdholder/s6-fdholder-getdumpc.o src/fdholder/s6-fdholder-getdumpc.lo: src/fdholder/s6-fdholder-getdumpc.c src/include/s6/s6-fdholder.h src/fdholder/s6-fdholder-list.o src/fdholder/s6-fdholder-list.lo: src/fdholder/s6-fdholder-list.c src/include/s6/config.h @@ -86,6 +89,7 @@ src/libs6/s6_fdholder_store_async.o src/libs6/s6_fdholder_store_async.lo: src/li src/libs6/s6_supervise_lock.o src/libs6/s6_supervise_lock.lo: src/libs6/s6_supervise_lock.c src/include/s6/s6-supervise.h src/libs6/s6_supervise_lock_mode.o src/libs6/s6_supervise_lock_mode.lo: src/libs6/s6_supervise_lock_mode.c src/include/s6/s6-supervise.h src/libs6/s6_svc_write.o src/libs6/s6_svc_write.lo: src/libs6/s6_svc_write.c src/include/s6/s6-supervise.h +src/libs6/s6_svc_writectl.o src/libs6/s6_svc_writectl.lo: src/libs6/s6_svc_writectl.c src/include/s6/s6-supervise.h src/libs6/s6_svstatus_pack.o src/libs6/s6_svstatus_pack.lo: src/libs6/s6_svstatus_pack.c src/include/s6/s6-supervise.h src/libs6/s6_svstatus_read.o src/libs6/s6_svstatus_read.lo: src/libs6/s6_svstatus_read.c src/include/s6/s6-supervise.h src/libs6/s6_svstatus_unpack.o src/libs6/s6_svstatus_unpack.lo: src/libs6/s6_svstatus_unpack.c src/include/s6/s6-supervise.h @@ -108,16 +112,17 @@ src/pipe-tools/s6-ftrig-listen1.o src/pipe-tools/s6-ftrig-listen1.lo: src/pipe-t src/pipe-tools/s6-ftrig-notify.o src/pipe-tools/s6-ftrig-notify.lo: src/pipe-tools/s6-ftrig-notify.c src/include/s6/ftrigw.h src/pipe-tools/s6-ftrig-wait.o src/pipe-tools/s6-ftrig-wait.lo: src/pipe-tools/s6-ftrig-wait.c src/include/s6/ftrigr.h src/pipe-tools/s6-mkfifodir.o src/pipe-tools/s6-mkfifodir.lo: src/pipe-tools/s6-mkfifodir.c src/include/s6/ftrigw.h -src/supervision/s6-notifywhenup.o src/supervision/s6-notifywhenup.lo: src/supervision/s6-notifywhenup.c src/include/s6/ftrigw.h src/include/s6/s6-supervise.h src/supervision/s6-supervise.o src/supervision/s6-supervise.lo: src/supervision/s6-supervise.c src/include/s6/ftrigw.h src/include/s6/s6-supervise.h src/supervision/s6-svc.o src/supervision/s6-svc.lo: src/supervision/s6-svc.c src/include/s6/config.h src/include/s6/s6-supervise.h -src/supervision/s6-svlisten.o src/supervision/s6-svlisten.lo: src/supervision/s6-svlisten.c src/include/s6/ftrigr.h src/include/s6/s6-supervise.h -src/supervision/s6-svlisten1.o src/supervision/s6-svlisten1.lo: src/supervision/s6-svlisten1.c src/include/s6/ftrigr.h src/include/s6/s6-supervise.h +src/supervision/s6-svlisten.o src/supervision/s6-svlisten.lo: src/supervision/s6-svlisten.c src/supervision/s6-svlisten.h +src/supervision/s6-svlisten1.o src/supervision/s6-svlisten1.lo: src/supervision/s6-svlisten1.c src/supervision/s6-svlisten.h src/supervision/s6-svok.o src/supervision/s6-svok.lo: src/supervision/s6-svok.c src/include/s6/s6-supervise.h src/supervision/s6-svscan.o src/supervision/s6-svscan.lo: src/supervision/s6-svscan.c src/include/s6/config.h src/include/s6/s6-supervise.h src/supervision/s6-svscanctl.o src/supervision/s6-svscanctl.lo: src/supervision/s6-svscanctl.c src/include/s6/s6-supervise.h src/supervision/s6-svstat.o src/supervision/s6-svstat.lo: src/supervision/s6-svstat.c src/include/s6/s6-supervise.h -src/supervision/s6-svwait.o src/supervision/s6-svwait.lo: src/supervision/s6-svwait.c src/include/s6/ftrigr.h src/include/s6/s6-supervise.h +src/supervision/s6-svwait.o src/supervision/s6-svwait.lo: src/supervision/s6-svwait.c src/supervision/s6-svlisten.h +src/supervision/s6_svlisten_loop.o src/supervision/s6_svlisten_loop.lo: src/supervision/s6_svlisten_loop.c src/supervision/s6-svlisten.h src/include/s6/ftrigr.h src/include/s6/s6-supervise.h +src/supervision/s6_svlisten_signal_handler.o src/supervision/s6_svlisten_signal_handler.lo: src/supervision/s6_svlisten_signal_handler.c src/supervision/s6-svlisten.h s6-accessrules-cdb-from-fs: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} s6-accessrules-cdb-from-fs: src/conn-tools/s6-accessrules-cdb-from-fs.o -lskarnet @@ -199,8 +204,8 @@ s6-fdholder-transferdumpc: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} s6-fdholder-transferdumpc: src/fdholder/s6-fdholder-transferdumpc.o ${LIBS6} -lskarnet s6-fdholderd: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} s6-fdholderd: src/fdholder/s6-fdholderd.o ${LIBS6} -lskarnet -libs6.a: src/libs6/ftrigr1_zero.o src/libs6/ftrigr_check.o src/libs6/ftrigr_end.o src/libs6/ftrigr_start.o src/libs6/ftrigr_startf.o src/libs6/ftrigr_subscribe.o src/libs6/ftrigr_unsubscribe.o src/libs6/ftrigr_update.o src/libs6/ftrigr_wait_and.o src/libs6/ftrigr_wait_or.o src/libs6/ftrigr_zero.o src/libs6/ftrigw_clean.o src/libs6/ftrigw_fifodir_make.o src/libs6/ftrigw_notify.o src/libs6/ftrigw_notifyb.o src/libs6/ftrigw_notifyb_nosig.o src/libs6/s6_accessrules_backend_cdb.o src/libs6/s6_accessrules_backend_fs.o src/libs6/s6_accessrules_keycheck_ip4.o src/libs6/s6_accessrules_keycheck_ip6.o src/libs6/s6_accessrules_keycheck_reversedns.o src/libs6/s6_accessrules_keycheck_uidgid.o src/libs6/s6_accessrules_params_free.o src/libs6/s6_accessrules_uidgid_cdb.o src/libs6/s6_accessrules_uidgid_fs.o src/libs6/s6_supervise_lock.o src/libs6/s6_supervise_lock_mode.o src/libs6/s6_svc_write.o src/libs6/s6_svstatus_pack.o src/libs6/s6_svstatus_read.o src/libs6/s6_svstatus_unpack.o src/libs6/s6_svstatus_write.o src/libs6/s6lock_acquire.o src/libs6/s6lock_check.o src/libs6/s6lock_end.o src/libs6/s6lock_release.o src/libs6/s6lock_start.o src/libs6/s6lock_startf.o src/libs6/s6lock_update.o src/libs6/s6lock_wait_and.o src/libs6/s6lock_wait_or.o src/libs6/s6lock_zero.o src/libs6/s6_fdholder_delete.o src/libs6/s6_fdholder_delete_async.o src/libs6/s6_fdholder_getdump.o src/libs6/s6_fdholder_list.o src/libs6/s6_fdholder_list_async.o src/libs6/s6_fdholder_list_cb.o src/libs6/s6_fdholder_retrieve.o src/libs6/s6_fdholder_retrieve_async.o src/libs6/s6_fdholder_retrieve_cb.o src/libs6/s6_fdholder_setdump.o src/libs6/s6_fdholder_store.o src/libs6/s6_fdholder_store_async.o -libs6.so: src/libs6/ftrigr1_zero.lo src/libs6/ftrigr_check.lo src/libs6/ftrigr_end.lo src/libs6/ftrigr_start.lo src/libs6/ftrigr_startf.lo src/libs6/ftrigr_subscribe.lo src/libs6/ftrigr_unsubscribe.lo src/libs6/ftrigr_update.lo src/libs6/ftrigr_wait_and.lo src/libs6/ftrigr_wait_or.lo src/libs6/ftrigr_zero.lo src/libs6/ftrigw_clean.lo src/libs6/ftrigw_fifodir_make.lo src/libs6/ftrigw_notify.lo src/libs6/ftrigw_notifyb.lo src/libs6/ftrigw_notifyb_nosig.lo src/libs6/s6_accessrules_backend_cdb.lo src/libs6/s6_accessrules_backend_fs.lo src/libs6/s6_accessrules_keycheck_ip4.lo src/libs6/s6_accessrules_keycheck_ip6.lo src/libs6/s6_accessrules_keycheck_reversedns.lo src/libs6/s6_accessrules_keycheck_uidgid.lo src/libs6/s6_accessrules_params_free.lo src/libs6/s6_accessrules_uidgid_cdb.lo src/libs6/s6_accessrules_uidgid_fs.lo src/libs6/s6_supervise_lock.lo src/libs6/s6_supervise_lock_mode.lo src/libs6/s6_svc_write.lo src/libs6/s6_svstatus_pack.lo src/libs6/s6_svstatus_read.lo src/libs6/s6_svstatus_unpack.lo src/libs6/s6_svstatus_write.lo src/libs6/s6lock_acquire.lo src/libs6/s6lock_check.lo src/libs6/s6lock_end.lo src/libs6/s6lock_release.lo src/libs6/s6lock_start.lo src/libs6/s6lock_startf.lo src/libs6/s6lock_update.lo src/libs6/s6lock_wait_and.lo src/libs6/s6lock_wait_or.lo src/libs6/s6lock_zero.lo src/libs6/s6_fdholder_delete.lo src/libs6/s6_fdholder_delete_async.lo src/libs6/s6_fdholder_getdump.lo src/libs6/s6_fdholder_list.lo src/libs6/s6_fdholder_list_async.lo src/libs6/s6_fdholder_list_cb.lo src/libs6/s6_fdholder_retrieve.lo src/libs6/s6_fdholder_retrieve_async.lo src/libs6/s6_fdholder_retrieve_cb.lo src/libs6/s6_fdholder_setdump.lo src/libs6/s6_fdholder_store.lo src/libs6/s6_fdholder_store_async.lo +libs6.a: src/libs6/ftrigr1_zero.o src/libs6/ftrigr_check.o src/libs6/ftrigr_end.o src/libs6/ftrigr_start.o src/libs6/ftrigr_startf.o src/libs6/ftrigr_subscribe.o src/libs6/ftrigr_unsubscribe.o src/libs6/ftrigr_update.o src/libs6/ftrigr_wait_and.o src/libs6/ftrigr_wait_or.o src/libs6/ftrigr_zero.o src/libs6/ftrigw_clean.o src/libs6/ftrigw_fifodir_make.o src/libs6/ftrigw_notify.o src/libs6/ftrigw_notifyb.o src/libs6/ftrigw_notifyb_nosig.o src/libs6/s6_accessrules_backend_cdb.o src/libs6/s6_accessrules_backend_fs.o src/libs6/s6_accessrules_keycheck_ip4.o src/libs6/s6_accessrules_keycheck_ip6.o src/libs6/s6_accessrules_keycheck_reversedns.o src/libs6/s6_accessrules_keycheck_uidgid.o src/libs6/s6_accessrules_params_free.o src/libs6/s6_accessrules_uidgid_cdb.o src/libs6/s6_accessrules_uidgid_fs.o src/libs6/s6_supervise_lock.o src/libs6/s6_supervise_lock_mode.o src/libs6/s6_svc_write.o src/libs6/s6_svc_writectl.o src/libs6/s6_svstatus_pack.o src/libs6/s6_svstatus_read.o src/libs6/s6_svstatus_unpack.o src/libs6/s6_svstatus_write.o src/libs6/s6lock_acquire.o src/libs6/s6lock_check.o src/libs6/s6lock_end.o src/libs6/s6lock_release.o src/libs6/s6lock_start.o src/libs6/s6lock_startf.o src/libs6/s6lock_update.o src/libs6/s6lock_wait_and.o src/libs6/s6lock_wait_or.o src/libs6/s6lock_zero.o src/libs6/s6_fdholder_delete.o src/libs6/s6_fdholder_delete_async.o src/libs6/s6_fdholder_getdump.o src/libs6/s6_fdholder_list.o src/libs6/s6_fdholder_list_async.o src/libs6/s6_fdholder_list_cb.o src/libs6/s6_fdholder_retrieve.o src/libs6/s6_fdholder_retrieve_async.o src/libs6/s6_fdholder_retrieve_cb.o src/libs6/s6_fdholder_setdump.o src/libs6/s6_fdholder_store.o src/libs6/s6_fdholder_store_async.o +libs6.so: src/libs6/ftrigr1_zero.lo src/libs6/ftrigr_check.lo src/libs6/ftrigr_end.lo src/libs6/ftrigr_start.lo src/libs6/ftrigr_startf.lo src/libs6/ftrigr_subscribe.lo src/libs6/ftrigr_unsubscribe.lo src/libs6/ftrigr_update.lo src/libs6/ftrigr_wait_and.lo src/libs6/ftrigr_wait_or.lo src/libs6/ftrigr_zero.lo src/libs6/ftrigw_clean.lo src/libs6/ftrigw_fifodir_make.lo src/libs6/ftrigw_notify.lo src/libs6/ftrigw_notifyb.lo src/libs6/ftrigw_notifyb_nosig.lo src/libs6/s6_accessrules_backend_cdb.lo src/libs6/s6_accessrules_backend_fs.lo src/libs6/s6_accessrules_keycheck_ip4.lo src/libs6/s6_accessrules_keycheck_ip6.lo src/libs6/s6_accessrules_keycheck_reversedns.lo src/libs6/s6_accessrules_keycheck_uidgid.lo src/libs6/s6_accessrules_params_free.lo src/libs6/s6_accessrules_uidgid_cdb.lo src/libs6/s6_accessrules_uidgid_fs.lo src/libs6/s6_supervise_lock.lo src/libs6/s6_supervise_lock_mode.lo src/libs6/s6_svc_write.lo src/libs6/s6_svc_writectl.lo src/libs6/s6_svstatus_pack.lo src/libs6/s6_svstatus_read.lo src/libs6/s6_svstatus_unpack.lo src/libs6/s6_svstatus_write.lo src/libs6/s6lock_acquire.lo src/libs6/s6lock_check.lo src/libs6/s6lock_end.lo src/libs6/s6lock_release.lo src/libs6/s6lock_start.lo src/libs6/s6lock_startf.lo src/libs6/s6lock_update.lo src/libs6/s6lock_wait_and.lo src/libs6/s6lock_wait_or.lo src/libs6/s6lock_zero.lo src/libs6/s6_fdholder_delete.lo src/libs6/s6_fdholder_delete_async.lo src/libs6/s6_fdholder_getdump.lo src/libs6/s6_fdholder_list.lo src/libs6/s6_fdholder_list_async.lo src/libs6/s6_fdholder_list_cb.lo src/libs6/s6_fdholder_retrieve.lo src/libs6/s6_fdholder_retrieve_async.lo src/libs6/s6_fdholder_retrieve_cb.lo src/libs6/s6_fdholder_setdump.lo src/libs6/s6_fdholder_store.lo src/libs6/s6_fdholder_store_async.lo s6-ftrigrd: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} s6-ftrigrd: src/libs6/s6-ftrigrd.o src/libs6/ftrig1_free.o src/libs6/ftrig1_make.o -lskarnet s6lockd: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} @@ -219,16 +224,14 @@ s6-ftrig-wait: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} s6-ftrig-wait: src/pipe-tools/s6-ftrig-wait.o ${LIBS6} -lskarnet s6-mkfifodir: private EXTRA_LIBS := s6-mkfifodir: src/pipe-tools/s6-mkfifodir.o ${LIBS6} -lskarnet -s6-notifywhenup: private EXTRA_LIBS := ${TAINNOW_LIB} -s6-notifywhenup: src/supervision/s6-notifywhenup.o ${LIBS6} -lskarnet s6-supervise: private EXTRA_LIBS := ${TAINNOW_LIB} s6-supervise: src/supervision/s6-supervise.o ${LIBS6} -lskarnet s6-svc: private EXTRA_LIBS := s6-svc: src/supervision/s6-svc.o ${LIBS6} -lskarnet s6-svlisten: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} -s6-svlisten: src/supervision/s6-svlisten.o ${LIBS6} -lexecline -lskarnet +s6-svlisten: src/supervision/s6-svlisten.o src/supervision/s6_svlisten_signal_handler.o src/supervision/s6_svlisten_loop.o ${LIBS6} -lexecline -lskarnet s6-svlisten1: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} -s6-svlisten1: src/supervision/s6-svlisten1.o ${LIBS6} -lskarnet +s6-svlisten1: src/supervision/s6-svlisten1.o src/supervision/s6_svlisten_signal_handler.o src/supervision/s6_svlisten_loop.o ${LIBS6} -lskarnet s6-svok: private EXTRA_LIBS := s6-svok: src/supervision/s6-svok.o -lskarnet s6-svscan: private EXTRA_LIBS := ${TAINNOW_LIB} @@ -238,4 +241,4 @@ s6-svscanctl: src/supervision/s6-svscanctl.o ${LIBS6} -lskarnet s6-svstat: private EXTRA_LIBS := ${SYSCLOCK_LIB} s6-svstat: src/supervision/s6-svstat.o ${LIBS6} -lskarnet s6-svwait: private EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} -s6-svwait: src/supervision/s6-svwait.o ${LIBS6} -lskarnet +s6-svwait: src/supervision/s6-svwait.o src/supervision/s6_svlisten_loop.o ${LIBS6} -lskarnet diff --git a/package/info b/package/info @@ -1,4 +1,4 @@ package=s6 -version=2.1.6.0 +version=2.2.0.0 category=admin package_macro_name=S6 diff --git a/package/modes b/package/modes @@ -8,7 +8,6 @@ s6lockd 0755 s6lockd-helper 0755 s6-cleanfifodir 0755 s6-mkfifodir 0755 -s6-notifywhenup 0755 s6-svscan 0755 s6-supervise 0755 s6-svc 0755 diff --git a/package/targets.mak b/package/targets.mak @@ -8,7 +8,6 @@ s6-ftrig-wait \ s6lockd \ s6-cleanfifodir \ s6-mkfifodir \ -s6-notifywhenup \ s6-svscan \ s6-supervise \ s6-svc \ diff --git a/src/include/s6/s6-supervise.h b/src/include/s6/s6-supervise.h @@ -3,39 +3,44 @@ #ifndef S6_SUPERVISE_H #define S6_SUPERVISE_H +#include <sys/types.h> #include <skalibs/tai.h> #define S6_SUPERVISE_CTLDIR "supervise" #define S6_SUPERVISE_EVENTDIR "event" #define S6_SVSCAN_CTLDIR ".s6-svscan" #define S6_SVSTATUS_FILENAME S6_SUPERVISE_CTLDIR "/status" -#define S6_SUPERVISE_READY_FILENAME S6_SUPERVISE_CTLDIR "/ready" -#define S6_SVSTATUS_SIZE 26 +#define S6_SVSTATUS_SIZE 35 extern int s6_svc_write (char const *, char const *, unsigned int) ; +extern int s6_svc_writectl (char const *, char const *, char const *, unsigned int) ; extern int s6_svc_main (int, char const *const *, char const *, char const *, char const *) ; typedef struct s6_svstatus_s s6_svstatus_t, *s6_svstatus_t_ref ; struct s6_svstatus_s { tain_t stamp ; - unsigned int pid ; - unsigned int flagwant : 1 ; - unsigned int flagwantup : 1 ; + tain_t readystamp ; + pid_t pid ; + int wstat ; unsigned int flagpaused : 1 ; unsigned int flagfinishing : 1 ; - unsigned int wstat ; + unsigned int flagwant : 1 ; + unsigned int flagwantup : 1 ; + unsigned int flagready : 1 ; } ; #define S6_SVSTATUS_ZERO \ { \ .stamp = TAIN_ZERO, \ + .readystamp = TAIN_ZERO, \ .pid = 0, \ - .flagwant = 0, \ - .flagwantup = 0, \ + .wstat = 0, \ .flagpaused = 0, \ .flagfinishing = 0, \ - .wstat = 0 \ + .flagwant = 1, \ + .flagwantup = 1, \ + .flagready = 1 \ } extern void s6_svstatus_pack (char *, s6_svstatus_t const *) ; diff --git a/src/libs6/deps-lib/s6 b/src/libs6/deps-lib/s6 @@ -26,6 +26,7 @@ s6_accessrules_uidgid_fs.o s6_supervise_lock.o s6_supervise_lock_mode.o s6_svc_write.o +s6_svc_writectl.o s6_svstatus_pack.o s6_svstatus_read.o s6_svstatus_unpack.o diff --git a/src/libs6/s6_svc_writectl.c b/src/libs6/s6_svc_writectl.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <s6/s6-supervise.h> + +int s6_svc_writectl (char const *service, char const *subdir, char const *s, unsigned int len) +{ + unsigned int svlen = str_len(service) ; + unsigned int sublen = str_len(subdir) ; + char fn[svlen + sublen + 10] ; + byte_copy(fn, svlen, service) ; + fn[svlen] = '/' ; + byte_copy(fn + svlen + 1, sublen, subdir) ; + byte_copy(fn + svlen + 1 + sublen, 9, "/control") ; + return s6_svc_write(fn, s, len) ; +} diff --git a/src/libs6/s6_svstatus_pack.c b/src/libs6/s6_svstatus_pack.c @@ -1,6 +1,6 @@ /* ISC license. */ -#include <skalibs/uint32.h> +#include <skalibs/uint16.h> #include <skalibs/uint64.h> #include <skalibs/tai.h> #include <s6/s6-supervise.h> @@ -8,8 +8,13 @@ void s6_svstatus_pack (char *pack, s6_svstatus_t const *sv) { tain_pack(pack, &sv->stamp) ; - uint32_pack(pack + 12, (uint32)sv->pid) ; - pack[16] = sv->flagpaused | (sv->flagfinishing << 1) ; - pack[17] = sv->flagwant ? sv->flagwantup ? 'u' : 'd' : 0 ; - uint64_pack(pack + 18, (uint64)sv->wstat) ; + tain_pack(pack + 12, &sv->readystamp) ; + uint64_pack_big(pack + 24, (uint64)sv->pid) ; + uint16_pack_big(pack + 32, (uint16)sv->wstat) ; + pack[34] = + sv->flagpaused | + (sv->flagfinishing << 1) | + (sv->flagwant << 2) | + (sv->flagwantup << 3) | + (sv->flagready << 4) ; } diff --git a/src/libs6/s6_svstatus_unpack.c b/src/libs6/s6_svstatus_unpack.c @@ -1,33 +1,24 @@ /* ISC license. */ -#include <skalibs/uint32.h> +#include <sys/types.h> +#include <skalibs/uint16.h> #include <skalibs/uint64.h> #include <skalibs/tai.h> #include <s6/s6-supervise.h> void s6_svstatus_unpack (char const *pack, s6_svstatus_t *sv) { - uint32 pid ; - uint64 wstat ; + uint64 pid ; + uint16 wstat ; tain_unpack(pack, &sv->stamp) ; - uint32_unpack(pack + 12, &pid) ; - sv->pid = (unsigned int)pid ; - uint64_unpack(pack + 18, &wstat) ; - sv->wstat = (unsigned int)wstat ; - sv->flagpaused = pack[16] & 1 ; - sv->flagfinishing = (pack[16] >> 1) & 1 ; - switch (pack[17]) - { - case 'u' : - sv->flagwant = 1 ; - sv->flagwantup = 1 ; - break ; - case 'd' : - sv->flagwant = 1 ; - sv->flagwantup = 0 ; - break ; - default : - sv->flagwant = 0 ; - sv->flagwantup = 0 ; - } + tain_unpack(pack + 12, &sv->readystamp) ; + uint64_unpack_big(pack + 24, &pid) ; + sv->pid = (pid_t)pid ; + uint16_unpack_big(pack + 32, &wstat) ; + sv->wstat = (int)wstat ; + sv->flagpaused = pack[34] & 1 ; + sv->flagfinishing = !!(pack[34] & 2) ; + sv->flagwant = !!(pack[34] & 4) ; + sv->flagwantup = !!(pack[34] & 8) ; + sv->flagready = !!(pack[34] & 16) ; } diff --git a/src/supervision/deps-exe/s6-notifywhenup b/src/supervision/deps-exe/s6-notifywhenup @@ -1,3 +0,0 @@ -${LIBS6} --lskarnet -${TAINNOW_LIB} diff --git a/src/supervision/deps-exe/s6-svlisten b/src/supervision/deps-exe/s6-svlisten @@ -1,3 +1,5 @@ +s6_svlisten_signal_handler.o +s6_svlisten_loop.o ${LIBS6} -lexecline -lskarnet diff --git a/src/supervision/deps-exe/s6-svlisten1 b/src/supervision/deps-exe/s6-svlisten1 @@ -1,3 +1,5 @@ +s6_svlisten_signal_handler.o +s6_svlisten_loop.o ${LIBS6} -lskarnet ${SOCKET_LIB} diff --git a/src/supervision/deps-exe/s6-svwait b/src/supervision/deps-exe/s6-svwait @@ -1,3 +1,4 @@ +s6_svlisten_loop.o ${LIBS6} -lskarnet ${SOCKET_LIB} diff --git a/src/supervision/s6-notifywhenup.c b/src/supervision/s6-notifywhenup.c @@ -1,99 +0,0 @@ -/* ISC license. */ - -#include <unistd.h> -#include <errno.h> -#include <skalibs/uint.h> -#include <skalibs/bytestr.h> -#include <skalibs/sgetopt.h> -#include <skalibs/strerr2.h> -#include <skalibs/allreadwrite.h> -#include <skalibs/tai.h> -#include <skalibs/iopause.h> -#include <skalibs/djbunix.h> -#include <s6/ftrigw.h> -#include <s6/s6-supervise.h> - -#define USAGE "s6-notifywhenup [ -d fd ] [ -e fifodir ] [ -f ] [ -X ] [ -t timeout ] prog..." -#define dieusage() strerr_dieusage(100, USAGE) - -static int run_child (int fd, char const *fifodir, unsigned int timeout) -{ - char dummy[4096] ; - iopause_fd x = { .fd = fd, .events = IOPAUSE_READ } ; - tain_t deadline ; - char pack[TAIN_PACK] ; - if (!tain_now_g()) strerr_diefu1sys(111, "tain_now") ; - if (timeout) tain_from_millisecs(&deadline, timeout) ; - else deadline = tain_infinite_relative ; - tain_add_g(&deadline, &deadline) ; - for (;;) - { - register int r = iopause_g(&x, 1, &deadline) ; - if (r < 0) strerr_diefu1sys(111, "iopause") ; - if (!r) return 99 ; - r = sanitize_read(fd_read(fd, dummy, 4096)) ; - if (r < 0) - if (errno == EPIPE) return 1 ; - else strerr_diefu1sys(111, "read from parent") ; - else if (r) - if (byte_chr(dummy, r, '\n') < r) break ; - } - close(fd) ; - tain_pack(pack, &STAMP) ; - if (!openwritenclose_suffix(S6_SUPERVISE_READY_FILENAME, pack, TAIN_PACK, ".new")) - strerr_warnwu1sys("open " S6_SUPERVISE_READY_FILENAME " for writing") ; - ftrigw_notify(fifodir, 'U') ; - return 0 ; -} - -int main (int argc, char const *const *argv, char const *const *envp) -{ - unsigned int fd = 1 ; - char const *fifodir = "event" ; - int df = 1, fake = 0 ; - unsigned int timeout = 0 ; - PROG = "s6-notifywhenup" ; - { - subgetopt_t l = SUBGETOPT_ZERO ; - for (;;) - { - register int opt = subgetopt_r(argc, argv, "Xd:e:ft:", &l) ; - if (opt == -1) break ; - switch (opt) - { - case 'X' : fake = 1 ; break ; - case 'd' : if (!uint0_scan(l.arg, &fd)) dieusage() ; break ; - case 'e' : fifodir = l.arg ; break ; - case 'f' : df = 0 ; break ; - case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ; - default : dieusage() ; - } - } - argc -= l.ind ; argv += l.ind ; - } - if (!argc) dieusage() ; - strerr_warnw1x("this program is deprecated. Use a notification-fd file instead.") ; - - { - int p[2] ; - pid_t pid ; - if (pipe(p) < 0) strerr_diefu1sys(111, "pipe") ; - pid = df ? doublefork() : fork() ; - if (pid < 0) strerr_diefu1sys(111, df ? "doublefork" : "fork") ; - else if (!pid) - { - PROG = "s6-notifywhenup (child)" ; - close(p[1]) ; - return run_child(p[0], fifodir, timeout) ; - } - close(p[0]) ; - if (fd_move((int)fd, p[1]) < 0) strerr_diefu1sys(111, "fd_move") ; - } - if (fake) - { - write(fd, "\n", 1) ; - close(fd) ; - } - pathexec_run(argv[0], argv, envp) ; - strerr_dieexec(111, argv[0]) ; -} diff --git a/src/supervision/s6-supervise.c b/src/supervision/s6-supervise.c @@ -45,18 +45,11 @@ typedef action_t *action_t_ref ; static tain_t deadline ; static tain_t dontrespawnbefore = TAIN_EPOCH ; -static s6_svstatus_t status = { .stamp = TAIN_ZERO, .pid = 0, .flagwant = 1, .flagwantup = 1, .flagpaused = 0, .flagfinishing = 0, .wstat = 0 } ; +static s6_svstatus_t status = S6_SVSTATUS_ZERO ; static state_t state = DOWN ; static int cont = 1 ; static int notifyfd = -1 ; -static inline void down_and_delay (void) -{ - state = DOWN ; - if (tain_future(&dontrespawnbefore)) deadline = dontrespawnbefore ; - else tain_copynow(&deadline) ; -} - static inline void settimeout (int secs) { tain_addsec_g(&deadline, secs) ; @@ -73,6 +66,37 @@ static inline void announce (void) strerr_warnwu1sys("write status file") ; } +static int read_uint (char const *file, unsigned int *fd) +{ + char buf[UINT_FMT + 1] ; + register int r = openreadnclose_nb(file, buf, UINT_FMT) ; + if (r < 0) + { + if (errno != ENOENT) strerr_warnwu2sys("open ", file) ; + return 0 ; + } + buf[byte_chr(buf, r, '\n')] = 0 ; + if (!uint0_scan(buf, fd)) + { + strerr_warnw2x("invalid ", file) ; + return 0 ; + } + return 1 ; +} + +static void set_down_and_ready (char const *s, unsigned int n) +{ + status.pid = 0 ; + status.flagfinishing = 0 ; + status.flagready = 1 ; + tain_copynow(&status.readystamp) ; + state = DOWN ; + if (tain_future(&dontrespawnbefore)) deadline = dontrespawnbefore ; + else tain_copynow(&deadline) ; + announce() ; + ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, s, n) ; +} + /* The action array. */ @@ -183,27 +207,12 @@ static void trystart (void) strerr_warnwu1sys("pipe (waiting 60 seconds)") ; return ; } + if (read_uint("notification-fd", &fd) && pipe(notifyp) < 0) { - char buf[UINT_FMT + 1] ; - register int r = openreadnclose("notification-fd", buf, UINT_FMT) ; - if (r < 0) - { - if (errno != ENOENT) - strerr_warnwu1sys("open notification-fd") ; - } - else - { - buf[byte_chr(buf, r, '\n')] = 0 ; - if (!uint0_scan(buf, &fd)) - strerr_warnw1x("invalid notification-fd") ; - else if (pipe(notifyp) < 0) - { - settimeout(60) ; - strerr_warnwu1sys("pipe (waiting 60 seconds)") ; - fd_close(p[1]) ; fd_close(p[0]) ; - return ; - } - } + settimeout(60) ; + strerr_warnwu1sys("pipe (waiting 60 seconds)") ; + fd_close(p[1]) ; fd_close(p[0]) ; + return ; } pid = fork() ; if (pid < 0) @@ -222,8 +231,6 @@ static void trystart (void) selfpipe_finish() ; if (notifyp[0] >= 0) close(notifyp[0]) ; close(p[0]) ; - if (unlink(S6_SUPERVISE_READY_FILENAME) < 0 && errno != ENOENT) - strerr_warnwu1sys("unlink " S6_SUPERVISE_READY_FILENAME) ; if (notifyp[1] >= 0 && fd_move((int)fd, notifyp[1]) < 0) { failcoe(p[1]) ; @@ -264,6 +271,7 @@ static void trystart (void) settimeout_infinite() ; state = UP ; status.pid = pid ; + status.flagready = 0 ; tain_copynow(&status.stamp) ; tain_addsec_g(&dontrespawnbefore, 1) ; announce() ; @@ -303,17 +311,25 @@ static void down_d (void) announce() ; } -static inline void tryfinish (int islast) +static int uplastup_z (void) { - register pid_t pid = fork() ; - if (pid < 0) + status.wstat = (int)status.pid ; + status.flagpaused = 0 ; + status.flagready = 0 ; + tain_copynow(&status.stamp) ; + if (notifyfd >= 0) + { + fd_close(notifyfd) ; + notifyfd = -1 ; + } + status.pid = fork() ; + if (status.pid < 0) { strerr_warnwu2sys("fork for ", "./finish") ; - if (islast) bail() ; - down_and_delay() ; - return ; + set_down_and_ready("dD", 2) ; + return 0 ; } - else if (!pid) + else if (!status.pid) { char fmt0[UINT_FMT] ; char fmt1[UINT_FMT] ; @@ -325,39 +341,35 @@ static inline void tryfinish (int islast) execve("./finish", cargv, (char *const *)environ) ; _exit(127) ; } - status.pid = pid ; status.flagfinishing = 1 ; - state = islast ? LASTFINISH : FINISH ; + announce() ; + ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "d", 1) ; + { + tain_t tto ; + unsigned int timeout ; + if (!read_uint("timeout-finish", &timeout)) timeout = 5000 ; + if (timeout && tain_from_millisecs(&tto, timeout)) + tain_add_g(&deadline, &tto) ; + else settimeout_infinite() ; + } + return 1 ; } -static void uptimeout (void) +static void up_z (void) { - settimeout_infinite() ; - strerr_warnw1x("can't happen: timeout while the service is up!") ; + if (uplastup_z()) state = FINISH ; } -static void uplastup_z (int islast) +static void lastup_z (void) { - status.wstat = status.pid ; - status.pid = 0 ; - tain_copynow(&status.stamp) ; - if (notifyfd >= 0) - { - fd_close(notifyfd) ; - notifyfd = -1 ; - } - tryfinish(islast) ; - announce() ; - ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "d", 1) ; - if (unlink(S6_SUPERVISE_READY_FILENAME) < 0 && errno != ENOENT) - strerr_warnwu1sys("unlink " S6_SUPERVISE_READY_FILENAME) ; - settimeout(5) ; + if (uplastup_z()) state = LASTFINISH ; + else bail() ; } -static void up_z (void) +static void uptimeout (void) { - status.flagpaused = 0 ; - uplastup_z(0) ; + settimeout_infinite() ; + strerr_warnw1x("can't happen: timeout while the service is up!") ; } static void up_o (void) @@ -400,17 +412,14 @@ static void up_term (void) static void finishtimeout (void) { - strerr_warnw1x("finish script takes too long - killing it") ; + strerr_warnw1x("finish script lifetime reached maximum value - sending it a SIGKILL") ; killc() ; killk() ; - settimeout(3) ; + settimeout(5) ; } static void finish_z (void) { - status.pid = 0 ; - status.flagfinishing = 0 ; - down_and_delay() ; - announce() ; + set_down_and_ready("D", 1) ; } static void finish_u (void) @@ -431,11 +440,6 @@ static void finish_X (void) finish_x() ; } -static void lastup_z (void) -{ - uplastup_z(1) ; -} - static action_t_ref const actions[5][24] = { { &downtimeout, &nop, &bail, &bail, &bail, @@ -470,10 +474,9 @@ static inline void handle_notifyfd (void) r = sanitize_read(fd_read(notifyfd, buf, 4096)) ; if (r > 0 && byte_chr(buf, r, '\n') < r) { - char pack[TAIN_PACK] ; - tain_pack(pack, &STAMP) ; - if (!openwritenclose_suffix(S6_SUPERVISE_READY_FILENAME, pack, TAIN_PACK, ".new")) - strerr_warnwu3sys("open ", S6_SUPERVISE_READY_FILENAME, " for writing") ; + tain_copynow(&status.readystamp) ; + status.flagready = 1 ; + announce() ; ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "U", 1) ; r = -1 ; } @@ -504,7 +507,7 @@ static inline void handle_signals (void) if (errno != ECHILD) strerr_diefu1sys(111, "wait_pid_nohang") ; else break ; else if (!r) break ; - status.pid = wstat ; /* don't overwrite status.wstat if it's ./finish */ + status.pid = (pid_t)wstat ; /* don't overwrite status.wstat if it's ./finish */ (*actions[state][V_CHLD])() ; } break ; diff --git a/src/supervision/s6-svc.c b/src/supervision/s6-svc.c @@ -10,7 +10,7 @@ #include <s6/config.h> #include <s6/s6-supervise.h> -#define USAGE "s6-svc [ -D | -U ] [ -T timeout ] [ -abqhkti12pcoduxOX ] servicedir" +#define USAGE "s6-svc [ -wu | -wU | -wd | -wD ] [ -T timeout ] [ -abqhkti12pcoduxOX ] servicedir" #define dieusage() strerr_dieusage(100, USAGE) #define DATASIZE 63 @@ -26,12 +26,10 @@ int main (int argc, char const *const *argv, char const *const *envp) subgetopt_t l = SUBGETOPT_ZERO ; for (;;) { - register int opt = subgetopt_r(argc, argv, "DUabqhkti12pcoduxOXT:", &l) ; + register int opt = subgetopt_r(argc, argv, "abqhkti12pcoduxOXT:w:", &l) ; if (opt == -1) break ; switch (opt) { - case 'D' : updown[1] = 'd' ; break ; - case 'U' : updown[1] = 'U' ; break ; case 'a' : case 'b' : case 'q' : @@ -55,6 +53,12 @@ int main (int argc, char const *const *argv, char const *const *envp) break ; } case 'T' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ; + case 'w' : + { + if (byte_chr("dDuU", 4, l.arg[0]) >= 4) dieusage() ; + updown[1] = l.arg[0] ; + break ; + } default : dieusage() ; } } @@ -63,6 +67,7 @@ int main (int argc, char const *const *argv, char const *const *envp) if (!argc) dieusage() ; if (argc > 1) strerr_warn1x("ignoring extra arguments") ; + if (datalen <= 1) return 0 ; if (updown[1] == 'U') { unsigned int arglen = str_len(argv[0]) ; @@ -72,8 +77,8 @@ int main (int argc, char const *const *argv, char const *const *envp) if (access(fn, F_OK) < 0) { if (errno != ENOENT) strerr_diefu2sys(111, "access ", fn) ; - updown[1] = 0 ; - strerr_warnw2x(fn, " not present - ignoring -U option") ; + updown[1] = 'u' ; + strerr_warnw2x(fn, " not present - converting -wU to -wu") ; } } @@ -100,15 +105,9 @@ int main (int argc, char const *const *argv, char const *const *envp) pathexec_run(newargv[0], newargv, envp) ; strerr_dieexec(111, newargv[0]) ; } - else if (datalen > 1) + else { - unsigned int arglen = str_len(argv[0]) ; - char tmp[arglen + 9 + sizeof(S6_SUPERVISE_CTLDIR)] ; - register int r ; - byte_copy(tmp, arglen, argv[0]) ; - tmp[arglen] = '/' ; - byte_copy(tmp + arglen + 1, 8 + sizeof(S6_SUPERVISE_CTLDIR), S6_SUPERVISE_CTLDIR "/control") ; - r = s6_svc_write(tmp, data + 1, datalen - 1) ; + register int r = s6_svc_writectl(argv[0], S6_SUPERVISE_CTLDIR, data + 1, datalen - 1) ; if (r < 0) strerr_diefu2sys(111, "control ", argv[0]) ; else if (!r) strerr_diefu3x(100, "control ", argv[0], ": supervisor not listening") ; } diff --git a/src/supervision/s6-svlisten.c b/src/supervision/s6-svlisten.c @@ -1,64 +1,40 @@ /* ISC license. */ #include <sys/types.h> -#include <unistd.h> -#include <errno.h> #include <skalibs/sgetopt.h> -#include <skalibs/bytestr.h> #include <skalibs/uint16.h> #include <skalibs/uint.h> #include <skalibs/bitarray.h> #include <skalibs/tai.h> #include <skalibs/strerr2.h> -#include <skalibs/iopause.h> #include <skalibs/djbunix.h> -#include <skalibs/sig.h> -#include <skalibs/selfpipe.h> #include <execline/execline.h> -#include <s6/ftrigr.h> -#include <s6/s6-supervise.h> +#include "s6-svlisten.h" -#define USAGE "s6-svlisten [ -U | -u | -d ] [ -A | -a | -o ] [ -t timeout ] servicedir... \"\" prog..." +#define USAGE "s6-svlisten [ -U | -u | -d | -D ] [ -a | -o ] [ -t timeout ] servicedir... \"\" prog..." #define dieusage() strerr_dieusage(100, USAGE) -static inline int check (unsigned char const *ba, unsigned int n, int wantup, int or) -{ - return (bitarray_first(ba, n, or == wantup) < n) == or ; -} - -static void handle_signals (void) -{ - for (;;) switch (selfpipe_read()) - { - case -1 : strerr_diefu1sys(111, "selfpipe_read") ; - case 0 : return ; - case SIGCHLD : wait_reap() ; break ; - default : strerr_dief1x(101, "unexpected data in selfpipe") ; - } -} - int main (int argc, char const **argv, char const *const *envp) { - ftrigr_t a = FTRIGR_ZERO ; tain_t deadline, tto ; int spfd ; int argc1 ; int or = 0 ; - int wantup = 1 ; - char re[4] = "u|d" ; + int wantup = 1, wantready = 0 ; PROG = "s6-svlisten" ; { subgetopt_t l = SUBGETOPT_ZERO ; unsigned int t = 0 ; for (;;) { - register int opt = subgetopt_r(argc, argv, "uUdAaot:", &l) ; + register int opt = subgetopt_r(argc, argv, "uUdDaot:", &l) ; if (opt == -1) break ; switch (opt) { - case 'U' : wantup = 1 ; re[0] = 'U' ; break ; - case 'u' : wantup = 1 ; re[0] = 'u' ; break ; - case 'd' : wantup = 0 ; break ; + case 'u' : wantup = 1 ; wantready = 0 ; break ; + case 'U' : wantup = 1 ; wantready = 1 ; break ; + case 'd' : wantup = 0 ; wantready = 0 ; break ; + case 'D' : wantup = 0 ; wantready = 1 ; break ; case 'a' : or = 0 ; break ; case 'o' : or = 1 ; break ; case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; @@ -74,79 +50,19 @@ int main (int argc, char const **argv, char const *const *envp) if (!argc1 || argc == argc1 + 1) dieusage() ; if (argc1 >= argc) strerr_dief1x(100, "unterminated servicedir block") ; - spfd = selfpipe_init() ; - if (spfd < 0) strerr_diefu1sys(111, "selfpipe_init") ; - if (selfpipe_trap(SIGCHLD) < 0) strerr_diefu1sys(111, "selfpipe_trap") ; - if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "sig_ignore") ; - tain_now_g() ; tain_add_g(&deadline, &tto) ; - - if (!ftrigr_startf_g(&a, &deadline)) strerr_diefu1sys(111, "ftrigr_startf") ; + spfd = s6_svlisten_selfpipe_init() ; { - iopause_fd x[2] = { { .fd = spfd, .events = IOPAUSE_READ }, { .fd = ftrigr_fd(&a), .events = IOPAUSE_READ } } ; + s6_svlisten_t foo = S6_SVLISTEN_ZERO ; pid_t pid ; - unsigned int i = 0 ; - uint16 list[argc1] ; - unsigned char states[bitarray_div8(argc1)] ; - for (; i < (unsigned int)argc1 ; i++) - { - unsigned int len = str_len(argv[i]) ; - char s[len + 1 + sizeof(S6_SUPERVISE_EVENTDIR)] ; - byte_copy(s, len, argv[i]) ; - s[len] = '/' ; - byte_copy(s + len + 1, sizeof(S6_SUPERVISE_EVENTDIR), S6_SUPERVISE_EVENTDIR) ; - list[i] = ftrigr_subscribe_g(&a, s, re, FTRIGR_REPEAT, &deadline) ; - if (!list[i]) strerr_diefu2sys(111, "subscribe to events for ", argv[i]) ; - } - - for (i = 0 ; i < (unsigned int)argc1 ; i++) - { - s6_svstatus_t st = S6_SVSTATUS_ZERO ; - int isup ; - if (!s6_svstatus_read(argv[i], &st)) strerr_diefu1sys(111, "s6_svstatus_read") ; - isup = !!st.pid ; - if (re[0] == 'U' && isup) - { - unsigned int len = str_len(argv[i]) ; - char s[len + 1 + sizeof(S6_SUPERVISE_READY_FILENAME)] ; - byte_copy(s, len, argv[i]) ; - s[len] = '/' ; - byte_copy(s + len + 1, sizeof(S6_SUPERVISE_READY_FILENAME), S6_SUPERVISE_READY_FILENAME) ; - if (access(s, F_OK) < 0) - { - if (errno == ENOENT) isup = 0 ; - else strerr_warnwu2sys("check ", s) ; - } - } - bitarray_poke(states, i, isup) ; - } - + uint16 ids[argc1] ; + unsigned char upstate[bitarray_div8(argc1)] ; + unsigned char readystate[bitarray_div8(argc1)] ; + s6_svlisten_init(argc1, argv, &foo, ids, upstate, readystate, &deadline) ; pid = child_spawn0(argv[argc1 + 1], argv + argc1 + 1, envp) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[argc1 + 1]) ; - - for (;;) - { - register int r ; - if (check(states, argc1, wantup, or)) break ; - r = iopause_g(x, 2, &deadline) ; - if (r < 0) strerr_diefu1sys(111, "iopause") ; - else if (!r) strerr_dief1x(1, "timed out") ; - - if (x[0].revents & IOPAUSE_READ) handle_signals() ; - if (x[1].revents & IOPAUSE_READ) - { - if (ftrigr_update(&a) < 0) strerr_diefu1sys(111, "ftrigr_update") ; - for (i = 0 ; i < (unsigned int)argc1 ; i++) - { - char what ; - register int r = ftrigr_check(&a, list[i], &what) ; - if (r < 0) strerr_diefu1sys(111, "ftrigr_check") ; - if (r) bitarray_poke(states, i, what == re[0]) ; - } - } - } + return s6_svlisten_loop(&foo, wantup, wantready, or, &deadline, spfd, &s6_svlisten_signal_handler) ; } - return 0 ; } diff --git a/src/supervision/s6-svlisten.h b/src/supervision/s6-svlisten.h @@ -0,0 +1,29 @@ +/* ISC license. */ + +#ifndef S6_SVLISTEN_H +#define S6_SVLISTEN_H + +#include <skalibs/uint16.h> +#include <skalibs/tai.h> +#include <s6/ftrigr.h> + +typedef void action_func_t (void) ; +typedef action_func_t *action_func_t_ref ; + +typedef struct s6_svlisten_s s6_svlisten_t, *s6_svlisten_t_ref ; +struct s6_svlisten_s +{ + ftrigr_t a ; + unsigned int n ; + uint16 *ids ; + unsigned char *upstate ; + unsigned char *readystate ; +} ; +#define S6_SVLISTEN_ZERO { .a = FTRIGR_ZERO, .n = 0, .ids = 0, .upstate = 0, .readystate = 0 } + +extern void s6_svlisten_signal_handler (void) ; +extern int s6_svlisten_selfpipe_init (void) ; +extern void s6_svlisten_init (int, char const *const *, s6_svlisten_t *, uint16 *, unsigned char *, unsigned char *, tain_t const *) ; +extern int s6_svlisten_loop (s6_svlisten_t *, int, int, int, tain_t const *, int, action_func_t_ref) ; + +#endif diff --git a/src/supervision/s6-svlisten1.c b/src/supervision/s6-svlisten1.c @@ -1,56 +1,40 @@ /* ISC license. */ #include <sys/types.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> #include <skalibs/sgetopt.h> -#include <skalibs/bytestr.h> #include <skalibs/uint16.h> #include <skalibs/uint.h> #include <skalibs/tai.h> #include <skalibs/strerr2.h> #include <skalibs/djbunix.h> -#include <skalibs/iopause.h> -#include <skalibs/sig.h> -#include <skalibs/selfpipe.h> -#include <s6/ftrigr.h> -#include <s6/s6-supervise.h> +#include "s6-svlisten.h" -#define USAGE "s6-svlisten1 [ -U | -u | -d ] [ -t timeout ] servicedir prog..." +#define USAGE "s6-svlisten1 [ -U | -u | -d | -D ] [ -t timeout ] servicedir prog..." #define dieusage() strerr_dieusage(100, USAGE) -static void handle_signals (void) -{ - for (;;) switch (selfpipe_read()) - { - case -1 : strerr_diefu1sys(111, "selfpipe_read") ; - case 0 : return ; - case SIGCHLD : wait_reap() ; break ; - default : strerr_dief1x(101, "unexpected data in selfpipe") ; - } -} - int main (int argc, char const *const *argv, char const *const *envp) { - ftrigr_t a = FTRIGR_ZERO ; + s6_svlisten_t foo = S6_SVLISTEN_ZERO ; tain_t deadline, tto ; + pid_t pid ; int spfd ; - int wantup = 1 ; - char re[4] = "u|d" ; + int wantup = 1, wantready = 0 ; + uint16 id ; + unsigned char upstate, readystate ; PROG = "s6-svlisten1" ; { subgetopt_t l = SUBGETOPT_ZERO ; unsigned int t = 0 ; for (;;) { - register int opt = subgetopt_r(argc, argv, "uUdt:", &l) ; + register int opt = subgetopt_r(argc, argv, "uUdDt:", &l) ; if (opt == -1) break ; switch (opt) { - case 'U' : wantup = 1 ; re[0] = 'U' ; break ; - case 'u' : wantup = 1 ; re[0] = 'u' ; break ; - case 'd' : wantup = 0 ; break ; + case 'u' : wantup = 1 ; wantready = 0 ; break ; + case 'U' : wantup = 1 ; wantready = 1 ; break ; + case 'd' : wantup = 0 ; wantready = 0 ; break ; + case 'D' : wantup = 0 ; wantready = 1 ; break ; case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; default : dieusage() ; } @@ -59,63 +43,11 @@ int main (int argc, char const *const *argv, char const *const *envp) if (t) tain_from_millisecs(&tto, t) ; else tto = tain_infinite_relative ; } if (!argc) dieusage() ; - - spfd = selfpipe_init() ; - if (spfd < 0) strerr_diefu1sys(111, "selfpipe_init") ; - if (selfpipe_trap(SIGCHLD) < 0) strerr_diefu1sys(111, "selfpipe_trap") ; - if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "sig_ignore") ; - tain_now_g() ; tain_add_g(&deadline, &tto) ; - - if (!ftrigr_startf_g(&a, &deadline)) strerr_diefu1sys(111, "ftrigr_startf") ; - - { - iopause_fd x[2] = { { .fd = spfd, .events = IOPAUSE_READ }, { .fd = ftrigr_fd(&a), .events = IOPAUSE_READ } } ; - unsigned int arglen = str_len(argv[0]) ; - pid_t pid ; - int isup ; - s6_svstatus_t st = S6_SVSTATUS_ZERO ; - uint16 id ; - char s[arglen + 1 + sizeof(S6_SUPERVISE_EVENTDIR)] ; - byte_copy(s, arglen, argv[0]) ; - s[arglen] = '/' ; - byte_copy(s + arglen + 1, sizeof(S6_SUPERVISE_EVENTDIR), S6_SUPERVISE_EVENTDIR) ; - id = ftrigr_subscribe_g(&a, s, re, FTRIGR_REPEAT, &deadline) ; - if (!id) strerr_diefu2sys(111, "subscribe to events for ", argv[0]) ; - if (!s6_svstatus_read(argv[0], &st)) strerr_diefu1sys(111, "s6_svstatus_read") ; - isup = !!st.pid ; - if (re[0] == 'U' && isup) - { - byte_copy(s + arglen + 1, sizeof(S6_SUPERVISE_READY_FILENAME), S6_SUPERVISE_READY_FILENAME) ; - if (access(s, F_OK) < 0) - { - if (errno == ENOENT) isup = 0 ; - else strerr_warnwu2sys("check ", s) ; - } - } - - pid = child_spawn0(argv[1], argv + 1, envp) ; - if (!pid) strerr_diefu2sys(111, "spawn ", argv[2]) ; - - for (;;) - { - register int r ; - if (isup == wantup) break ; - r = iopause_g(x, 2, &deadline) ; - if (r < 0) strerr_diefu1sys(111, "iopause") ; - else if (!r) strerr_dief1x(1, "timed out") ; - - if (x[0].revents & IOPAUSE_READ) handle_signals() ; - if (x[1].revents & IOPAUSE_READ) - { - char what ; - if (ftrigr_update(&a) < 0) strerr_diefu1sys(111, "ftrigr_update") ; - r = ftrigr_check(&a, id, &what) ; - if (r < 0) strerr_diefu1sys(111, "ftrigr_check") ; - if (r) isup = what == re[0] ; - } - } - } - return 0 ; + spfd = s6_svlisten_selfpipe_init() ; + s6_svlisten_init(1, argv, &foo, &id, &upstate, &readystate, &deadline) ; + pid = child_spawn0(argv[1], argv + 1, envp) ; + if (!pid) strerr_diefu2sys(111, "spawn ", argv[1]) ; + return s6_svlisten_loop(&foo, wantup, wantready, 1, &deadline, spfd, &s6_svlisten_signal_handler) ; } diff --git a/src/supervision/s6-svscanctl.c b/src/supervision/s6-svscanctl.c @@ -52,14 +52,8 @@ int main (int argc, char const *const *argv) } if (!argc) dieusage() ; - { - unsigned int arglen = str_len(*argv) ; - char tmp[arglen + 20] ; - byte_copy(tmp, arglen, *argv) ; - byte_copy(tmp + arglen, 20, "/.s6-svscan/control") ; - r = s6_svc_write(tmp, data, datalen) ; - } - if (r < 0) strerr_diefu2sys(111, "control ", *argv) ; - else if (!r) strerr_diefu3x(100, "control ", *argv, ": supervisor not listening") ; + r = s6_svc_writectl(argv[0], S6_SVSCAN_CTLDIR, data, datalen) ; + if (r < 0) strerr_diefu2sys(111, "control ", argv[0]) ; + else if (!r) strerr_diefu3x(100, "control ", argv[0], ": supervisor not listening") ; return 0 ; } diff --git a/src/supervision/s6-svstat.c b/src/supervision/s6-svstat.c @@ -1,8 +1,8 @@ /* ISC license. */ #include <sys/types.h> -#include <sys/stat.h> #include <sys/wait.h> +#include <unistd.h> #include <errno.h> #include <skalibs/uint64.h> #include <skalibs/uint.h> @@ -23,7 +23,6 @@ int main (int argc, char const *const *argv) s6_svstatus_t status ; int flagnum = 0 ; int isup, normallyup ; - tain_t readytime = TAIN_ZERO ; char fmt[UINT_FMT] ; PROG = "s6-svstat" ; { @@ -49,26 +48,14 @@ int main (int argc, char const *const *argv) if (tain_future(&status.stamp)) tain_copynow(&status.stamp) ; { - char pack[TAIN_PACK] ; - struct stat st ; unsigned int dirlen = str_len(*argv) ; - char fn[dirlen + sizeof(S6_SUPERVISE_READY_FILENAME) + 1] ; + char fn[dirlen + 6] ; byte_copy(fn, dirlen, *argv) ; byte_copy(fn + dirlen, 6, "/down") ; - if (stat(fn, &st) == -1) - if (errno != ENOENT) strerr_diefu2sys(111, "stat ", fn) ; + if (access(fn, F_OK) < 0) + if (errno != ENOENT) strerr_diefu2sys(111, "access ", fn) ; else normallyup = 1 ; else normallyup = 0 ; - byte_copy(fn + dirlen, sizeof(S6_SUPERVISE_READY_FILENAME) + 1, "/" S6_SUPERVISE_READY_FILENAME) ; - if (openreadnclose(fn, pack, TAIN_PACK) < TAIN_PACK) - { - if (errno != ENOENT) strerr_warnwu2sys("read ", fn) ; - } - else - { - tain_unpack(pack, &readytime) ; - if (tain_future(&readytime)) tain_copynow(&readytime) ; - } } isup = status.pid && !status.flagfinishing ; @@ -110,16 +97,16 @@ int main (int argc, char const *const *argv) buffer_putnoflush(buffer_1small, ", normally up", 13) ; if (isup && status.flagpaused) buffer_putnoflush(buffer_1small, ", paused", 8) ; - if (!isup && (status.flagwant == 'u')) + if (!isup && status.flagwant) buffer_putnoflush(buffer_1small, ", want up", 10) ; - if (isup && (status.flagwant == 'd')) + if (isup && !status.flagwant) buffer_putnoflush(buffer_1small, ", want down", 12) ; - if (readytime.sec.x) + if (status.flagready) { - tain_sub(&readytime, &STAMP, &readytime) ; + tain_sub(&status.readystamp, &STAMP, &status.readystamp) ; buffer_putnoflush(buffer_1small, ", ready ", 8) ; - buffer_putnoflush(buffer_1small, fmt, uint64_fmt(fmt, readytime.sec.x)) ; + buffer_putnoflush(buffer_1small, fmt, uint64_fmt(fmt, status.readystamp.sec.x)) ; buffer_putnoflush(buffer_1small, " seconds", 8) ; } if (buffer_putflush(buffer_1small, "\n", 1) < 0) diff --git a/src/supervision/s6-svwait.c b/src/supervision/s6-svwait.c @@ -1,46 +1,35 @@ /* ISC license. */ -#include <unistd.h> -#include <errno.h> #include <skalibs/sgetopt.h> -#include <skalibs/bytestr.h> #include <skalibs/uint16.h> #include <skalibs/uint.h> #include <skalibs/bitarray.h> #include <skalibs/tai.h> #include <skalibs/strerr2.h> -#include <skalibs/iopause.h> -#include <s6/ftrigr.h> -#include <s6/s6-supervise.h> +#include "s6-svlisten.h" -#define USAGE "s6-svwait [ -U | -u | -d ] [ -a | -o ] [ -t timeout ] servicedir..." +#define USAGE "s6-svwait [ -U | -u | -d | -D ] [ -a | -o ] [ -t timeout ] servicedir..." #define dieusage() strerr_dieusage(100, USAGE) -static inline int check (unsigned char const *ba, unsigned int n, int wantup, int or) -{ - return (bitarray_first(ba, n, or == wantup) < n) == or ; -} - int main (int argc, char const *const *argv) { tain_t deadline, tto ; - ftrigr_t a = FTRIGR_ZERO ; int or = 0 ; - int wantup = 1 ; - char re[4] = "u|d" ; + int wantup = 1, wantready = 0 ; PROG = "s6-svwait" ; { subgetopt_t l = SUBGETOPT_ZERO ; unsigned int t = 0 ; for (;;) { - register int opt = subgetopt_r(argc, argv, "uUdaot:", &l) ; + register int opt = subgetopt_r(argc, argv, "UudDaot:", &l) ; if (opt == -1) break ; switch (opt) { - case 'U' : wantup = 1 ; re[0] = 'U' ; break ; - case 'u' : wantup = 1 ; re[0] = 'u' ; break ; - case 'd' : wantup = 0 ; break ; + case 'U' : wantup = 1 ; wantready = 1 ; break ; + case 'u' : wantup = 1 ; wantready = 0 ; break ; + case 'd' : wantup = 0 ; wantready = 0 ; break ; + case 'D' : wantup = 0 ; wantready = 1 ; break ; case 'a' : or = 0 ; break ; case 'o' : or = 1 ; break ; case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; @@ -55,65 +44,12 @@ int main (int argc, char const *const *argv) tain_now_g() ; tain_add_g(&deadline, &tto) ; - if (!ftrigr_startf_g(&a, &deadline)) strerr_diefu1sys(111, "ftrigr_startf") ; - { - iopause_fd x = { -1, IOPAUSE_READ, 0 } ; - unsigned int i = 0 ; - uint16 list[argc] ; - unsigned char states[bitarray_div8(argc)] ; - x.fd = ftrigr_fd(&a) ; - for (; i < (unsigned int)argc ; i++) - { - unsigned int len = str_len(argv[i]) ; - char s[len + 1 + sizeof(S6_SUPERVISE_EVENTDIR)] ; - byte_copy(s, len, argv[i]) ; - s[len] = '/' ; - byte_copy(s + len + 1, sizeof(S6_SUPERVISE_EVENTDIR), S6_SUPERVISE_EVENTDIR) ; - list[i] = ftrigr_subscribe_g(&a, s, re, FTRIGR_REPEAT, &deadline) ; - if (!list[i]) strerr_diefu2sys(111, "subscribe to events for ", argv[i]) ; - } - - for (i = 0 ; i < (unsigned int)argc ; i++) - { - s6_svstatus_t st = S6_SVSTATUS_ZERO ; - int isup ; - if (!s6_svstatus_read(argv[i], &st)) strerr_diefu1sys(111, "s6_svstatus_read") ; - isup = !!st.pid ; - if (re[0] == 'U' && isup) - { - unsigned int len = str_len(argv[i]) ; - char s[len + 1 + sizeof(S6_SUPERVISE_READY_FILENAME)] ; - byte_copy(s, len, argv[i]) ; - s[len] = '/' ; - byte_copy(s + len + 1, sizeof(S6_SUPERVISE_READY_FILENAME), S6_SUPERVISE_READY_FILENAME) ; - if (access(s, F_OK) < 0) - { - if (errno == ENOENT) isup = 0 ; - else strerr_warnwu2sys("check ", s) ; - } - } - bitarray_poke(states, i, isup) ; - } - - for (;;) - { - if (check(states, argc, wantup, or)) break ; - { - register int r = iopause_g(&x, 1, &deadline) ; - if (r < 0) strerr_diefu1sys(111, "iopause") ; - else if (!r) strerr_dief1x(1, "timed out") ; - } - - if (ftrigr_update(&a) < 0) strerr_diefu1sys(111, "ftrigr_update") ; - for (i = 0 ; i < (unsigned int)argc ; i++) - { - char what ; - register int r = ftrigr_check(&a, list[i], &what) ; - if (r < 0) strerr_diefu1sys(111, "ftrigr_check") ; - if (r) bitarray_poke(states, i, what == re[0]) ; - } - } + s6_svlisten_t foo = S6_SVLISTEN_ZERO ; + uint16 ids[argc] ; + unsigned char upstate[bitarray_div8(argc)] ; + unsigned char readystate[bitarray_div8(argc)] ; + s6_svlisten_init(argc, argv, &foo, ids, upstate, readystate, &deadline) ; + return s6_svlisten_loop(&foo, wantup, wantready, or, &deadline, -1, 0) ; } - return 0 ; } diff --git a/src/supervision/s6_svlisten_loop.c b/src/supervision/s6_svlisten_loop.c @@ -0,0 +1,78 @@ +/* ISC license. */ + +#include <unistd.h> +#include <errno.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint16.h> +#include <skalibs/bitarray.h> +#include <skalibs/tai.h> +#include <skalibs/strerr2.h> +#include <skalibs/iopause.h> +#include <skalibs/djbunix.h> +#include <s6/ftrigr.h> +#include <s6/s6-supervise.h> +#include "s6-svlisten.h" + +void s6_svlisten_init (int argc, char const *const *argv, s6_svlisten_t *foo, uint16 *ids, unsigned char *upstate, unsigned char *readystate, tain_t const *deadline) +{ + register unsigned int i = 0 ; + foo->n = (unsigned int)argc ; + foo->ids = ids ; + foo->upstate = upstate ; + foo->readystate = readystate ; + if (!ftrigr_startf_g(&foo->a, deadline)) strerr_diefu1sys(111, "ftrigr_startf") ; + for (; i < foo->n ; i++) + { + s6_svstatus_t status = S6_SVSTATUS_ZERO ; + unsigned int len = str_len(argv[i]) ; + char s[len + 1 + sizeof(S6_SUPERVISE_EVENTDIR)] ; + byte_copy(s, len, argv[i]) ; + s[len] = '/' ; + byte_copy(s + len + 1, sizeof(S6_SUPERVISE_EVENTDIR), S6_SUPERVISE_EVENTDIR) ; + foo->ids[i] = ftrigr_subscribe_g(&foo->a, s, "D|u|U|d", FTRIGR_REPEAT, deadline) ; + if (!foo->ids[i]) strerr_diefu2sys(111, "subscribe to events for ", argv[i]) ; + if (!s6_svstatus_read(argv[i], &status)) strerr_diefu1sys(111, "s6_svstatus_read") ; + bitarray_poke(foo->upstate, i, status.pid && !status.flagfinishing) ; + bitarray_poke(foo->readystate, i, status.flagready) ; + } +} + +static inline int got (s6_svlisten_t const *foo, int wantup, int wantready, int or) +{ + register unsigned int m = bitarray_div8(foo->n) ; + unsigned char t[m] ; + byte_copy(t, m, foo->upstate) ; + if (!wantup) bitarray_not(t, 0, foo->n) ; + if (wantready) bitarray_and(t, t, foo->readystate, foo->n) ; + return (bitarray_first(t, foo->n, or) < foo->n) == or ; +} + +int s6_svlisten_loop (s6_svlisten_t *foo, int wantup, int wantready, int or, tain_t const *deadline, int spfd, action_func_t_ref handler) +{ + iopause_fd x[2] = { { .fd = ftrigr_fd(&foo->a), .events = IOPAUSE_READ }, { .fd = spfd, .events = IOPAUSE_READ, .revents = 0 } } ; + while (!got(foo, wantup, wantready, or)) + { + register int r = iopause_g(x, 1 + (spfd >= 0), deadline) ; + if (r < 0) strerr_diefu1sys(111, "iopause") ; + else if (!r) strerr_dief1x(1, "timed out") ; + if (x[1].revents & IOPAUSE_READ) (*handler)() ; + if (x[0].revents & IOPAUSE_READ) + { + register unsigned int i = 0 ; + if (ftrigr_update(&foo->a) < 0) strerr_diefu1sys(111, "ftrigr_update") ; + for (; i < foo->n ; i++) + { + char what ; + register int r = ftrigr_check(&foo->a, foo->ids[i], &what) ; + if (r < 0) strerr_diefu1sys(111, "ftrigr_check") ; + if (r) + { + register unsigned int d = byte_chr("dDuU", 4, what) ; + bitarray_poke(foo->upstate, i, d & 2) ; + bitarray_poke(foo->readystate, i, d & 1) ; + } + } + } + } + return 0 ; +} diff --git a/src/supervision/s6_svlisten_signal_handler.c b/src/supervision/s6_svlisten_signal_handler.c @@ -0,0 +1,29 @@ +/* ISC license. */ + +#include <signal.h> +#include <skalibs/strerr2.h> +#include <skalibs/sig.h> +#include <skalibs/djbunix.h> +#include <skalibs/selfpipe.h> +#include "s6-svlisten.h" + +int s6_svlisten_selfpipe_init (void) +{ + register int spfd = selfpipe_init() ; + if (spfd < 0) strerr_diefu1sys(111, "selfpipe_init") ; + if (selfpipe_trap(SIGCHLD) < 0) strerr_diefu1sys(111, "selfpipe_trap") ; + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + return spfd ; +} + +void s6_svlisten_signal_handler (void) +{ + for (;;) switch (selfpipe_read()) + { + case -1 : strerr_diefu1sys(111, "selfpipe_read") ; + case 0 : return ; + case SIGCHLD : wait_reap() ; break ; + default : strerr_dief1x(101, "unexpected data in selfpipe") ; + } +} +