main.c revision db813c2a9199d694f8e97618889425a2401524d6
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2010 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_dump_core = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_crash_shell = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_confirm_spawn = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_show_status = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_switched_root = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic char **arg_default_controllers = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic char ***arg_join_controllers = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {};
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic uint64_t arg_capability_bounding_set_drop = 0;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic nsec_t arg_timer_slack_nsec = (nsec_t) -1;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* We want to wait for the core process, hence let's enable SIGCHLD */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Caught <%s>, cannot fork for core dump: %s", signal_to_string(sig), strerror(errno));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering else if (pid == 0) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Enable default signal handler for core dump */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert_se(sigaction(sig, &sa, NULL) == 0);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* Don't limit the core dump size */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* Just to be sure... */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* Raise the signal again */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering assert_not_reached("We shouldn't be here...");
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* Order things nicely. */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if ((r = wait_for_terminate(pid, &status)) < 0)
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r));
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_error("Caught <%s>, core dump failed.", signal_to_string(sig));
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_error("Caught <%s>, dumped core as pid %lu.", signal_to_string(sig), (unsigned long) pid);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_info("Executing crash shell in 10s...");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Let the kernel reap children for us */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to fork off crash shell: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else if (pid == 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_info("Successfully spawned crash shell as pid %lu.", (unsigned long) pid);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void install_crash_handler(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* If we are init, we connect stdin/stdout/stderr to /dev/null
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * and make sure we don't have a controlling tty. */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* We don't want to force text mode.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * plymouth may be showing pictures already from initrd. */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_error("Failed to reset /dev/console: %s", strerror(-r));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int set_default_unit(const char *u) {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poetteringstatic int parse_proc_cmdline_word(const char *word) {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering static const char * const rlmap[] = {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "rd.systemd.unit=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.log_target=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if (log_set_target_from_string(word + 19) < 0)
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse log target %s. Ignoring.", word + 19);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.log_level=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if (log_set_max_level_from_string(word + 18) < 0)
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse log level %s. Ignoring.", word + 18);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.log_color=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if (log_show_color_from_string(word + 18) < 0)
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse log color setting %s. Ignoring.", word + 18);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.log_location=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if (log_show_location_from_string(word + 21) < 0)
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse log location setting %s. Ignoring.", word + 21);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.dump_core=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse dump core switch %s. Ignoring.", word + 18);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.crash_shell=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse crash shell switch %s. Ignoring.", word + 20);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.confirm_spawn=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse confirm spawn switch %s. Ignoring.", word + 22);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.crash_chvt=")) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_warning("Failed to parse crash chvt switch %s. Ignoring.", word + 19);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (startswith(word, "systemd.show_status=")) {
arg_show_status = r;
char *eq;
if (!cenv)
return -ENOMEM;
if (!eq) {
*eq = 0;
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()) {
static int config_parse_level2(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
static int config_parse_target(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
static int config_parse_color(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
static int config_parse_location(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
static int config_parse_cpu_affinity2(
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) {
if (!arg_join_controllers)
static int config_parse_join_controllers(
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]},
FILE *f;
const char *fn;
fclose(f);
static int parse_proc_cmdline(void) {
size_t l;
char *word;
r = -ENOMEM;
goto finish;
goto finish;
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;
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) {
" --log-target=TARGET Set log target (console, journal, syslog, kmsg, journal-or-kmsg, syslog-or-kmsg, null)\n"
static int version(void) {
assert(m);
m->n_reloading ++;
r = manager_open_serialization(m, &f);
goto fail;
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();
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.");
static int initialize_join_controllers(void) {
if (!arg_join_controllers)
return -ENOMEM;
if (!arg_join_controllers[0])
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;
log_open();
if (in_initrd()) {
if (rd_timestamp) {
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;
log_close();
goto finish;
if (serialization)
#ifdef HAVE_SPLIT_USR
if (!in_initrd())
setsid();
umask(0);
log_open();
goto finish;
if (virtualization)
if (in_initrd())
locale_setup();
#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 (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;