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/genrc.c | |
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/genrc.c')
-rw-r--r-- | src/genrc.c | 41 |
1 files changed, 34 insertions, 7 deletions
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"; |
51 | 55 | ||
52 | struct sigdefn { | 56 | struct sigdefn { |
53 | char const *sig_name; | 57 | char const *sig_name; |
@@ -124,22 +128,28 @@ is_numeric_str(char const *s) | |||
124 | s++; | 128 | s++; |
125 | } | 129 | } |
126 | return 1; | 130 | return 1; |
127 | } | 131 | } |
128 | 132 | ||
129 | int | 133 | int |
130 | sig_name_to_str(char const *s) | 134 | str_to_int(char const *s) |
131 | { | 135 | { |
132 | if (is_numeric_str(s)) { | ||
133 | char *end; | 136 | char *end; |
134 | unsigned long n; | 137 | unsigned long n; |
135 | errno = 0; | 138 | errno = 0; |
136 | n = strtoul(s, &end, 10); | 139 | n = strtoul(s, &end, 10); |
137 | if (errno || *end || n > UINT_MAX) | 140 | if (errno || *end || n > UINT_MAX) |
138 | return -1; | 141 | return -1; |
139 | return n; | 142 | return n; |
143 | } | ||
144 | |||
145 | int | ||
146 | str_to_sig(char const *s) | ||
147 | { | ||
148 | if (is_numeric_str(s)) { | ||
149 | return str_to_int(s); | ||
140 | } else { | 150 | } else { |
141 | struct sigdefn *sd; | 151 | struct sigdefn *sd; |
142 | 152 | ||
143 | for (sd = sigdefn; sd->sig_name; sd++) { | 153 | for (sd = sigdefn; sd->sig_name; sd++) { |
144 | if (s[0] == 's' || s[0] == 'S') { | 154 | if (s[0] == 's' || s[0] == 'S') { |
145 | if (strcasecmp(sd->sig_name, s) == 0) | 155 | if (strcasecmp(sd->sig_name, s) == 0) |
@@ -180,23 +190,32 @@ char const *help_msg[] = { | |||
180 | " run with this group(s) privileges", | 190 | " run with this group(s) privileges", |
181 | "", | 191 | "", |
182 | "Additional configuration:", | 192 | "Additional configuration:", |
183 | "", | 193 | "", |
184 | " -t, --timeout=SECONDS time to wait for the program to start up or", | 194 | " -t, --timeout=SECONDS time to wait for the program to start up or", |
185 | " terminate", | 195 | " terminate", |
186 | " --sentinel PROGRAM runs in foreground; disconnect from the", | ||
187 | " controlling terminal, run it and act as a sentinel", | ||
188 | " -P, --pid-from=SOURCE where to look for PIDs of the running programs", | 196 | " -P, --pid-from=SOURCE where to look for PIDs of the running programs", |
189 | " -F, --pidfile=NAME name of the PID file", | 197 | " -F, --pidfile=NAME name of the PID file", |
190 | " (same as --pid-from=FILE:NAME)", | 198 | " (same as --pid-from=FILE:NAME)", |
191 | " --signal-reload=SIG signal to send on reload (default: SIGHUP)", | 199 | " --signal-reload=SIG signal to send on reload (default: SIGHUP)", |
192 | " setting to 0 is equivalent to --no-reload", | 200 | " setting to 0 is equivalent to --no-reload", |
193 | " --no-reload makes reload equivalent to restart", | 201 | " --no-reload makes reload equivalent to restart", |
194 | " --signal-stop=SIG signal to send in order to terminate the program", | 202 | " --signal-stop=SIG signal to send in order to terminate the program", |
195 | " (default: SIGTERM)", | 203 | " (default: SIGTERM)", |
196 | "", | 204 | "", |
205 | "Sentinel mode:", | ||
206 | "", | ||
207 | " --sentinel PROGRAM runs in foreground; disconnect from the", | ||
208 | " controlling terminal, run it and act as a sentinel", | ||
209 | " --restart-on-exit=[!]CODE[,...]", | ||
210 | " restart the program if it exits with one of the", | ||
211 | " listed status codes", | ||
212 | " --restart-on-signal=[!]SIG[,...]", | ||
213 | " restart the program if it terminates on one of the", | ||
214 | " listed signals", | ||
215 | "", | ||
197 | "Informational options:", | 216 | "Informational options:", |
198 | "", | 217 | "", |
199 | " -h, --help display this help list", | 218 | " -h, --help display this help list", |
200 | " --usage display short usage information", | 219 | " --usage display short usage information", |
201 | " --version display program version and exist", | 220 | " --version display program version and exist", |
202 | "", | 221 | "", |
@@ -269,12 +288,14 @@ char const *usage_msg[] = { | |||
269 | "[--group GROUP[,GROUP...]]", | 288 | "[--group GROUP[,GROUP...]]", |
270 | "[--help]", | 289 | "[--help]", |
271 | "[--no-reload]", | 290 | "[--no-reload]", |
272 | "[--pid-from=SOURCE]", | 291 | "[--pid-from=SOURCE]", |
273 | "[--pidfile=PIDFILE]", | 292 | "[--pidfile=PIDFILE]", |
274 | "[--program=PROGRAM]", | 293 | "[--program=PROGRAM]", |
294 | "[--restart-on-exit=[!]CODE[,...]]", | ||
295 | "[--restart-on-signal=[!]SIG[,...]]", | ||
275 | "[--sentinel]", | 296 | "[--sentinel]", |
276 | "[--signal-reload=SIG]", | 297 | "[--signal-reload=SIG]", |
277 | "[--signal-stop=SIG]", | 298 | "[--signal-stop=SIG]", |
278 | "[--timeout=SECONDS]", | 299 | "[--timeout=SECONDS]", |
279 | "[--usage]", | 300 | "[--usage]", |
280 | "[--user=USER]", | 301 | "[--user=USER]", |
@@ -419,12 +440,18 @@ main(int argc, char **argv) | |||
419 | case 't': | 440 | case 't': |
420 | setenv("GENRC_TIMEOUT", optarg, 1); | 441 | setenv("GENRC_TIMEOUT", optarg, 1); |
421 | break; | 442 | break; |
422 | case 'S': | 443 | case 'S': |
423 | setenv("GENRC_SENTINEL", "1", 1); | 444 | setenv("GENRC_SENTINEL", "1", 1); |
424 | break; | 445 | break; |
446 | case OPT_RESTART_ON_EXIT: | ||
447 | add_restart_condition(RESTART_ON_EXIT, optarg); | ||
448 | break; | ||
449 | case OPT_RESTART_ON_SIGNAL: | ||
450 | add_restart_condition(RESTART_ON_SIGNAL, optarg); | ||
451 | break; | ||
425 | case OPT_NO_RELOAD: | 452 | case OPT_NO_RELOAD: |
426 | no_reload = 1; | 453 | no_reload = 1; |
427 | break; | 454 | break; |
428 | case OPT_SIGNAL_RELOAD: | 455 | case OPT_SIGNAL_RELOAD: |
429 | setenv("GENRC_SIGNAL_RELOAD", optarg, 1); | 456 | setenv("GENRC_SIGNAL_RELOAD", optarg, 1); |
430 | break; | 457 | break; |
@@ -447,21 +474,21 @@ main(int argc, char **argv) | |||
447 | if ((p = getenv("GENRC_PROGRAM")) != NULL) | 474 | if ((p = getenv("GENRC_PROGRAM")) != NULL) |
448 | genrc_program = p; | 475 | genrc_program = p; |
449 | 476 | ||
450 | if (no_reload) | 477 | if (no_reload) |
451 | genrc_no_reload = 1; | 478 | genrc_no_reload = 1; |
452 | else if ((p = getenv("GENRC_SIGNAL_RELOAD")) != NULL) { | 479 | else if ((p = getenv("GENRC_SIGNAL_RELOAD")) != NULL) { |
453 | genrc_signal_reload = sig_name_to_str(p); | 480 | genrc_signal_reload = str_to_sig(p); |
454 | if (genrc_signal_reload == -1) | 481 | if (genrc_signal_reload == -1) |
455 | usage_error("%s: invalid signal number", p); | 482 | usage_error("%s: invalid signal number", p); |
456 | else if (genrc_signal_reload == 0) | 483 | else if (genrc_signal_reload == 0) |
457 | genrc_no_reload = 1; | 484 | genrc_no_reload = 1; |
458 | } | 485 | } |
459 | 486 | ||
460 | if ((p = getenv("GENRC_SIGNAL_STOP")) != NULL) { | 487 | if ((p = getenv("GENRC_SIGNAL_STOP")) != NULL) { |
461 | genrc_signal_stop = sig_name_to_str(p); | 488 | genrc_signal_stop = str_to_sig(p); |
462 | if (genrc_signal_stop <= 0) | 489 | if (genrc_signal_stop <= 0) |
463 | usage_error("%s: invalid signal number", p); | 490 | usage_error("%s: invalid signal number", p); |
464 | } | 491 | } |
465 | 492 | ||
466 | if ((p = getenv("GENRC_TIMEOUT")) != NULL) { | 493 | if ((p = getenv("GENRC_TIMEOUT")) != NULL) { |
467 | char *end; | 494 | char *end; |