From 0dabda6f6ff3744c6f1b1d2afd57845554384977 Mon Sep 17 00:00:00 2001 From: William Hubbs Date: Thu, 15 Aug 2019 12:02:30 -0500 Subject: [PATCH] fix sysvinit compatibility This allows openrc to direct sysvinit to shut down the system by setting the INIT_HALT environment variable appropriately. Also, we do not try to communicate with sysvinit if its fifo does not exist. --- src/rc/openrc-shutdown.c | 29 +++++++++++++----- src/rc/rc-sysvinit.c | 64 +++++++++++++++++++++++++++++++--------- src/rc/rc-sysvinit.h | 1 + 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/rc/openrc-shutdown.c b/src/rc/openrc-shutdown.c index 4dcd7e16..ec240b2a 100644 --- a/src/rc/openrc-shutdown.c +++ b/src/rc/openrc-shutdown.c @@ -330,16 +330,29 @@ int main(int argc, char **argv) unlink(nologin_file); unlink(shutdown_pid); if (do_halt) { - sysvinit_runlevel('0'); - send_cmd("halt"); + if (exists("/run/initctl")) { + sysvinit_setenv("INIT_HALT", "HALT"); + sysvinit_runlevel('0'); + } else + send_cmd("halt"); } else if (do_kexec) send_cmd("kexec"); - else if (do_poweroff) - send_cmd("poweroff"); - else if (do_reboot) { - sysvinit_runlevel('6'); + else if (do_poweroff) { + if (exists("/run/initctl")) { + sysvinit_setenv("INIT_HALT", "POWEROFF"); + sysvinit_runlevel('0'); + } else + send_cmd("poweroff"); + } else if (do_reboot) { + if (exists("/run/initctl")) + sysvinit_runlevel('6'); + else send_cmd("reboot"); - } else if (do_single) - send_cmd("single"); + } else if (do_single) { + if (exists("/run/initctl")) + sysvinit_runlevel('S'); + else + send_cmd("single"); + } return 0; } diff --git a/src/rc/rc-sysvinit.c b/src/rc/rc-sysvinit.c index d9d17146..4ef074ca 100644 --- a/src/rc/rc-sysvinit.c +++ b/src/rc/rc-sysvinit.c @@ -26,31 +26,21 @@ #include "einfo.h" #include "rc-sysvinit.h" -void sysvinit_runlevel(char rl) +static void sysvinit_send_cmd(struct init_request *request) { - struct init_request request; int fd; char *p; size_t bytes; ssize_t r; - if (!rl) - return; - fd = open("/run/initctl", O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); if (fd < 0) { if (errno != ENOENT) eerror("Failed to open initctl fifo: %s", strerror(errno)); return; } - request = (struct init_request) { - .magic = INIT_MAGIC, - .sleeptime = 0, - .cmd = INIT_CMD_RUNLVL, - .runlevel = rl, - }; - p = (char *) &request; - bytes = sizeof(request); + p = (char *) request; + bytes = sizeof(*request); do { r = write(fd, p, bytes); if (r < 0) { @@ -62,5 +52,51 @@ void sysvinit_runlevel(char rl) p += r; bytes -= r; } while (bytes > 0); - exit(0); +} + +void sysvinit_runlevel(char rl) +{ + struct init_request request; + + if (!rl) + return; + + request = (struct init_request) { + .magic = INIT_MAGIC, + .sleeptime = 0, + .cmd = INIT_CMD_RUNLVL, + .runlevel = rl, + }; + sysvinit_send_cmd(&request); + return; +} + +/* + * Set environment variables in the init process. + */ +void sysvinit_setenv(char *name, char *value) +{ + struct init_request request; + size_t nl; + size_t vl; + + memset(&request, 0, sizeof(request)); + request.magic = INIT_MAGIC; + request.cmd = INIT_CMD_SETENV; + nl = strlen(name); + if (value) + vl = strlen(value); +else + vl = 0; + + if (nl + vl + 3 >= (int)sizeof(request.i.data)) + return -1; + + memcpy(request.i.data, name, nl); + if (value) { + request.i.data[nl] = '='; + memcpy(request.i.data + nl + 1, value, vl); + } + sysvinit_send_cmd(&request); + return 0; } diff --git a/src/rc/rc-sysvinit.h b/src/rc/rc-sysvinit.h index 55bc434d..754a8266 100644 --- a/src/rc/rc-sysvinit.h +++ b/src/rc/rc-sysvinit.h @@ -67,5 +67,6 @@ struct init_request { }; void sysvinit_runlevel(char rl); +void sysvinit_setenv(char *name, char *value); #endif