main.c revision b8f8323268ae974288e49a7cc6c1c47531e436c9
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland This file is part of systemd.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland Copyright 2010 Lennart Poettering
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland systemd is free software; you can redistribute it and/or modify it
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland under the terms of the GNU Lesser General Public License as published by
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland the Free Software Foundation; either version 2.1 of the License, or
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (at your option) any later version.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland systemd is distributed in the hope that it will be useful, but
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland WITHOUT ANY WARRANTY; without even the implied warranty of
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland Lesser General Public License for more details.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland You should have received a copy of the GNU Lesser General Public License
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland along with systemd; If not, see <http://www.gnu.org/licenses/>.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic bool arg_dump_core = true;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic bool arg_crash_shell = false;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic bool arg_confirm_spawn = false;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic bool arg_show_status = true;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic bool arg_sysv_console = true;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic char **arg_default_controllers = NULL;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* We want to wait for the core process, hence let's enable SIGCHLD */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Caught <%s>, cannot fork for core dump: %s", signal_to_string(sig), strerror(errno));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland else if (pid == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* Enable default signal handler for core dump */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* Don't limit the core dump size */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* Just to be sure... */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* Raise the signal again */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland assert_not_reached("We shouldn't be here...");
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* Order things nicely. */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((r = wait_for_terminate(pid, &status)) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Caught <%s>, core dump failed.", signal_to_string(sig));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Caught <%s>, dumped core as pid %lu.", signal_to_string(sig), (unsigned long) pid);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_info("Executing crash shell in 10s...");
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* Let the kernel reap children for us */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Failed to fork off crash shell: %s", strerror(errno));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland else if (pid == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((fd = acquire_terminal("/dev/console", false, true, true)) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Failed to acquire terminal: %s", strerror(-fd));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Failed to duplicate terminal fd: %s", strerror(-r));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("execl() failed: %s", strerror(errno));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_info("Successfully spawned crash shell as pid %lu.", (unsigned long) pid);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic void install_crash_handler(void) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* If we are init, we connect stdin/stdout/stderr to /dev/null
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * and make sure we don't have a controlling tty. */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* We don't want to force text mode.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * plymouth may be showing pictures already from initrd. */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("Failed to reset /dev/console: %s", strerror(-r));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int set_default_unit(const char *u) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(c = strdup(u)))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int parse_proc_cmdline_word(const char *word) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland static const char * const rlmap[] = {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland else if (startswith(word, "systemd.log_target=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (log_set_target_from_string(word + 19) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse log target %s. Ignoring.", word + 19);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.log_level=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (log_set_max_level_from_string(word + 18) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse log level %s. Ignoring.", word + 18);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.log_color=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (log_show_color_from_string(word + 18) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse log color setting %s. Ignoring.", word + 18);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.log_location=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (log_show_location_from_string(word + 21) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse log location setting %s. Ignoring.", word + 21);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.dump_core=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse dump core switch %s. Ignoring.", word + 18);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.crash_shell=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse crash shell switch %s. Ignoring.", word + 20);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.confirm_spawn=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse confirm spawn switch %s. Ignoring.", word + 22);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.crash_chvt=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse crash chvt switch %s. Ignoring.", word + 19);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.show_status=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse show status switch %s. Ignoring.", word + 20);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.default_standard_output=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((r = exec_output_from_string(word + 32)) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse default standard output switch %s. Ignoring.", word + 32);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.default_standard_error=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((r = exec_output_from_string(word + 31)) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse default standard error switch %s. Ignoring.", word + 31);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.setenv=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("unsetenv failed %s. Ignoring.", strerror(errno));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("setenv failed %s. Ignoring.", strerror(errno));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (startswith(word, "systemd.sysv_console=")) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to parse SysV console switch %s. Ignoring.", word + 20);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Unknown kernel switch %s. Ignoring.", word);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.unit=UNIT Default unit to start\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.dump_core=0|1 Dump core on crash\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.crash_shell=0|1 Run shell on crash\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.crash_chvt=N Change to VT #N on crash\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.confirm_spawn=0|1 Confirm every process spawn\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.show_status=0|1 Show status updates on the console during bootup\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.sysv_console=0|1 Connect output of SysV scripts to console\n"
62224350e5355e6834f7deb9d8a7d062a50cb7c2Casper H.S. Dik "systemd.log_target=console|kmsg|journal|journal-or-kmsg|syslog|syslog-or-kmsg|null\n"
62224350e5355e6834f7deb9d8a7d062a50cb7c2Casper H.S. Dik " Log target\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.log_level=LEVEL Log level\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.log_color=0|1 Highlight important log messages\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.log_location=0|1 Include code location in log messages\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.default_standard_output=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland " Set default log output for services\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "systemd.default_standard_error=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland " Set default log error output for services\n");
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* SysV compatibility */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(t = strndup(w, l)))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland log_warning("Failed to set CPU affinity: %m");
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic void strv_free_free(char ***l) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland for (i = l; *i; i++)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic void free_join_controllers(void) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland unsigned n = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland FOREACH_WORD_QUOTED(w, length, rvalue, state) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland char *s, **l;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland for (a = arg_join_controllers; *a; a++) {
c = strv_merge(*a, l);
strv_free(l);
strv_free_free(t);
return -ENOMEM;
strv_free(l);
c = strv_copy(*a);
strv_free(l);
strv_free_free(t);
return -ENOMEM;
t[n++] = strv_uniq(l);
arg_join_controllers = t;
static int parse_config_file(void) {
#ifdef HAVE_SYSV_COMPAT
FILE *f;
const char *fn;
fclose(f);
static int parse_proc_cmdline(void) {
size_t l;
char *word;
r = -ENOMEM;
goto finish;
goto finish;
#ifdef HAVE_SYSV_COMPAT
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:
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:
arg_show_status = r;
#ifdef HAVE_SYSV_COMPAT
case ARG_SYSV_CONSOLE:
arg_sysv_console = r;
case ARG_DESERIALIZE: {
int fd;
FILE *f;
if (serialization)
serialization = f;
case ARG_INTROSPECT: {
const char * const * i = NULL;
if (optarg)
if (!i[0] && optarg)
return -EINVAL;
return -EINVAL;
if ((r = parse_proc_cmdline_word(*a)) < 0)
static int help(void) {
#ifdef HAVE_SYSV_COMPAT
" --log-target=TARGET Set log target (console, journal, syslog, kmsg, journal-or-kmsg, syslog-or-kmsg, null)\n"
assert(m);
m->n_reloading ++;
if ((r = manager_open_serialization(m, &f)) < 0) {
goto fail;
r = -ENOMEM;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
*_f = f;
fail:
fclose(f);
assert(t);
return NULL;
return NULL;
static void test_mtab(void) {
free(p);
"Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
static void test_usr(void) {
log_warning("/usr appears to be on its own filesytem 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 void test_cgroups(void) {
"Consult http://0pointer.de/blog/projects/cgroups-vs-cgroups.html for more information.");
r = -errno;
goto fail;
r = -errno;
goto fail;
fail:
bool reexecute = false;
bool is_reexec = false;
bool loaded_policy = false;
bool arm_reboot_watchdog = false;
#ifdef HAVE_SYSV_COMPAT
is_reexec = true;
log_show_location(false);
if (!is_reexec) {
goto finish;
if (ima_setup() < 0)
goto finish;
log_open();
goto finish;
if (!is_reexec)
if (hwclock_is_localtime() > 0) {
int min;
log_open();
goto finish;
if (!arg_join_controllers)
goto finish;
if (!arg_join_controllers[0])
goto finish;
goto finish;
if (parse_config_file() < 0)
goto finish;
if (parse_proc_cmdline() < 0)
goto finish;
goto finish;
goto finish;
running_in_chroot() > 0) {
goto finish;
goto finish;
goto finish;
goto finish;
log_close();
if (serialization) {
goto finish;
#ifdef HAVE_SPLIT_USR
setsid();
umask(0);
log_open();
goto finish;
PACKAGE_STRING " running in %s mode. (" SYSTEMD_FEATURES "; " DISTRIBUTION ")", manager_running_as_to_string(arg_running_as));
locale_setup();
kmod_setup();
test_mtab();
test_usr();
test_cgroups();
goto finish;
#ifdef HAVE_SYSV_COMPAT
if (fds) {
if (serialization) {
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
r = manager_loop(m);
goto finish;
switch (m->exit_code) {
case MANAGER_EXIT:
goto finish;
case MANAGER_RELOAD:
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_REBOOT:
case MANAGER_POWEROFF:
case MANAGER_HALT:
case MANAGER_KEXEC: {
goto finish;
manager_free(m);
label_finish();
if (reexecute) {
const char **args;
unsigned i, args_size;
watchdog_close(true);
if (switch_root)
if (!switch_root_init) {
if (serialization) {
if (fds) {
if (switch_root_init) {
if (serialization)
if (fds)
if (shutdown_verb) {
const char * command_line[] = {
char **env_block;
watchdog_close(false);
char_array_0(e);
watchdog_close(true);
freeze();
return retval;