mirror of
https://github.com/troglobit/finit.git
synced 2026-11-07 16:01:08 +00:00
Add individual timeout support for pre/post/ready scripts
Syntax:
[pre|post|ready]:[0-3600,]/path/to/script
Description:
Before this patch all pre/post/ready scripts used the global kill
delay as timeout. After this patch it is possible to disable the
timeout as well as set a timeout >60, which is max kill delay.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
3 files changed
+78
-32
No files matched your search
+32
-20
@@ -890,33 +890,45 @@ configurable with the following options:
|
|||||||
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
||||||
`post:script` action if set, see below.
|
`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
|
||||||
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
moving to another runlevel, Finit starts by sending `SIGTERM`, to allow
|
||||||
allow the process to shut down gracefully. If the process has not
|
the process to shut down gracefully. However, if the process has not
|
||||||
been collected within 3 seconds, Finit sends `SIGKILL`. To halt the
|
been collected within 3 seconds, Finit will send `SIGKILL`. To stop the
|
||||||
process using a different signal, use the option `halt:SIGNAL`, e.g.,
|
process using a different signal than `SIGTERM`, use `halt:SIGNAL`,
|
||||||
`halt:SIGPWR`. To change the delay between your halt signal and KILL,
|
e.g., `halt:SIGPWR`. To change the delay between the stop signal and
|
||||||
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
KILL, use the option `kill:<1-60>`, e.g., `kill:10` to wait 10 seconds
|
||||||
sending `SIGKILL`.
|
before sending `SIGKILL`.
|
||||||
|
|
||||||
Services support `pre:script` and `post:script` actions as well. These
|
Services, including the `sysv` variant, support pre/post/ready scripts:
|
||||||
run as the same `@USER:GROUP` as the service itself, with any `env:file`
|
|
||||||
sourced. The scripts must use an absolute path, but are executed from
|
* `pre:[0-3600,]script`
|
||||||
the `$HOME` of the given user. The scripts are not called with any
|
* `post:[0-3600,]script`
|
||||||
argument (currently), but both get the `SERVICE_IDENT=foo` environment
|
* `ready:[0-3600,]script`
|
||||||
variable set. Here `foo` denotes the identity of the service, which if
|
|
||||||
there are multiple services named `foo`, may be `foo:1`, or any unique
|
The optional number (0-3600) is the timeout before Finit kills the
|
||||||
identifier specified in the .conf file. The `post:script` is called
|
script, it defaults to the kill delay value and can be disabled by
|
||||||
with an additional set of environment variables:
|
setting it to zero. These scripts run as the same `@USER:GROUP` as the
|
||||||
|
service itself, with any `env:file` sourced. The scripts must use an
|
||||||
|
absolute path, but are executed from the `$HOME` of the given user. The
|
||||||
|
scripts are not called with any argument, but get a set of environment
|
||||||
|
variables:
|
||||||
|
|
||||||
|
* `SERVICE_IDENT=foo:1`
|
||||||
|
* `SERVICE_NAME=foo`
|
||||||
|
* `SERVICE_ID=1`
|
||||||
|
|
||||||
|
The `post:script` is called with an additional set of environment
|
||||||
|
variables:
|
||||||
|
|
||||||
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
|
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
|
||||||
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
||||||
the program, if it exited normally, or the signal name (`HUP`,
|
the program, if it exited normally, or the signal name (`HUP`,
|
||||||
`TERM`, etc.) if it exited due to signal
|
`TERM`, etc.) if it exited due to signal
|
||||||
|
|
||||||
These script actions *must terminate*, so they have a default execution
|
> [!IMPORTANT]
|
||||||
time of 3 seconds before they are SIGKILLed, this can be adjusted using
|
> These script actions are intended for setup, cleanup, and readiness
|
||||||
the above `kill:SEC` syntax.
|
> notification. It is up to the user to ensure the scripts terminate.
|
||||||
|
|
||||||
|
|
||||||
#### Conditional Loading
|
#### Conditional Loading
|
||||||
|
|
||||||
|
|||||||
+43
-12
@@ -100,6 +100,9 @@ static void service_timeout_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
|
int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
|
||||||
{
|
{
|
||||||
|
if (timeout == 0)
|
||||||
|
return 0; /* OK, not starting timer. */
|
||||||
|
|
||||||
if (svc->timer_cb)
|
if (svc->timer_cb)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
@@ -153,7 +156,7 @@ static void service_script_kill(svc_t *svc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_script_add(svc_t *svc, pid_t pid)
|
static int service_script_add(svc_t *svc, pid_t pid, int tmo)
|
||||||
{
|
{
|
||||||
struct assoc *ptr = malloc(sizeof(*ptr));
|
struct assoc *ptr = malloc(sizeof(*ptr));
|
||||||
|
|
||||||
@@ -166,7 +169,7 @@ static int service_script_add(svc_t *svc, pid_t pid)
|
|||||||
ptr->pid = pid;
|
ptr->pid = pid;
|
||||||
TAILQ_INSERT_TAIL(&svc_assoc_list, ptr, link);
|
TAILQ_INSERT_TAIL(&svc_assoc_list, ptr, link);
|
||||||
|
|
||||||
service_timeout_after(svc, svc->killdelay, service_script_kill);
|
service_timeout_after(svc, tmo, service_script_kill);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1297,12 +1300,35 @@ static void parse_killdelay(svc_t *svc, char *delay)
|
|||||||
svc->killdelay = (int)(sec * 1000);
|
svc->killdelay = (int)(sec * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_script(char *type, char *script, char *buf, size_t len)
|
/*
|
||||||
|
* pre:[0-3600,]/path/to/script
|
||||||
|
*/
|
||||||
|
static void parse_script(svc_t *svc, char *type, char *script, int *tmo, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
if (access(script, X_OK))
|
char *path;
|
||||||
logit(LOG_WARNING, "%s:%s is missing or not executable, skipping.", type, script);
|
|
||||||
|
path = strchr(script, ',');
|
||||||
|
if (path) {
|
||||||
|
const char *errstr;
|
||||||
|
long long sec;
|
||||||
|
|
||||||
|
*path++ = 0;
|
||||||
|
|
||||||
|
sec = strtonum(script, 0, 3600, &errstr);
|
||||||
|
if (errstr) {
|
||||||
|
errx(1, "%s: tmo %s is %s (0-3600)", svc_ident(svc, NULL, 0), script, errstr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*tmo = (int)(sec * 1000);
|
||||||
|
} else {
|
||||||
|
path = script;
|
||||||
|
*tmo = svc->killdelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access(path, X_OK))
|
||||||
|
logit(LOG_WARNING, "%s:%s is missing or not executable, skipping.", type, path);
|
||||||
else
|
else
|
||||||
strlcpy(buf, script, len);
|
strlcpy(buf, path, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1770,15 +1796,15 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
else
|
else
|
||||||
svc->killdelay = SVC_TERM_TIMEOUT;
|
svc->killdelay = SVC_TERM_TIMEOUT;
|
||||||
if (pre_script)
|
if (pre_script)
|
||||||
parse_script("pre", pre_script, svc->pre_script, sizeof(svc->pre_script));
|
parse_script(svc, "pre", pre_script, &svc->pre_tmo, svc->pre_script, sizeof(svc->pre_script));
|
||||||
else
|
else
|
||||||
memset(svc->pre_script, 0, sizeof(svc->pre_script));
|
memset(svc->pre_script, 0, sizeof(svc->pre_script));
|
||||||
if (post_script)
|
if (post_script)
|
||||||
parse_script("post", post_script, svc->post_script, sizeof(svc->post_script));
|
parse_script(svc, "post", post_script, &svc->post_tmo, svc->post_script, sizeof(svc->post_script));
|
||||||
else
|
else
|
||||||
memset(svc->post_script, 0, sizeof(svc->post_script));
|
memset(svc->post_script, 0, sizeof(svc->post_script));
|
||||||
if (ready_script)
|
if (ready_script)
|
||||||
parse_script("ready", ready_script, svc->ready_script, sizeof(svc->ready_script));
|
parse_script(svc, "ready", ready_script, &svc->ready_tmo, svc->ready_script, sizeof(svc->ready_script));
|
||||||
else
|
else
|
||||||
memset(svc->ready_script, 0, sizeof(svc->ready_script));
|
memset(svc->ready_script, 0, sizeof(svc->ready_script));
|
||||||
if (!svc_is_tty(svc)) {
|
if (!svc_is_tty(svc)) {
|
||||||
@@ -2059,6 +2085,9 @@ static void set_pre_post_envs(svc_t *svc, const char *type)
|
|||||||
char buf[25 + 256] = "/etc/default:/etc/conf.d";
|
char buf[25 + 256] = "/etc/default:/etc/conf.d";
|
||||||
|
|
||||||
setenv("SERVICE_TYPE", svc_typestr(svc), 1);
|
setenv("SERVICE_TYPE", svc_typestr(svc), 1);
|
||||||
|
setenv("SERVICE_NAME", svc->name, 1);
|
||||||
|
if (svc->id[0])
|
||||||
|
setenv("SERVICE_ID", svc->id, 1);
|
||||||
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
|
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
|
||||||
setenv("SERVICE_SCRIPT_TYPE", type, 1);
|
setenv("SERVICE_SCRIPT_TYPE", type, 1);
|
||||||
|
|
||||||
@@ -2087,6 +2116,8 @@ static void service_pre_script(svc_t *svc)
|
|||||||
};
|
};
|
||||||
char *env_file;
|
char *env_file;
|
||||||
|
|
||||||
|
redirect(svc);
|
||||||
|
|
||||||
env_file = svc_getenv(svc);
|
env_file = svc_getenv(svc);
|
||||||
if (env_file)
|
if (env_file)
|
||||||
snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->pre_script);
|
snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->pre_script);
|
||||||
@@ -2101,7 +2132,7 @@ static void service_pre_script(svc_t *svc)
|
|||||||
dbg("%s: pre:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->pre_script, svc->pid);
|
dbg("%s: pre:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->pre_script, svc->pid);
|
||||||
|
|
||||||
/* Short hard-coded timeout to prevent locking up Finit */
|
/* Short hard-coded timeout to prevent locking up Finit */
|
||||||
service_timeout_after(svc, svc->killdelay, service_kill_script);
|
service_timeout_after(svc, svc->pre_tmo, service_kill_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_post_script(svc_t *svc)
|
static void service_post_script(svc_t *svc)
|
||||||
@@ -2154,7 +2185,7 @@ static void service_post_script(svc_t *svc)
|
|||||||
dbg("%s: post:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->post_script, svc->pid);
|
dbg("%s: post:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->post_script, svc->pid);
|
||||||
|
|
||||||
/* Short hard-coded timeout to prevent locking up Finit */
|
/* Short hard-coded timeout to prevent locking up Finit */
|
||||||
service_timeout_after(svc, svc->killdelay, service_kill_script);
|
service_timeout_after(svc, svc->post_tmo, service_kill_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void service_ready_script(svc_t *svc)
|
void service_ready_script(svc_t *svc)
|
||||||
@@ -2194,7 +2225,7 @@ void service_ready_script(svc_t *svc)
|
|||||||
dbg("%s: ready:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->ready_script, pid);
|
dbg("%s: ready:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->ready_script, pid);
|
||||||
|
|
||||||
/* Short hard-coded timeout to prevent locking up Finit */
|
/* Short hard-coded timeout to prevent locking up Finit */
|
||||||
service_script_add(svc, pid);
|
service_script_add(svc, pid, svc->ready_tmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_retry(svc_t *svc)
|
static void service_retry(svc_t *svc)
|
||||||
|
|||||||
@@ -197,8 +197,11 @@ typedef struct svc {
|
|||||||
char desc[MAX_STR_LEN];
|
char desc[MAX_STR_LEN];
|
||||||
char env[MAX_CMD_LEN];
|
char env[MAX_CMD_LEN];
|
||||||
char pre_script[MAX_CMD_LEN];
|
char pre_script[MAX_CMD_LEN];
|
||||||
|
int pre_tmo;
|
||||||
char post_script[MAX_CMD_LEN];
|
char post_script[MAX_CMD_LEN];
|
||||||
|
int post_tmo;
|
||||||
char ready_script[MAX_CMD_LEN];
|
char ready_script[MAX_CMD_LEN];
|
||||||
|
int ready_tmo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to forcefully kill services that won't shutdown on
|
* Used to forcefully kill services that won't shutdown on
|
||||||
|
|||||||
Reference in new issue
Block a user