main.c revision 8be28fb1e0aa57b2a6ba7736440c9bba54cb86d1
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek This file is part of systemd.
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek Copyright 2010 Lennart Poettering
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek (at your option) any later version.
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek ACTION_DUMP_CONFIGURATION_ITEMS,
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic char *arg_default_unit = NULL;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic bool arg_dump_core = true;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic bool arg_crash_shell = false;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic bool arg_confirm_spawn = false;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic bool arg_show_status = true;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic bool arg_switched_root = false;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic char ***arg_join_controllers = NULL;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic usec_t arg_runtime_watchdog = 0;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic char **arg_default_environment = NULL;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {};
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic uint64_t arg_capability_bounding_set_drop = 0;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic nsec_t arg_timer_slack_nsec = (nsec_t) -1;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic FILE* serialization = NULL;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic void nop_handler(int sig) {
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek_noreturn_ static void crash(int sig) {
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek /* Pass this on immediately, if this is not PID 1 */
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek .sa_flags = SA_NOCLDSTOP|SA_RESTART,
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek /* We want to wait for the core process, hence let's enable SIGCHLD */
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek log_error("Caught <%s>, cannot fork for core dump: %s", signal_to_string(sig), strerror(errno));
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek else if (pid == 0) {
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek /* Enable default signal handler for core dump */
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek /* Don't limit the core dump size */
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek /* Just to be sure... */
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek /* Raise the signal again */
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek assert_not_reached("We shouldn't be here...");
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek /* Order things nicely. */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r));
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak log_error("Caught <%s>, core dump failed.", signal_to_string(sig));
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak log_error("Caught <%s>, dumped core as pid %lu.", signal_to_string(sig), (unsigned long) pid);
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak /* Let the kernel reap children for us */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak else if (pid == 0) {
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek execl("/bin/sh", "/bin/sh", NULL);
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek log_error("execl() failed: %m");
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek log_info("Successfully spawned crash shell as pid %lu.", (unsigned long) pid);
a75f4e2a02e287294b21ae9e5b1f28b2f8faea39Zbigniew Jędrzejewski-Szmek log_info("Freezing execution.");
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekstatic void install_crash_handler(void) {
a75f4e2a02e287294b21ae9e5b1f28b2f8faea39Zbigniew Jędrzejewski-Szmek sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering /* If we are init, we connect stdin/stdout/stderr to /dev/null
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering * and make sure we don't have a controlling tty. */
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering /* We don't want to force text mode.
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering * plymouth may be showing pictures already from initrd. */
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering log_error("Failed to reset /dev/console: %s", strerror(-r));
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poetteringstatic int set_default_unit(const char *u) {
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poetteringstatic int parse_proc_cmdline_word(const char *word) {
6550203eb471595e41e27f46e5d0a00a4c0e47bbLennart Poettering static const char * const rlmap[] = {
if (!in_initrd())
if (in_initrd())
arg_dump_core = r;
arg_crash_shell = r;
arg_confirm_spawn = r;
arg_crash_chvt = k;
arg_show_status = r;
if (!cenv)
return -ENOMEM;
char **env;
if (env)
c = word;
"rd.systemd.unit=UNIT Default unit to start when run in initrd\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 Show status updates on the console during bootup\n"
"systemd.default_standard_output=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
"systemd.default_standard_error=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
"systemd.setenv=ASSIGNMENT Set an environment variable for all spawned processes\n");
arg_show_status = false;
} else if (!in_initrd()) {
const char *filename, \
unsigned line, \
const char *section, \
const char *lvalue, \
int ltype, \
const char *rvalue, \
void *data, \
void *userdata) { \
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
size_t l;
char *state;
unsigned ncpus = 0;
unsigned cpu;
if (!(t = strndup(w, l)))
return log_oom();
free(t);
return log_oom();
CPU_FREE(c);
return -EBADMSG;
CPU_FREE(c);
static void strv_free_free(char ***l) {
strv_free(*i);
free(l);
static void free_join_controllers(void) {
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char *state, *w;
return log_oom();
free(s);
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)) {
c = strv_merge(*a, l);
strv_free(l);
strv_free_free(t);
return log_oom();
strv_free(l);
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 },
{ "Manager", "DefaultLimitSIGPENDING",config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING]},
const char *fn;
r = config_parse(NULL, fn, f, "Manager\0", config_item_table_lookup, (void*) items, false, false, NULL);
static int parse_proc_cmdline(void) {
char *w, *state;
size_t l;
if (!word)
return log_oom();
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_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:
arg_show_status = r;
case ARG_DESERIALIZE: {
int fd;
FILE *f;
if (r < 0 || fd < 0) {
return r < 0 ? r : -EINVAL;
return -errno;
if (serialization)
serialization = f;
case ARG_SWITCHED_ROOT:
arg_switched_root = true;
return -EINVAL;
return -EINVAL;
r = parse_proc_cmdline_word(*a);
static int help(void) {
" --log-target=TARGET Set log target (console, journal, syslog, kmsg, journal-or-kmsg, syslog-or-kmsg, null)\n"
static int version(void) {
assert(m);
r = manager_open_serialization(m, &f);
goto fail;
m->n_reloading ++;
bus_broadcast_reloading(m, true);
if (!fds) {
r = -ENOMEM;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
*_f = f;
fail:
fclose(f);
return -errno;
if (!rl)
return log_oom();
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.");
static int initialize_join_controllers(void) {
if (!arg_join_controllers)
return -ENOMEM;
return -ENOMEM;
bool reexecute = false;
bool skip_setup = false;
bool loaded_policy = false;
bool arm_reboot_watchdog = false;
bool queue_default_job = false;
#ifdef HAVE_SYSV_COMPAT
skip_setup = true;
skip_setup = false;
umask(0);
log_open();
if (in_initrd())
if (!skip_setup) {
goto finish;
if (ima_setup() < 0)
goto finish;
if (smack_setup() < 0)
goto finish;
goto finish;
if (!skip_setup) {
if (hwclock_is_localtime() > 0) {
int min;
} else if (!in_initrd()) {
log_open();
log_open();
goto finish;
r = initialize_join_controllers();
goto finish;
goto finish;
if (parse_config_file() < 0)
goto finish;
if (parse_proc_cmdline() < 0)
goto finish;
goto finish;
geteuid() == 0) {
goto finish;
sd_booted() <= 0) {
goto finish;
running_in_chroot() > 0) {
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
log_close();
goto finish;
if (serialization)
setsid();
log_open();
goto finish;
if (virtualization)
if (in_initrd())
#ifdef HAVE_KMOD
kmod_setup();
test_mtab();
test_usr();
test_cgroups();
goto finish;
goto finish;
goto finish;
if (serialization) {
if (queue_default_job) {
goto finish;
goto finish;
goto finish;
if (r == -EPERM) {
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);
for (j = 0; j < RLIMIT_NLIMITS; j++)
label_finish();
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)
clearenv();
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;