diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-05-20 10:53:30 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-05-20 10:53:30 +0300 |
commit | ddb46c6aa42ada061e51c635c0230e4dc8eab881 (patch) | |
tree | b003ae6af354f553207981b4fc281e8f9e19c60e /src | |
parent | ed8389beadb7cf1f8d95fe7addbc9ff2783f4d07 (diff) | |
download | genrc-ddb46c6aa42ada061e51c635c0230e4dc8eab881.tar.gz genrc-ddb46c6aa42ada061e51c635c0230e4dc8eab881.tar.bz2 |
Sentinel mode: restart the program on certain conditions
* Makefile.am: Create the ChangeLog file from git log.
* configure.ac: Request git2chg
* src/com_start.c: Use sigaction instead of signal.
* src/genrc.8: Document new options.
* src/genrc.c: New options --restart-on-exit and --restart-on-signal.
* src/genrc.h (str_to_sig, str_to_int): New prototypes.
(add_restart_condition): New prototype.
* src/sentinel.c (restart_on, add_restart_condition):
(check_failure_rate): New functions.
(wait_loop): Return if restart is requested.
(sentinel): Restart the program if needed.
Diffstat (limited to 'src')
-rw-r--r-- | src/com_start.c | 10 | ||||
-rw-r--r-- | src/genrc.8 | 58 | ||||
-rw-r--r-- | src/genrc.c | 41 | ||||
-rw-r--r-- | src/genrc.h | 10 | ||||
-rw-r--r-- | src/sentinel.c | 190 |
5 files changed, 291 insertions, 18 deletions
diff --git a/src/com_start.c b/src/com_start.c index 5744e39..3a9dffc 100644 --- a/src/com_start.c +++ b/src/com_start.c | |||
@@ -40,15 +40,19 @@ sigchld(int sig) | |||
40 | 40 | ||
41 | int | 41 | int |
42 | timedwaitpid(pid_t pid, int *status) | 42 | timedwaitpid(pid_t pid, int *status) |
43 | { | 43 | { |
44 | struct timeval now, stoptime, ttw; | 44 | struct timeval now, stoptime, ttw; |
45 | int rc = -1; | 45 | int rc = -1; |
46 | SIGHANDLER oldsig; | 46 | struct sigaction act, oldact; |
47 | |||
48 | act.sa_handler = sigchld; | ||
49 | act.sa_flags = 0; | ||
50 | sigemptyset(&act.sa_mask); | ||
51 | sigaction(SIGCHLD, &act, &oldact); | ||
47 | 52 | ||
48 | oldsig = signal(SIGCHLD, sigchld); | ||
49 | gettimeofday(&stoptime, NULL); | 53 | gettimeofday(&stoptime, NULL); |
50 | stoptime.tv_sec += genrc_timeout; | 54 | stoptime.tv_sec += genrc_timeout; |
51 | while (1) { | 55 | while (1) { |
52 | pid_t p; | 56 | pid_t p; |
53 | 57 | ||
54 | p = waitpid(pid, status, WNOHANG); | 58 | p = waitpid(pid, status, WNOHANG); |
@@ -70,13 +74,13 @@ timedwaitpid(pid_t pid, int *status) | |||
70 | system_error(errno, "select"); | 74 | system_error(errno, "select"); |
71 | break; | 75 | break; |
72 | } | 76 | } |
73 | } | 77 | } |
74 | 78 | ||
75 | } | 79 | } |
76 | signal(SIGCHLD, oldsig); | 80 | sigaction(SIGCHLD, &oldact, NULL); |
77 | if (rc) { | 81 | if (rc) { |
78 | kill(pid, SIGKILL); | 82 | kill(pid, SIGKILL); |
79 | } | 83 | } |
80 | return rc; | 84 | return rc; |
81 | } | 85 | } |
82 | 86 | ||
diff --git a/src/genrc.8 b/src/genrc.8 index 00522ee..959a00e 100644 --- a/src/genrc.8 +++ b/src/genrc.8 | |||
@@ -10,13 +10,13 @@ | |||
10 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | .\" GNU General Public License for more details. | 12 | .\" GNU General Public License for more details. |
13 | .\" | 13 | .\" |
14 | .\" You should have received a copy of the GNU General Public License | 14 | .\" You should have received a copy of the GNU General Public License |
15 | .\" along with genrc. If not, see <http://www.gnu.org/licenses/>. | 15 | .\" along with genrc. If not, see <http://www.gnu.org/licenses/>. |
16 | .TH GENRC 8 "May 17, 2018" "GENRC" "Genrc User Manual" | 16 | .TH GENRC 8 "May 20, 2018" "GENRC" "Genrc User Manual" |
17 | .SH NAME | 17 | .SH NAME |
18 | genrc \- generic system initialization script helper | 18 | genrc \- generic system initialization script helper |
19 | .SH SYNOPSIS | 19 | .SH SYNOPSIS |
20 | .nh | 20 | .nh |
21 | .na | 21 | .na |
22 | \fBgenrc\fR\ | 22 | \fBgenrc\fR\ |
@@ -33,12 +33,14 @@ genrc \- generic system initialization script helper | |||
33 | [\fB\-\-group=\fIGROUP\fR[,\fIGROUP\fR...]]\ | 33 | [\fB\-\-group=\fIGROUP\fR[,\fIGROUP\fR...]]\ |
34 | [\fB\-\-help\fR]\ | 34 | [\fB\-\-help\fR]\ |
35 | [\fB\-\-no\-reload\fR]\ | 35 | [\fB\-\-no\-reload\fR]\ |
36 | [\fB\-\-pid\-from=\fISOURCE\fR]\ | 36 | [\fB\-\-pid\-from=\fISOURCE\fR]\ |
37 | [\fB\-\-pidfile=\fIPIDFILE\fR]\ | 37 | [\fB\-\-pidfile=\fIPIDFILE\fR]\ |
38 | [\fB\-\-program=\fIPROGRAM\fR]\ | 38 | [\fB\-\-program=\fIPROGRAM\fR]\ |
39 | [\fB\-\-restart\-on\-exit=\fR[\fB!\fR]\fISTATUS\fR[\fB,\fISTATUS\fR...]]\ | ||
40 | [\fB\-\-restart\-on\-signal=\fR[\fB!\fR]\fISIG\fR[\fB,\fISIG\fR...]]\ | ||
39 | [\fB\-\-sentinel\fR]\ | 41 | [\fB\-\-sentinel\fR]\ |
40 | [\fB\-\-signal\-reload=\fISIG\fR]\ | 42 | [\fB\-\-signal\-reload=\fISIG\fR]\ |
41 | [\fB\-\-signal\-stop=\fISIG\fR]\ | 43 | [\fB\-\-signal\-stop=\fISIG\fR]\ |
42 | [\fB\-\-timeout=\fISECONDS\fR]\ | 44 | [\fB\-\-timeout=\fISECONDS\fR]\ |
43 | [\fB\-\-user=\fIUSER\fR]\ | 45 | [\fB\-\-user=\fIUSER\fR]\ |
44 | [\fB\-\-usage\fR]\ | 46 | [\fB\-\-usage\fR]\ |
@@ -98,12 +100,36 @@ with the priority \fBinfo\fR and the error with the priority | |||
98 | .PP | 100 | .PP |
99 | If the \fB\-\-create\-pidfile=\fIFILENAME\fR option is given together with | 101 | If the \fB\-\-create\-pidfile=\fIFILENAME\fR option is given together with |
100 | \fB\-\-sentinel\fR, the PID of the subsidiary command will be stored | 102 | \fB\-\-sentinel\fR, the PID of the subsidiary command will be stored |
101 | in \fIFILE\fR. The file will be unlinked after the subsidiary command | 103 | in \fIFILE\fR. The file will be unlinked after the subsidiary command |
102 | terminates. Unless the \fB\-\-pid\-from\fR option is given, | 104 | terminates. Unless the \fB\-\-pid\-from\fR option is given, |
103 | \fB\-\-pid\-from=FILE:\fIFILENAME\fR will be assumed. | 105 | \fB\-\-pid\-from=FILE:\fIFILENAME\fR will be assumed. |
106 | .PP | ||
107 | In sentinel mode, it is possible to restart the program if it | ||
108 | terminates with a specific exit code or on a specific signal. This is | ||
109 | controlled by the \fB\-\-restart\-on\-exit\fR and | ||
110 | \fB\-\-restart\-on\-signal\fR options. Use this feature to ensure the | ||
111 | service provided by the program won't get terminated because of | ||
112 | hitting a bug or encountering an unforeseen external condition. For | ||
113 | example, the following two options will ensure that the program will | ||
114 | be terminated only if it exits with status 0 or it is terminated by | ||
115 | SIGTERM or SIGQUIT signal: | ||
116 | .EX | ||
117 | --restart-on-exit='!0' --restart-on-signal='!TERM,QUIT' | ||
118 | .EE | ||
119 | .PP | ||
120 | If restarts are requested, \fBgenrc\fR will control how often it has | ||
121 | to restart the program using the same algorithm as | ||
122 | .B init (8). | ||
123 | Namely, if the program is restarted more than 10 times within two | ||
124 | minutes, \fBgenrc\fR will disable subsequent restarts for the next | ||
125 | 5 minutes. If the \fB\-\-create\-pidfile\fR option was used, the | ||
126 | PID of the controlling \fBgenrc\fR process will be stored in the | ||
127 | file during that interval. If the \fBSIGHUP\fR signal is delivered | ||
128 | during the sleep interval, the sleep will be broken prematurely and | ||
129 | the program restarted again. | ||
104 | .SS status | 130 | .SS status |
105 | In \fBstatus\fR mode \fBgenrc\fR verifies if the \fICOMMAND\fR is | 131 | In \fBstatus\fR mode \fBgenrc\fR verifies if the \fICOMMAND\fR is |
106 | already running and outputs its status on the standard output. To this | 132 | already running and outputs its status on the standard output. To this |
107 | effect, it uses an abstraction called \fIPID source\fR, which allows | 133 | effect, it uses an abstraction called \fIPID source\fR, which allows |
108 | it to determine the PID of the program by its name of command line. | 134 | it to determine the PID of the program by its name of command line. |
109 | .PP | 135 | .PP |
@@ -185,15 +211,43 @@ Makes \fBreload\fR equivalent to \fBrestart\fR. | |||
185 | \fB\-p\fR, \fB\-\-program=\fIPROGRAM\fR | 211 | \fB\-p\fR, \fB\-\-program=\fIPROGRAM\fR |
186 | Name of the program to run. | 212 | Name of the program to run. |
187 | .TP | 213 | .TP |
188 | \fB\-P\fR, \fB\-\-pid\-from=\fISOURCE\fR | 214 | \fB\-P\fR, \fB\-\-pid\-from=\fISOURCE\fR |
189 | Where to look for PIDs of the running programs. | 215 | Where to look for PIDs of the running programs. |
190 | .TP | 216 | .TP |
217 | \fB\-\-restart\-on\-exit=\fR[\fB!\fR]\fISTATUS\fR[\fB,\fISTATUS\fR...] | ||
218 | This option takes effect when used together with | ||
219 | \fB\-\-sentinel\fR. If the program terminates with one of status | ||
220 | codes listed as the argument to this option, it will be immediately | ||
221 | restarted. The exclamation mark at the start of the list inverts the | ||
222 | set, e.g. \fB\-\-restart\-on\-exit='!0,1'\fR means restart unless the | ||
223 | program exit code is 0 or 1. Note the use of quotation to prevent the | ||
224 | \fB!\fR from being interpreted by the shell. | ||
225 | .TP | ||
226 | \fB\-\-restart\-on\-signal=\fR[\fB!\fR]\fISIG\fR[\fB,\fISIG\fR...] | ||
227 | This option takes effect when used together with | ||
228 | \fB\-\-sentinel\fR. If the program terminates due to receiving one of | ||
229 | the signals from this list, it will be immediately restarted. Each | ||
230 | \fISIG\fR is either a signal number, or a signal name, as listed in | ||
231 | .BR signal (7). | ||
232 | The \fBSIG\fR prefix can be omitted from the signal name. Names are | ||
233 | case-insensitive. Thus, \fB1\fR, \fBHUP\fR, \fBSIGHUP\fR, and | ||
234 | \fBsighup\fR all stand for the same signal. | ||
235 | .sp | ||
236 | The exclamation mark at the start of the list complements the signal | ||
237 | set, so that e.g. \fB\-\-restart\-on\-signal='!TERM,QUIT,INT'\fR will | ||
238 | restart the program unless it terminates on one of the listed signals. | ||
239 | .TP | ||
191 | \fB\-\-sentinel\fR | 240 | \fB\-\-sentinel\fR |
192 | \fIPROGRAM\fR runs in foreground; disconnect from the controlling | 241 | \fIPROGRAM\fR runs in foreground; disconnect from the controlling |
193 | terminal, run it and act as a sentinel. | 242 | terminal, start it and run in background until it terminates. The |
243 | program's stdout and stderr are sent to the syslog facility | ||
244 | \fBdaemon\fR, priorities \fBinfo\fR and \fBerr\fR, correspondingly. | ||
245 | |||
246 | See the options \fB\-\-restart\-on\-exit\fR and | ||
247 | \fB\-\-restart\-on\-signal\fR for details on how to restart the program. | ||
194 | .TP | 248 | .TP |
195 | \fB\-\-signal\-reload=\fISIG\fR | 249 | \fB\-\-signal\-reload=\fISIG\fR |
196 | Signal to send on reload (default: \fBSIGHUP\fR). Setting it to 0 is | 250 | Signal to send on reload (default: \fBSIGHUP\fR). Setting it to 0 is |
197 | equivalent to \fB\-\-no\-reload\fR. | 251 | equivalent to \fB\-\-no\-reload\fR. |
198 | .TP | 252 | .TP |
199 | \fB\-\-signal\-stop=\fISIG\fR | 253 | \fB\-\-signal\-stop=\fISIG\fR |
diff --git a/src/genrc.c b/src/genrc.c index ae3070d..9052987 100644 --- a/src/genrc.c +++ b/src/genrc.c | |||
@@ -22,13 +22,15 @@ int genrc_verbose; | |||
22 | enum { | 22 | enum { |
23 | OPT_USAGE = 256, | 23 | OPT_USAGE = 256, |
24 | OPT_VERSION, | 24 | OPT_VERSION, |
25 | OPT_SIGNAL_RELOAD, | 25 | OPT_SIGNAL_RELOAD, |
26 | OPT_NO_RELOAD, | 26 | OPT_NO_RELOAD, |
27 | OPT_SIGNAL_STOP, | 27 | OPT_SIGNAL_STOP, |
28 | OPT_CREATE_PIDFILE | 28 | OPT_CREATE_PIDFILE, |
29 | OPT_RESTART_ON_EXIT, | ||
30 | OPT_RESTART_ON_SIGNAL, | ||
29 | }; | 31 | }; |
30 | 32 | ||
31 | struct option longopts[] = { | 33 | struct option longopts[] = { |
32 | { "help", no_argument, 0, 'h' }, | 34 | { "help", no_argument, 0, 'h' }, |
33 | { "usage", no_argument, 0, OPT_USAGE }, | 35 | { "usage", no_argument, 0, OPT_USAGE }, |
34 | { "command", required_argument, 0, 'c' }, | 36 | { "command", required_argument, 0, 'c' }, |
@@ -42,12 +44,14 @@ struct option longopts[] = { | |||
42 | { "sentinel", no_argument, 0, 'S' }, | 44 | { "sentinel", no_argument, 0, 'S' }, |
43 | { "create-pidfile", required_argument, 0, OPT_CREATE_PIDFILE }, | 45 | { "create-pidfile", required_argument, 0, OPT_CREATE_PIDFILE }, |
44 | { "version", no_argument, 0, OPT_VERSION }, | 46 | { "version", no_argument, 0, OPT_VERSION }, |
45 | { "verbose", no_argument, 0, 'v' }, | 47 | { "verbose", no_argument, 0, 'v' }, |
46 | { "user", required_argument, 0, 'u' }, | 48 | { "user", required_argument, 0, 'u' }, |
47 | { "group", required_argument, 0, 'g' }, | 49 | { "group", required_argument, 0, 'g' }, |
50 | { "restart-on-exit", required_argument, 0, OPT_RESTART_ON_EXIT }, | ||
51 | { "restart-on-signal", required_argument, 0, OPT_RESTART_ON_SIGNAL }, | ||
48 | { NULL } | 52 | { NULL } |
49 | }; | 53 | }; |
50 | char shortopts[] = "c:hF:g:P:p:St:u:v"; | 54 | char shortopts[] = "c:hF:g:P:p:St:u:v"; |