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();
signature.asc
Description: This is a digitally signed message part