From 50a00de6e4aa6337b17a179019ec7689a2cc6b6d Mon Sep 17 00:00:00 2001
From: Laurent Bercot
Date: Fri, 15 Jun 2018 12:36:00 +0000
Subject: Down signal customization: add ./down-signal file and s6-svc -r
---
NEWS | 4 ++++
doc/s6-svc.html | 14 +++++++++++---
doc/servicedir.html | 32 ++++++++++++++++--------------
doc/upgrade.html | 6 ++++++
src/supervision/s6-supervise.c | 44 ++++++++++++++++++++++++++++++------------
src/supervision/s6-svc.c | 5 +++--
6 files changed, 74 insertions(+), 31 deletions(-)
diff --git a/NEWS b/NEWS
index 1996769..c96a861 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,10 @@ In 2.7.2.0
*shallow readiness*, i.e. readiness will be reported when s6-svscan is ready
to receive s6-svscanctl commands; it does *not* mean all the services started
at s6-svscan launch will be ready.
+ - New optional file in a service directory: down-signal. It allows you to
+customize the signal sent by s6-svc -d (and now s6-svc -r too).
+ - New s6-svc option: -r. Sends the signal defined in the down-signal file
+(still SIGTERM by default).
In 2.7.1.1
diff --git a/doc/s6-svc.html b/doc/s6-svc.html
index 22a4f68..c1e617f 100644
--- 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.
Interface
- s6-svc [ -wu | -wU | -wd | -wD | -wr | -wR ] [ -T timeout ] [ -abqhkti12pcyoduxO ] servicedir
+ s6-svc [ -wu | -wU | -wd | -wD | -wr | -wR ] [ -T timeout ] [ -abqhkti12pcyoduxOr ] servicedir
@@ -55,7 +55,10 @@ a command, or 100 if no s6-supervise process is running on servicedir.
-y : send a SIGWINCH to the supervised process
-o : once. Equivalent to "-uO".
-d : down. If the supervised process is up, send it
-a SIGTERM and a SIGCONT. Do not restart it.
+a SIGTERM (by default) then a SIGCONT (to make sure even stopped processes
+receive the signal aimed to kill them) and do not restart it.
+The SIGTERM default can be changed by editing the ./down-signal
+file in the service directory.
-u : up. If the supervised process is down, start it.
Automatically restart it when it dies.
-x : exit. When the service is asked to be down and
@@ -71,6 +74,11 @@ stdin, stdout and stderr redirected to /dev/null.
-O : mark the service to run once at most. iow: do not
restart the supervised process when it dies. If it is down when the command
is received, do not even start it.
+ -r : If the service is up, restart it, by sending it a
+signal to kill it and letting s6-supervise
+start it again. By default, the signal is a SIGTERM; this can be configured
+via the ./down-signal file in the service
+directory.
-T timeout : if the -wstate
option has been given, -T specifies a timeout
(in milliseconds) after which s6-svc will exit 1 with an error message if
@@ -106,7 +114,7 @@ service directory. Traditionally, this makes web servers reload their
configuration file.
- s6-svc -t /service/sshd
+ s6-svc -r /service/sshd
Kill (and automatically restart, if the wanted state of the service is up)
the process represented by the /service/sshd service directory -
diff --git a/doc/servicedir.html b/doc/servicedir.html
index 29236e7..2e6a937 100644
--- a/doc/servicedir.html
+++ b/doc/servicedir.html
@@ -40,7 +40,7 @@ for historical and compatibility reasons.)
A service directory foo may contain the following elements:
- - An executable file named run. It can be any executable
+
- An executable file named run. It can be any executable
file (such as a binary file or a link to any other executable file),
but most of the time it will be a script, called run script.
This file is the most important one in your service directory: it
@@ -80,14 +80,13 @@ them afterwards.
s6-supervise, i.e. the real foo
daemon. That process must not "background itself": being run by a supervision
tree already makes it a "background" task.
-
- An optional executable file named finish. Like run,
+
+ An optional executable file named finish. Like run,
it can be any executable file. This finish script, if present,
is executed everytime the run script dies. Generally, its main
purpose is to clean up non-volatile data such as the filesystem after the supervised
process has been killed. If the foo service is supposed to be up,
-foo/run is restarted
-after foo/finish dies.
+foo/run is restarted after foo/finish dies.
- By default, a finish script must do its work and exit in less than
5 seconds; if it takes more than that, it is killed. (The point is that the run
@@ -102,19 +101,19 @@ the signal that killed the run script).
interprets this as a permanent failure for the service, and does not restart it,
as if an s6-svc -O command had been sent.
- A directory named supervise. It is automatically created by
+ A directory named supervise. It is automatically created by
s6-supervise if it does not exist. This is where
s6-supervise stores its information. The directory
must be writable.
- An optional, empty, regular file named down. If such a file exists,
+ An optional, empty, regular file named down. If such a file exists,
the default state of the service is considered down, not up: s6-supervise will not
automatically start it until it receives a s6-svc -u command. If no
down file exists, the default state of the service is up.
- An optional, empty, regular file named nosetsid. If such a file exists,
+ An optional, empty, regular file named nosetsid. If such a file exists,
s6-supervise will not make the service a process group and session leader; the service
will be run in the same process group as s6-supervise. If no nosetsid file
exists, the service has its own process group and is started as a session leader.
- An optional regular file named notification-fd. If such a file
+ An optional regular file named notification-fd. If such a file
exists, it means that the service supports
readiness notification. The file must only
contain an unsigned integer, which is the number of the file descriptor that
@@ -128,7 +127,7 @@ notification from the service and broadcast readiness, i.e. any
s6-svlisten1 -U or
s6-svlisten -U processes will be
triggered.
- An optional regular file named timeout-kill. If such a file
+ An optional regular file named timeout-kill. If such a file
exists, it must only contain an unsigned integer t. If t
is nonzero, then on receipt of a s6-svc -d command,
which sends a SIGTERM and a SIGCONT to the service, a timeout of t
@@ -137,25 +136,30 @@ milliseconds, then it is sent a SIGKILL. If timeout-kill does not
exist, or contains 0 or an invalid value, then the service is never
forcibly killed (unless, of course, a s6-svc -k
command is sent).
- An optional regular file named timeout-finish. If such a file
+ An optional regular file named timeout-finish. If such a file
exists, it must only contain an unsigned integer, which is the number of
milliseconds after which the ./finish 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.
- An optional regular file named max-death-tally. If such a file
+ An optional regular file named max-death-tally. If such a file
exists, it must only contain an unsigned integer, which is the maximum number of
service death events that s6-supervise will keep track of. If the service dies
more than this number of times, the oldest events will be forgotten. Tracking
death events is useful, for instance, when throttling service restarts. The
value cannot be greater than 4096. If the file does not exist, a default of 100
is used.
- A fifodir named event. It is automatically
+ An optional regular file named down-signal. If such a file
+exists, it must only contain the name or number of a signal, followed by a
+newline. This signal will be used to kill the supervised process when a
+s6-svc -d or s6-svc -r
+command is used. If the file does not exist, SIGTERM will be used by default.
+ A fifodir named event. It is automatically
created by s6-supervise if it does not exist.
foo/event
is the rendez-vous point for listeners, where s6-supervise
will send notifications when the service goes up or down.
- An optional service directory named log. If it exists and foo
+ An optional service directory named log. If it exists and foo
is in a scandir, and s6-svscan
runs on that scandir, then two services are monitored: foo and
foo/log. A pipe is open and maintained between foo and
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 4ea789c..428e41f 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -25,6 +25,12 @@
s6-ipcserver-socketbinder.
-d notif option added to
s6-svscan.
+ New optional ./down-signal file in a
+service directory, to tell
+s6-supervise to use another signal than
+SIGTERM when bringing the service down.
+ New -r option added to s6-svc, to
+restart the service via the signal defined in ./down-signal.
in 2.7.1.1
diff --git a/src/supervision/s6-supervise.c b/src/supervision/s6-supervise.c
index 9d821bd..bdc4730 100644
--- a/src/supervision/s6-supervise.c
+++ b/src/supervision/s6-supervise.c
@@ -30,7 +30,7 @@ typedef enum trans_e trans_t, *trans_t_ref ;
enum trans_e
{
V_TIMEOUT, V_CHLD, V_TERM, V_HUP, V_QUIT,
- V_a, V_b, V_q, V_h, V_k, V_t, V_i, V_1, V_2, V_f, V_F, V_p, V_c, V_y,
+ V_a, V_b, V_q, V_h, V_k, V_t, V_i, V_1, V_2, V_f, V_F, V_p, V_c, V_y, V_r,
V_o, V_d, V_u, V_x, V_O, V_X
} ;
@@ -71,16 +71,22 @@ static inline void announce (void)
strerr_warnwu1sys("write status file") ;
}
-static int read_uint (char const *file, unsigned int *fd)
+static int read_file (char const *file, char *buf, size_t n)
{
- char buf[UINT_FMT + 1] ;
- ssize_t r = openreadnclose_nb(file, buf, UINT_FMT) ;
+ ssize_t r = openreadnclose_nb(file, buf, n) ;
if (r < 0)
{
if (errno != ENOENT) strerr_warnwu2sys("open ", file) ;
return 0 ;
}
buf[byte_chr(buf, r, '\n')] = 0 ;
+ return 1 ;
+}
+
+static int read_uint (char const *file, unsigned int *fd)
+{
+ char buf[UINT_FMT + 1] ;
+ if (!read_file(file, buf, UINT_FMT)) return 0 ;
if (!uint0_scan(buf, fd))
{
strerr_warnw2x("invalid ", file) ;
@@ -89,6 +95,15 @@ static int read_uint (char const *file, unsigned int *fd)
return 1 ;
}
+static inline int read_downsig (void)
+{
+ int sig = SIGTERM ;
+ char buf[16] ;
+ if (read_file("down-signal", buf, 15) && !sig0_scan(buf, &sig))
+ strerr_warnw1x("invalid down-signal") ;
+ return sig ;
+}
+
static void set_down_and_ready (char const *s, unsigned int n)
{
status.pid = 0 ;
@@ -188,6 +203,11 @@ static void killy (void)
kill(status.pid, SIGWINCH) ;
}
+static void killr (void)
+{
+ kill(status.pid, read_downsig()) ;
+}
+
static void failcoe (int fd)
{
int e = errno ;
@@ -430,7 +450,7 @@ static void up_d (void)
tain_t tto ;
unsigned int timeout ;
status.flagwantup = 0 ;
- killt() ;
+ killr() ;
killc() ;
if (!read_uint("timeout-kill", &timeout)) timeout = 0 ;
if (timeout && tain_from_millisecs(&tto, timeout))
@@ -505,22 +525,22 @@ static void lastfinish_z (void)
bail() ;
}
-static action_t_ref const actions[5][25] =
+static action_t_ref const actions[5][26] =
{
{ &downtimeout, &nop, &bail, &bail, &bail,
- &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
+ &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
&down_o, &down_d, &down_u, &bail, &down_O, &bail },
{ &uptimeout, &up_z, &up_term, &up_x, &up_X,
- &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &nop, &nop, &killp, &killc, &killy,
+ &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &nop, &nop, &killp, &killc, &killy, &killr,
&up_o, &up_d, &up_u, &up_x, &up_o, &up_X },
{ &finishtimeout, &finish_z, &finish_x, &finish_x, &finish_X,
- &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
+ &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
&up_o, &down_d, &finish_u, &finish_x, &up_o, &finish_X },
{ &uptimeout, &lastup_z, &up_d, &nop, &closethem,
- &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &nop, &nop, &killp, &killc, &killy,
+ &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &nop, &nop, &killp, &killc, &killy, &killr,
&up_o, &up_d, &nop, &nop, &up_o, &closethem },
{ &finishtimeout, &lastfinish_z, &nop, &nop, &closethem,
- &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
+ &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
&nop, &nop, &nop, &nop, &nop, &closethem }
} ;
@@ -600,7 +620,7 @@ static inline void handle_control (int fd)
else if (!r) break ;
else
{
- size_t pos = byte_chr("abqhkti12fFpcyoduxOX", 20, c) ;
+ size_t pos = byte_chr("abqhkti12fFpcyroduxOX", 20, c) ;
if (pos < 20) (*actions[state][V_a + pos])() ;
}
}
diff --git a/src/supervision/s6-svc.c b/src/supervision/s6-svc.c
index d844b20..2166551 100644
--- a/src/supervision/s6-svc.c
+++ b/src/supervision/s6-svc.c
@@ -10,7 +10,7 @@
#include
#include
-#define USAGE "s6-svc [ -wu | -wU | -wd | -wD | -wr | -wR ] [ -T timeout ] [ -abqhkti12pcoduxOX ] servicedir"
+#define USAGE "s6-svc [ -wu | -wU | -wd | -wD | -wr | -wR ] [ -T timeout ] [ -abqhkti12pcyroduxOX ] servicedir"
#define dieusage() strerr_dieusage(100, USAGE)
#define DATASIZE 63
@@ -41,13 +41,14 @@ int main (int argc, char const *const *argv, char const *const *envp)
case '2' :
case 'p' :
case 'c' :
+ case 'y' :
+ case 'r' :
case 'o' :
case 'd' :
case 'u' :
case 'x' :
case 'O' :
case 'X' :
- case 'y' :
{
if (datalen >= DATASIZE) strerr_dief1x(100, "too many commands") ;
data[datalen++] = opt ;
--
cgit v1.2.3