]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
main: add a kernel command line option for setting the system clock early during...
authorLennart Poettering <lennart@poettering.net>
Thu, 14 May 2020 08:41:47 +0000 (10:41 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 18 May 2020 18:20:50 +0000 (20:20 +0200)
man/kernel-command-line.xml
src/core/main.c

index 8a899aee56a24fa1be53589f4037014fce0a04ae..fd49b65a8d43ef050d89390052e75a5e78985707 100644 (file)
         of the <filename>systemd-firstboot.service</filename> system service but has no effect on the
         condition check (see above).</para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>systemd.clock-usec=</varname></term>
+
+        <listitem><para>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).</para></listitem>
+      </varlistentry>
     </variablelist>
 
   </refsect1>
index c9eaf70bd6c84d7eb231a305892f8bea4c04eba1..3ab4aa4e1988eab923339fd128005178db7973c9 100644 (file)
@@ -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);