/* * Copyright (C) 2013 Felix Fietkau * Copyright (C) 2013 John Crispin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(WITH_SELINUX) #include #include #include #endif #include "../utils/utils.h" #include "init.h" #include "../watchdog.h" unsigned int debug = 0; static void signal_shutdown(int signal, siginfo_t *siginfo, void *data) { fprintf(stderr, "reboot\n"); fflush(stderr); sync(); sleep(2); reboot(RB_AUTOBOOT); while (1) ; } static struct sigaction sa_shutdown = { .sa_sigaction = signal_shutdown, .sa_flags = SA_SIGINFO }; static void cmdline(void) { char line[20]; char* res; long r; res = get_cmdline_val("init_debug", line, sizeof(line)); if (res != NULL) { r = strtol(line, NULL, 10); if ((r != LONG_MIN) && (r != LONG_MAX)) debug = (int) r; } } #if defined(WITH_SELINUX) static int selinux(char **argv) { int ret; int enforce = selinux_status_getenforce(); /* is SELinux already initialized? */ if (getenv("SELINUX_INIT")) { /* have initramfs permissions already been restored? */ if (!getenv("INITRAMFS") || getenv("SELINUX_RESTORECON")) { unsetenv("SELINUX_INIT"); unsetenv("SELINUX_RESTORECON"); return 0; } /* Second call (initramfs only): restore filesystem labels */ const char *exclude_list[] = { "/dev/console", "/proc", "/sys", 0 }; selinux_restorecon_set_exclude_list(exclude_list); ret = selinux_restorecon("/", SELINUX_RESTORECON_RECURSE | SELINUX_RESTORECON_MASS_RELABEL); putenv("SELINUX_RESTORECON=1"); } else { /* First call: load policy */ ret = selinux_init_load_policy(&enforce); putenv("SELINUX_INIT=1"); } if (ret == 0) execv(argv[0], argv); if (enforce > 0) { fprintf(stderr, "Cannot load SELinux policy, but system in enforcing mode. Halting.\n"); return 1; } return 0; } #else static int selinux(char **argv) { return 0; } #endif int main(int argc, char **argv) { pid_t pid; ulog_open(ULOG_KMSG, LOG_DAEMON, "init"); sigaction(SIGTERM, &sa_shutdown, NULL); sigaction(SIGUSR1, &sa_shutdown, NULL); sigaction(SIGUSR2, &sa_shutdown, NULL); sigaction(SIGPWR, &sa_shutdown, NULL); if (selinux(argv)) exit(-1); early(); cmdline(); watchdog_init(1); pid = fork(); if (!pid) { char *kmod[] = { "/sbin/kmodloader", "/etc/modules-boot.d/", NULL }; if (debug < 3) patch_stdio("/dev/null"); execvp(kmod[0], kmod); ERROR("Failed to start kmodloader: %m\n"); exit(EXIT_FAILURE); } if (pid <= 0) { ERROR("Failed to start kmodloader instance: %m\n"); } else { const struct timespec req = {0, 10 * 1000 * 1000}; int i; for (i = 0; i < 1200; i++) { if (waitpid(pid, NULL, WNOHANG) > 0) break; nanosleep(&req, NULL); watchdog_ping(); } } uloop_init(); preinit(); uloop_run(); return 0; }