chiark / gitweb /
cryptsetup: allow configuration of LUKS disks via the kernel cmdline
[elogind.git] / src / core / main.c
index 486dac8a8aa2487b0a225c7038b64c2ee3b097d3..546582cff02af96391f36099e386fa87bd56b5fc 100644 (file)
@@ -50,6 +50,7 @@
 #include "watchdog.h"
 #include "path-util.h"
 #include "switch-root.h"
+#include "capability.h"
 
 #include "mount-setup.h"
 #include "loopback-setup.h"
@@ -77,6 +78,7 @@ static bool arg_crash_shell = false;
 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
@@ -86,6 +88,9 @@ static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
 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;
 
@@ -228,11 +233,13 @@ static int set_default_unit(const char *u) {
 
         assert(u);
 
-        if (!(c = strdup(u)))
+        c = strdup(u);
+        if (!c)
                 return -ENOMEM;
 
         free(arg_default_unit);
         arg_default_unit = c;
+
         return 0;
 }
 
@@ -254,10 +261,17 @@ static int parse_proc_cmdline_word(const char *word) {
 
         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);
@@ -360,12 +374,14 @@ static int parse_proc_cmdline_word(const char *word) {
                         arg_sysv_console = r;
 #endif
 
-        } else if (startswith(word, "systemd.")) {
+        } else if (startswith(word, "systemd.") ||
+                   (in_initrd() && startswith(word, "rd.systemd."))) {
 
                 log_warning("Unknown kernel switch %s. Ignoring.", word);
 
                 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"
@@ -382,14 +398,15 @@ static int parse_proc_cmdline_word(const char *word) {
                          "systemd.default_standard_output=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
                          "                                         Set default log output for services\n"
                          "systemd.default_standard_error=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
-                         "                                         Set default log error output for services\n");
+                         "                                         Set default log error output for services\n"
+                         "systemd.setenv=ASSIGNMENT                Set an environment variable for all spawned processes\n");
 
         } else if (streq(word, "quiet")) {
                 arg_show_status = false;
 #ifdef HAVE_SYSV_COMPAT
                 arg_sysv_console = false;
 #endif
-        } else {
+        } else if (!in_initrd()) {
                 unsigned i;
 
                 /* SysV compatibility */
@@ -666,6 +683,24 @@ static int parse_config_file(void) {
                 { "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 }
         };
 
@@ -945,7 +980,7 @@ static int parse_argv(int argc, char *argv[]) {
                 }
 
                 case ARG_SWITCHED_ROOT:
-                        /* Nothing special yet */
+                        arg_switched_root = true;
                         break;
 
                 case ARG_INTROSPECT: {
@@ -1188,6 +1223,7 @@ int main(int argc, char *argv[]) {
         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
@@ -1455,6 +1491,23 @@ int main(int argc, char *argv[]) {
         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));
@@ -1470,6 +1523,8 @@ int main(int argc, char *argv[]) {
         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;
 
@@ -1478,16 +1533,18 @@ int main(int argc, char *argv[]) {
 
         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;
         }
@@ -1495,7 +1552,9 @@ int main(int argc, char *argv[]) {
         if (serialization) {
                 fclose(serialization);
                 serialization = NULL;
-        } else {
+        }
+
+        if (queue_default_job) {
                 DBusError error;
                 Unit *target = NULL;
                 Job *default_unit_job;
@@ -1629,6 +1688,9 @@ finish:
         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();
@@ -1711,12 +1773,15 @@ finish:
                 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)