#include "kmod-setup.h"
#include "locale-setup.h"
#include "selinux-setup.h"
+#include "ima-setup.h"
#include "machine-id-setup.h"
#include "load-fragment.h"
#include "fdset.h"
#include "strv.h"
#include "def.h"
#include "virt.h"
+#include "watchdog.h"
static enum {
ACTION_RUN,
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;
log_warning("Failed to parse default standard error switch %s. Ignoring.", word + 31);
else
arg_default_std_error = r;
+ } else if (startswith(word, "systemd.setenv=")) {
+ char *cenv, *eq;
+ int r;
+
+ cenv = strdup(word + 15);
+ if (!cenv)
+ return -ENOMEM;
+
+ eq = strchr(cenv, '=');
+ if (!eq) {
+ r = unsetenv(cenv);
+ if (r < 0)
+ log_warning("unsetenv failed %s. Ignoring.", strerror(errno));
+ } else {
+ *eq = 0;
+ r = setenv(cenv, eq + 1, 1);
+ if (r < 0)
+ log_warning("setenv failed %s. Ignoring.", strerror(errno));
+ }
+ free(cenv);
#ifdef HAVE_SYSV_COMPAT
} else if (startswith(word, "systemd.sysv_console=")) {
int r;
{ "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 }
};
assert(t);
- if (!(e = getenv("RD_TIMESTAMP")))
+ e = getenv("RD_TIMESTAMP");
+ if (!e)
return NULL;
if (sscanf(e, "%llu %llu", &a, &b) != 2)
"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);
}
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")) {
arg_running_as = MANAGER_SYSTEM;
log_set_target(detect_container(NULL) > 0 ? LOG_TARGET_CONSOLE : LOG_TARGET_JOURNAL_OR_KMSG);
- if (!is_reexec)
+ if (!is_reexec) {
if (selinux_setup(&loaded_policy) < 0)
goto finish;
+ if (ima_setup() < 0)
+ goto finish;
+ }
log_open();
/* 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;
}
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 */
}
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;
}
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;
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) {
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)
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;
}
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;
}
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;
};
assert_se(shutdown_verb = table[m->exit_code]);
+ arm_reboot_watchdog = m->exit_code == MANAGER_REBOOT;
log_notice("Shutting down.");
goto 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");
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");
}