Merge upgrade-to-244 into tizen 38/229638/1 submit/tizen/20200402.112550
authorAdrian Szyndela <adrian.s@samsung.com>
Thu, 2 Apr 2020 10:37:36 +0000 (12:37 +0200)
committerAdrian Szyndela <adrian.s@samsung.com>
Thu, 2 Apr 2020 10:40:07 +0000 (12:40 +0200)
Change-Id: Id3fa41d3beb40586cf5eb4a9069c4a1ce39366c9

1  2 
src/core/main.c

diff --cc src/core/main.c
@@@ -1880,304 -1948,798 +1948,798 @@@ static int initialize_runtime
                  }
          }
  
-         for (;;) {
-                 r = manager_loop(m);
+         if (arg_system && arg_no_new_privs) {
+                 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
+                         *ret_error_message = "Failed to disable new privileges";
+                         return log_emergency_errno(errno, "Failed to disable new privileges: %m");
+                 }
+         }
+         if (arg_syscall_archs) {
+                 r = enforce_syscall_archs(arg_syscall_archs);
                  if (r < 0) {
-                         log_emergency_errno(r, "Failed to run main loop: %m");
-                         error_message = "Failed to run main loop";
-                         goto finish;
+                         *ret_error_message = "Failed to set syscall architectures";
+                         return r;
                  }
+         }
  
-                 switch (m->exit_code) {
+         if (!arg_system)
+                 /* Become reaper of our children */
+                 if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
+                         log_warning_errno(errno, "Failed to make us a subreaper: %m");
  
-                 case MANAGER_RELOAD:
-                         log_info("Reloading.");
+         /* Bump up RLIMIT_NOFILE for systemd itself */
+         (void) bump_rlimit_nofile(saved_rlimit_nofile);
+         (void) bump_rlimit_memlock(saved_rlimit_memlock);
  
-                         r = parse_config_file();
-                         if (r < 0)
-                                 log_error("Failed to parse config file.");
+         return 0;
+ }
  
-                         manager_set_defaults(m);
+ static int do_queue_default_job(
+                 Manager *m,
+                 const char **ret_error_message) {
  
-                         r = manager_reload(m);
-                         if (r < 0)
-                                 log_error_errno(r, "Failed to reload: %m");
-                         break;
+         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+         Job *default_unit_job;
+         Unit *target = NULL;
+         int r;
  
-                 case MANAGER_REEXECUTE:
+         log_debug("Activating default unit: %s", arg_default_unit);
  
-                         if (prepare_reexecute(m, &arg_serialization, &fds, false) < 0) {
-                                 error_message = "Failed to prepare for reexecution";
-                                 goto finish;
-                         }
+         r = manager_load_startable_unit_or_warn(m, arg_default_unit, NULL, &target);
+         if (r < 0) {
+                 log_info("Falling back to rescue target: " SPECIAL_RESCUE_TARGET);
  
-                         reexecute = true;
-                         log_notice("Reexecuting.");
-                         goto finish;
+                 r = manager_load_startable_unit_or_warn(m, SPECIAL_RESCUE_TARGET, NULL, &target);
+                 if (r < 0) {
+                         *ret_error_message = r == -ERFKILL ? "Rescue target masked"
+                                                            : "Failed to load rescue target";
+                         return r;
+                 }
+         }
  
-                 case MANAGER_SWITCH_ROOT:
-                         /* Steal the switch root parameters */
-                         switch_root_dir = m->switch_root;
-                         switch_root_init = m->switch_root_init;
-                         m->switch_root = m->switch_root_init = NULL;
+         assert(target->load_state == UNIT_LOADED);
  
-                         if (!switch_root_init)
-                                 if (prepare_reexecute(m, &arg_serialization, &fds, true) < 0) {
-                                         error_message = "Failed to prepare for reexecution";
-                                         goto finish;
-                                 }
+         r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, NULL, &error, &default_unit_job);
+         if (r == -EPERM) {
+                 log_debug_errno(r, "Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
  
-                         reexecute = true;
-                         log_notice("Switching root.");
-                         goto finish;
+                 sd_bus_error_free(&error);
  
-                 case MANAGER_EXIT:
-                         retval = m->return_value;
+                 r = manager_add_job(m, JOB_START, target, JOB_REPLACE, NULL, &error, &default_unit_job);
+                 if (r < 0) {
+                         *ret_error_message = "Failed to start default target";
+                         return log_emergency_errno(r, "Failed to start default target: %s", bus_error_message(&error, r));
+                 }
  
-                         if (MANAGER_IS_USER(m)) {
-                                 log_debug("Exit.");
-                                 goto finish;
-                         }
+         } else if (r < 0) {
+                 *ret_error_message = "Failed to isolate default target";
+                 return log_emergency_errno(r, "Failed to isolate default target: %s", bus_error_message(&error, r));
+         }
  
-                         /* fallthrough */
-                 case MANAGER_REBOOT:
-                 case MANAGER_POWEROFF:
-                 case MANAGER_HALT:
-                 case MANAGER_KEXEC: {
-                         static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
-                                 [MANAGER_EXIT] = "exit",
-                                 [MANAGER_REBOOT] = "reboot",
-                                 [MANAGER_POWEROFF] = "poweroff",
-                                 [MANAGER_HALT] = "halt",
-                                 [MANAGER_KEXEC] = "kexec"
-                         };
+         m->default_unit_job_id = default_unit_job->id;
  
-                         assert_se(shutdown_verb = table[m->exit_code]);
-                         arm_reboot_watchdog = m->exit_code == MANAGER_REBOOT;
+         return 0;
+ }
  
-                         log_notice("Shutting down.");
-                         goto finish;
-                 }
+ static void save_rlimits(struct rlimit *saved_rlimit_nofile,
+                          struct rlimit *saved_rlimit_memlock) {
  
-                 default:
-                         assert_not_reached("Unknown exit code.");
-                 }
+         assert(saved_rlimit_nofile);
+         assert(saved_rlimit_memlock);
+         if (getrlimit(RLIMIT_NOFILE, saved_rlimit_nofile) < 0)
+                 log_warning_errno(errno, "Reading RLIMIT_NOFILE failed, ignoring: %m");
+         if (getrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock) < 0)
+                 log_warning_errno(errno, "Reading RLIMIT_MEMLOCK failed, ignoring: %m");
+ }
+ static void fallback_rlimit_nofile(const struct rlimit *saved_rlimit_nofile) {
+         struct rlimit *rl;
+         if (arg_default_rlimit[RLIMIT_NOFILE])
+                 return;
+         /* Make sure forked processes get limits based on the original kernel setting */
+         rl = newdup(struct rlimit, saved_rlimit_nofile, 1);
+         if (!rl) {
+                 log_oom();
+                 return;
          }
  
- finish:
-         pager_close();
+         /* Bump the hard limit for system services to a substantially higher value. The default
+          * hard limit current kernels set is pretty low (4K), mostly for historical
+          * reasons. According to kernel developers, the fd handling in recent kernels has been
+          * optimized substantially enough, so that we can bump the limit now, without paying too
+          * high a price in memory or performance. Note however that we only bump the hard limit,
+          * not the soft limit. That's because select() works the way it works, and chokes on fds
+          * >= 1024. If we'd bump the soft limit globally, it might accidentally happen to
+          * unexpecting programs that they get fds higher than what they can process using
+          * select(). By only bumping the hard limit but leaving the low limit as it is we avoid
+          * this pitfall:  programs that are written by folks aware of the select() problem in mind
+          * (and thus use poll()/epoll instead of select(), the way everybody should) can
+          * explicitly opt into high fds by bumping their soft limit beyond 1024, to the hard limit
+          * we pass. */
+         if (arg_system) {
+                 int nr;
+                 /* Get the underlying absolute limit the kernel enforces */
+                 nr = read_nr_open();
+                 rl->rlim_max = MIN((rlim_t) nr, MAX(rl->rlim_max, (rlim_t) HIGH_RLIMIT_NOFILE));
+         }
+         /* If for some reason we were invoked with a soft limit above 1024 (which should never
+          * happen!, but who knows what we get passed in from pam_limit when invoked as --user
+          * instance), then lower what we pass on to not confuse our children */
+         rl->rlim_cur = MIN(rl->rlim_cur, (rlim_t) FD_SETSIZE);
+         arg_default_rlimit[RLIMIT_NOFILE] = rl;
+ }
+ static void fallback_rlimit_memlock(const struct rlimit *saved_rlimit_memlock) {
+         struct rlimit *rl;
  
-         if (m)
-                 arg_shutdown_watchdog = m->shutdown_watchdog;
+         /* Pass the original value down to invoked processes */
  
-         m = manager_free(m);
+         if (arg_default_rlimit[RLIMIT_MEMLOCK])
+                 return;
+         rl = newdup(struct rlimit, saved_rlimit_memlock, 1);
+         if (!rl) {
+                 log_oom();
+                 return;
+         }
  
-         for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++)
-                 arg_default_rlimit[j] = mfree(arg_default_rlimit[j]);
+         arg_default_rlimit[RLIMIT_MEMLOCK] = rl;
+ }
+ static void reset_arguments(void) {
+         /* Frees/resets arg_* variables, with a few exceptions commented below. */
  
          arg_default_unit = mfree(arg_default_unit);
-         arg_join_controllers = strv_free_free(arg_join_controllers);
+         /* arg_system — ignore */
+         arg_dump_core = true;
+         arg_crash_chvt = -1;
+         arg_crash_shell = false;
+         arg_crash_reboot = false;
+         arg_confirm_spawn = mfree(arg_confirm_spawn);
+         arg_show_status = _SHOW_STATUS_INVALID;
+         arg_status_unit_format = STATUS_UNIT_FORMAT_DEFAULT;
+         arg_switched_root = false;
+         arg_pager_flags = 0;
+         arg_service_watchdogs = true;
+         arg_default_std_output = EXEC_OUTPUT_JOURNAL;
+         arg_default_std_error = EXEC_OUTPUT_INHERIT;
+         arg_default_restart_usec = DEFAULT_RESTART_USEC;
+         arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
+         arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
+         arg_default_timeout_abort_usec = DEFAULT_TIMEOUT_USEC;
+         arg_default_timeout_abort_set = false;
+         arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
+         arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
+         arg_runtime_watchdog = 0;
 -        arg_reboot_watchdog = 10 * USEC_PER_MINUTE;
++        arg_reboot_watchdog = 0; /* 10 * USEC_PER_MINUTE; */
+         arg_kexec_watchdog = 0;
+         arg_early_core_pattern = NULL;
+         arg_watchdog_device = NULL;
          arg_default_environment = strv_free(arg_default_environment);
+         rlimit_free_all(arg_default_rlimit);
+         arg_capability_bounding_set = CAP_ALL;
+         arg_no_new_privs = false;
+         arg_timer_slack_nsec = NSEC_INFINITY;
+         arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
          arg_syscall_archs = set_free(arg_syscall_archs);
  
-         mac_selinux_finish();
+         /* arg_serialization — ignore */
+         arg_default_cpu_accounting = -1;
+         arg_default_io_accounting = false;
+         arg_default_ip_accounting = false;
+         arg_default_blockio_accounting = false;
+         arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT;
+         arg_default_tasks_accounting = true;
+         arg_default_tasks_max = DEFAULT_TASKS_MAX;
+         arg_machine_id = (sd_id128_t) {};
+         arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
+         arg_default_oom_policy = OOM_STOP;
+         cpu_set_reset(&arg_cpu_affinity);
+         numa_policy_reset(&arg_numa_policy);
+ }
  
-         if (reexecute) {
-                 const char **args;
-                 unsigned i, args_size;
+ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
+                                const struct rlimit *saved_rlimit_memlock) {
+         int r;
  
-                 /* 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);
+         assert(saved_rlimit_nofile);
+         assert(saved_rlimit_memlock);
  
-                 /* 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)
-                         (void) setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
-                 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. */
-                         r = switch_root(switch_root_dir, "/mnt", true, MS_MOVE);
-                         if (r < 0)
-                                 log_error_errno(r, "Failed to switch root, trying to continue: %m");
+         /* Assign configuration defaults */
+         reset_arguments();
+         r = parse_config_file();
+         if (r < 0)
+                 log_warning_errno(r, "Failed to parse config file, ignoring: %m");
+         if (arg_system) {
+                 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
+                 if (r < 0)
+                         log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
+         }
+         /* Initialize some default rlimits for services if they haven't been configured */
+         fallback_rlimit_nofile(saved_rlimit_nofile);
+         fallback_rlimit_memlock(saved_rlimit_memlock);
+         /* Note that this also parses bits from the kernel command line, including "debug". */
+         log_parse_environment();
+         return 0;
+ }
+ static int load_configuration(
+                 int argc,
+                 char **argv,
+                 const struct rlimit *saved_rlimit_nofile,
+                 const struct rlimit *saved_rlimit_memlock,
+                 const char **ret_error_message) {
+         int r;
+         assert(saved_rlimit_nofile);
+         assert(saved_rlimit_memlock);
+         assert(ret_error_message);
+         (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
+         r = parse_argv(argc, argv);
+         if (r < 0) {
+                 *ret_error_message = "Failed to parse commandline arguments";
+                 return r;
+         }
+         /* Initialize default unit */
+         if (!arg_default_unit) {
+                 arg_default_unit = strdup(SPECIAL_DEFAULT_TARGET);
+                 if (!arg_default_unit) {
+                         *ret_error_message = "Failed to set default unit";
+                         return log_oom();
                  }
+         }
  
-                 /* Reopen the console */
-                 (void) make_console_stdio();
+         /* Initialize the show status setting if it hasn't been set explicitly yet */
+         if (arg_show_status == _SHOW_STATUS_INVALID)
+                 arg_show_status = SHOW_STATUS_YES;
  
-                 args_size = MAX(6, argc+1);
-                 args = newa(const char*, args_size);
+         return 0;
+ }
+ static int safety_checks(void) {
  
-                 if (!switch_root_init) {
-                         char sfd[DECIMAL_STR_MAX(int) + 1];
+         if (getpid_cached() == 1 &&
+             arg_action != ACTION_RUN)
+                 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+                                        "Unsupported execution mode while PID 1.");
  
-                         /* 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. */
+         if (getpid_cached() == 1 &&
+             !arg_system)
+                 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+                                        "Can't run --user mode as PID 1.");
  
-                         assert(arg_serialization);
-                         assert(fds);
+         if (arg_action == ACTION_RUN &&
+             arg_system &&
+             getpid_cached() != 1)
+                 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+                                        "Can't run system mode unless PID 1.");
  
-                         xsprintf(sfd, "%i", fileno(arg_serialization));
+         if (arg_action == ACTION_TEST &&
+             geteuid() == 0)
+                 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+                                        "Don't run test mode as root.");
  
-                         i = 0;
-                         args[i++] = SYSTEMD_BINARY_PATH;
-                         if (switch_root_dir)
-                                 args[i++] = "--switched-root";
-                         args[i++] = arg_system ? "--system" : "--user";
-                         args[i++] = "--deserialize";
-                         args[i++] = sfd;
-                         args[i++] = NULL;
+         if (!arg_system &&
+             arg_action == ACTION_RUN &&
+             sd_booted() <= 0)
+                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                        "Trying to run as user instance, but the system has not been booted with systemd.");
+         if (!arg_system &&
+             arg_action == ACTION_RUN &&
+             !getenv("XDG_RUNTIME_DIR"))
+                 return log_error_errno(SYNTHETIC_ERRNO(EUNATCH),
+                                        "Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
+         if (arg_system &&
+             arg_action == ACTION_RUN &&
+             running_in_chroot() > 0)
+                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                        "Cannot be run in a chroot() environment.");
+         return 0;
+ }
+ static int initialize_security(
+                 bool *loaded_policy,
+                 dual_timestamp *security_start_timestamp,
+                 dual_timestamp *security_finish_timestamp,
+                 const char **ret_error_message) {
+         int r;
  
-                         assert(i <= args_size);
+         assert(loaded_policy);
+         assert(security_start_timestamp);
+         assert(security_finish_timestamp);
+         assert(ret_error_message);
  
-                         /*
-                          * We want valgrind to print its memory usage summary before reexecution.
-                          * Valgrind won't do this is on its own on exec(), but it will do it on exit().
-                          * Hence, to ensure we get a summary here, fork() off a child, let it exit() cleanly,
-                          * so that it prints the summary, and wait() for it in the parent, before proceeding into the exec().
-                          */
-                         valgrind_summary_hack();
+         dual_timestamp_get(security_start_timestamp);
  
-                         (void) execv(args[0], (char* const*) args);
+         r = mac_selinux_setup(loaded_policy);
+         if (r < 0) {
+                 *ret_error_message = "Failed to load SELinux policy";
+                 return r;
+         }
+         r = mac_smack_setup(loaded_policy);
+         if (r < 0) {
+                 *ret_error_message = "Failed to load SMACK policy";
+                 return r;
+         }
+         r = ima_setup();
+         if (r < 0) {
+                 *ret_error_message = "Failed to load IMA policy";
+                 return r;
+         }
+         dual_timestamp_get(security_finish_timestamp);
+         return 0;
+ }
+ static void test_summary(Manager *m) {
+         assert(m);
+         printf("-> By units:\n");
+         manager_dump_units(m, stdout, "\t");
+         printf("-> By jobs:\n");
+         manager_dump_jobs(m, stdout, "\t");
+ }
+ static int collect_fds(FDSet **ret_fds, const char **ret_error_message) {
+         int r;
+         assert(ret_fds);
+         assert(ret_error_message);
+         r = fdset_new_fill(ret_fds);
+         if (r < 0) {
+                 *ret_error_message = "Failed to allocate fd set";
+                 return log_emergency_errno(r, "Failed to allocate fd set: %m");
+         }
+         fdset_cloexec(*ret_fds, true);
+         if (arg_serialization)
+                 assert_se(fdset_remove(*ret_fds, fileno(arg_serialization)) >= 0);
+         return 0;
+ }
+ static void setup_console_terminal(bool skip_setup) {
+         if (!arg_system)
+                 return;
+         /* Become a session leader if we aren't one yet. */
+         (void) setsid();
+         /* If we are init, we connect stdin/stdout/stderr to /dev/null and make sure we don't have a controlling
+          * tty. */
+         (void) release_terminal();
+         /* Reset the console, but only if this is really init and we are freshly booted */
+         if (getpid_cached() == 1 && !skip_setup)
+                 (void) console_setup();
+ }
+ static bool early_skip_setup_check(int argc, char *argv[]) {
+         bool found_deserialize = false;
+         int i;
+         /* 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. Note that if we have switched root, do all the special setup things
+          * anyway, even if in that case we also do deserialization. */
+         for (i = 1; i < argc; i++) {
+                 if (streq(argv[i], "--switched-root"))
+                         return false; /* If we switched root, don't skip the setup. */
+                 else if (streq(argv[i], "--deserialize"))
+                         found_deserialize = true;
+         }
+         return found_deserialize; /* When we are deserializing, then we are reexecuting, hence avoid the extensive setup */
+ }
+ static int save_env(void) {
+         char **l;
+         l = strv_copy(environ);
+         if (!l)
+                 return -ENOMEM;
+         strv_free_and_replace(saved_env, l);
+         return 0;
+ }
+ int main(int argc, char *argv[]) {
+         dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL, userspace_timestamp = DUAL_TIMESTAMP_NULL, kernel_timestamp = DUAL_TIMESTAMP_NULL,
+                 security_start_timestamp = DUAL_TIMESTAMP_NULL, security_finish_timestamp = DUAL_TIMESTAMP_NULL;
+         struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0),
+                 saved_rlimit_memlock = RLIMIT_MAKE_CONST(RLIM_INFINITY); /* The original rlimits we passed
+                                                                           * in. Note we use different values
+                                                                           * for the two that indicate whether
+                                                                           * these fields are initialized! */
+         bool skip_setup, loaded_policy = false, queue_default_job = false, first_boot = false, reexecute = false;
+         char *switch_root_dir = NULL, *switch_root_init = NULL;
+         usec_t before_startup, after_startup;
+         static char systemd[] = "systemd";
+         char timespan[FORMAT_TIMESPAN_MAX];
+         const char *shutdown_verb = NULL, *error_message = NULL;
+         int r, retval = EXIT_FAILURE;
+         Manager *m = NULL;
+         FDSet *fds = NULL;
+         /* SysV compatibility: redirect init → telinit */
+         redirect_telinit(argc, argv);
+         /* Take timestamps early on */
+         dual_timestamp_from_monotonic(&kernel_timestamp, 0);
+         dual_timestamp_get(&userspace_timestamp);
+         /* Figure out whether we need to do initialize the system, or if we already did that because we are
+          * reexecuting */
+         skip_setup = early_skip_setup_check(argc, argv);
+         /* If we get started via the /sbin/init symlink then we are called 'init'. After a subsequent reexecution we
+          * are then called 'systemd'. That is confusing, hence let's call us systemd right-away. */
+         program_invocation_short_name = systemd;
+         (void) prctl(PR_SET_NAME, systemd);
+         /* Save the original command line */
+         save_argc_argv(argc, argv);
+         /* Save the original environment as we might need to restore it if we're requested to execute another
+          * system manager later. */
+         r = save_env();
+         if (r < 0) {
+                 error_message = "Failed to copy environment block";
+                 goto finish;
+         }
+         /* Make sure that if the user says "syslog" we actually log to the journal. */
+         log_set_upgrade_syslog_to_journal(true);
+         if (getpid_cached() == 1) {
+                 /* When we run as PID 1 force system mode */
+                 arg_system = true;
+                 /* Disable the umask logic */
+                 umask(0);
+                 /* Make sure that at least initially we do not ever log to journald/syslogd, because it might not be
+                  * activated yet (even though the log socket for it exists). */
+                 log_set_prohibit_ipc(true);
+                 /* Always reopen /dev/console when running as PID 1 or one of its pre-execve() children. This is
+                  * important so that we never end up logging to any foreign stderr, for example if we have to log in a
+                  * child process right before execve()'ing the actual binary, at a point in time where socket
+                  * activation stderr/stdout area already set up. */
+                 log_set_always_reopen_console(true);
+                 if (detect_container() <= 0) {
+                         /* Running outside of a container as PID 1 */
+                         log_set_target(LOG_TARGET_KMSG);
+                         log_open();
+                         if (in_initrd())
+                                 initrd_timestamp = userspace_timestamp;
+                         if (!skip_setup) {
+                                 r = mount_setup_early();
+                                 if (r < 0) {
+                                         error_message = "Failed to mount early API filesystems";
+                                         goto finish;
+                                 }
+                                 /* Let's open the log backend a second time, in case the first time didn't
+                                  * work. Quite possibly we have mounted /dev just now, so /dev/kmsg became
+                                  * available, and it previously wasn't. */
+                                 log_open();
+                                 disable_printk_ratelimit();
+                                 r = initialize_security(
+                                                 &loaded_policy,
+                                                 &security_start_timestamp,
+                                                 &security_finish_timestamp,
+                                                 &error_message);
+                                 if (r < 0)
+                                         goto finish;
+                         }
+                         if (mac_selinux_init() < 0) {
+                                 error_message = "Failed to initialize SELinux policy";
+                                 goto finish;
+                         }
+                         if (!skip_setup)
+                                 initialize_clock();
+                         /* 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 opening that before we parsed /proc/cmdline which might redirect output
+                          * elsewhere. */
+                         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+                 } else {
+                         /* Running inside a container, as PID 1 */
+                         log_set_target(LOG_TARGET_CONSOLE);
+                         log_open();
+                         /* For later on, see above... */
+                         log_set_target(LOG_TARGET_JOURNAL);
+                         /* clear the kernel timestamp,
+                          * because we are in a container */
+                         kernel_timestamp = DUAL_TIMESTAMP_NULL;
                  }
  
-                 /* 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.) */
+                 initialize_coredump(skip_setup);
  
-                 arg_serialization = safe_fclose(arg_serialization);
-                 fds = fdset_free(fds);
+                 r = fixup_environment();
+                 if (r < 0) {
+                         log_emergency_errno(r, "Failed to fix up PID 1 environment: %m");
+                         error_message = "Failed to fix up PID1 environment";
+                         goto finish;
+                 }
  
-                 for (j = 1, i = 1; j < (unsigned) argc; j++)
-                         args[i++] = argv[j];
-                 args[i++] = NULL;
-                 assert(i <= args_size);
+         } else {
+                 /* Running as user instance */
+                 arg_system = false;
+                 log_set_target(LOG_TARGET_AUTO);
+                 log_open();
+                 /* clear the kernel timestamp,
+                  * because we are not PID 1 */
+                 kernel_timestamp = DUAL_TIMESTAMP_NULL;
+         }
+         if (arg_system) {
+                 /* Try to figure out if we can use colors with the console. No need to do that for user instances since
+                  * they never log into the console. */
+                 log_show_color(colors_enabled());
  
-                 /* Reenable any blocked signals, especially important
-                  * if we switch from initial ramdisk to init=... */
-                 (void) reset_all_signal_handlers();
-                 (void) reset_signal_mask();
+                 r = make_null_stdio();
+                 if (r < 0)
+                         log_warning_errno(r, "Failed to redirect standard streams to /dev/null, ignoring: %m");
+         }
  
-                 if (switch_root_init) {
-                         args[0] = switch_root_init;
-                         (void) execv(args[0], (char* const*) args);
-                         log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
+         /* Mount /proc, /sys and friends, so that /proc/cmdline and
+          * /proc/$PID/fd is available. */
+         if (getpid_cached() == 1) {
+                 /* Load the kernel modules early. */
+                 if (!skip_setup)
+                         kmod_setup();
+                 r = mount_setup(loaded_policy);
+                 if (r < 0) {
+                         error_message = "Failed to mount API filesystems";
+                         goto finish;
                  }
  
-                 args[0] = "/sbin/init";
-                 (void) execv(args[0], (char* const*) args);
+                 /* The efivarfs is now mounted, let's read the random seed off it */
+                 (void) efi_take_random_seed();
+         }
  
-                 if (errno == ENOENT) {
-                         log_warning("No /sbin/init, trying fallback");
+         /* Save the original RLIMIT_NOFILE/RLIMIT_MEMLOCK so that we can reset it later when
+          * transitioning from the initrd to the main systemd or suchlike. */
+         save_rlimits(&saved_rlimit_nofile, &saved_rlimit_memlock);
  
-                         args[0] = "/bin/sh";
-                         args[1] = NULL;
-                         (void) execv(args[0], (char* const*) args);
-                         log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
-                 } else
-                         log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m");
+         /* Reset all signal handlers. */
+         (void) reset_all_signal_handlers();
+         (void) ignore_signals(SIGNALS_IGNORE, -1);
+         r = load_configuration(argc, argv, &saved_rlimit_nofile, &saved_rlimit_memlock, &error_message);
+         if (r < 0)
+                 goto finish;
+         r = safety_checks();
+         if (r < 0)
+                 goto finish;
+         if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES))
+                 (void) pager_open(arg_pager_flags);
+         if (arg_action != ACTION_RUN)
+                 skip_setup = true;
+         if (arg_action == ACTION_HELP) {
+                 retval = help() < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+                 goto finish;
+         } else if (arg_action == ACTION_VERSION) {
+                 retval = version();
+                 goto finish;
+         } else if (arg_action == ACTION_DUMP_CONFIGURATION_ITEMS) {
+                 unit_dump_config_items(stdout);
+                 retval = EXIT_SUCCESS;
+                 goto finish;
+         } else if (arg_action == ACTION_DUMP_BUS_PROPERTIES) {
+                 dump_bus_properties(stdout);
+                 retval = EXIT_SUCCESS;
+                 goto finish;
          }
  
-         arg_serialization = safe_fclose(arg_serialization);
-         fds = fdset_free(fds);
+         assert_se(IN_SET(arg_action, ACTION_RUN, ACTION_TEST));
  
- #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. */
-         if (getpid() == 1 && RUNNING_ON_VALGRIND)
-                 return 0;
- #endif
+         /* Move out of the way, so that we won't block unmounts */
+         assert_se(chdir("/") == 0);
  
-         if (shutdown_verb) {
-                 char log_level[DECIMAL_STR_MAX(int) + 1];
-                 char exit_code[DECIMAL_STR_MAX(uint8_t) + 1];
-                 const char* command_line[11] = {
-                         SYSTEMD_SHUTDOWN_BINARY_PATH,
-                         shutdown_verb,
-                         "--log-level", log_level,
-                         "--log-target",
-                 };
-                 unsigned pos = 5;
-                 _cleanup_strv_free_ char **env_block = NULL;
+         if (arg_action == ACTION_RUN) {
  
-                 assert(command_line[pos] == NULL);
-                 env_block = strv_copy(environ);
+                 /* A core pattern might have been specified via the cmdline.  */
+                 initialize_core_pattern(skip_setup);
  
-                 xsprintf(log_level, "%d", log_get_max_level());
+                 /* Close logging fds, in order not to confuse collecting passed fds and terminal logic below */
+                 log_close();
  
-                 switch (log_get_target()) {
+                 /* Remember open file descriptors for later deserialization */
+                 r = collect_fds(&fds, &error_message);
+                 if (r < 0)
+                         goto finish;
  
-                 case LOG_TARGET_KMSG:
-                 case LOG_TARGET_JOURNAL_OR_KMSG:
-                 case LOG_TARGET_SYSLOG_OR_KMSG:
-                         command_line[pos++] = "kmsg";
-                         break;
+                 /* Give up any control of the console, but make sure its initialized. */
+                 setup_console_terminal(skip_setup);
  
-                 case LOG_TARGET_NULL:
-                         command_line[pos++] = "null";
-                         break;
+                 /* Open the logging devices, if possible and necessary */
+                 log_open();
+         }
  
-                 case LOG_TARGET_CONSOLE:
-                 default:
-                         command_line[pos++] = "console";
-                         break;
-                 };
+         log_execution_mode(&first_boot);
  
-                 if (log_get_show_color())
-                         command_line[pos++] = "--log-color";
+         r = initialize_runtime(skip_setup,
+                                &saved_rlimit_nofile,
+                                &saved_rlimit_memlock,
+                                &error_message);
+         if (r < 0)
+                 goto finish;
  
-                 if (log_get_show_location())
-                         command_line[pos++] = "--log-location";
+         r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+                         arg_action == ACTION_TEST ? MANAGER_TEST_FULL : 0,
+                         &m);
+         if (r < 0) {
+                 log_emergency_errno(r, "Failed to allocate manager object: %m");
+                 error_message = "Failed to allocate manager object";
+                 goto finish;
+         }
  
-                 if (streq(shutdown_verb, "exit")) {
-                         command_line[pos++] = "--exit-code";
-                         command_line[pos++] = exit_code;
-                         xsprintf(exit_code, "%d", retval);
-                 }
+         m->timestamps[MANAGER_TIMESTAMP_KERNEL] = kernel_timestamp;
+         m->timestamps[MANAGER_TIMESTAMP_INITRD] = initrd_timestamp;
+         m->timestamps[MANAGER_TIMESTAMP_USERSPACE] = userspace_timestamp;
+         m->timestamps[manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_SECURITY_START)] = security_start_timestamp;
+         m->timestamps[manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_SECURITY_FINISH)] = security_finish_timestamp;
  
-                 assert(pos < ELEMENTSOF(command_line));
+         set_manager_defaults(m);
+         set_manager_settings(m);
+         manager_set_first_boot(m, first_boot);
  
-                 if (arm_reboot_watchdog && arg_shutdown_watchdog > 0 && arg_shutdown_watchdog != USEC_INFINITY) {
-                         char *e;
+         /* Remember whether we should queue the default job */
+         queue_default_job = !arg_serialization || arg_switched_root;
  
-                         /* If we reboot let's set the shutdown
-                          * watchdog and tell the shutdown binary to
-                          * repeatedly ping it */
-                         r = watchdog_set_timeout(&arg_shutdown_watchdog);
-                         watchdog_close(r < 0);
+         before_startup = now(CLOCK_MONOTONIC);
  
-                         /* Tell the binary how often to ping, ignore failure */
-                         if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0)
-                                 (void) strv_push(&env_block, e);
-                 } else
-                         watchdog_close(true);
+         r = manager_startup(m, arg_serialization, fds);
+         if (r < 0) {
+                 error_message = "Failed to start up manager";
+                 goto finish;
+         }
  
-                 /* Avoid the creation of new processes forked by the
-                  * kernel; at this point, we will not listen to the
-                  * signals anyway */
-                 if (detect_container() <= 0)
-                         (void) cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
+         /* This will close all file descriptors that were opened, but not claimed by any unit. */
+         fds = fdset_free(fds);
+         arg_serialization = safe_fclose(arg_serialization);
  
-                 execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
-                 log_error_errno(errno, "Failed to execute shutdown binary, %s: %m",
-                           getpid() == 1 ? "freezing" : "quitting");
+         if (queue_default_job) {
+                 r = do_queue_default_job(m, &error_message);
+                 if (r < 0)
+                         goto finish;
          }
  
-         if (getpid() == 1) {
+         after_startup = now(CLOCK_MONOTONIC);
+         log_full(arg_action == ACTION_TEST ? LOG_INFO : LOG_DEBUG,
+                  "Loaded units and determined initial transaction in %s.",
+                  format_timespan(timespan, sizeof(timespan), after_startup - before_startup, 100 * USEC_PER_MSEC));
+         if (arg_action == ACTION_TEST) {
+                 test_summary(m);
+                 retval = EXIT_SUCCESS;
+                 goto finish;
+         }
+         (void) invoke_main_loop(m,
+                                 &saved_rlimit_nofile,
+                                 &saved_rlimit_memlock,
+                                 &reexecute,
+                                 &retval,
+                                 &shutdown_verb,
+                                 &fds,
+                                 &switch_root_dir,
+                                 &switch_root_init,
+                                 &error_message);
+ finish:
+         pager_close();
+         if (m) {
+                 arg_reboot_watchdog = m->reboot_watchdog;
+                 arg_kexec_watchdog = m->kexec_watchdog;
+                 m = manager_free(m);
+         }
+         reset_arguments();
+         mac_selinux_finish();
+         if (reexecute)
+                 do_reexecute(argc, argv,
+                              &saved_rlimit_nofile,
+                              &saved_rlimit_memlock,
+                              fds,
+                              switch_root_dir,
+                              switch_root_init,
+                              &error_message); /* This only returns if reexecution failed */
+         arg_serialization = safe_fclose(arg_serialization);
+         fds = fdset_free(fds);
+         saved_env = strv_free(saved_env);
+ #if 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. */
+         if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
+                 /* Cleanup watchdog_device strings for valgrind. We need them
+                  * in become_shutdown() so normally we cannot free them yet. */
+                 watchdog_free_device();
+                 arg_watchdog_device = mfree(arg_watchdog_device);
+                 return retval;
+         }
+ #endif
+ #if HAS_FEATURE_ADDRESS_SANITIZER
+         __lsan_do_leak_check();
+ #endif
+         if (shutdown_verb) {
+                 r = become_shutdown(shutdown_verb, retval);
+                 log_error_errno(r, "Failed to execute shutdown binary, %s: %m", getpid_cached() == 1 ? "freezing" : "quitting");
+                 error_message = "Failed to execute shutdown binary";
+         }
+         watchdog_free_device();
+         arg_watchdog_device = mfree(arg_watchdog_device);
+         if (getpid_cached() == 1) {
                  if (error_message)
                          manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,
                                                ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL,