X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fmain.c;h=4e800e7430224f0a0219b1dd88fcea2e49cbc980;hb=e5f3d1ba124f14477d6b5434982d7d44a472a66f;hp=7ae88414a93a74ed7c09791c86646a7c02c8bd25;hpb=816115863962548a9a0d9fbfe429c7f8e685beac;p=elogind.git diff --git a/src/main.c b/src/main.c index 7ae88414a..4e800e743 100644 --- a/src/main.c +++ b/src/main.c @@ -54,6 +54,7 @@ #include "strv.h" #include "def.h" #include "virt.h" +#include "watchdog.h" static enum { ACTION_RUN, @@ -80,6 +81,8 @@ static char **arg_default_controllers = NULL; static char ***arg_join_controllers = NULL; static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL; static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; +static usec_t arg_runtime_watchdog = 0; +static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE; static FILE* serialization = NULL; @@ -660,6 +663,8 @@ static int parse_config_file(void) { { "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output }, { "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error }, { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, + { "Manager", "RuntimeWatchdogSec", config_parse_usec, 0, &arg_runtime_watchdog }, + { "Manager", "ShutdownWatchdogSec", config_parse_usec, 0, &arg_shutdown_watchdog }, { NULL, NULL, NULL, 0, NULL } }; @@ -1092,7 +1097,8 @@ static struct dual_timestamp* parse_initrd_timestamp(struct dual_timestamp *t) { assert(t); - if (!(e = getenv("RD_TIMESTAMP"))) + e = getenv("RD_TIMESTAMP"); + if (!e) return NULL; if (sscanf(e, "%llu %llu", &a, &b) != 2) @@ -1145,7 +1151,8 @@ static void test_cgroups(void) { "Systems without control groups are not supported. " "We will now sleep for 10s, and then continue boot-up. " "Expect breakage and please do not file bugs. " - "Instead fix your kernel and enable CONFIG_CGROUPS." ); + "Instead fix your kernel and enable CONFIG_CGROUPS. " + "Consult http://0pointer.de/blog/projects/cgroups-vs-cgroups.html for more information."); sleep(10); } @@ -1163,6 +1170,7 @@ int main(int argc, char *argv[]) { bool is_reexec = false; int j; bool loaded_policy = false; + bool arm_reboot_watchdog = false; #ifdef HAVE_SYSV_COMPAT if (getpid() != 1 && strstr(program_invocation_short_name, "init")) { @@ -1305,7 +1313,8 @@ int main(int argc, char *argv[]) { /* Remember open file descriptors for later deserialization */ if (serialization) { - if ((r = fdset_new_fill(&fds)) < 0) { + r = fdset_new_fill(&fds); + if (r < 0) { log_error("Failed to allocate fd set: %s", strerror(-r)); goto finish; } @@ -1324,15 +1333,22 @@ int main(int argc, char *argv[]) { arg_running_as == MANAGER_SYSTEM); if (arg_running_as == MANAGER_SYSTEM) { - /* Parse the data passed to us by the initrd and unset it */ + /* Parse the data passed to us. We leave this + * variables set, but the manager later on will not + * pass them on to our children. */ parse_initrd_timestamp(&initrd_timestamp); - filter_environ("RD_"); /* Unset some environment variables passed in from the * kernel that don't really make sense for us. */ unsetenv("HOME"); unsetenv("TERM"); + /* When we are invoked by a shell, these might be set, + * but make little sense to pass on */ + unsetenv("PWD"); + unsetenv("SHLVL"); + unsetenv("_"); + /* All other variables are left as is, so that clients * can still read them via /proc/1/environ */ } @@ -1391,7 +1407,11 @@ int main(int argc, char *argv[]) { test_cgroups(); } - if ((r = manager_new(arg_running_as, &m)) < 0) { + if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0) + watchdog_set_timeout(&arg_runtime_watchdog); + + r = manager_new(arg_running_as, &m); + if (r < 0) { log_error("Failed to allocate manager object: %s", strerror(-r)); goto finish; } @@ -1404,6 +1424,8 @@ int main(int argc, char *argv[]) { m->swap_auto = arg_swap_auto; m->default_std_output = arg_default_std_output; m->default_std_error = arg_default_std_error; + m->runtime_watchdog = arg_runtime_watchdog; + m->shutdown_watchdog = arg_shutdown_watchdog; if (dual_timestamp_is_set(&initrd_timestamp)) m->initrd_timestamp = initrd_timestamp; @@ -1415,7 +1437,8 @@ int main(int argc, char *argv[]) { before_startup = now(CLOCK_MONOTONIC); - if ((r = manager_startup(m, serialization, fds)) < 0) + r = manager_startup(m, serialization, fds); + if (r < 0) log_error("Failed to fully start up daemon: %s", strerror(-r)); if (fds) { @@ -1438,7 +1461,8 @@ int main(int argc, char *argv[]) { log_debug("Activating default unit: %s", arg_default_unit); - if ((r = manager_load_unit(m, arg_default_unit, NULL, &error, &target)) < 0) { + r = manager_load_unit(m, arg_default_unit, NULL, &error, &target); + if (r < 0) { log_error("Failed to load default target: %s", bus_error(&error, r)); dbus_error_free(&error); } else if (target->load_state == UNIT_ERROR) @@ -1449,7 +1473,8 @@ int main(int argc, char *argv[]) { if (!target || target->load_state != UNIT_LOADED) { log_info("Trying to load rescue target..."); - if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target)) < 0) { + r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target); + if (r < 0) { log_error("Failed to load rescue target: %s", bus_error(&error, r)); dbus_error_free(&error); goto finish; @@ -1491,7 +1516,8 @@ int main(int argc, char *argv[]) { } for (;;) { - if ((r = manager_loop(m)) < 0) { + r = manager_loop(m); + if (r < 0) { log_error("Failed to run mainloop: %s", strerror(-r)); goto finish; } @@ -1505,7 +1531,8 @@ int main(int argc, char *argv[]) { case MANAGER_RELOAD: log_info("Reloading."); - if ((r = manager_reload(m)) < 0) + r = manager_reload(m); + if (r < 0) log_error("Failed to reload: %s", strerror(-r)); break; @@ -1529,6 +1556,7 @@ int main(int argc, char *argv[]) { }; assert_se(shutdown_verb = table[m->exit_code]); + arm_reboot_watchdog = m->exit_code == MANAGER_REBOOT; log_notice("Shutting down."); goto finish; @@ -1603,6 +1631,11 @@ finish: assert(i <= ELEMENTSOF(args)); + /* Close and disarm the watchdog, so that the new + * instance can reinitialize it, but doesn't get + * rebooted while we do that */ + watchdog_close(true); + execv(args[0], (char* const*) args); log_error("Failed to reexecute: %m"); @@ -1615,13 +1648,33 @@ finish: fdset_free(fds); if (shutdown_verb) { + char e[32]; + const char * command_line[] = { SYSTEMD_SHUTDOWN_BINARY_PATH, shutdown_verb, NULL }; + const char * env_block[] = { + NULL, + NULL + }; - execv(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line); + if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) { + /* If we reboot let's set the shutdown + * watchdog and tell the shutdown binary to + * repeatedly ping it */ + watchdog_set_timeout(&arg_shutdown_watchdog); + watchdog_close(false); + + /* Tell the binary how often to ping */ + snprintf(e, sizeof(e), "WATCHDOG_USEC=%llu", (unsigned long long) arg_shutdown_watchdog); + char_array_0(e); + env_block[0] = e; + } else + watchdog_close(true); + + execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, (char**) env_block); log_error("Failed to execute shutdown binary, freezing: %m"); }