mirror of
https://github.com/troglobit/finit.git
synced 2026-10-29 12:40:44 +00:00
Fix #302: add support for running scripts at shutdown
This change adds support for running hook scripts at two new hook points during the shutdown process: - HOOK_SVC_DN: after all services and non-reserved processes have been killed (and collected) - HOOK_SYS_DN: after all file systems have been unmounted, *just prior* to Finit calling reboot() to shut down or reboot the system See doc/plugins.md for details and an example. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
5f74adad06
commit
d810ac00bc
5 files changed
+74
-11
No files matched your search
+26
-1
@@ -104,7 +104,23 @@ Hooks
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
In the below listings, the first label is the hook point for a C plugin,
|
In the below listings, the first label is the hook point for a C plugin,
|
||||||
the second is the condition name and hook script path.
|
the second is the condition name and hook script path. A hook script is
|
||||||
|
a plain shell script, or program, that does a very small dedicated job
|
||||||
|
at the below hook points.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
$ mkdir -p /libexec/finit/hook/sys/down
|
||||||
|
$ cat <<EOF >/libexec/finit/hook/sys/foo.sh
|
||||||
|
#!/bin/sh
|
||||||
|
echo 'I run just before the reboot() syscall at shutdown/reboot'
|
||||||
|
echo 'I have access to /dev since devtmpfs is exempt from umount'
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
$ chmod +x /libexec/finit/hook/sys/foo.sh
|
||||||
|
|
||||||
|
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
|
||||||
|
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
|
||||||
|
|
||||||
### Bootstrap Hooks
|
### Bootstrap Hooks
|
||||||
|
|
||||||
@@ -150,6 +166,15 @@ the second is the condition name and hook script path.
|
|||||||
* `HOOK_SHUTDOWN`, `hook/sys/shutdown`: Called at shutdown/reboot, right
|
* `HOOK_SHUTDOWN`, `hook/sys/shutdown`: Called at shutdown/reboot, right
|
||||||
before all services are sent `SIGTERM`
|
before all services are sent `SIGTERM`
|
||||||
|
|
||||||
|
* `HOOK_SVC_DN`, `hook/svc/down`: In shutdown/reboot, all services and
|
||||||
|
non-reserved processes have been killed. **Note:** only hook scripts
|
||||||
|
can run here!
|
||||||
|
|
||||||
|
* `HOOK_SYSTEM_DN`, `hook/sys/down`: In shutdown/reboot, called after
|
||||||
|
all non-reserved file systems have been unmounted, just before Finit
|
||||||
|
tells the kernel to reboot or shut down. **Note:** only hook scripts
|
||||||
|
can run here!
|
||||||
|
|
||||||
Plugins like `tty.so` extend finit by acting on events, they are called
|
Plugins like `tty.so` extend finit by acting on events, they are called
|
||||||
I/O plugins and are called from the finit main loop when `poll()`
|
I/O plugins and are called from the finit main loop when `poll()`
|
||||||
detects an event. See the source code for `plugins/*.c` for more help
|
detects an event. See the source code for `plugins/*.c` for more help
|
||||||
|
|||||||
+11
-10
@@ -26,18 +26,11 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#define CHOOSE(x, y) y
|
extern void plugin_script_run(hook_point_t no);
|
||||||
static const char *hscript_paths[] = HOOK_TYPES;
|
|
||||||
#undef CHOOSE
|
|
||||||
|
|
||||||
static void hscript_run_parts(hook_point_t hook)
|
static void hscript_run_parts(hook_point_t no)
|
||||||
{
|
{
|
||||||
char path[CMD_SIZE] = "";
|
plugin_script_run(no);
|
||||||
|
|
||||||
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
|
|
||||||
strlcat(path, hscript_paths[hook] + 4, sizeof(path));
|
|
||||||
|
|
||||||
run_parts(path, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hscript_banner(void *arg)
|
static void hscript_banner(void *arg)
|
||||||
@@ -96,6 +89,14 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
|
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
|
||||||
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
|
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
|
||||||
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
|
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
|
||||||
|
/*
|
||||||
|
* We have exited here, so these are handled a bit differently by Finit,
|
||||||
|
* when hook scripts are enabled, just to provide the user with the same
|
||||||
|
* interface:
|
||||||
|
*
|
||||||
|
* .hook[HOOK_SVC_DN] = { .cb = hscript_svc_down },
|
||||||
|
* .hook[HOOK_SYS_DN] = { .cb = hscript_system_down },
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -195,11 +195,40 @@ int plugin_exists(hook_point_t no)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_HOOK_SCRIPTS_PLUGIN
|
||||||
|
#define CHOOSE(x, y) y
|
||||||
|
static const char *hscript_paths[] = HOOK_TYPES;
|
||||||
|
#undef CHOOSE
|
||||||
|
|
||||||
|
void plugin_script_run(hook_point_t no)
|
||||||
|
{
|
||||||
|
char path[CMD_SIZE] = "";
|
||||||
|
|
||||||
|
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
|
||||||
|
strlcat(path, hscript_paths[no] + 4, sizeof(path));
|
||||||
|
|
||||||
|
run_parts(path, NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void plugin_script_run(hook_point_t no)
|
||||||
|
{
|
||||||
|
(void)no;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Some hooks are called with a fixed argument */
|
/* Some hooks are called with a fixed argument */
|
||||||
void plugin_run_hook(hook_point_t no, void *arg)
|
void plugin_run_hook(hook_point_t no, void *arg)
|
||||||
{
|
{
|
||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
|
if (!cond_is_available()) {
|
||||||
|
#ifdef HAVE_HOOK_SCRIPTS_PLUGIN
|
||||||
|
warnx("conditions not available, calling script script based hooks only!");
|
||||||
|
plugin_script_run(no);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (p->hook[no].cb) {
|
if (p->hook[no].cb) {
|
||||||
dbg("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg ?: "NIL");
|
dbg("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg ?: "NIL");
|
||||||
|
|||||||
@@ -82,6 +82,8 @@
|
|||||||
\
|
\
|
||||||
/* Shutdown hooks, runlevel [06] */ \
|
/* Shutdown hooks, runlevel [06] */ \
|
||||||
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
||||||
|
CHOOSE(HOOK_SVC_DN, "hook/svc/down"), \
|
||||||
|
CHOOSE(HOOK_SYS_DN, "hook/sys/down"), \
|
||||||
CHOOSE(HOOK_MAX_NUM, "nop") \
|
CHOOSE(HOOK_MAX_NUM, "nop") \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -329,6 +329,9 @@ void do_shutdown(shutop_t op)
|
|||||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* All services and (non-critical) processes have stopped. */
|
||||||
|
plugin_run_hooks(HOOK_SVC_DN);
|
||||||
|
|
||||||
if (in_cont) {
|
if (in_cont) {
|
||||||
if (osheading)
|
if (osheading)
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "%s, shutting down container.", osheading);
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s, shutting down container.", osheading);
|
||||||
@@ -374,6 +377,9 @@ void do_shutdown(shutop_t op)
|
|||||||
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||||
mdadm_wait();
|
mdadm_wait();
|
||||||
|
|
||||||
|
/* Last chance to run scripts (all .so plugins have exited already) */
|
||||||
|
plugin_run_hooks(HOOK_SYS_DN);
|
||||||
|
|
||||||
/* Reboot via watchdog or kernel, or shutdown? */
|
/* Reboot via watchdog or kernel, or shutdown? */
|
||||||
if (op == SHUT_REBOOT) {
|
if (op == SHUT_REBOOT) {
|
||||||
if (wdog && wdog->pid > 1) {
|
if (wdog && wdog->pid > 1) {
|
||||||
|
|||||||
Reference in new issue
Block a user