X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fmain.c;h=a732c6945afc5a671d134e235cafd31e03241771;hp=086e283dc63de4761b48680e4d1454acf717bb96;hb=3408ba015aee3a88c91962c028738be757779519;hpb=d9d93745cd2efcdfca8f82d798e61e0ee70cef5c diff --git a/src/core/main.c b/src/core/main.c index 086e283dc..a732c6945 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -35,6 +35,9 @@ #ifdef HAVE_VALGRIND_VALGRIND_H #include #endif +#ifdef HAVE_SECCOMP +#include +#endif #include "sd-daemon.h" #include "sd-messages.h" @@ -58,7 +61,7 @@ #include "capability.h" #include "killall.h" #include "env-util.h" -#include "hwclock.h" +#include "clock-util.h" #include "fileio.h" #include "dbus-manager.h" #include "bus-error.h" @@ -102,11 +105,15 @@ 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; -static struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {}; +static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {}; static uint64_t arg_capability_bounding_set_drop = 0; static nsec_t arg_timer_slack_nsec = (nsec_t) -1; +static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE; static Set* arg_syscall_archs = NULL; static FILE* arg_serialization = NULL; +static bool arg_default_cpu_accounting = false; +static bool arg_default_blockio_accounting = false; +static bool arg_default_memory_accounting = false; static void nop_handler(int sig) {} @@ -234,7 +241,7 @@ static int console_setup(bool do_reset) { if (r < 0) log_error("Failed to reset /dev/console: %s", strerror(-r)); - close_nointr_nofail(tty_fd); + safe_close(tty_fd); return r; } @@ -253,7 +260,7 @@ static int set_default_unit(const char *u) { return 0; } -static int parse_proc_cmdline_word(const char *word) { +static int parse_proc_cmdline_item(const char *key, const char *value) { static const char * const rlmap[] = { "emergency", SPECIAL_EMERGENCY_TARGET, @@ -268,162 +275,126 @@ static int parse_proc_cmdline_word(const char *word) { "4", SPECIAL_RUNLEVEL4_TARGET, "5", SPECIAL_RUNLEVEL5_TARGET, }; + int r; - assert(word); + assert(key); - if (startswith(word, "systemd.unit=")) { + if (streq(key, "systemd.unit") && value) { if (!in_initrd()) - return set_default_unit(word + 13); + return set_default_unit(value); - } else if (startswith(word, "rd.systemd.unit=")) { + } else if (streq(key, "rd.systemd.unit") && value) { if (in_initrd()) - return set_default_unit(word + 16); + return set_default_unit(value); - } else if (startswith(word, "systemd.log_target=")) { + } else if (streq(key, "systemd.log_target") && value) { - if (log_set_target_from_string(word + 19) < 0) - log_warning("Failed to parse log target %s. Ignoring.", word + 19); + if (log_set_target_from_string(value) < 0) + log_warning("Failed to parse log target %s. Ignoring.", value); - } else if (startswith(word, "systemd.log_level=")) { + } else if (streq(key, "systemd.log_level") && value) { - if (log_set_max_level_from_string(word + 18) < 0) - log_warning("Failed to parse log level %s. Ignoring.", word + 18); + if (log_set_max_level_from_string(value) < 0) + log_warning("Failed to parse log level %s. Ignoring.", value); - } else if (startswith(word, "systemd.log_color=")) { + } else if (streq(key, "systemd.log_color") && value) { - if (log_show_color_from_string(word + 18) < 0) - log_warning("Failed to parse log color setting %s. Ignoring.", word + 18); + if (log_show_color_from_string(value) < 0) + log_warning("Failed to parse log color setting %s. Ignoring.", value); - } else if (startswith(word, "systemd.log_location=")) { + } else if (streq(key, "systemd.log_location") && value) { - if (log_show_location_from_string(word + 21) < 0) - log_warning("Failed to parse log location setting %s. Ignoring.", word + 21); + if (log_show_location_from_string(value) < 0) + log_warning("Failed to parse log location setting %s. Ignoring.", value); - } else if (startswith(word, "systemd.dump_core=")) { - int r; + } else if (streq(key, "systemd.dump_core") && value) { - r = parse_boolean(word + 18); + r = parse_boolean(value); if (r < 0) - log_warning("Failed to parse dump core switch %s. Ignoring.", word + 18); + log_warning("Failed to parse dump core switch %s. Ignoring.", value); else arg_dump_core = r; - } else if (startswith(word, "systemd.crash_shell=")) { - int r; + } else if (streq(key, "systemd.crash_shell") && value) { - r = parse_boolean(word + 20); + r = parse_boolean(value); if (r < 0) - log_warning("Failed to parse crash shell switch %s. Ignoring.", word + 20); + log_warning("Failed to parse crash shell switch %s. Ignoring.", value); else arg_crash_shell = r; - } else if (startswith(word, "systemd.confirm_spawn=")) { - int r; + } else if (streq(key, "systemd.crash_chvt") && value) { - r = parse_boolean(word + 22); - if (r < 0) - log_warning("Failed to parse confirm spawn switch %s. Ignoring.", word + 22); + if (safe_atoi(value, &r) < 0) + log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); else - arg_confirm_spawn = r; + arg_crash_chvt = r; - } else if (startswith(word, "systemd.crash_chvt=")) { - int k; + } else if (streq(key, "systemd.confirm_spawn") && value) { - if (safe_atoi(word + 19, &k) < 0) - log_warning("Failed to parse crash chvt switch %s. Ignoring.", word + 19); + r = parse_boolean(value); + if (r < 0) + log_warning("Failed to parse confirm spawn switch %s. Ignoring.", value); else - arg_crash_chvt = k; + arg_confirm_spawn = r; - } else if (startswith(word, "systemd.show_status=")) { - int r; + } else if (streq(key, "systemd.show_status") && value) { - r = parse_show_status(word + 20, &arg_show_status); + r = parse_show_status(value, &arg_show_status); if (r < 0) - log_warning("Failed to parse show status switch %s. Ignoring.", word + 20); - } else if (startswith(word, "systemd.default_standard_output=")) { - int r; + log_warning("Failed to parse show status switch %s. Ignoring.", value); + + } else if (streq(key, "systemd.default_standard_output") && value) { - r = exec_output_from_string(word + 32); + r = exec_output_from_string(value); if (r < 0) - log_warning("Failed to parse default standard output switch %s. Ignoring.", word + 32); + log_warning("Failed to parse default standard output switch %s. Ignoring.", value); else arg_default_std_output = r; - } else if (startswith(word, "systemd.default_standard_error=")) { - int r; - r = exec_output_from_string(word + 31); + } else if (streq(key, "systemd.default_standard_error") && value) { + + r = exec_output_from_string(value); if (r < 0) - log_warning("Failed to parse default standard error switch %s. Ignoring.", word + 31); + log_warning("Failed to parse default standard error switch %s. Ignoring.", value); else arg_default_std_error = r; - } else if (startswith(word, "systemd.setenv=")) { - const char *cenv = word + 15; - if (env_assignment_is_valid(cenv)) { + } else if (streq(key, "systemd.setenv") && value) { + + if (env_assignment_is_valid(value)) { char **env; - env = strv_env_set(arg_default_environment, cenv); + env = strv_env_set(arg_default_environment, value); if (env) arg_default_environment = env; else - log_warning("Setting environment variable '%s' failed, ignoring: %s", - cenv, strerror(ENOMEM)); + log_warning("Setting environment variable '%s' failed, ignoring: %s", value, strerror(ENOMEM)); } else - log_warning("Environment variable name '%s' is not valid. Ignoring.", cenv); - - } else if (startswith(word, "systemd.") || - (in_initrd() && startswith(word, "rd.systemd."))) { - - const char *c; - - /* Ignore systemd.journald.xyz and friends */ - c = word; - if (startswith(c, "rd.")) - c += 3; - if (startswith(c, "systemd.")) - c += 8; - if (c[strcspn(c, ".=")] != '.') { - - log_warning("Unknown kernel switch %s. Ignoring.", word); - - log_info("Supported kernel switches:\n" - "systemd.unit=UNIT Default unit to start\n" - "rd.systemd.unit=UNIT Default unit to start when run in initrd\n" - "systemd.dump_core=0|1 Dump core on crash\n" - "systemd.crash_shell=0|1 Run shell on crash\n" - "systemd.crash_chvt=N Change to VT #N on crash\n" - "systemd.confirm_spawn=0|1 Confirm every process spawn\n" - "systemd.show_status=0|1|auto Show status updates on the console during bootup\n" - "systemd.log_target=console|kmsg|journal|journal-or-kmsg|syslog|syslog-or-kmsg|null\n" - " Log target\n" - "systemd.log_level=LEVEL Log level\n" - "systemd.log_color=0|1 Highlight important log messages\n" - "systemd.log_location=0|1 Include code location in log messages\n" - "systemd.default_standard_output=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n" - " Set default log output for services\n" - "systemd.default_standard_error=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n" - " Set default log error output for services\n" - "systemd.setenv=ASSIGNMENT Set an environment variable for all spawned processes\n"); - } + log_warning("Environment variable name '%s' is not valid. Ignoring.", value); + + } else if (streq(key, "quiet") && !value) { + + log_set_max_level(LOG_NOTICE); - } else if (streq(word, "quiet")) { if (arg_show_status == _SHOW_STATUS_UNSET) arg_show_status = SHOW_STATUS_AUTO; - } 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. */ + + } else if (streq(key, "debug") && !value) { + log_set_max_level(LOG_DEBUG); - log_set_target(detect_container(NULL) > 0 ? LOG_TARGET_CONSOLE : LOG_TARGET_KMSG); - } else if (!in_initrd()) { + + if (detect_container(NULL) > 0) + log_set_target(LOG_TARGET_CONSOLE); + + } else if (!in_initrd() && !value) { unsigned i; /* SysV compatibility */ for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(word, rlmap[i])) + if (streq(key, rlmap[i])) return set_default_unit(rlmap[i+1]); } @@ -462,16 +433,17 @@ DEFINE_SETTER(config_parse_target, log_set_target_from_string, "target") DEFINE_SETTER(config_parse_color, log_show_color_from_string, "color" ) DEFINE_SETTER(config_parse_location, log_show_location_from_string, "location") -static int config_parse_cpu_affinity2(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +static int config_parse_cpu_affinity2( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { char *w; size_t l; @@ -518,6 +490,36 @@ static int config_parse_cpu_affinity2(const char *unit, return 0; } +static int config_parse_show_status( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + int k; + ShowStatus *b = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + k = parse_show_status(rvalue, b); + if (k < 0) { + log_syntax(unit, LOG_ERR, filename, line, -k, + "Failed to parse show status setting, ignoring: %s", rvalue); + return 0; + } + + return 0; +} + static void strv_free_free(char ***l) { char ***i; @@ -649,6 +651,7 @@ static int parse_config_file(void) { { "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs }, #endif { "Manager", "TimerSlackNSec", config_parse_nsec, 0, &arg_timer_slack_nsec }, + { "Manager", "DefaultTimerAccuracySec", config_parse_sec, 0, &arg_default_timer_accuracy_usec }, { "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 }, @@ -673,6 +676,9 @@ static int parse_config_file(void) { { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] }, { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, + { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting }, + { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, + { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, {} }; @@ -960,7 +966,18 @@ static int parse_argv(int argc, char *argv[]) { * instead. */ for (a = argv; a < argv + argc; a++) { - r = parse_proc_cmdline_word(*a); + _cleanup_free_ char *w; + char *value; + + w = strdup(*a); + if (!w) + return log_oom(); + + value = strchr(w, '='); + if (value) + *(value++) = 0; + + r = parse_proc_cmdline_item(w, value); if (r < 0) { log_error("Failed on cmdline argument %s: %s", *a, strerror(-r)); return r; @@ -1103,19 +1120,25 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { } static void test_mtab(void) { - char *p; - /* Check that /etc/mtab is a symlink */ + static const char ok[] = + "/proc/self/mounts\0" + "/proc/mounts\0" + "../proc/self/mounts\0" + "../proc/mounts\0"; - if (readlink_malloc("/etc/mtab", &p) >= 0) { - bool b; + _cleanup_free_ char *p = NULL; + int r; - b = streq(p, "/proc/self/mounts") || streq(p, "/proc/mounts"); - free(p); + /* Check that /etc/mtab is a symlink to the right place or + * non-existing. But certainly not a file, or a symlink to + * some weird place... */ - if (b) - return; - } + r = readlink_malloc("/etc/mtab", &p); + if (r == -ENOENT) + return; + if (r >= 0 && nulstr_contains(ok, p)) + return; log_warning("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " "This is not supported anymore. " @@ -1134,21 +1157,6 @@ static void test_usr(void) { "Consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken for more information."); } -static void test_cgroups(void) { - - if (access("/proc/cgroups", F_OK) >= 0) - return; - - log_warning("CONFIG_CGROUPS was not set when your kernel was compiled. " - "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. " - "Consult http://0pointer.de/blog/projects/cgroups-vs-cgroups.html for more information."); - - sleep(10); -} - static int initialize_join_controllers(void) { /* By default, mount "cpu" + "cpuacct" together, and "net_cls" * + "net_prio". We'd like to add "cpuset" to the mix, but @@ -1218,9 +1226,15 @@ static int status_welcome(void) { "PRETTY_NAME", &pretty_name, "ANSI_COLOR", &ansi_color, NULL); + if (r == -ENOENT) { + r = parse_env_file("/usr/lib/os-release", NEWLINE, + "PRETTY_NAME", &pretty_name, + "ANSI_COLOR", &ansi_color, + NULL); + } if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/os-release: %s", strerror(-r)); + log_warning("Failed to read os-release file: %s", strerror(-r)); return status_printf(NULL, false, false, "\nWelcome to \x1B[%sm%s\x1B[0m!\n", @@ -1228,6 +1242,16 @@ static int status_welcome(void) { isempty(pretty_name) ? "Linux" : pretty_name); } +static int write_container_id(void) { + const char *c; + + c = getenv("container"); + if (isempty(c)) + return 0; + + return write_string_file("/run/systemd/container", c); +} + int main(int argc, char *argv[]) { Manager *m = NULL; int r, retval = EXIT_FAILURE; @@ -1247,6 +1271,7 @@ int main(int argc, char *argv[]) { bool loaded_policy = false; bool arm_reboot_watchdog = false; bool queue_default_job = false; + bool empty_etc = false; char *switch_root_dir = NULL, *switch_root_init = NULL; static struct rlimit saved_rlimit_nofile = { 0, 0 }; @@ -1310,7 +1335,7 @@ int main(int argc, char *argv[]) { goto finish; if (ima_setup() < 0) goto finish; - if (smack_setup() < 0) + if (smack_setup(&loaded_policy) < 0) goto finish; dual_timestamp_get(&security_finish_timestamp); } @@ -1319,11 +1344,11 @@ int main(int argc, char *argv[]) { goto finish; if (!skip_setup) { - if (hwclock_is_localtime() > 0) { + if (clock_is_localtime() > 0) { int min; /* The first-time call to settimeofday() does a time warp in the kernel */ - r = hwclock_set_timezone(&min); + r = clock_set_timezone(&min); if (r < 0) log_error("Failed to apply local time delta, ignoring: %s", strerror(-r)); else @@ -1337,10 +1362,10 @@ int main(int argc, char *argv[]) { * that way. In such case, we need to delay the time-warp or the sealing * until we reach the real system. */ - hwclock_reset_timezone(); + clock_reset_timezone(); /* Tell the kernel our timezone */ - r = hwclock_set_timezone(NULL); + r = clock_set_timezone(NULL); if (r < 0) log_error("Failed to set the kernel's timezone, ignoring: %s", strerror(-r)); } @@ -1409,7 +1434,7 @@ int main(int argc, char *argv[]) { goto finish; if (arg_running_as == SYSTEMD_SYSTEM) - if (parse_proc_cmdline(parse_proc_cmdline_word) < 0) + if (parse_proc_cmdline(parse_proc_cmdline_item) < 0) goto finish; log_parse_environment(); @@ -1511,15 +1536,29 @@ int main(int argc, char *argv[]) { if (virtualization) log_info("Detected virtualization '%s'.", virtualization); + write_container_id(); + log_info("Detected architecture '%s'.", architecture_to_string(uname_architecture())); if (in_initrd()) log_info("Running in initial RAM disk."); + /* Let's check whether /etc is already populated. We + * don't actually really check for that, but use + * /etc/machine-id as flag file. This allows container + * managers and installers to provision a couple of + * files already. If the container manager wants to + * provision the machine ID itself it should pass + * $container_uuid to PID 1.*/ + + empty_etc = access("/etc/machine-id", F_OK) < 0; + if (empty_etc) + log_info("Running with unpopulated /etc."); } else { - _cleanup_free_ char *t = uid_to_name(getuid()); - log_debug(PACKAGE_STRING " running in user mode for user "PID_FMT"/%s. (" SYSTEMD_FEATURES ")", - getuid(), t); + _cleanup_free_ char *t; + + t = uid_to_name(getuid()); + log_debug(PACKAGE_STRING " running in user mode for user "UID_FMT"/%s. (" SYSTEMD_FEATURES ")", getuid(), strna(t)); } if (arg_running_as == SYSTEMD_SYSTEM && !skip_setup) { @@ -1527,16 +1566,14 @@ int main(int argc, char *argv[]) { status_welcome(); #ifdef HAVE_KMOD - if (detect_container(NULL) <= 0) - kmod_setup(); + kmod_setup(); #endif hostname_setup(); - machine_id_setup(); + machine_id_setup(NULL); loopback_setup(); test_mtab(); test_usr(); - test_cgroups(); } if (arg_running_as == SYSTEMD_SYSTEM && arg_runtime_watchdog > 0) @@ -1574,9 +1611,18 @@ int main(int argc, char *argv[]) { } } - if (arg_running_as == SYSTEMD_SYSTEM) + if (arg_running_as == SYSTEMD_SYSTEM) { bump_rlimit_nofile(&saved_rlimit_nofile); + if (empty_etc) { + r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_FULL, false, NULL, 0); + if (r < 0) + log_warning("Failed to populate /etc with preset unit settings, ignoring: %s", strerror(-r)); + else + log_info("Populated /etc with preset unit settings."); + } + } + r = manager_new(arg_running_as, &m); if (r < 0) { log_error("Failed to allocate manager object: %s", strerror(-r)); @@ -1584,6 +1630,7 @@ int main(int argc, char *argv[]) { } m->confirm_spawn = arg_confirm_spawn; + m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec; m->default_std_output = arg_default_std_output; m->default_std_error = arg_default_std_error; m->default_restart_usec = arg_default_restart_usec; @@ -1591,6 +1638,9 @@ int main(int argc, char *argv[]) { 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->default_cpu_accounting = arg_default_cpu_accounting; + m->default_blockio_accounting = arg_default_blockio_accounting; + m->default_memory_accounting = arg_default_memory_accounting; m->runtime_watchdog = arg_runtime_watchdog; m->shutdown_watchdog = arg_shutdown_watchdog; m->userspace_timestamp = userspace_timestamp; @@ -1783,6 +1833,7 @@ finish: if (reexecute) { const char **args; unsigned i, args_size; + sigset_t ss; /* Close and disarm the watchdog, so that the new * instance can reinitialize it, but doesn't get @@ -1866,6 +1917,13 @@ finish: args[i++] = NULL; assert(i <= args_size); + /* reenable any blocked signals, especially important + * if we switch from initial ramdisk to init=... */ + reset_all_signal_handlers(); + + assert_se(sigemptyset(&ss) == 0); + assert_se(sigprocmask(SIG_SETMASK, &ss, NULL) == 0); + if (switch_root_init) { args[0] = switch_root_init; execv(args[0], (char* const*) args); @@ -1940,7 +1998,7 @@ finish: if (log_get_show_location()) command_line[pos++] = "--log-location"; - assert(pos + 1 < ELEMENTSOF(command_line)); + assert(pos < ELEMENTSOF(command_line)); if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) { char *e;