main.c revision 3f6fd1ba65f962702753c4ad284b588e59689a23
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen This file is part of systemd.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Copyright 2010 Lennart Poettering
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is free software; you can redistribute it and/or modify it
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen under the terms of the GNU Lesser General Public License as published by
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen (at your option) any later version.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is distributed in the hope that it will be useful, but
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Lesser General Public License for more details.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen You should have received a copy of the GNU Lesser General Public License
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersenstatic ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersenstatic bool arg_dump_core = true;
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersenstatic bool arg_crash_shell = false;
c0dda18697e0994272c0c9616d36f6777b60e2c7Tom Gundersenstatic bool arg_confirm_spawn = false;
02b59d57e0c08231645120077f651151f5bb2babTom Gundersenstatic ShowStatus arg_show_status = _SHOW_STATUS_UNSET;
02b59d57e0c08231645120077f651151f5bb2babTom Gundersenstatic bool arg_switched_root = false;
672682a6b9d6fb6a3722c3fea1a93b4831747b54Tom Gundersenstatic ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersenstatic ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
54abf461d6b10dc270c4bb2aeac65f240ff1c5cdTom Gundersenstatic usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC;
50add2909c2e4b13a04d285b058b1c2270137656Tom Gundersenstatic usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersenstatic usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
02b59d57e0c08231645120077f651151f5bb2babTom Gundersenstatic usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
52433f6b65eccd1c54606dde999610640f3458acTom Gundersenstatic unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
02b59d57e0c08231645120077f651151f5bb2babTom Gundersenstatic usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic uint64_t arg_capability_bounding_set_drop = 0;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic nsec_t arg_timer_slack_nsec = NSEC_INFINITY;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic bool arg_default_cpu_accounting = false;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic bool arg_default_blockio_accounting = false;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic bool arg_default_memory_accounting = false;
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersenstatic bool arg_default_tasks_accounting = false;
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersenstatic void pager_open_if_enabled(void) {
1346b1f0388f4100bb3c2a2bb23bc881769c020cTom Gundersen /* Pass this on immediately, if this is not PID 1 */
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
06f021a8048583d66202e3ac5cd0a12386d33ac2Tom Gundersen /* We want to wait for the core process, hence let's enable SIGCHLD */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen else if (pid == 0) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* Enable default signal handler for core dump */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* Don't limit the core dump size */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* Just to be sure... */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* Raise the signal again */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen (void) kill(pid, sig); /* raise() would kill the parent */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen assert_not_reached("We shouldn't be here...");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* Order things nicely. */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen log_emergency_errno(r, "Caught <%s>, waitpid() failed: %m", signal_to_string(sig));
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen log_emergency("Caught <%s>, core dump failed (child "PID_FMT", code=%s, status=%i/%s).",
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen ? exit_status_to_string(status.si_status, EXIT_STATUS_FULL)
f882c247ad59776c3a7753bb963c1f8e2386cb79Tom Gundersen log_emergency("Caught <%s>, dumped core as pid "PID_FMT".", signal_to_string(sig), pid);
f882c247ad59776c3a7753bb963c1f8e2386cb79Tom Gundersen .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
fe8db0c5ee3365a2fc80ee7ebffa238f9a0a2ae2Tom Gundersen /* Let the kernel reap children for us */
1e9be60bbabe179f5233217384f1daec757c17c7Tom Gundersen log_emergency_errno(errno, "Failed to fork off crash shell: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen else if (pid == 0) {
f882c247ad59776c3a7753bb963c1f8e2386cb79Tom Gundersen (void) execle("/bin/sh", "/bin/sh", NULL, environ);
f882c247ad59776c3a7753bb963c1f8e2386cb79Tom Gundersen log_emergency_errno(errno, "execle() failed: %m");
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen log_info("Successfully spawned crash shell as PID "PID_FMT".", pid);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic void install_crash_handler(void) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen .sa_flags = SA_NODEFER, /* So that we can raise the signal again from the signal handler */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* We ignore the return value here, since, we don't mind if we
0c2f9b84698b25e6065b9febd21486669a13870fTom Gundersen * cannot set up a crash handler */
0c2f9b84698b25e6065b9febd21486669a13870fTom Gundersen r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
bbf7c04821a71fec67eaf0e7a34d17afc5913c13Tom Gundersen log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
52433f6b65eccd1c54606dde999610640f3458acTom Gundersenstatic int console_setup(void) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek return log_error_errno(tty_fd, "Failed to open /dev/console: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* We don't want to force text mode. plymouth may be showing
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen * pictures already from initrd. */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return log_error_errno(r, "Failed to reset /dev/console: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic int parse_proc_cmdline_item(const char *key, const char *value) {
505f8da7325591defe5f751f328bd26915267602Tom Gundersen static const char * const rlmap[] = {
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen return free_and_strdup(&arg_default_unit, value);
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen } else if (streq(key, "rd.systemd.unit") && value) {
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen return free_and_strdup(&arg_default_unit, value);
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen } else if (streq(key, "systemd.dump_core") && value) {
c0dda18697e0994272c0c9616d36f6777b60e2c7Tom Gundersen log_warning("Failed to parse dump core switch %s. Ignoring.", value);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen } else if (streq(key, "systemd.crash_shell") && value) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen log_warning("Failed to parse crash shell switch %s. Ignoring.", value);
505f8da7325591defe5f751f328bd26915267602Tom Gundersen } else if (streq(key, "systemd.crash_chvt") && value) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen } else if (streq(key, "systemd.confirm_spawn") && value) {
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen log_warning("Failed to parse confirm spawn switch %s. Ignoring.", value);
54abf461d6b10dc270c4bb2aeac65f240ff1c5cdTom Gundersen } else if (streq(key, "systemd.show_status") && value) {
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen r = parse_show_status(value, &arg_show_status);
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen log_warning("Failed to parse show status switch %s. Ignoring.", value);
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen } else if (streq(key, "systemd.default_standard_output") && value) {
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen log_warning("Failed to parse default standard output switch %s. Ignoring.", value);
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog } else if (streq(key, "systemd.default_standard_error") && value) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen log_warning("Failed to parse default standard error switch %s. Ignoring.", value);
71a6151083d842b2f5bf04e50239f0bf85d34d2eTom Gundersen } else if (streq(key, "systemd.setenv") && value) {
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen env = strv_env_set(arg_default_environment, value);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen log_warning_errno(ENOMEM, "Setting environment variable '%s' failed, ignoring: %m", value);
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog log_warning("Environment variable name '%s' is not valid. Ignoring.", value);
3bef724f7e7f7eaca69881548b06e221b77d7031Tom Gundersen /* Note that log_parse_environment() handles 'debug'
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen * too, and sets the log level to LOG_DEBUG. */
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen /* SysV compatibility */
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen return free_and_strdup(&arg_default_unit, rlmap[i+1]);
dd3efc0993b6e95ff04775e9125e2fc9d30fe261Tom Gundersen const char *filename, \
505f8da7325591defe5f751f328bd26915267602Tom Gundersen const char *section, \
fe8db0c5ee3365a2fc80ee7ebffa238f9a0a2ae2Tom Gundersen const char *lvalue, \
bbf7c04821a71fec67eaf0e7a34d17afc5913c13Tom Gundersen const char *rvalue, \
39032b87779323a244dd89f4832949d462b2ac68Zbigniew Jędrzejewski-Szmek log_syntax(unit, LOG_ERR, filename, line, r, \
3333d748facc15f49935b6b793490ba0824976e6Zbigniew Jędrzejewski-SzmekDEFINE_SETTER(config_parse_level2, log_set_max_level_from_string, "log level")
52433f6b65eccd1c54606dde999610640f3458acTom GundersenDEFINE_SETTER(config_parse_target, log_set_target_from_string, "target")
52433f6b65eccd1c54606dde999610640f3458acTom GundersenDEFINE_SETTER(config_parse_color, log_show_color_from_string, "color" )
52433f6b65eccd1c54606dde999610640f3458acTom GundersenDEFINE_SETTER(config_parse_location, log_show_location_from_string, "location")
int ncpus;
if (ncpus < 0)
return ncpus;
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) {
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
return log_oom();
strv_uniq(l);
strv_free(l);
if (!arg_join_controllers) {
if (!arg_join_controllers) {
strv_free(l);
return log_oom();
arg_join_controllers[0] = l;
strv_free(l);
return log_oom();
for (a = arg_join_controllers; *a; a++) {
if (strv_overlap(*a, l)) {
if (strv_extend_strv(&l, *a) < 0) {
strv_free(l);
strv_free_free(t);
return log_oom();
c = strv_copy(*a);
strv_free(l);
strv_free_free(t);
return log_oom();
t[n++] = strv_uniq(l);
arg_join_controllers = t;
static int parse_config_file(void) {
{ "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop },
#ifdef HAVE_SECCOMP
{ "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
assert(m);
opterr = 0;
case ARG_LOG_LEVEL:
case ARG_LOG_TARGET:
case ARG_LOG_COLOR:
if (optarg) {
log_show_color(true);
case ARG_LOG_LOCATION:
if (optarg) {
log_show_location(true);
case ARG_DEFAULT_STD_OUTPUT:
case ARG_DEFAULT_STD_ERROR:
case ARG_UNIT:
case ARG_SYSTEM:
case ARG_USER:
case ARG_TEST:
if (arg_no_pager < 0)
arg_no_pager = true;
case ARG_NO_PAGER:
arg_no_pager = true;
case ARG_VERSION:
case ARG_DUMP_CORE:
arg_dump_core = r;
case ARG_CRASH_SHELL:
arg_crash_shell = r;
case ARG_CONFIRM_SPAWN:
arg_confirm_spawn = r;
case ARG_SHOW_STATUS:
if (optarg) {
case ARG_DESERIALIZE: {
int fd;
FILE *f;
if (r < 0 || fd < 0) {
return r < 0 ? r : -EINVAL;
arg_serialization = f;
case ARG_SWITCHED_ROOT:
arg_switched_root = true;
if (arg_no_pager < 0)
arg_no_pager = true;
return -EINVAL;
return -EINVAL;
static int help(void) {
assert(m);
r = manager_open_serialization(m, &f);
m->n_reloading ++;
bus_manager_send_reloading(m, true);
if (!fds)
return log_oom();
*_f = f;
f = NULL;
if (!rl)
return log_oom();
static void test_mtab(void) {
static const char ok[] =
if (r == -ENOENT)
"Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
freeze();
static void test_usr(void) {
log_warning("/usr appears to be on its own filesystem and is not already mounted. This is not a supported setup. "
"Consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken for more information.");
static int initialize_join_controllers(void) {
if (!arg_join_controllers)
return -ENOMEM;
if (!arg_join_controllers[0])
goto oom;
goto oom;
oom:
return -ENOMEM;
#ifdef HAVE_SECCOMP
Iterator i;
void *id;
if (!seccomp)
return log_oom();
if (r == -EEXIST)
goto finish;
goto finish;
static int status_welcome(void) {
NULL);
if (r == -ENOENT)
NULL);
if (r < 0 && r != -ENOENT)
static int write_container_id(void) {
if (isempty(c))
bool reexecute = false;
bool skip_setup = false;
bool loaded_policy = false;
bool arm_reboot_watchdog = false;
bool queue_default_job = false;
bool empty_etc = false;
#ifdef HAVE_SYSV_COMPAT
skip_setup = true;
skip_setup = false;
umask(0);
log_open();
if (in_initrd())
if (!skip_setup) {
goto finish;
} else if (ima_setup() < 0) {
goto finish;
goto finish;
goto finish;
if (!skip_setup) {
if (clock_is_localtime() > 0) {
int min;
} else if (!in_initrd()) {
log_open();
log_open();
goto finish;
r = initialize_join_controllers();
goto finish;
if (!skip_setup)
kmod_setup();
goto finish;
(void) reset_all_signal_handlers();
if (parse_config_file() < 0) {
goto finish;
goto finish;
geteuid() == 0) {
goto finish;
sd_booted() <= 0) {
goto finish;
running_in_chroot() > 0) {
goto finish;
skip_setup = true;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
log_close();
goto finish;
if (arg_serialization)
setsid();
log_open();
goto finish;
v = detect_virtualization();
if (in_initrd())
* /etc/machine-id as flag file. This allows container
if (empty_etc)
_cleanup_free_ char *t;
if (arg_show_status > 0)
test_mtab();
test_usr();
goto finish;
goto finish;
if (arg_syscall_archs) {
goto finish;
if (empty_etc) {
r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, false, NULL, 0);
goto finish;
if (queue_default_job) {
goto finish;
goto finish;
goto finish;
if (r == -EPERM) {
log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
goto finish;
goto finish;
goto finish;
r = manager_loop(m);
goto finish;
switch (m->exit_code) {
case MANAGER_RELOAD:
r = parse_config_file();
r = manager_reload(m);
case MANAGER_REEXECUTE:
goto finish;
reexecute = true;
goto finish;
case MANAGER_SWITCH_ROOT:
if (!switch_root_init)
goto finish;
reexecute = true;
goto finish;
case MANAGER_EXIT:
goto finish;
case MANAGER_REBOOT:
case MANAGER_POWEROFF:
case MANAGER_HALT:
case MANAGER_KEXEC: {
goto finish;
pager_close();
m = manager_free(m);
if (reexecute) {
const char **args;
unsigned i, args_size;
watchdog_close(true);
if (switch_root_dir) {
if (!switch_root_init) {
if (switch_root_dir)
if (switch_root_dir)
(void) clearenv();
(void) make_console_stdio();
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
if (switch_root_init) {
#ifdef HAVE_VALGRIND_VALGRIND_H
if (shutdown_verb) {
switch (log_get_target()) {
case LOG_TARGET_KMSG:
case LOG_TARGET_NULL:
case LOG_TARGET_CONSOLE:
if (log_get_show_color())
if (log_get_show_location())
watchdog_close(r < 0);
watchdog_close(true);
if (detect_container() <= 0)
if (error_message)
freeze();
return retval;