Here's a patch to VBoxService that makes it write to the RTC after it
updates the system clock.

-- 
Sam Morris <https://robots.org.uk/>
CAAA AA1A CA69 A83A 892B  1855 D20B 4202 5CDA 27B9

--- virtualbox-5.0.14-dfsg.orig/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp
+++ virtualbox-5.0.14-dfsg/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp
@@ -86,6 +86,15 @@
 #ifdef RT_OS_WINDOWS
 # include <Windows.h>
 #else
+# ifdef RT_OS_LINUX
+#  include <fcntl.h>
+#  include <linux/rtc.h>
+#  include <stdio.h>
+#  include <stdlib.h>
+#  include <sys/ioctl.h>
+#  include <sys/stat.h>
+#  include <sys/types.h>
+# endif /* RT_OS_LINUX */
 # include <unistd.h>
 # include <errno.h>
 # include <time.h>
@@ -450,6 +459,89 @@ static void vgsvcTimeSyncCancelAdjust(vo
 #endif /* !RT_OS_WINDOWS */
 }
 
+/**
+ * Updates "hardware" RTC, so that time is correct during early boot.
+ *
+ */
+static void vgsvcTimeSyncSaveToRTC() {
+#ifdef RT_OS_LINUX
+    FILE *adjtime_f = NULL;
+    char *adjtime_line = NULL;
+    size_t adjtime_buffer_len = 0;
+    ssize_t adjtime_line_len;
+    struct tm * (*xtime) (const time_t *) = NULL;
+    time_t now;
+    struct tm *now_tm = NULL;
+    int rtc_fd = -1;
+
+    if (!(adjtime_f = fopen("/etc/adjtime", "re")))
+    {
+        VGSvcError("vgsvcTimeSyncSaveToRTC: open(/etc/adjtime) failed, error=%d\n", errno);
+        goto out;
+    }
+
+    getline(&adjtime_line, &adjtime_buffer_len, adjtime_f);
+    getline(&adjtime_line, &adjtime_buffer_len, adjtime_f);
+    if ((adjtime_line_len = getline(&adjtime_line, &adjtime_buffer_len, adjtime_f)) == -1) {
+        VGSvcError("vgsvcTimeSyncSaveToRTC: could not read /etc/adjtime, assuming UTC is in use, error=%d\n", errno);
+        xtime = &gmtime;
+    }
+    else
+    {
+        if (adjtime_line[adjtime_line_len-1] == '\n')
+            adjtime_line[adjtime_line_len-1] = '\0';
+
+        if (strcmp(adjtime_line, "LOCAL") == 0)
+        {
+            VGSvcVerbose(3, "RTC using local time\n");
+            xtime = &localtime;
+        }
+        else if (strcmp(adjtime_line, "UTC") == 0)
+        {
+            VGSvcVerbose(3, "RTC using UTC\n");
+            xtime = &gmtime;
+        }
+        else
+        {
+            VGSvcError("vgsvcTimeSyncSaveToRTC: unknown time standard '%s', not setting RTC\n", adjtime_line);
+            goto out;
+        }
+    }
+
+    if ((now = time(NULL)) == (time_t)-1)
+    {
+        VGSvcError("vgsvcTimeSyncSaveToRTC: time() failed, error=%d\n", errno);
+        goto out;
+    }
+    if (!(now_tm = (*xtime)(&now)))
+    {
+        VGSvcError("vgsvcTimeSyncSaveToRTC: {gm|local}time() failed\n");
+        goto out;
+    }
+
+    if ((rtc_fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC)) == -1)
+    {
+        VGSvcError("vgsvcTimeSyncSaveToRTC: open(/dev/rtc) failed, error=%d\n", errno);
+        goto out;
+    }
+
+    if (ioctl(rtc_fd, RTC_SET_TIME, now_tm) == -1)
+    {
+        VGSvcError("vgsvcTimeSyncSaveToRTC: ioctl(RTC_SET_TIME) failed, errno=%d\n", errno);
+        goto out;
+    }
+
+    VGSvcVerbose(3, "RTC updated\n");
+
+out:
+    close(rtc_fd);
+    free(adjtime_line);
+    if (adjtime_f)
+        fclose(adjtime_f);
+    return;
+#endif /* !RT_OS_LINUX */
+}
+
 
 /**
  * Try adjust the time using adjtime or similar.
@@ -585,6 +677,7 @@ DECLCALLBACK(int) vgsvcTimeSyncWorker(bo
                         vgsvcTimeSyncCancelAdjust();
                         vgsvcTimeSyncSet(&Drift);
                     }
+                    vgsvcTimeSyncSaveToRTC();
                 }
                 else
                     vgsvcTimeSyncCancelAdjust();

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to