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.
This commit is contained in:
William Hubbs 2019-08-15 12:02:30 -05:00
parent 92de9a693b
commit 0dabda6f6f
3 changed files with 72 additions and 22 deletions

View File

@ -330,16 +330,29 @@ int main(int argc, char **argv)
unlink(nologin_file); unlink(nologin_file);
unlink(shutdown_pid); unlink(shutdown_pid);
if (do_halt) { if (do_halt) {
sysvinit_runlevel('0'); if (exists("/run/initctl")) {
send_cmd("halt"); sysvinit_setenv("INIT_HALT", "HALT");
sysvinit_runlevel('0');
} else
send_cmd("halt");
} else if (do_kexec) } else if (do_kexec)
send_cmd("kexec"); send_cmd("kexec");
else if (do_poweroff) else if (do_poweroff) {
send_cmd("poweroff"); if (exists("/run/initctl")) {
else if (do_reboot) { sysvinit_setenv("INIT_HALT", "POWEROFF");
sysvinit_runlevel('6'); sysvinit_runlevel('0');
} else
send_cmd("poweroff");
} else if (do_reboot) {
if (exists("/run/initctl"))
sysvinit_runlevel('6');
else
send_cmd("reboot"); send_cmd("reboot");
} else if (do_single) } else if (do_single) {
send_cmd("single"); if (exists("/run/initctl"))
sysvinit_runlevel('S');
else
send_cmd("single");
}
return 0; return 0;
} }

View File

@ -26,31 +26,21 @@
#include "einfo.h" #include "einfo.h"
#include "rc-sysvinit.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; int fd;
char *p; char *p;
size_t bytes; size_t bytes;
ssize_t r; ssize_t r;
if (!rl)
return;
fd = open("/run/initctl", O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); fd = open("/run/initctl", O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
if (fd < 0) { if (fd < 0) {
if (errno != ENOENT) if (errno != ENOENT)
eerror("Failed to open initctl fifo: %s", strerror(errno)); eerror("Failed to open initctl fifo: %s", strerror(errno));
return; return;
} }
request = (struct init_request) { p = (char *) request;
.magic = INIT_MAGIC, bytes = sizeof(*request);
.sleeptime = 0,
.cmd = INIT_CMD_RUNLVL,
.runlevel = rl,
};
p = (char *) &request;
bytes = sizeof(request);
do { do {
r = write(fd, p, bytes); r = write(fd, p, bytes);
if (r < 0) { if (r < 0) {
@ -62,5 +52,51 @@ void sysvinit_runlevel(char rl)
p += r; p += r;
bytes -= r; bytes -= r;
} while (bytes > 0); } 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;
} }

View File

@ -67,5 +67,6 @@ struct init_request {
}; };
void sysvinit_runlevel(char rl); void sysvinit_runlevel(char rl);
void sysvinit_setenv(char *name, char *value);
#endif #endif