/* * openrc-init.c * This is the init process (pid 1) for OpenRC. * * This is based on code written by James Hammons , so * I would like to publically thank him for his work. */ /* * 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 #include #include #include #include #include #include #include #include #include #include #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_reexec(char *my_name) { execl(my_name, my_name, "reexec", NULL); return; } 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; char buf[2048]; int count; FILE *fifo; bool reexec = false; struct sigaction sa; if (getpid() != 1) return 1; if (argc > 1) default_runlevel = argv[1]; else default_runlevel = NULL; if (default_runlevel && strcmp(default_runlevel, "reexec") == 0) reexec = true; printf("OpenRC init version %s starting\n", VERSION); if (! reexec) 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 && errno != EEXIST) 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); else if (strcmp(buf, "reexec") == 0) handle_reexec(argv[0]); } return 0; }