diff --git a/src/api.c b/src/api.c index f3bc15c7..e1365c22 100644 --- a/src/api.c +++ b/src/api.c @@ -182,6 +182,49 @@ static svc_t *do_find_byc(char *buf, size_t len) return NULL; } +static int do_reboot(int cmd, char *buf, size_t len) +{ + int rc = 1; + + switch (cmd) { + case INIT_CMD_REBOOT: + _d("reboot"); + halt = SHUT_REBOOT; + service_runlevel(6); + break; + + case INIT_CMD_HALT: + _d("halt"); + halt = SHUT_HALT; + service_runlevel(0); + break; + + case INIT_CMD_POWEROFF: + _d("poweroff"); + halt = SHUT_OFF; + service_runlevel(0); + break; + + case INIT_CMD_SUSPEND: + _d("suspend"); + sync(); + rc = reboot(RB_SW_SUSPEND); + if (rc) { + if (errno == EINVAL) + snprintf(buf, len, "Kernel does not support suspend."); + else + snprintf(buf, len, "Failed: %s", strerror(errno)); + } + break; + + default: + rc = 255; + break; + } + + return rc; +} + typedef struct { char *event; void (*cb)(void); @@ -302,6 +345,13 @@ static void api_cb(uev_t *w, void *arg, int events) rq.sleeptime = prevlevel; break; + case INIT_CMD_REBOOT: + case INIT_CMD_HALT: + case INIT_CMD_POWEROFF: + case INIT_CMD_SUSPEND: + result = do_reboot(rq.cmd, rq.data, sizeof(rq.data)); + break; + case INIT_CMD_ACK: _d("Client failed reading ACK"); goto leave; diff --git a/src/finit.h b/src/finit.h index bb9b8686..7a29eb9e 100644 --- a/src/finit.h +++ b/src/finit.h @@ -74,6 +74,10 @@ #define INIT_CMD_UNUSED2 14 /* Unused, was INIT_CMD_QUERY_INETD */ #define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */ #define INIT_CMD_GET_RUNLEVEL 16 +#define INIT_CMD_REBOOT 20 +#define INIT_CMD_HALT 21 +#define INIT_CMD_POWEROFF 22 +#define INIT_CMD_SUSPEND 23 #define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */ #define INIT_CMD_SVC_ITER 129 #define INIT_CMD_SVC_QUERY 130 diff --git a/src/reboot.c b/src/reboot.c index aac059ba..340471d4 100644 --- a/src/reboot.c +++ b/src/reboot.c @@ -27,13 +27,8 @@ #include #include #include -#include #include "util.h" -#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */ -#define RB_SW_SUSPEND 0xd000fce2 -#endif - typedef enum { CMD_UNKNOWN = -1, CMD_REBOOT = 0, diff --git a/src/util.h b/src/util.h index eb7aaa34..e65cd8c2 100644 --- a/src/util.h +++ b/src/util.h @@ -28,9 +28,14 @@ #ifdef HAVE_TERMIOS_H /* for screen_width() */ #include #include +#include #include #endif +#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */ +#define RB_SW_SUSPEND 0xd000fce2 +#endif + extern int screen_rows; extern int screen_cols; extern char *prognm;