diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 8a899aee56a..fd49b65a8d4 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -459,6 +459,14 @@ of the systemd-firstboot.service system service but has no effect on the condition check (see above). + + + systemd.clock-usec= + + Takes a decimal, numeric timestamp in µs since January 1st 1970, 00:00am, to set the + system clock to. The system time is set to the specified timestamp early during + boot. It is not propagated to the hardware clock (RTC). + diff --git a/src/core/main.c b/src/core/main.c index c9eaf70bd6c..3ab4aa4e198 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -146,6 +146,7 @@ static EmergencyAction arg_cad_burst_action; static OOMPolicy arg_default_oom_policy; static CPUSet arg_cpu_affinity; static NUMAPolicy arg_numa_policy; +static usec_t arg_clock_usec; /* A copy of the original environment block */ static char **saved_env = NULL; @@ -491,6 +492,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat (void) parse_path_argument_and_warn(value, false, &arg_watchdog_device); + } else if (proc_cmdline_key_streq(key, "systemd.clock_usec")) { + + if (proc_cmdline_value_missing(key, value)) + return 0; + + r = safe_atou64(value, &arg_clock_usec); + if (r < 0) + log_warning_errno(r, "Failed to parse systemd.clock_usec= argument, ignoring: %s", value); + } else if (streq(key, "quiet") && !value) { if (arg_show_status == _SHOW_STATUS_INVALID) @@ -1504,6 +1514,9 @@ static int become_shutdown( static void initialize_clock(void) { int r; + /* This is called very early on, before we parse the kernel command line or otherwise figure out why + * we are running, but only once. */ + if (clock_is_localtime(NULL) > 0) { int min; @@ -1542,6 +1555,25 @@ static void initialize_clock(void) { log_info("System time before build time, advancing clock."); } +static void apply_clock_update(void) { + struct timespec ts; + + /* This is called later than initialize_clock(), i.e. after we parsed configuration files/kernel + * command line and such. */ + + if (arg_clock_usec == 0) + return; + + if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, arg_clock_usec)) < 0) + log_error_errno(errno, "Failed to set system clock to time specified on kernel command line: %m"); + else { + char buf[FORMAT_TIMESTAMP_MAX]; + + log_info("Set system clock to %s, as specified on the kernel command line.", + format_timestamp(buf, sizeof(buf), arg_clock_usec)); + } +} + static void initialize_coredump(bool skip_setup) { #if ENABLE_COREDUMP if (getpid_cached() != 1) @@ -2658,6 +2690,8 @@ int main(int argc, char *argv[]) { assert_se(chdir("/") == 0); if (arg_action == ACTION_RUN) { + /* Apply the systemd.clock_usec= kernel command line switch */ + apply_clock_update(); /* A core pattern might have been specified via the cmdline. */ initialize_core_pattern(skip_setup);