<term><varname>systemd.import_credentials=</varname></term>
<term><varname>systemd.reload_limit_interval_sec=</varname></term>
<term><varname>systemd.reload_limit_burst=</varname></term>
+ <term><varname>systemd.minimum_uptime_sec=</varname></term>
<listitem>
<para>Parameters understood by the system and service
manager to control system behavior. For details, see
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>MinimumUptimeSec=</varname></term>
+
+ <listitem><para>Specifies the minimum uptime for the system which has to be reached before a shutdown
+ is executed. Defaults to 15s. This mechanism is introduced to avoid high frequency reboot loops, when
+ technical failures trigger an automatic shutdown during the boot process. Each reboot cycle is
+ delayed to the specified minimum time, giving the user a chance to review screen contents or
+ otherwise interact with the device before the shutdown proceeds. The delay takes place during the
+ very last phase of system shutdown, immediately before the <function>reboot()</function> system call
+ is executed. If the system is already running for longer than the specified time, this setting has no
+ effect. This logic is also skipped in container environments. Set to zero in order to disable this
+ logic.</para>
+
+ <xi:include href="version-info.xml" xpointer="v261"/></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<xi:include href="version-info.xml" xpointer="v186"/></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.minimum_uptime_sec=</varname></term>
+
+ <listitem><para>Takes a time in seconds. Specifies the minimum uptime of the system before the system
+ shuts down. For more information see the <varname>MinimumUptimeSec=</varname> setting described in
+ <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+ <xi:include href="version-info.xml" xpointer="v261"/></listitem>
+ </varlistentry>
</variablelist>
<para>For other kernel command line parameters understood by
static size_t arg_random_seed_size;
static usec_t arg_reload_limit_interval_sec;
static unsigned arg_reload_limit_burst;
+static usec_t arg_minimum_uptime_usec;
/* A copy of the original environment block */
static char **saved_env = NULL;
return 0;
}
+ } else if (proc_cmdline_key_streq(key, "systemd.minimum_uptime_sec")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = parse_sec(value, &arg_minimum_uptime_usec);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse systemd.minimum_uptime_sec= argument '%s', ignoring: %m", value);
+ return 0;
+ }
+
} else if (streq(key, "quiet") && !value) {
if (arg_show_status == _SHOW_STATUS_INVALID)
{ "Manager", "ReloadLimitIntervalSec", config_parse_sec, 0, &arg_reload_limit_interval_sec },
{ "Manager", "ReloadLimitBurst", config_parse_unsigned, 0, &arg_reload_limit_burst },
{ "Manager", "DefaultMemoryZSwapWriteback", config_parse_bool, 0, &arg_defaults.memory_zswap_writeback },
+ { "Manager", "MinimumUptimeSec", config_parse_sec, 0, &arg_minimum_uptime_usec },
#if ENABLE_SMACK
{ "Manager", "DefaultSmackProcessLabel", config_parse_string, 0, &arg_defaults.smack_process_label },
#else
if (arg_watchdog_device)
(void) strv_extendf(&env_block, "WATCHDOG_DEVICE=%s", arg_watchdog_device);
+ if (arg_minimum_uptime_usec != USEC_INFINITY)
+ (void) strv_extendf(&env_block, "MINIMUM_UPTIME_USEC=" USEC_FMT, arg_minimum_uptime_usec);
+
(void) write_boot_or_shutdown_osc("shutdown");
execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
arg_reload_limit_interval_sec = 0;
arg_reload_limit_burst = 0;
+
+ arg_minimum_uptime_usec = USEC_INFINITY;
}
static void determine_default_oom_score_adjust(void) {
#RebootWatchdogSec=10min
#KExecWatchdogSec=off
#WatchdogDevice=
+#MinimumUptimeSec=15s
#CapabilityBoundingSet=
#NoNewPrivileges=no
#ProtectSystem=auto
#define SYNC_PROGRESS_ATTEMPTS 3
#define SYNC_TIMEOUT_USEC (10*USEC_PER_SEC)
+#define DEFAULT_MINIMUM_UPTIME_USEC (15U * USEC_PER_SEC)
static const char *arg_verb = NULL;
static uint8_t arg_exit_code = 0;
arg_exit_code, arg_verb);
}
+static void sleep_until_minimum_uptime(void) {
+ uint64_t minimum_uptime_usec = DEFAULT_MINIMUM_UPTIME_USEC;
+ int r;
+
+ const char *e = secure_getenv("MINIMUM_UPTIME_USEC");
+ if (e) {
+ r = safe_atou64(e, &minimum_uptime_usec);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse $MINIMUM_UPTIME_USEC, ignoring: %s", e);
+ }
+
+ if (minimum_uptime_usec <= 0) /* turned off? */
+ return;
+
+ for (;;) {
+ usec_t n = now(CLOCK_BOOTTIME);
+ if (n >= minimum_uptime_usec)
+ break;
+
+ usec_t m = minimum_uptime_usec - n;
+ log_notice("Delaying shutdown for %s, in order to reach minimum uptime of %s.",
+ FORMAT_TIMESPAN(m, USEC_PER_SEC),
+ FORMAT_TIMESPAN(minimum_uptime_usec, USEC_PER_SEC));
+
+ /* Sleep for up to 3s, then show message again, as a progress indicator. */
+ usleep_safe(MIN(m, 3 * USEC_PER_SEC));
+ }
+}
+
int main(int argc, char *argv[]) {
static const char* const dirs[] = {
SYSTEM_SHUTDOWN_PATH,
notify_supervisor();
+ /* Enforce the minimum uptime, but don't bother with it in containers, since – unlike on bare metal
+ * and VMs – the screen output isn't flushed out immediately when we reboot (as OVMF or real PC
+ * firmwares do) */
+ if (!in_container)
+ sleep_until_minimum_uptime();
+
if (streq(arg_verb, "exit")) {
if (in_container) {
log_info("Exiting container.");