main.c revision ee05e7795bb9ad7d1212dd49ad362f3e9603c4fd
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include <fcntl.h>
#ifdef HAVE_VALGRIND_VALGRIND_H
#include <valgrind/valgrind.h>
#endif
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
#include "sd-daemon.h"
#include "sd-messages.h"
#include "sd-bus.h"
#include "manager.h"
#include "log.h"
#include "load-fragment.h"
#include "fdset.h"
#include "special.h"
#include "conf-parser.h"
#include "missing.h"
#include "label.h"
#include "pager.h"
#include "build.h"
#include "strv.h"
#include "def.h"
#include "virt.h"
#include "architecture.h"
#include "watchdog.h"
#include "path-util.h"
#include "switch-root.h"
#include "capability.h"
#include "killall.h"
#include "env-util.h"
#include "clock-util.h"
#include "fileio.h"
#include "dbus-manager.h"
#include "bus-error.h"
#include "bus-util.h"
#include "mount-setup.h"
#include "loopback-setup.h"
#include "hostname-setup.h"
#include "machine-id-setup.h"
#include "selinux-setup.h"
#include "ima-setup.h"
#include "smack-setup.h"
#include "kmod-setup.h"
static enum {
} arg_action = ACTION_RUN;
static char *arg_default_unit = NULL;
static bool arg_dump_core = true;
static bool arg_crash_shell = false;
static int arg_crash_chvt = -1;
static bool arg_confirm_spawn = false;
static bool arg_switched_root = false;
static int arg_no_pager = -1;
static char ***arg_join_controllers = NULL;
static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
static usec_t arg_runtime_watchdog = 0;
static char **arg_default_environment = NULL;
static uint64_t arg_capability_bounding_set_drop = 0;
static bool arg_default_cpu_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static void nop_handler(int sig) {}
static void pager_open_if_enabled(void) {
if (arg_no_pager <= 0)
return;
pager_open(false);
}
if (getpid() != 1)
/* Pass this on immediately, if this is not PID 1 */
else if (!arg_dump_core)
else {
};
/* We want to wait for the core process, hence let's enable SIGCHLD */
if (pid < 0)
else if (pid == 0) {
/* Enable default signal handler for core dump */
/* Don't limit the core dump size */
/* Just to be sure... */
chdir("/");
/* Raise the signal again */
pid = raw_getpid();
assert_not_reached("We shouldn't be here...");
_exit(1);
} else {
int r;
/* Order things nicely. */
if (r < 0)
else
}
}
if (arg_crash_chvt)
if (arg_crash_shell) {
.sa_handler = SIG_IGN,
};
log_info("Executing crash shell in 10s...");
sleep(10);
/* Let the kernel reap children for us */
if (pid < 0)
else if (pid == 0) {
_exit(1);
} else
}
log_emergency("Freezing execution.");
freeze();
}
static void install_crash_handler(void) {
.sa_handler = crash,
.sa_flags = SA_NODEFER,
};
}
static int console_setup(void) {
int r;
if (tty_fd < 0)
/* We don't want to force text mode. plymouth may be showing
* pictures already from initrd. */
r = reset_terminal_fd(tty_fd, false);
if (r < 0)
return log_error_errno(r, "Failed to reset /dev/console: %m");
return 0;
}
static int set_default_unit(const char *u) {
char *c;
assert(u);
c = strdup(u);
if (!c)
return -ENOMEM;
arg_default_unit = c;
return 0;
}
static const char * const rlmap[] = {
"emergency", SPECIAL_EMERGENCY_TARGET,
"-b", SPECIAL_EMERGENCY_TARGET,
"rescue", SPECIAL_RESCUE_TARGET,
"single", SPECIAL_RESCUE_TARGET,
"-s", SPECIAL_RESCUE_TARGET,
"s", SPECIAL_RESCUE_TARGET,
"S", SPECIAL_RESCUE_TARGET,
"1", SPECIAL_RESCUE_TARGET,
"2", SPECIAL_RUNLEVEL2_TARGET,
"3", SPECIAL_RUNLEVEL3_TARGET,
"4", SPECIAL_RUNLEVEL4_TARGET,
"5", SPECIAL_RUNLEVEL5_TARGET,
};
int r;
if (!in_initrd())
return set_default_unit(value);
if (in_initrd())
return set_default_unit(value);
r = parse_boolean(value);
if (r < 0)
else
arg_dump_core = r;
r = parse_boolean(value);
if (r < 0)
else
arg_crash_shell = r;
else
arg_crash_chvt = r;
r = parse_boolean(value);
if (r < 0)
else
arg_confirm_spawn = r;
if (r < 0)
r = exec_output_from_string(value);
if (r < 0)
else
r = exec_output_from_string(value);
if (r < 0)
else
if (env_assignment_is_valid(value)) {
char **env;
if (env)
else
} else
if (arg_show_status == _SHOW_STATUS_UNSET)
/* Note that log_parse_environment() handles 'debug'
* too, and sets the log level to LOG_DEBUG. */
if (detect_container(NULL) > 0)
unsigned i;
/* SysV compatibility */
}
return 0;
}
const char *filename, \
unsigned line, \
const char *section, \
unsigned section_line, \
const char *lvalue, \
int ltype, \
const char *rvalue, \
void *data, \
void *userdata) { \
\
int r; \
\
\
if (r < 0) \
\
return 0; \
}
static int config_parse_cpu_affinity2(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
size_t l;
unsigned ncpus = 0;
char *t;
int r;
unsigned cpu;
return log_oom();
free(t);
if (!c)
if (!(c = cpu_set_malloc(&ncpus)))
return log_oom();
"Failed to parse CPU affinity '%s'", rvalue);
CPU_FREE(c);
return -EBADMSG;
}
}
"Trailing garbage, ignoring.");
if (c) {
CPU_FREE(c);
}
return 0;
}
static int config_parse_show_status(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
int k;
ShowStatus *b = data;
k = parse_show_status(rvalue, b);
if (k < 0) {
"Failed to parse show status setting, ignoring: %s", rvalue);
return 0;
}
return 0;
}
static void strv_free_free(char ***l) {
char ***i;
if (!l)
return;
for (i = l; *i; i++)
strv_free(*i);
free(l);
}
static void free_join_controllers(void) {
}
static int config_parse_join_controllers(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
unsigned n = 0;
char *s, **l;
if (!s)
return log_oom();
l = strv_split(s, ",");
free(s);
strv_uniq(l);
if (strv_length(l) <= 1) {
strv_free(l);
continue;
}
if (!arg_join_controllers) {
if (!arg_join_controllers) {
strv_free(l);
return log_oom();
}
arg_join_controllers[0] = l;
n = 1;
} else {
char ***a;
char ***t;
t = new0(char**, n+2);
if (!t) {
strv_free(l);
return log_oom();
}
n = 0;
for (a = arg_join_controllers; *a; a++) {
if (strv_overlap(*a, l)) {
if (strv_extend_strv(&l, *a) < 0) {
strv_free(l);
strv_free_free(t);
return log_oom();
}
} else {
char **c;
c = strv_copy(*a);
if (!c) {
strv_free(l);
strv_free_free(t);
return log_oom();
}
t[n++] = c;
}
}
t[n++] = strv_uniq(l);
arg_join_controllers = t;
}
}
"Trailing garbage, ignoring.");
return 0;
}
static int parse_config_file(void) {
const ConfigTableItem items[] = {
{ "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop },
#ifdef HAVE_SECCOMP
#endif
{ "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
{}
};
const char *fn, *conf_dirs_nulstr;
conf_dirs_nulstr = arg_running_as == SYSTEMD_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
return 0;
}
enum {
ARG_LOG_LEVEL = 0x100,
};
{}
};
int c, r;
if (getpid() == 1)
opterr = 0;
switch (c) {
case ARG_LOG_LEVEL:
if (r < 0) {
return r;
}
break;
case ARG_LOG_TARGET:
if (r < 0) {
return r;
}
break;
case ARG_LOG_COLOR:
if (optarg) {
if (r < 0) {
return r;
}
} else
log_show_color(true);
break;
case ARG_LOG_LOCATION:
if (optarg) {
if (r < 0) {
return r;
}
} else
log_show_location(true);
break;
case ARG_DEFAULT_STD_OUTPUT:
if (r < 0) {
return r;
} else
break;
case ARG_DEFAULT_STD_ERROR:
if (r < 0) {
return r;
} else
break;
case ARG_UNIT:
r = set_default_unit(optarg);
if (r < 0)
break;
case ARG_SYSTEM:
break;
case ARG_USER:
break;
case ARG_TEST:
if (arg_no_pager < 0)
arg_no_pager = true;
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_VERSION:
break;
break;
case ARG_DUMP_CORE:
if (r < 0) {
return r;
}
arg_dump_core = r;
break;
case ARG_CRASH_SHELL:
if (r < 0) {
return r;
}
arg_crash_shell = r;
break;
case ARG_CONFIRM_SPAWN:
if (r < 0) {
return r;
}
arg_confirm_spawn = r;
break;
case ARG_SHOW_STATUS:
if (optarg) {
if (r < 0) {
return r;
}
} else
break;
case ARG_DESERIALIZE: {
int fd;
FILE *f;
if (r < 0 || fd < 0) {
return r < 0 ? r : -EINVAL;
}
fd_cloexec(fd, true);
if (!f)
if (arg_serialization)
arg_serialization = f;
break;
}
case ARG_SWITCHED_ROOT:
arg_switched_root = true;
break;
case 'h':
if (arg_no_pager < 0)
arg_no_pager = true;
break;
case 'D':
break;
case 'b':
case 's':
case 'z':
/* Just to eat away the sysvinit kernel
* cmdline args without getopt() error
* messages that we'll parse in
* parse_proc_cmdline_word() or ignore. */
case '?':
if (getpid() != 1)
return -EINVAL;
else
return 0;
default:
assert_not_reached("Unhandled option code.");
}
/* Hmm, when we aren't run as init system
* let's complain about excess arguments */
log_error("Excess arguments.");
return -EINVAL;
}
return 0;
}
static int help(void) {
printf("%s [OPTIONS...]\n\n"
"Starts up and maintains the system or user services.\n\n"
" -h --help Show this help\n"
" --test Determine startup sequence, dump it and exit\n"
" --no-pager Do not pipe output into a pager\n"
" --dump-configuration-items Dump understood unit configuration items\n"
" --unit=UNIT Set default unit\n"
" --system Run a system instance, even if PID != 1\n"
" --user Run a user instance\n"
" --dump-core[=0|1] Dump core on crash\n"
" --crash-shell[=0|1] Run shell on crash\n"
" --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n"
" --show-status[=0|1] Show status updates on the console during bootup\n"
" --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n"
" --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
" --log-color[=0|1] Highlight important log messages\n"
" --log-location[=0|1] Include code location in log messages\n"
" --default-standard-output= Set default standard output for services\n"
" --default-standard-error= Set default standard error output for services\n",
return 0;
}
static int version(void) {
return 0;
}
int r;
assert(m);
r = manager_open_serialization(m, &f);
if (r < 0) {
log_error_errno(r, "Failed to create serialization file: %m");
goto fail;
}
/* Make sure nothing is really destructed when we shut down */
m->n_reloading ++;
bus_manager_send_reloading(m, true);
if (!fds) {
r = -ENOMEM;
log_error_errno(r, "Failed to allocate fd set: %m");
goto fail;
}
if (r < 0) {
log_error_errno(r, "Failed to serialize state: %m");
goto fail;
}
goto fail;
}
r = fd_cloexec(fileno(f), false);
if (r < 0) {
log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
goto fail;
}
r = fdset_cloexec(fds, false);
if (r < 0) {
log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
goto fail;
}
*_f = f;
return 0;
fail:
if (f)
fclose(f);
return r;
}
int r;
/* Save the original RLIMIT_NOFILE so that we can reset it
* later when transitioning from the initrd to the main
* systemd or suchlike. */
/* Make sure forked processes get the default kernel setting */
if (!arg_default_rlimit[RLIMIT_NOFILE]) {
if (!rl)
return log_oom();
}
/* Bump up the resource limit for ourselves substantially */
if (r < 0)
return log_error_errno(r, "Setting RLIMIT_NOFILE failed: %m");
return 0;
}
static void test_mtab(void) {
static const char ok[] =
_cleanup_free_ char *p = NULL;
int r;
* non-existing. But certainly not a file, or a symlink to
* some weird place... */
r = readlink_malloc("/etc/mtab", &p);
if (r == -ENOENT)
return;
if (r >= 0 && nulstr_contains(ok, p))
return;
"This is not supported anymore. "
"Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
}
static void test_usr(void) {
/* Check that /usr is not a separate fs */
if (dir_is_empty("/usr") <= 0)
return;
log_warning("/usr appears to be on its own filesytem and is not already mounted. This is not a supported setup. "
"Some things will probably break (sometimes even silently) in mysterious ways. "
"Consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken for more information.");
}
static int initialize_join_controllers(void) {
/* By default, mount "cpu" + "cpuacct" together, and "net_cls"
* + "net_prio". We'd like to add "cpuset" to the mix, but
* "cpuset" does't really work for groups with no initialized
* attributes. */
if (!arg_join_controllers)
return -ENOMEM;
return -ENOMEM;
}
return 0;
}
#ifdef HAVE_SECCOMP
Iterator i;
void *id;
int r;
if (!seccomp)
return log_oom();
if (r == -EEXIST)
continue;
if (r < 0) {
log_error_errno(r, "Failed to add architecture to seccomp: %m");
goto finish;
}
}
if (r < 0) {
log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m");
goto finish;
}
r = seccomp_load(seccomp);
if (r < 0)
log_error_errno(r, "Failed to add install architecture seccomp: %m");
return r;
#else
return 0;
#endif
}
static int status_welcome(void) {
int r;
"PRETTY_NAME", &pretty_name,
"ANSI_COLOR", &ansi_color,
NULL);
if (r == -ENOENT) {
"PRETTY_NAME", &pretty_name,
"ANSI_COLOR", &ansi_color,
NULL);
}
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read os-release file: %m");
return status_printf(NULL, false, false,
"\nWelcome to \x1B[%sm%s\x1B[0m!\n",
}
static int write_container_id(void) {
const char *c;
c = getenv("container");
if (isempty(c))
return 0;
return write_string_file("/run/systemd/container", c);
}
int r, retval = EXIT_FAILURE;
char timespan[FORMAT_TIMESPAN_MAX];
bool reexecute = false;
const char *shutdown_verb = NULL;
static char systemd[] = "systemd";
bool skip_setup = false;
unsigned j;
bool loaded_policy = false;
bool arm_reboot_watchdog = false;
bool queue_default_job = false;
bool empty_etc = false;
static struct rlimit saved_rlimit_nofile = { 0, 0 };
const char *error_message = NULL;
#ifdef HAVE_SYSV_COMPAT
/* This is compatibility support for SysV, where
* calling init as a user is identical to telinit. */
return 1;
}
#endif
/* Determine if this is a reexecution or normal bootup. We do
* the full command line parsing much later, so let's just
* have a quick peek here. */
skip_setup = true;
/* If we have switched root, do all the special setup
* things */
skip_setup = false;
called 'init'. After a subsequent reexecution we are then
called 'systemd'. That is confusing, hence let's call us
systemd right-away. */
saved_argv = argv;
saved_argc = argc;
/* Disable the umask logic */
if (getpid() == 1)
umask(0);
/* Running outside of a container as PID 1 */
log_open();
if (in_initrd())
if (!skip_setup) {
if (mac_selinux_setup(&loaded_policy) < 0) {
error_message = "Failed to load SELinux policy";
goto finish;
} else if (ima_setup() < 0) {
error_message = "Failed to load IMA policy";
goto finish;
} else if (mac_smack_setup(&loaded_policy) < 0) {
error_message = "Failed to load SMACK policy";
goto finish;
}
}
if (mac_selinux_init(NULL) < 0) {
error_message = "Failed to initialize SELinux policy";
goto finish;
}
if (!skip_setup) {
if (clock_is_localtime() > 0) {
int min;
/*
* The very first call of settimeofday() also does a time warp in the kernel.
*
* In the rtc-in-local time mode, we set the kernel's timezone, and rely on
* external tools to take care of maintaining the RTC and do all adjustments.
* This matches the behavior of Windows, which leaves the RTC alone if the
* registry tells that the RTC runs in UTC.
*/
r = clock_set_timezone(&min);
if (r < 0)
log_error_errno(r, "Failed to apply local time delta, ignoring: %m");
else
} else if (!in_initrd()) {
/*
* Do a dummy very first call to seal the kernel's time warp magic.
*
* Do not call this this from inside the initrd. The initrd might not
* that way. In such case, we need to delay the time-warp or the sealing
* until we reach the real system.
*
* Do no set the kernel's timezone. The concept of local time cannot
* be supported reliably, the time will jump or be incorrect at every daylight
* saving time change. All kernel local time concepts will be treated
* as UTC that way.
*/
}
}
/* Set the default for later on, but don't actually
* open the logs like this for now. Note that if we
* are transitioning from the initrd there might still
* be journal fd open, and we shouldn't attempt
* might redirect output elsewhere. */
} else if (getpid() == 1) {
/* Running inside a container, as PID 1 */
log_close_console(); /* force reopen of /dev/console */
log_open();
/* For the later on, see above... */
/* clear the kernel timestamp,
* because we are in a container */
} else {
/* Running as user instance */
log_open();
/* clear the kernel timestamp,
* because we are not PID 1 */
}
/* Initialize default unit */
if (r < 0) {
error_message = "Failed to set default unit";
goto finish;
}
r = initialize_join_controllers();
if (r < 0) {
error_message = "Failed to initalize cgroup controllers";
goto finish;
}
if (getpid() == 1) {
/* Load the kernel modules early, so that we kdbus.ko is loaded before kdbusfs shall be mounted */
if (!skip_setup)
kmod_setup();
r = mount_setup(loaded_policy);
if (r < 0) {
error_message = "Failed to mount API filesystems";
goto finish;
}
}
/* Reset all signal handlers. */
assert_se(reset_all_signal_handlers() == 0);
if (parse_config_file() < 0) {
error_message = "Failed to parse config file";
goto finish;
}
if (arg_running_as == SYSTEMD_SYSTEM) {
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
}
/* Note that this also parses bits from the kernel command
* line, including "debug". */
error_message = "Failed to parse commandline arguments";
goto finish;
}
if (arg_action == ACTION_TEST &&
geteuid() == 0) {
log_error("Don't run test mode as root.");
goto finish;
}
if (arg_running_as == SYSTEMD_USER &&
arg_action == ACTION_RUN &&
sd_booted() <= 0) {
log_error("Trying to run as user instance, but the system has not been booted with systemd.");
goto finish;
}
if (arg_running_as == SYSTEMD_SYSTEM &&
arg_action == ACTION_RUN &&
running_in_chroot() > 0) {
log_error("Cannot be run in a chroot() environment.");
goto finish;
}
if (arg_action == ACTION_TEST)
skip_setup = true;
if (arg_action == ACTION_HELP) {
goto finish;
} else if (arg_action == ACTION_VERSION) {
goto finish;
} else if (arg_action == ACTION_DUMP_CONFIGURATION_ITEMS) {
goto finish;
} else if (arg_action == ACTION_DONE) {
goto finish;
}
if (arg_running_as == SYSTEMD_USER &&
!getenv("XDG_RUNTIME_DIR")) {
log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
goto finish;
}
/* Close logging fds, in order not to confuse fdset below */
log_close();
/* Remember open file descriptors for later deserialization */
r = fdset_new_fill(&fds);
if (r < 0) {
log_emergency_errno(r, "Failed to allocate fd set: %m");
error_message = "Failed to allocate fd set";
goto finish;
} else
fdset_cloexec(fds, true);
if (arg_serialization)
if (arg_running_as == SYSTEMD_SYSTEM)
/* Become a session leader if we aren't one yet. */
setsid();
/* Move out of the way, so that we won't block unmounts */
/* Reset the console, but only if this is really init and we
* are freshly booted */
* tty. */
}
/* Open the logging devices, if possible and necessary */
log_open();
if (arg_show_status == _SHOW_STATUS_UNSET)
/* Make sure we leave a core dump without panicing the
* kernel. */
if (getpid() == 1) {
if (r < 0)
goto finish;
}
if (arg_running_as == SYSTEMD_SYSTEM) {
const char *virtualization = NULL;
if (virtualization)
if (in_initrd())
log_info("Running in initial RAM disk.");
/* Let's check whether /etc is already populated. We
* don't actually really check for that, but use
* /etc/machine-id as flag file. This allows container
* managers and installers to provision a couple of
* files already. If the container manager wants to
* provision the machine ID itself it should pass
* $container_uuid to PID 1. */
if (empty_etc)
log_info("Running with unpopulated /etc.");
} else {
_cleanup_free_ char *t;
t = uid_to_name(getuid());
}
if (arg_show_status > 0 || plymouth_running())
test_mtab();
test_usr();
}
if (arg_timer_slack_nsec != NSEC_INFINITY)
if (r < 0) {
log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
error_message = "Failed to drop capability bounding set of usermode helpers";
goto finish;
}
if (r < 0) {
log_emergency_errno(r, "Failed to drop capability bounding set: %m");
error_message = "Failed to drop capability bounding set";
goto finish;
}
}
if (arg_syscall_archs) {
if (r < 0) {
error_message = "Failed to set syscall architectures";
goto finish;
}
}
if (arg_running_as == SYSTEMD_USER) {
/* Become reaper of our children */
log_info("Perhaps the kernel version is too old (< 3.4?)");
}
}
if (arg_running_as == SYSTEMD_SYSTEM) {
if (empty_etc) {
if (r < 0)
log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m");
else
log_info("Populated /etc with preset unit settings.");
}
}
if (r < 0) {
log_emergency_errno(r, "Failed to allocate manager object: %m");
error_message = "Failed to allocate manager object";
goto finish;
}
/* Remember whether we should queue the default job */
if (r < 0)
log_error_errno(r, "Failed to fully start up daemon: %m");
/* This will close all file descriptors that were opened, but
* not claimed by any unit. */
if (arg_serialization) {
}
if (queue_default_job) {
if (r < 0)
log_error("Default target masked.");
log_info("Trying to load rescue target...");
if (r < 0) {
error_message = "Failed to load rescue target";
goto finish;
error_message = "Failed to load rescue target";
goto finish;
log_emergency("Rescue target masked.");
error_message = "Rescue target masked";
goto finish;
}
}
if (arg_action == ACTION_TEST) {
printf("-> By units:\n");
}
if (r == -EPERM) {
log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
if (r < 0) {
error_message = "Failed to start default target";
goto finish;
}
} else if (r < 0) {
error_message = "Failed to isolate default target";
goto finish;
}
"Loaded units and determined initial transaction in %s.",
if (arg_action == ACTION_TEST) {
printf("-> By jobs:\n");
goto finish;
}
}
for (;;) {
r = manager_loop(m);
if (r < 0) {
log_emergency_errno(r, "Failed to run main loop: %m");
error_message = "Failed to run main loop";
goto finish;
}
switch (m->exit_code) {
case MANAGER_EXIT:
log_debug("Exit.");
goto finish;
case MANAGER_RELOAD:
log_info("Reloading.");
r = manager_reload(m);
if (r < 0)
log_error_errno(r, "Failed to reload: %m");
break;
case MANAGER_REEXECUTE:
error_message = "Failed to prepare for reexection";
goto finish;
}
reexecute = true;
log_notice("Reexecuting.");
goto finish;
case MANAGER_SWITCH_ROOT:
/* Steal the switch root parameters */
switch_root_dir = m->switch_root;
if (!switch_root_init)
error_message = "Failed to prepare for reexection";
goto finish;
}
reexecute = true;
log_notice("Switching root.");
goto finish;
case MANAGER_REBOOT:
case MANAGER_POWEROFF:
case MANAGER_HALT:
case MANAGER_KEXEC: {
static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
[MANAGER_REBOOT] = "reboot",
[MANAGER_POWEROFF] = "poweroff",
[MANAGER_HALT] = "halt",
[MANAGER_KEXEC] = "kexec"
};
log_notice("Shutting down.");
goto finish;
}
default:
assert_not_reached("Unknown exit code.");
}
}
pager_close();
m = manager_free(m);
for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) {
free(arg_default_rlimit[j]);
arg_default_rlimit[j] = NULL;
}
if (reexecute) {
const char **args;
unsigned i, args_size;
/* Close and disarm the watchdog, so that the new
* instance can reinitialize it, but doesn't get
* rebooted while we do that */
watchdog_close(true);
/* Reset the RLIMIT_NOFILE to the kernel default, so
* that the new systemd can pass the kernel default to
* its child processes */
if (saved_rlimit_nofile.rlim_cur > 0)
if (switch_root_dir) {
/* Kill all remaining processes from the
* initrd, but don't wait for them, so that we
* can handle the SIGCHLD for them after
* deserializing. */
broadcast_signal(SIGTERM, false, true);
/* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */
if (r < 0)
log_error_errno(r, "Failed to switch root, trying to continue: %m");
}
if (!switch_root_init) {
char sfd[16];
/* First try to spawn ourselves with the right
* path, and with full serialization. We do
* this only if the user didn't specify an
* explicit init to spawn. */
i = 0;
args[i++] = SYSTEMD_BINARY_PATH;
if (switch_root_dir)
args[i++] = "--switched-root";
args[i++] = "--deserialize";
/* do not pass along the environment we inherit from the kernel or initrd */
if (switch_root_dir)
clearenv();
}
/* Try the fallback, if there is any, without any
* serialization. We pass the original argv[] and
* envp[]. (Well, modulo the ordering changes due to
* getopt() in argv[], and some cleanups in envp[],
* but let's hope that doesn't matter.) */
if (arg_serialization) {
}
if (fds) {
}
/* Reopen the console */
/* Reenable any blocked signals, especially important
* if we switch from initial ramdisk to init=... */
if (switch_root_init) {
args[0] = switch_root_init;
}
log_warning("No /sbin/init, trying fallback");
} else
}
if (arg_serialization) {
}
if (fds) {
}
#ifdef HAVE_VALGRIND_VALGRIND_H
/* If we are PID 1 and running under valgrind, then let's exit
* here explicitly. valgrind will only generate nice output on
* exit(), not on exec(), hence let's do the former not the
* latter here. */
return 0;
#endif
if (shutdown_verb) {
const char* command_line[9] = {
"--log-level", log_level,
"--log-target",
};
unsigned pos = 5;
switch (log_get_target()) {
case LOG_TARGET_KMSG:
break;
case LOG_TARGET_CONSOLE:
default:
break;
};
if (log_get_show_color())
if (log_get_show_location())
if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) {
char *e;
/* If we reboot let's set the shutdown
* watchdog and tell the shutdown binary to
* repeatedly ping it */
watchdog_close(false);
/* Tell the binary how often to ping, ignore failure */
} else
watchdog_close(true);
/* Avoid the creation of new processes forked by the
* kernel; at this point, we will not listen to the
* signals anyway */
if (detect_container(NULL) <= 0)
}
if (getpid() == 1) {
if (error_message)
"%s, freezing.", error_message);
freeze();
}
return retval;
}