diff --git a/doc/config.md b/doc/config.md index cfa27fbb..a8224de6 100644 --- a/doc/config.md +++ b/doc/config.md @@ -549,7 +549,8 @@ configurable with the following options: was originally designed for so not the default behavior * `oncrash:reboot` -- when all retries have failed, and the service 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 moving to another runlevel, Finit starts by sending `SIGTERM`, to diff --git a/man/finit.conf.5 b/man/finit.conf.5 index 6ec4c535..68a9568e 100644 --- a/man/finit.conf.5 +++ b/man/finit.conf.5 @@ -366,10 +366,21 @@ was originally designed for so not the default behavior. when all retries have failed, and the service has .Em crashed , -if this option is set the system is rebooted. Note, future releases -may include other -.Cm oncrash: -actions. +if this option is set the system is rebooted. +.It Cm oncrash:script +Similar to +.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 .Pp 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 is called with an additional set of environment variables: .Bl -tag -offset indent -width 1n -.It Cm EXIT_CODE=[exited,signal] +.It Cm EXIT_CODE=[exited,signal,crashed] set to one of -.Cm exited +.Cm exited , +.Cm signal , or -.Cm signal +.Cm crashed +(see above). .It Cm EXIT_STATUS=[num,SIGNAME] 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 diff --git a/src/service.c b/src/service.c index a3adb680..997e8768 100644 --- a/src/service.c +++ b/src/service.c @@ -1403,6 +1403,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) else if (MATCH_CMD(cmd, "oncrash:", arg)) { if (MATCH_CMD(arg, "reboot", arg)) oncrash_action = SVC_ONCRASH_REBOOT; + if (MATCH_CMD(arg, "script", arg)) + oncrash_action = SVC_ONCRASH_SCRIPT; } else if (MATCH_CMD(cmd, "respawn", arg)) respawn = 1; @@ -1868,6 +1870,9 @@ static void service_post_script(svc_t *svc) setenv("EXIT_STATUS", sig2str(sig), 1); } + if (svc_is_crashing(svc)) + setenv("EXIT_CODE", "crashed", 1); + execvp(_PATH_BSHELL, argv); _exit(EX_OSERR); } @@ -1945,10 +1950,20 @@ static void service_retry(svc_t *svc) svc_ident(svc, NULL, 0)); svc_crashing(svc); *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)); sync(); 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); return; diff --git a/src/svc.h b/src/svc.h index e4b6f150..2ba60238 100644 --- a/src/svc.h +++ b/src/svc.h @@ -78,7 +78,8 @@ typedef enum { typedef enum { SVC_ONCRASH_IGNORE = 0, - SVC_ONCRASH_REBOOT = 1, + SVC_ONCRASH_REBOOT, + SVC_ONCRASH_SCRIPT, } svc_oncrash_action_t; #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_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_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; } #define svc_start(svc) svc_unblock(svc)