main.c revision a07fdfa376add41d9101d39db25fb2ecb17d5fca
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering This file is part of systemd.
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering Copyright 2010 Lennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering systemd is free software; you can redistribute it and/or modify it
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering under the terms of the GNU Lesser General Public License as published by
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering (at your option) any later version.
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering systemd is distributed in the hope that it will be useful, but
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering Lesser General Public License for more details.
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering You should have received a copy of the GNU Lesser General Public License
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic bool arg_dump_core = true;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic bool arg_crash_shell = false;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic bool arg_confirm_spawn = false;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic bool arg_show_status = true;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic bool arg_switched_root = false;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic char **arg_default_controllers = NULL;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic char ***arg_join_controllers = NULL;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {};
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic uint64_t arg_capability_bounding_set_drop = 0;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poetteringstatic nsec_t arg_timer_slack_nsec = (nsec_t) -1;
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering /* We want to wait for the core process, hence let's enable SIGCHLD */
else if (pid == 0) {
if (arg_crash_chvt)
if (arg_crash_shell) {
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;
if (!cenv)
return -ENOMEM;
if (!eq) {
*eq = 0;
"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 (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;
goto finish;
if (!skip_setup) {
if (hwclock_is_localtime() > 0) {
int min;
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;
goto finish;
running_in_chroot() > 0) {
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
log_close();
if (serialization) {
goto finish;
#ifdef HAVE_SPLIT_USR
if (!in_initrd())
setsid();
umask(0);
log_open();
goto finish;
if (virtualization)
if (in_initrd())
locale_setup();
kmod_setup();
test_mtab();
test_usr();
test_cgroups();
goto finish;
goto finish;
goto finish;
if (fds) {
if (serialization) {
if (queue_default_job) {
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);
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;