#include "watchdog.h"
#include "path-util.h"
#include "switch-root.h"
+#include "capability.h"
#include "mount-setup.h"
#include "loopback-setup.h"
static int arg_crash_chvt = -1;
static bool arg_confirm_spawn = false;
static bool arg_show_status = true;
+static bool arg_switched_root = false;
#ifdef HAVE_SYSV_COMPAT
static bool arg_sysv_console = true;
#endif
static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
static usec_t arg_runtime_watchdog = 0;
static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
+static struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {};
+static uint64_t arg_capability_bounding_set_drop = 0;
+static nsec_t arg_timer_slack_nsec = (nsec_t) -1;
static FILE* serialization = NULL;
assert(u);
- if (!(c = strdup(u)))
+ c = strdup(u);
+ if (!c)
return -ENOMEM;
free(arg_default_unit);
arg_default_unit = c;
+
return 0;
}
assert(word);
- if (startswith(word, "systemd.unit="))
- return set_default_unit(word + 13);
+ if (startswith(word, "systemd.unit=")) {
+
+ if (!in_initrd())
+ return set_default_unit(word + 13);
+
+ } else if (startswith(word, "rd.systemd.unit=")) {
+
+ if (in_initrd())
+ return set_default_unit(word + 16);
- else if (startswith(word, "systemd.log_target=")) {
+ } else if (startswith(word, "systemd.log_target=")) {
if (log_set_target_from_string(word + 19) < 0)
log_warning("Failed to parse log target %s. Ignoring.", word + 19);
log_info("Supported kernel switches:\n"
"systemd.unit=UNIT Default unit to start\n"
+ "rd.systemd.unit=UNIT Default unit to start when run in initrd\n"
"systemd.dump_core=0|1 Dump core on crash\n"
"systemd.crash_shell=0|1 Run shell on crash\n"
"systemd.crash_chvt=N Change to VT #N on crash\n"
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
{ "Manager", "RuntimeWatchdogSec", config_parse_usec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_usec, 0, &arg_shutdown_watchdog },
+ { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop },
+ { "Manager", "TimerSlackNSec", config_parse_nsec, 0, &arg_timer_slack_nsec },
+ { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU]},
+ { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE]},
+ { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA]},
+ { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK]},
+ { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE]},
+ { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS]},
+ { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE]},
+ { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS]},
+ { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC]},
+ { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK]},
+ { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS]},
+ { "Manager", "DefaultLimitSIGPENDING",config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING]},
+ { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE]},
+ { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE]},
+ { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO]},
+ { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME]},
{ NULL, NULL, NULL, 0, NULL }
};
}
case ARG_SWITCHED_ROOT:
- /* Nothing special yet */
+ arg_switched_root = true;
break;
case ARG_INTROSPECT: {
int j;
bool loaded_policy = false;
bool arm_reboot_watchdog = false;
+ bool queue_default_job = false;
char *switch_root_dir = NULL, *switch_root_init = NULL;
#ifdef HAVE_SYSV_COMPAT
if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0)
watchdog_set_timeout(&arg_runtime_watchdog);
+ if (arg_timer_slack_nsec != (nsec_t) -1)
+ if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
+ log_error("Failed to adjust timer slack: %m");
+
+ if (arg_capability_bounding_set_drop) {
+ r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
+ if (r < 0) {
+ log_error("Failed to drop capability bounding set: %s", strerror(-r));
+ goto finish;
+ }
+ r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
+ if (r < 0) {
+ log_error("Failed to drop capability bounding set of usermode helpers: %s", strerror(-r));
+ goto finish;
+ }
+ }
+
r = manager_new(arg_running_as, &m);
if (r < 0) {
log_error("Failed to allocate manager object: %s", strerror(-r));
m->runtime_watchdog = arg_runtime_watchdog;
m->shutdown_watchdog = arg_shutdown_watchdog;
+ manager_set_default_rlimits(m, arg_default_rlimit);
+
if (dual_timestamp_is_set(&initrd_timestamp))
m->initrd_timestamp = initrd_timestamp;
manager_set_show_status(m, arg_show_status);
+ /* Remember whether we should queue the default job */
+ queue_default_job = !serialization || arg_switched_root;
+
before_startup = now(CLOCK_MONOTONIC);
r = manager_startup(m, serialization, fds);
if (r < 0)
log_error("Failed to fully start up daemon: %s", strerror(-r));
+ /* This will close all file descriptors that were opened, but
+ * not claimed by any unit. */
if (fds) {
- /* This will close all file descriptors that were opened, but
- * not claimed by any unit. */
-
fdset_free(fds);
fds = NULL;
}
if (serialization) {
fclose(serialization);
serialization = NULL;
- } else {
+ }
+
+ if (queue_default_job) {
DBusError error;
Unit *target = NULL;
Job *default_unit_job;
if (m)
manager_free(m);
+ for (j = 0; j < RLIMIT_NLIMITS; j++)
+ free (arg_default_rlimit[j]);
+
free(arg_default_unit);
strv_free(arg_default_controllers);
free_join_controllers();
args[0] = "/sbin/init";
execv(args[0], (char* const*) args);
- log_warning("Failed to execute /sbin/init, trying fallback: %m");
+ if (errno == ENOENT) {
+ log_warning("No /sbin/init, trying fallback");
- args[0] = "/bin/sh";
- args[1] = NULL;
- execv(args[0], (char* const*) args);
- log_error("Failed to execute /bin/sh, giving up: %m");
+ args[0] = "/bin/sh";
+ args[1] = NULL;
+ execv(args[0], (char* const*) args);
+ log_error("Failed to execute /bin/sh, giving up: %m");
+ } else
+ log_warning("Failed to execute /sbin/init, giving up: %m");
}
if (serialization)