Fix #282: add support for oncrash:script to call post:script action

This patch adds the oncrash:script option to call the post:script
action, if defined, for a crashing service.  The EXIT_CODE variable
sent to the script is set to `crashed`.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2022-11-06 13:07:10 +01:00
1 parent 278994781b
commit 5dd1a676ac
4 files changed
+41 -10

No files matched your search

+2 -1
View File
@@ -549,7 +549,8 @@ configurable with the following options:
was originally designed for so not the default behavior was originally designed for so not the default behavior
* `oncrash:reboot` -- when all retries have failed, and the service * `oncrash:reboot` -- when all retries have failed, and the service
has *crashed*, if this option is set the system is rebooted. has *crashed*, if this option is set the system is rebooted.
Note, future releases may include other `oncrash:` actions * `oncrash:script` -- similarly, but instead of rebooting, call the
`post:script` action if set, see below.
When stopping a service (run/task/sysv/service), either manually or When stopping a service (run/task/sysv/service), either manually or
when moving to another runlevel, Finit starts by sending `SIGTERM`, to when moving to another runlevel, Finit starts by sending `SIGTERM`, to
+20 -7
View File
@@ -366,10 +366,21 @@ was originally designed for so not the default behavior.
when all retries have failed, and the service when all retries have failed, and the service
has has
.Em crashed , .Em crashed ,
if this option is set the system is rebooted. Note, future releases if this option is set the system is rebooted.
may include other .It Cm oncrash:script
.Cm oncrash: Similar to
actions. .Cm oncrash:reboot ,
but instead of rebooting this action calls the
.Cm post:script
(see below) to let the operator decide the best course of action. If
the post:script option is not set, this is a no-op.
.Pp
The post:script is called with the same environment variables
.Sy except
for the
.Cm EXIT_CODE
variable which is set to
.Cm "crashed" .
.El .El
.Pp .Pp
When stopping a service (run/task/sysv/service), either manually or when When stopping a service (run/task/sysv/service), either manually or when
@@ -412,11 +423,13 @@ or any unique identifier specified in the .conf file. The
.Cm post:script .Cm post:script
is called with an additional set of environment variables: is called with an additional set of environment variables:
.Bl -tag -offset indent -width 1n .Bl -tag -offset indent -width 1n
.It Cm EXIT_CODE=[exited,signal] .It Cm EXIT_CODE=[exited,signal,crashed]
set to one of set to one of
.Cm exited .Cm exited ,
.Cm signal ,
or or
.Cm signal .Cm crashed
(see above).
.It Cm EXIT_STATUS=[num,SIGNAME] .It Cm EXIT_STATUS=[num,SIGNAME]
set to one of exit status code from the program, if it exited normally, set to one of exit status code from the program, if it exited normally,
or the signal name (HUP, TERM, etc.) if it exited due to signal or the signal name (HUP, TERM, etc.) if it exited due to signal
+16 -1
View File
@@ -1403,6 +1403,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
else if (MATCH_CMD(cmd, "oncrash:", arg)) { else if (MATCH_CMD(cmd, "oncrash:", arg)) {
if (MATCH_CMD(arg, "reboot", arg)) if (MATCH_CMD(arg, "reboot", arg))
oncrash_action = SVC_ONCRASH_REBOOT; oncrash_action = SVC_ONCRASH_REBOOT;
if (MATCH_CMD(arg, "script", arg))
oncrash_action = SVC_ONCRASH_SCRIPT;
} }
else if (MATCH_CMD(cmd, "respawn", arg)) else if (MATCH_CMD(cmd, "respawn", arg))
respawn = 1; respawn = 1;
@@ -1868,6 +1870,9 @@ static void service_post_script(svc_t *svc)
setenv("EXIT_STATUS", sig2str(sig), 1); setenv("EXIT_STATUS", sig2str(sig), 1);
} }
if (svc_is_crashing(svc))
setenv("EXIT_CODE", "crashed", 1);
execvp(_PATH_BSHELL, argv); execvp(_PATH_BSHELL, argv);
_exit(EX_OSERR); _exit(EX_OSERR);
} }
@@ -1945,10 +1950,20 @@ static void service_retry(svc_t *svc)
svc_ident(svc, NULL, 0)); svc_ident(svc, NULL, 0));
svc_crashing(svc); svc_crashing(svc);
*restart_cnt = 0; *restart_cnt = 0;
if (svc->oncrash_action == SVC_ONCRASH_REBOOT) { switch (svc->oncrash_action) {
case SVC_ONCRASH_REBOOT:
logit(LOG_ERR, "%s issuing reboot", svc_ident(svc, NULL, 0)); logit(LOG_ERR, "%s issuing reboot", svc_ident(svc, NULL, 0));
sync(); sync();
kill(1, SIGTERM); kill(1, SIGTERM);
break;
case SVC_ONCRASH_SCRIPT:
if (svc_has_post(svc)) {
dbg("calling post:script %s, crashing.", svc->post_script);
service_post_script(svc);
}
break;
default:
break;
} }
service_step(svc); service_step(svc);
return; return;
+3 -1
View File
@@ -78,7 +78,8 @@ typedef enum {
typedef enum { typedef enum {
SVC_ONCRASH_IGNORE = 0, SVC_ONCRASH_IGNORE = 0,
SVC_ONCRASH_REBOOT = 1, SVC_ONCRASH_REBOOT,
SVC_ONCRASH_SCRIPT,
} svc_oncrash_action_t; } svc_oncrash_action_t;
#define MAX_ID_LEN 16 #define MAX_ID_LEN 16
@@ -260,6 +261,7 @@ static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty
static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; } static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; }
static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; } static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; }
static inline int svc_is_missing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_MISSING; } static inline int svc_is_missing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_MISSING; }
static inline int svc_is_crashing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_CRASHING; }
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; } static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
#define svc_start(svc) svc_unblock(svc) #define svc_start(svc) svc_unblock(svc)