main.c revision c3a170f3d3358135a39ac6eafe66f18aef0bd67d
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering This file is part of systemd.
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering Copyright 2010 Lennart Poettering
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering systemd is free software; you can redistribute it and/or modify it
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering under the terms of the GNU Lesser General Public License as published by
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering (at your option) any later version.
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering systemd is distributed in the hope that it will be useful, but
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering Lesser General Public License for more details.
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering You should have received a copy of the GNU Lesser General Public License
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic bool arg_dump_core = true;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic bool arg_crash_shell = false;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic bool arg_confirm_spawn = false;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic bool arg_show_status = true;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic bool arg_switched_root = false;
3c5a87a879e3eb66c9c159a26051d940ff2db7a1Lennart Poetteringstatic char **arg_default_controllers = NULL;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic char ***arg_join_controllers = NULL;
3c5a87a879e3eb66c9c159a26051d940ff2db7a1Lennart Poetteringstatic ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poetteringstatic struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {};
94c156cd452424ea59931920df2454d9da7cb774Lennart Poetteringstatic uint64_t arg_capability_bounding_set_drop = 0;
94c156cd452424ea59931920df2454d9da7cb774Lennart Poetteringstatic nsec_t arg_timer_slack_nsec = (nsec_t) -1;
3c5a87a879e3eb66c9c159a26051d940ff2db7a1Lennart Poettering log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
3c5a87a879e3eb66c9c159a26051d940ff2db7a1Lennart Poettering /* We want to wait for the core process, hence let's enable SIGCHLD */
3c5a87a879e3eb66c9c159a26051d940ff2db7a1Lennart Poettering assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
3c5a87a879e3eb66c9c159a26051d940ff2db7a1Lennart Poettering log_error("Caught <%s>, cannot fork for core dump: %s", signal_to_string(sig), strerror(errno));
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering else if (pid == 0) {
3c5a87a879e3eb66c9c159a26051d940ff2db7a1Lennart Poettering /* Enable default signal handler for core dump */
94c156cd452424ea59931920df2454d9da7cb774Lennart Poettering assert_se(sigaction(sig, &sa, NULL) == 0);
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering /* Don't limit the core dump size */
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering /* Just to be sure... */
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering /* Raise the signal again */
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering assert_not_reached("We shouldn't be here...");
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering /* Order things nicely. */
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r));
b5884878a2874447b2a9f07f324a7cd909d96d48Lennart Poettering log_error("Caught <%s>, core dump failed.", signal_to_string(sig));
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering log_error("Caught <%s>, dumped core as pid %lu.", signal_to_string(sig), (unsigned long) pid);
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering log_info("Executing crash shell in 10s...");
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering /* Let the kernel reap children for us */
326bb68c40ff2a7119c344b9ab7a7473f9fcdf3cLennart Poettering assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
if (pid < 0)
else if (pid == 0) {
freeze();
static void install_crash_handler(void) {
int tty_fd, r;
if (!do_reset)
if (tty_fd < 0) {
return -tty_fd;
static int set_default_unit(const char *u) {
assert(u);
c = strdup(u);
return -ENOMEM;
arg_default_unit = c;
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;
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()) {
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;
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;
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;
#ifdef ENABLE_EFI
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;