diff options
Diffstat (limited to 'src/rc/openrc-init.c')
-rw-r--r-- | src/rc/openrc-init.c | 168 |
1 files changed, 168 insertions, 0 deletions
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; +} |