aboutsummaryrefslogtreecommitdiff
path: root/src/rc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rc')
-rw-r--r--src/rc/Makefile5
-rw-r--r--src/rc/openrc-shutdown.c15
-rw-r--r--src/rc/rc-sysvinit.c66
-rw-r--r--src/rc/rc-sysvinit.h71
4 files changed, 149 insertions, 8 deletions
diff --git a/src/rc/Makefile b/src/rc/Makefile
index ea4a8c81..982e7af1 100644
--- a/src/rc/Makefile
+++ b/src/rc/Makefile
@@ -14,7 +14,8 @@ SRCS+= rc-selinux.c
endif
ifeq (${OS},Linux)
-SRCS+= kill_all.c openrc-init.c openrc-shutdown.c broadcast.c rc-wtmp.c
+SRCS+= kill_all.c openrc-init.c openrc-shutdown.c rc-sysvinit.c broadcast.c \
+ rc-wtmp.c
endif
CLEANFILES= version.h rc-selinux.o
@@ -134,7 +135,7 @@ mountinfo: mountinfo.o _usage.o rc-misc.o
openrc rc: rc.o rc-logger.o rc-misc.o rc-plugin.o _usage.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-openrc-shutdown: openrc-shutdown.o rc-misc.o _usage.o broadcast.o rc-wtmp.o
+openrc-shutdown: openrc-shutdown.o rc-misc.o _usage.o broadcast.o rc-wtmp.o rc-sysvinit.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o
diff --git a/src/rc/openrc-shutdown.c b/src/rc/openrc-shutdown.c
index 82dde517..4dcd7e16 100644
--- a/src/rc/openrc-shutdown.c
+++ b/src/rc/openrc-shutdown.c
@@ -35,8 +35,9 @@
#include "rc.h"
#include "helpers.h"
#include "rc-misc.h"
-#include "_usage.h"
+#include "rc-sysvinit.h"
#include "rc-wtmp.h"
+#include "_usage.h"
const char *applet = NULL;
const char *extraopts = NULL;
@@ -328,15 +329,17 @@ int main(int argc, char **argv)
syslog(LOG_NOTICE, "The system will %s now", state);
unlink(nologin_file);
unlink(shutdown_pid);
- if (do_halt)
+ if (do_halt) {
+ sysvinit_runlevel('0');
send_cmd("halt");
- else if (do_kexec)
+ } else if (do_kexec)
send_cmd("kexec");
else if (do_poweroff)
send_cmd("poweroff");
- else if (do_reboot)
- send_cmd("reboot");
- else if (do_single)
+ else if (do_reboot) {
+ sysvinit_runlevel('6');
+ send_cmd("reboot");
+ } else if (do_single)
send_cmd("single");
return 0;
}
diff --git a/src/rc/rc-sysvinit.c b/src/rc/rc-sysvinit.c
new file mode 100644
index 00000000..d9d17146
--- /dev/null
+++ b/src/rc/rc-sysvinit.c
@@ -0,0 +1,66 @@
+/*
+ * rc-sysvinit.c
+ * Helper to send a runlevel change to sysvinit
+ */
+
+/*
+ * Copyright (c) 2019 The OpenRC Authors.
+ * See the Authors file at the top-level directory of this distribution and
+ * https://github.com/OpenRC/openrc/blob/master/AUTHORS
+ *
+ * This file is part of OpenRC. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "einfo.h"
+#include "rc-sysvinit.h"
+
+void sysvinit_runlevel(char rl)
+{
+ 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);
+ do {
+ r = write(fd, p, bytes);
+ if (r < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ eerror("Failed to write to /run/initctl: %s", strerror(errno));
+ return;
+ }
+ p += r;
+ bytes -= r;
+ } while (bytes > 0);
+ exit(0);
+}
diff --git a/src/rc/rc-sysvinit.h b/src/rc/rc-sysvinit.h
new file mode 100644
index 00000000..55bc434d
--- /dev/null
+++ b/src/rc/rc-sysvinit.h
@@ -0,0 +1,71 @@
+/*
+ * rc-sysvinit.h - Interface to communicate with sysvinit via /run/initctl.
+ */
+
+/*
+ * Copyright (c) 2019 The OpenRC Authors.
+ * See the Authors file at the top-level directory of this distribution and
+ * https://github.com/OpenRC/openrc/blob/master/AUTHORS
+ *
+ * This file is part of OpenRC. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file.
+ */
+
+#ifndef _RC_SYSVINIT_H
+#define _RC_SYSVINIT_H
+
+/*
+ * The #defines and structures below are taken from initreq.h in
+ * sysvinit and must be used by any program wishing to communicate with
+ * it.
+ */
+
+#define INIT_MAGIC 0x03091969
+#define INIT_CMD_START 0
+#define INIT_CMD_RUNLVL 1
+#define INIT_CMD_POWERFAIL 2
+#define INIT_CMD_POWERFAILNOW 3
+#define INIT_CMD_POWEROK 4
+#define INIT_CMD_BSD 5
+#define INIT_CMD_SETENV 6
+#define INIT_CMD_UNSETENV 7
+
+/*
+ * This is what BSD 4.4 uses when talking to init.
+ * Linux doesn't use this right now.
+ */
+struct init_request_bsd {
+ char gen_id[8]; /* Beats me.. telnetd uses "fe" */
+ char tty_id[16]; /* Tty name minus /dev/tty */
+ char host[64]; /* Hostname */
+ char term_type[16]; /* Terminal type */
+ int signal; /* Signal to send */
+ int pid; /* Process to send to */
+ char exec_name[128]; /* Program to execute */
+ char reserved[128]; /* For future expansion. */
+};
+
+/*
+ * Because of legacy interfaces, "runlevel" and "sleeptime"
+ * aren't in a seperate struct in the union.
+ *
+ * The weird sizes are because init expects the whole
+ * struct to be 384 bytes.
+ */
+struct init_request {
+ int magic; /* Magic number */
+ int cmd; /* What kind of request */
+ int runlevel; /* Runlevel to change to */
+ int sleeptime; /* Time between TERM and KILL */
+ union {
+ struct init_request_bsd bsd;
+ char data[368];
+ } i;
+};
+
+void sysvinit_runlevel(char rl);
+
+#endif