diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/librc/rc.h.in | 1 | ||||
-rw-r--r-- | src/rc/.gitignore | 2 | ||||
-rw-r--r-- | src/rc/Makefile | 21 | ||||
-rw-r--r-- | src/rc/openrc-init.c | 168 | ||||
-rw-r--r-- | src/rc/openrc-shutdown.c | 119 |
5 files changed, 309 insertions, 2 deletions
diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in index 92ecbb4e..1f984d52 100644 --- a/src/librc/rc.h.in +++ b/src/librc/rc.h.in @@ -39,6 +39,7 @@ extern "C" { #define RC_CONFDIR RC_SYSCONFDIR "/conf.d" #define RC_PLUGINDIR RC_LIBDIR "/plugins" +#define RC_INIT_FIFO RC_SVCDIR"/init.ctl" #define RC_PROFILE_ENV RC_SYSCONFDIR "/profile.env" #define RC_SYS_WHITELIST RC_LIBEXECDIR "/conf.d/env_whitelist" #define RC_USR_WHITELIST RC_SYSCONFDIR "/conf.d/env_whitelist" diff --git a/src/rc/.gitignore b/src/rc/.gitignore index c9779194..c3e7b3f6 100644 --- a/src/rc/.gitignore +++ b/src/rc/.gitignore @@ -59,4 +59,6 @@ mark_service_failed rc-abort rc openrc +openrc-init openrc-run +openrc-shutdown diff --git a/src/rc/Makefile b/src/rc/Makefile index 74d74a08..2bc03f76 100644 --- a/src/rc/Makefile +++ b/src/rc/Makefile @@ -1,3 +1,7 @@ +include ../../Makefile.inc +MK= ../../mk +include ${MK}/os.mk + SRCS= checkpath.c do_e.c do_mark_service.c do_service.c \ do_value.c fstabinfo.c is_newer_than.c is_older_than.c \ mountinfo.c openrc-run.c rc-abort.c rc.c \ @@ -9,6 +13,10 @@ ifeq (${MKSELINUX},yes) SRCS+= rc-selinux.c endif +ifeq (${OS},Linux) +SRCS+= openrc-init.c openrc-shutdown.c +endif + CLEANFILES= version.h rc-selinux.o BINDIR= ${PREFIX}/bin @@ -34,6 +42,11 @@ RC_SBINPROGS= mark_service_starting mark_service_started \ mark_service_inactive mark_service_wasinactive \ mark_service_hotplugged mark_service_failed \ rc-abort swclock + +ifeq (${OS},Linux) +SBINPROGS+= openrc-init openrc-shutdown +endif + ALL_PROGS= ${BINPROGS} ${SBINPROGS} ${RC_BINPROGS} ${RC_SBINPROGS} CLEANFILES+= ${ALL_PROGS} @@ -41,8 +54,6 @@ LOCAL_CPPFLAGS=-I../includes -I../librc -I../libeinfo LOCAL_LDFLAGS=-L../librc -L../libeinfo LDADD+= -lutil -lrc -leinfo -include ../../Makefile.inc -MK= ../../mk include ${MK}/prog.mk include ${MK}/gitver.mk include ${MK}/cc.mk @@ -96,6 +107,9 @@ veinfo vewarn vebegin veend vewend veindent veoutdent: do_e.o rc-misc.o fstabinfo: fstabinfo.o _usage.o rc-misc.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} +openrc-init: openrc-init.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + is_newer_than: is_newer_than.o rc-misc.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} @@ -114,6 +128,9 @@ 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 _usage.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o ifeq (${MKSELINUX},yes) openrc-run runscript: rc-selinux.o diff --git a/src/rc/openrc-init.c b/src/rc/openrc-init.c new file mode 100644 index 00000000..e7d62432 --- /dev/null +++ b/src/rc/openrc-init.c @@ -0,0 +1,168 @@ +/* + * openrc-init.c + * This is the init process (pid 1) for OpenRC. + */ + +/* + * Copyright (c) 2017 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 <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/reboot.h> +#include <sys/wait.h> + +#include "helpers.h" +#include "rc.h" +#include "version.h" + +static const char *rc_default_runlevel = "default"; + +static pid_t do_openrc(const char *runlevel) +{ + pid_t pid; + + pid = fork(); + switch(pid) { + case -1: + perror("fork"); + break; + case 0: + setsid(); + printf("Starting %s runlevel\n", runlevel); + execl("/sbin/openrc", "/sbin/openrc", runlevel, NULL); + perror("exec"); + break; + default: + break; + } + return pid; +} + +static void init(const char *default_runlevel) +{ + const char *runlevel = NULL; + pid_t pid; + + pid = do_openrc("sysinit"); + waitpid(pid, NULL, 0); + pid = do_openrc("boot"); + waitpid(pid, NULL, 0); + if (default_runlevel) + runlevel = default_runlevel; + else + runlevel = rc_conf_value("rc_default_runlevel"); + if (!runlevel) + runlevel = rc_default_runlevel; + if (!rc_runlevel_exists(runlevel)) { + printf("%s is an invalid runlevel\n", runlevel); + runlevel = rc_default_runlevel; + } + pid = do_openrc(runlevel); + waitpid(pid, NULL, 0); +} + +static void handle_shutdown(const char *runlevel, int cmd) +{ + pid_t pid; + + pid = do_openrc(runlevel); + while (waitpid(pid, NULL, 0) != pid); + sync(); + reboot(cmd); +} + +static void reap_zombies(void) +{ + pid_t pid; + + for (;;) { + pid = waitpid(-1, NULL, WNOHANG); + if (pid == 0) + break; + else if (pid == -1) { + if (errno == ECHILD) + break; + perror("waitpid"); + continue; + } + } +} + +static void signal_handler(int sig) +{ + switch(sig) { + case SIGINT: + handle_shutdown("reboot", RB_AUTOBOOT); + break; + case SIGCHLD: + reap_zombies(); + break; + default: + printf("Unknown signal received, %d\n", sig); + break; + } +} + +int main(int argc, char **argv) +{ + char *default_runlevel = NULL; + char buf[2048]; + int count; + FILE *fifo; + struct sigaction sa; + + if (getpid() != 1) + return 1; + + if (argc > 1) + default_runlevel = argv[1]; + + printf("OpenRC init version %s starting\n", VERSION); + init(default_runlevel); + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + reboot(RB_DISABLE_CAD); + + if (mkfifo(RC_INIT_FIFO, 0600) == -1) + perror("mkfifo"); + + for (;;) { + /* This will block until a command is sent down the pipe... */ + fifo = fopen(RC_INIT_FIFO, "r"); + if (!fifo) { + if (errno != EINTR) + perror("fopen"); + continue; + } + count = fread(buf, 1, 2048, fifo); + buf[count] = 0; + fclose(fifo); + printf("PID1: Received \"%s\" from FIFO...\n", buf); + if (strcmp(buf, "halt") == 0) + handle_shutdown("shutdown", RB_HALT_SYSTEM); + else if (strcmp(buf, "kexec") == 0) + handle_shutdown("reboot", RB_KEXEC); + else if (strcmp(buf, "poweroff") == 0) + handle_shutdown("shutdown", RB_POWER_OFF); + else if (strcmp(buf, "reboot") == 0) + handle_shutdown("reboot", RB_AUTOBOOT); + } + return 0; +} diff --git a/src/rc/openrc-shutdown.c b/src/rc/openrc-shutdown.c new file mode 100644 index 00000000..b68ffd36 --- /dev/null +++ b/src/rc/openrc-shutdown.c @@ -0,0 +1,119 @@ +/* + * openrc-shutdown.c + * If you are using OpenRC's provided init, this will shut down or + * reboot your system. + */ + +/* + * Copyright 2017 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 <getopt.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> + +#include "einfo.h" +#include "rc.h" +#include "helpers.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "kpr" getoptstring_COMMON; +const struct option longopts[] = { + { "halt", no_argument, NULL, 'H'}, + { "kexec", no_argument, NULL, 'k'}, + { "poweroff", no_argument, NULL, 'p'}, + { "reboot", no_argument, NULL, 'r'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "halt the system", + "reboot the system using kexec", + "power off the system", + "reboot the system", + longopts_help_COMMON +}; +const char *usagestring = NULL; +const char *exclusive = "Select one of --halt, --kexec, --poweroff or --reboot"; + +static void send_cmd(const char *cmd) +{ + FILE *fifo; + size_t ignored; + + fifo = fopen(RC_INIT_FIFO, "w"); + + if (!fifo) { + perror("fopen"); + return; + } + + ignored = fwrite(cmd, 1, strlen(cmd), fifo); + if (ignored != strlen(cmd)) + printf("Error writing to init fifo\n"); + fclose(fifo); +} + +int main(int argc, char **argv) +{ + int opt; + int cmd_count = 0; + bool do_halt = false; + bool do_kexec = false; + bool do_poweroff = false; + bool do_reboot = false; + + applet = basename_c(argv[0]); +if (geteuid() != 0) + eerrorx("%s: you must be root\n", applet); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'H': + do_halt = true; + cmd_count++; + break; + case 'k': + do_kexec = true; + cmd_count++; + break; + case 'p': + do_poweroff = true; + cmd_count++; + break; + case 'r': + do_reboot = true; + cmd_count++; + break; + case_RC_COMMON_GETOPT + } + } + if (cmd_count != 1) { + eerror("%s: %s\n", applet, exclusive); + usage(EXIT_FAILURE); + } + if (do_halt) + send_cmd("halt"); + else if (do_kexec) + send_cmd("kexec"); + else if (do_poweroff) + send_cmd("poweroff"); + else if (do_reboot) + send_cmd("reboot"); + return 0; +} |