diff --git a/src/api.c b/src/api.c index 66fb9b9f..43d6e014 100644 --- a/src/api.c +++ b/src/api.c @@ -45,8 +45,9 @@ #include "log.h" #include "plugin.h" #include "private.h" -#include "sig.h" +#include "schedule.h" #include "service.h" +#include "sig.h" #include "util.h" extern svc_t *wdog; @@ -227,10 +228,44 @@ static svc_t *do_find_byc(char *buf, size_t len) return NULL; } -static int do_reboot(int cmd, char *buf, size_t len) +static void bypass_shutdown(void *); +struct wq emergency = { .cb = bypass_shutdown }; + +static void bypass_shutdown(void *unused) +{ + cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n"); + do_shutdown(halt); +} + +static int do_reboot(int cmd, int timeout, char *buf, size_t len) { int rc = 1; + switch (cmd) { + case INIT_CMD_REBOOT: + halt = SHUT_REBOOT; + break; + + case INIT_CMD_HALT: + halt = SHUT_HALT; + break; + + case INIT_CMD_POWEROFF: + halt = SHUT_OFF; + break; + + case INIT_CMD_SUSPEND: + break; + + default: + return 255; + } + + if (timeout > 0) { + emergency.delay = timeout * 1000; + schedule_work(&emergency); + } + switch (cmd) { case INIT_CMD_REBOOT: _d("reboot"); @@ -263,7 +298,7 @@ static int do_reboot(int cmd, char *buf, size_t len) break; default: - rc = 255; + /* Handled previously */ break; } @@ -404,7 +439,7 @@ static void api_cb(uev_t *w, void *arg, int events) case INIT_CMD_HALT: case INIT_CMD_POWEROFF: case INIT_CMD_SUSPEND: - result = do_reboot(rq.cmd, rq.data, sizeof(rq.data)); + result = do_reboot(rq.cmd, rq.sleeptime, rq.data, sizeof(rq.data)); break; case INIT_CMD_ACK: diff --git a/src/initctl.c b/src/initctl.c index f830278b..890e99b5 100644 --- a/src/initctl.c +++ b/src/initctl.c @@ -64,6 +64,7 @@ int verbose = 0; int plain = 0; int quiet = 0; int runlevel = 0; +int timeout = 0; int cgrp = 0; int utmp = 0; @@ -513,8 +514,9 @@ static int do_cond_show(char *arg) static int do_cmd(int cmd) { struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = cmd, + .magic = INIT_MAGIC, + .cmd = cmd, + .sleeptime = timeout, }; if (client_send(&rq, sizeof(rq))) { diff --git a/src/reboot.c b/src/reboot.c index 05aeb1c5..7258b79b 100644 --- a/src/reboot.c +++ b/src/reboot.c @@ -43,6 +43,8 @@ static cmd_t cmd = CMD_UNKNOWN; static char *msg = NULL; /* initctl API */ +extern int timeout; + extern int do_reboot (char *arg); extern int do_halt (char *arg); extern int do_poweroff(char *arg); @@ -103,12 +105,13 @@ static int usage(int rc) { fprintf(stderr, "Usage: %s [OPTIONS]\n\n" "Options:\n" - " -?, --help This help text\n" - " -f, --force Force unsafe %s now, do not contact the init system.\n" - " --halt Halt system, regardless of how the command is called.\n" - " -h Halt or power off after shutdown.\n" - " -P, --poweroff Power-off system, regardless of how the command is called.\n" - " -r, --reboot Reboot system, regardless of how the command is called.\n" + " -?, --help This help text\n" + " -f, --force Force unsafe %s now, do not contact the init system.\n" + " --halt Halt system, regardless of how the command is called.\n" + " -h Halt or power off after shutdown.\n" + " -P, --poweroff Power-off system, regardless of how the command is called.\n" + " -r, --reboot Reboot system, regardless of how the command is called.\n" + " -t, --timeout=SEC Force reboot/shutdown after a given timeout\n" "\n", prognm, msg); return rc; @@ -122,14 +125,16 @@ int reboot_main(int argc, char *argv[]) {"halt", 0, NULL, 'H'}, {"poweroff", 0, NULL, 'p'}, {"reboot", 0, NULL, 'r'}, + {"timeout", 1, NULL, 't'}, {NULL, 0, NULL, 0} }; int c, force = 0; + int tmp; /* Initial command taken from program name */ transform(prognm); - while ((c = getopt_long(argc, argv, "h?fHPpr", long_options, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "h?fHPprt:", long_options, NULL)) != EOF) { switch(c) { case '?': return usage(0); @@ -152,6 +157,13 @@ int reboot_main(int argc, char *argv[]) cmd = CMD_REBOOT; break; + case 't': + tmp = atoi(optarg); + if (tmp < 1) + errx(1, "Invalid forced timeout value."); + timeout = tmp; + break; + default: return usage(1); }