X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fmain.c;h=4d4f6e8f4caf664f772406840213b6f73326c8e8;hb=128c3c5881e5708b3f15517ee24dd8c0a1c6307e;hp=243855fa153e1a89a354d91aa1b81fb3667070f1;hpb=ec26be514ff3c5367b21f9881369080bda54fd2d;p=elogind.git
diff --git a/src/core/main.c b/src/core/main.c
index 243855fa1..4d4f6e8f4 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -19,8 +19,6 @@
along with systemd; If not, see .
***/
-#include
-
#include
#include
#include
@@ -34,13 +32,19 @@
#include
#include
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include
+#endif
+
+#include "sd-daemon.h"
+#include "sd-messages.h"
+#include "sd-bus.h"
#include "manager.h"
#include "log.h"
#include "load-fragment.h"
#include "fdset.h"
#include "special.h"
#include "conf-parser.h"
-#include "dbus-common.h"
#include "missing.h"
#include "label.h"
#include "build.h"
@@ -54,21 +58,21 @@
#include "killall.h"
#include "env-util.h"
#include "hwclock.h"
-#include "sd-daemon.h"
-#include "sd-messages.h"
+#include "fileio.h"
+#include "dbus-manager.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "mount-setup.h"
#include "loopback-setup.h"
-#ifdef HAVE_KMOD
-#include "kmod-setup.h"
-#endif
#include "hostname-setup.h"
#include "machine-id-setup.h"
-#include "locale-setup.h"
#include "selinux-setup.h"
#include "ima-setup.h"
-#include "fileio.h"
#include "smack-setup.h"
+#ifdef HAVE_KMOD
+#include "kmod-setup.h"
+#endif
static enum {
ACTION_RUN,
@@ -91,6 +95,11 @@ static bool arg_switched_root = false;
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_default_restart_usec = DEFAULT_RESTART_USEC;
+static usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
+static usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
+static usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
+static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
static usec_t arg_runtime_watchdog = 0;
static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
static char **arg_default_environment = NULL;
@@ -349,32 +358,21 @@ static int parse_proc_cmdline_word(const char *word) {
arg_default_std_error = r;
} else if (startswith(word, "systemd.setenv=")) {
_cleanup_free_ char *cenv = NULL;
- char *eq;
- int r;
cenv = strdup(word + 15);
if (!cenv)
return -ENOMEM;
- eq = strchr(cenv, '=');
- if (!eq) {
- if (!env_name_is_valid(cenv))
- log_warning("Environment variable name '%s' is not valid. Ignoring.", cenv);
- else {
- r = unsetenv(cenv);
- if (r < 0)
- log_warning("Unsetting environment variable '%s' failed, ignoring: %m", cenv);
- }
- } else {
- if (!env_assignment_is_valid(cenv))
- log_warning("Environment variable assignment '%s' is not valid. Ignoring.", cenv);
- else {
- *eq = 0;
- r = setenv(cenv, eq + 1, 1);
- if (r < 0)
- log_warning("Setting environment variable '%s=%s' failed, ignoring: %m", cenv, eq + 1);
- }
- }
+ if (env_assignment_is_valid(cenv)) {
+ char **env;
+
+ env = strv_env_set(arg_default_environment, cenv);
+ if (env)
+ arg_default_environment = env;
+ else
+ log_warning("Setting environment variable '%s' failed, ignoring: %m", cenv);
+ } else
+ log_warning("Environment variable name '%s' is not valid. Ignoring.", cenv);
} else if (startswith(word, "systemd.") ||
(in_initrd() && startswith(word, "rd.systemd."))) {
@@ -413,9 +411,14 @@ static int parse_proc_cmdline_word(const char *word) {
} else if (streq(word, "quiet"))
arg_show_status = false;
- else if (streq(word, "debug"))
+ else if (streq(word, "debug")) {
+ /* Log to kmsg, the journal socket will fill up before the
+ * journal is started and tools running during that time
+ * will block with every log message for for 60 seconds,
+ * before they give up. */
log_set_max_level(LOG_DEBUG);
- else if (!in_initrd()) {
+ log_set_target(LOG_TARGET_KMSG);
+ } else if (!in_initrd()) {
unsigned i;
/* SysV compatibility */
@@ -643,6 +646,11 @@ static int parse_config_file(void) {
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
{ "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output },
{ "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error },
+ { "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec },
+ { "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec },
+ { "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec },
+ { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
+ { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
@@ -692,19 +700,14 @@ static int parse_config_file(void) {
static int parse_proc_cmdline(void) {
_cleanup_free_ char *line = NULL;
char *w, *state;
- int r;
size_t l;
+ int r;
- /* Don't read /proc/cmdline if we are in a container, since
- * that is only relevant for the host system */
- if (detect_container(NULL) > 0)
- return 0;
-
- r = read_one_line_file("/proc/cmdline", &line);
- if (r < 0) {
+ r = proc_cmdline(&line);
+ if (r < 0)
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
+ if (r <= 0)
return 0;
- }
FOREACH_WORD_QUOTED(w, l, line, state) {
_cleanup_free_ char *word;
@@ -742,7 +745,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SHOW_STATUS,
ARG_DESERIALIZE,
ARG_SWITCHED_ROOT,
- ARG_INTROSPECT,
ARG_DEFAULT_STD_OUTPUT,
ARG_DEFAULT_STD_ERROR
};
@@ -765,7 +767,6 @@ static int parse_argv(int argc, char *argv[]) {
{ "show-status", optional_argument, NULL, ARG_SHOW_STATUS },
{ "deserialize", required_argument, NULL, ARG_DESERIALIZE },
{ "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT },
- { "introspect", optional_argument, NULL, ARG_INTROSPECT },
{ "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, },
{ "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, },
{ NULL, 0, NULL, 0 }
@@ -937,27 +938,6 @@ static int parse_argv(int argc, char *argv[]) {
arg_switched_root = true;
break;
- case ARG_INTROSPECT: {
- const char * const * i = NULL;
-
- for (i = bus_interface_table; *i; i += 2)
- if (!optarg || streq(i[0], optarg)) {
- fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
- "\n", stdout);
- fputs(i[1], stdout);
- fputs("\n", stdout);
-
- if (optarg)
- break;
- }
-
- if (!i[0] && optarg)
- log_error("Unknown interface %s.", optarg);
-
- arg_action = ACTION_DONE;
- break;
- }
-
case 'h':
arg_action = ACTION_HELP;
break;
@@ -1003,11 +983,13 @@ static int parse_argv(int argc, char *argv[]) {
* relevant for the container, hence we rely on argv[]
* instead. */
- for (a = argv; a < argv + argc; a++)
- if ((r = parse_proc_cmdline_word(*a)) < 0) {
+ for (a = argv; a < argv + argc; a++) {
+ r = parse_proc_cmdline_word(*a);
+ if (r < 0) {
log_error("Failed on cmdline argument %s: %s", *a, strerror(-r));
return r;
}
+ }
}
return 0;
@@ -1020,7 +1002,6 @@ static int help(void) {
" -h --help Show this help\n"
" --test Determine startup sequence, dump it and exit\n"
" --dump-configuration-items Dump understood unit configuration items\n"
- " --introspect[=INTERFACE] Extract D-Bus interface data\n"
" --unit=UNIT Set default unit\n"
" --system Run a system instance, even if PID != 1\n"
" --user Run a user instance\n"
@@ -1055,15 +1036,16 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
assert(_f);
assert(_fds);
- /* Make sure nothing is really destructed when we shut down */
- m->n_reloading ++;
-
r = manager_open_serialization(m, &f);
if (r < 0) {
log_error("Failed to create serialization file: %s", strerror(-r));
goto fail;
}
+ /* Make sure nothing is really destructed when we shut down */
+ m->n_reloading ++;
+ bus_manager_send_reloading(m, true);
+
fds = fdset_new();
if (!fds) {
r = -ENOMEM;
@@ -1144,25 +1126,6 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
return 0;
}
-static struct dual_timestamp* parse_initrd_timestamp(struct dual_timestamp *t) {
- const char *e;
- unsigned long long a, b;
-
- assert(t);
-
- e = getenv("RD_TIMESTAMP");
- if (!e)
- return NULL;
-
- if (sscanf(e, "%llu %llu", &a, &b) != 2)
- return NULL;
-
- t->realtime = (usec_t) a;
- t->monotonic = (usec_t) b;
-
- return t;
-}
-
static void test_mtab(void) {
char *p;
@@ -1243,6 +1206,8 @@ int main(int argc, char *argv[]) {
dual_timestamp initrd_timestamp = { 0ULL, 0ULL };
dual_timestamp userspace_timestamp = { 0ULL, 0ULL };
dual_timestamp kernel_timestamp = { 0ULL, 0ULL };
+ dual_timestamp security_start_timestamp = { 0ULL, 0ULL };
+ dual_timestamp security_finish_timestamp = { 0ULL, 0ULL };
static char systemd[] = "systemd";
bool skip_setup = false;
int j;
@@ -1290,6 +1255,10 @@ int main(int argc, char *argv[]) {
log_show_color(isatty(STDERR_FILENO) > 0);
+ /* Disable the umask logic */
+ if (getpid() == 1)
+ umask(0);
+
if (getpid() == 1 && detect_container(NULL) <= 0) {
/* Running outside of a container as PID 1 */
@@ -1298,27 +1267,19 @@ int main(int argc, char *argv[]) {
log_set_target(LOG_TARGET_KMSG);
log_open();
- if (in_initrd()) {
- char *rd_timestamp = NULL;
-
+ if (in_initrd())
initrd_timestamp = userspace_timestamp;
- asprintf(&rd_timestamp, "%llu %llu",
- (unsigned long long) initrd_timestamp.realtime,
- (unsigned long long) initrd_timestamp.monotonic);
- if (rd_timestamp) {
- setenv("RD_TIMESTAMP", rd_timestamp, 1);
- free(rd_timestamp);
- }
- }
if (!skip_setup) {
mount_setup_early();
+ dual_timestamp_get(&security_start_timestamp);
if (selinux_setup(&loaded_policy) < 0)
goto finish;
if (ima_setup() < 0)
goto finish;
if (smack_setup() < 0)
goto finish;
+ dual_timestamp_get(&security_finish_timestamp);
}
if (label_init(NULL) < 0)
@@ -1457,6 +1418,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (arg_running_as == SYSTEMD_USER &&
+ !getenv("XDG_RUNTIME_DIR")) {
+ log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
+ goto finish;
+ }
+
assert_se(arg_action == ACTION_RUN || arg_action == ACTION_TEST);
/* Close logging fds, in order not to confuse fdset below */
@@ -1473,62 +1440,12 @@ int main(int argc, char *argv[]) {
if (serialization)
assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
- /* Set up PATH unless it is already set */
- setenv("PATH",
-#ifdef HAVE_SPLIT_USR
- "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
-#else
- "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
-#endif
- arg_running_as == SYSTEMD_SYSTEM);
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
- /* Parse the data passed to us. We leave this
- * variables set, but the manager later on will not
- * pass them on to our children. */
- if (!in_initrd())
- parse_initrd_timestamp(&initrd_timestamp);
-
- /* 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("_");
-
- /* When we are invoked by a chroot-like tool such as
- * nspawn, these might be set, but make little sense
- * to pass on */
- unsetenv("USER");
- unsetenv("LOGNAME");
-
- /* We suppress the socket activation env vars, as
- * we'll try to match *any* open fd to units if
- * possible. */
- unsetenv("LISTEN_FDS");
- unsetenv("LISTEN_PID");
-
- /* All other variables are left as is, so that clients
- * can still read them via /proc/1/environ */
- }
-
- /* Move out of the way, so that we won't block unmounts */
- assert_se(chdir("/") == 0);
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
+ if (arg_running_as == SYSTEMD_SYSTEM)
/* Become a session leader if we aren't one yet. */
setsid();
- /* Disable the umask logic */
- umask(0);
- }
-
- /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */
- dbus_connection_set_change_sigpipe(FALSE);
+ /* Move out of the way, so that we won't block unmounts */
+ assert_se(chdir("/") == 0);
/* Reset the console, but only if this is really init and we
* are freshly booted */
@@ -1564,8 +1481,6 @@ int main(int argc, char *argv[]) {
log_debug(PACKAGE_STRING " running in user mode. (" SYSTEMD_FEATURES ")");
if (arg_running_as == SYSTEMD_SYSTEM && !skip_setup) {
- locale_setup();
-
if (arg_show_status || plymouth_running())
status_welcome();
@@ -1589,14 +1504,14 @@ int main(int argc, char *argv[]) {
log_error("Failed to adjust timer slack: %m");
if (arg_capability_bounding_set_drop) {
- r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
+ r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
if (r < 0) {
- log_error("Failed to drop capability bounding set: %s", strerror(-r));
+ log_error("Failed to drop capability bounding set of usermode helpers: %s", strerror(-r));
goto finish;
}
- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
+ r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
if (r < 0) {
- log_error("Failed to drop capability bounding set of usermode helpers: %s", strerror(-r));
+ log_error("Failed to drop capability bounding set: %s", strerror(-r));
goto finish;
}
}
@@ -1613,7 +1528,7 @@ int main(int argc, char *argv[]) {
if (arg_running_as == SYSTEMD_SYSTEM)
bump_rlimit_nofile(&saved_rlimit_nofile);
- r = manager_new(arg_running_as, &m);
+ r = manager_new(arg_running_as, !!serialization, &m);
if (r < 0) {
log_error("Failed to allocate manager object: %s", strerror(-r));
goto finish;
@@ -1622,16 +1537,23 @@ int main(int argc, char *argv[]) {
m->confirm_spawn = arg_confirm_spawn;
m->default_std_output = arg_default_std_output;
m->default_std_error = arg_default_std_error;
+ m->default_restart_usec = arg_default_restart_usec;
+ m->default_timeout_start_usec = arg_default_timeout_start_usec;
+ m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
+ m->default_start_limit_interval = arg_default_start_limit_interval;
+ m->default_start_limit_burst = arg_default_start_limit_burst;
m->runtime_watchdog = arg_runtime_watchdog;
m->shutdown_watchdog = arg_shutdown_watchdog;
m->userspace_timestamp = userspace_timestamp;
m->kernel_timestamp = kernel_timestamp;
m->initrd_timestamp = initrd_timestamp;
+ m->security_start_timestamp = security_start_timestamp;
+ m->security_finish_timestamp = security_finish_timestamp;
manager_set_default_rlimits(m, arg_default_rlimit);
if (arg_default_environment)
- manager_set_default_environment(m, arg_default_environment);
+ manager_environment_add(m, NULL, arg_default_environment);
manager_set_show_status(m, arg_show_status);
@@ -1647,6 +1569,7 @@ int main(int argc, char *argv[]) {
/* This will close all file descriptors that were opened, but
* not claimed by any unit. */
fdset_free(fds);
+ fds = NULL;
if (serialization) {
fclose(serialization);
@@ -1654,19 +1577,16 @@ int main(int argc, char *argv[]) {
}
if (queue_default_job) {
- DBusError error;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
Unit *target = NULL;
Job *default_unit_job;
- dbus_error_init(&error);
-
log_debug("Activating default unit: %s", arg_default_unit);
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 || target->load_state == UNIT_NOT_FOUND)
+ if (r < 0)
+ log_error("Failed to load default target: %s", bus_error_message(&error, r));
+ else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND)
log_error("Failed to load default target: %s", strerror(-target->load_error));
else if (target->load_state == UNIT_MASKED)
log_error("Default target masked.");
@@ -1676,8 +1596,7 @@ int main(int argc, char *argv[]) {
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);
+ log_error("Failed to load rescue target: %s", bus_error_message(&error, r));
goto finish;
} else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) {
log_error("Failed to load rescue target: %s", strerror(-target->load_error));
@@ -1697,18 +1616,15 @@ int main(int argc, char *argv[]) {
r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, false, &error, &default_unit_job);
if (r == -EPERM) {
- log_debug("Default target could not be isolated, starting instead: %s", bus_error(&error, r));
- dbus_error_free(&error);
+ log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job);
if (r < 0) {
- log_error("Failed to start default target: %s", bus_error(&error, r));
- dbus_error_free(&error);
+ log_error("Failed to start default target: %s", bus_error_message(&error, r));
goto finish;
}
} else if (r < 0) {
- log_error("Failed to isolate default target: %s", bus_error(&error, r));
- dbus_error_free(&error);
+ log_error("Failed to isolate default target: %s", bus_error_message(&error, r));
goto finish;
}
@@ -1804,7 +1720,6 @@ finish:
free(arg_default_unit);
free_join_controllers();
- dbus_shutdown();
label_finish();
if (reexecute) {
@@ -1861,6 +1776,10 @@ finish:
args[i++] = sfd;
args[i++] = NULL;
+ /* do not pass along the environment we inherit from the kernel or initrd */
+ if (switch_root_dir)
+ clearenv();
+
assert(i <= args_size);
execv(args[0], (char* const*) args);
}
@@ -1915,6 +1834,15 @@ finish:
if (fds)
fdset_free(fds);
+#ifdef HAVE_VALGRIND_VALGRIND_H
+ /* If we are PID 1 and running under valgrind, then let's exit
+ * here explicitly. valgrind will only generate nice output on
+ * exit(), not on exec(), hence let's do the former not the
+ * latter here. */
+ if (getpid() == 1 && RUNNING_ON_VALGRIND)
+ return 0;
+#endif
+
if (shutdown_verb) {
const char * command_line[] = {
SYSTEMD_SHUTDOWN_BINARY_PATH,
@@ -1942,9 +1870,11 @@ finish:
watchdog_close(true);
}
- /* avoid the creation of new processes forked by the kernel; at this
- * point, we will not listen to the signals anyway */
- cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
+ /* Avoid the creation of new processes forked by the
+ * kernel; at this point, we will not listen to the
+ * signals anyway */
+ if (detect_container(NULL) <= 0)
+ cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
free(env_block);