From 6cb3d86cd1b6f7363da668ea78eae4b7bd483cdb Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 23 Oct 2016 23:02:38 +0200 Subject: [PATCH] Add support for registering a watchdog daemon This patch adds initial support for registering a watchdog daemon with Finit. Needed for situations when you want the system to actually be rebooted by the watchdog timer (WDT) circuitry rather than the kernel. The initctl API has been extended with a INIT_CMD_WDOG_HELLO command that is used to both register and "ping" Finit periodically. As long as Finit responds (with an ACK) the watchdog daemon knows Finit is alive. At shutdown Finit stops all services (except kernel threads and daemons marked with @ in the first character of their process name) and, if a watchdog has registered, SIGPWR is sent to it when Finit has finished unmounting etc., just prior to kernel reboot/halt/poweroff. Signed-off-by: Joachim Nilsson --- api.c | 13 +++++++++++++ finit.c | 1 + finit.h | 2 ++ sig.c | 9 +++++++++ 4 files changed, 25 insertions(+) diff --git a/api.c b/api.c index 129e50db..2f16ad51 100644 --- a/api.c +++ b/api.c @@ -323,6 +323,19 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events)) _d("Client failed reading ACK"); goto leave; + case INIT_CMD_WDOG_HELLO: + if (rq.runlevel <= 0) { + result = 1; + break; + } + + if (wdogpid > 0 && wdogpid != rq.runlevel) { + kill(wdogpid, SIGTERM); + do_sleep(1); + } + wdogpid = rq.runlevel; + break; + default: _d("Unsupported cmd: %d", rq.cmd); break; diff --git a/finit.c b/finit.c index c97d2009..1facf826 100644 --- a/finit.c +++ b/finit.c @@ -50,6 +50,7 @@ int debug = 0; int quiet = QUIET_MODE; /* Delayed disable of silent mode. */ int silent = SILENT_MODE; /* Completely silent, including boot */ +int wdogpid = 0; /* No watchdog by default */ int runlevel = 0; /* Bootstrap 'S' */ int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */ int prevlevel = -1; diff --git a/finit.h b/finit.h index 71b8fa23..285da21c 100644 --- a/finit.h +++ b/finit.h @@ -67,6 +67,7 @@ #define INIT_CMD_QUERY_INETD 14 #define INIT_CMD_EMIT 15 #define INIT_CMD_GET_RUNLEVEL 16 +#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */ #define INIT_CMD_NACK 254 #define INIT_CMD_ACK 255 @@ -81,6 +82,7 @@ struct init_request { extern int debug; extern int quiet; extern int silent; +extern int wdogpid; extern int runlevel; extern int cfglevel; extern int prevlevel; diff --git a/sig.c b/sig.c index dd0f9aa7..e552c71f 100644 --- a/sig.c +++ b/sig.c @@ -194,6 +194,15 @@ void do_shutdown(shutop_t op) /* Call mdadm to mark any RAID array(s) as clean before halting. */ mdadm_wait(); + /* Wait here until the WDT reboots, or timeout */ + if (wdogpid) { + int timeout = 10; + + print(kill(wdogpid, SIGPWR) == 1, "Pending watchdog reboot"); + while (timeout--) + do_sleep(1); + } + _d("%s", op == SHUT_REBOOT ? "Rebooting" : "Halting"); if (op == SHUT_REBOOT) reboot(RB_AUTOBOOT);