aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qga/commands-posix.c37
-rw-r--r--qga/commands-win32.c34
-rw-r--r--qga/qapi-schema.json9
3 files changed, 51 insertions, 29 deletions
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index cae4171..9188560 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -142,7 +142,7 @@ int64_t qmp_guest_get_time(Error **errp)
return time_ns;
}
-void qmp_guest_set_time(int64_t time_ns, Error **errp)
+void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
{
int ret;
int status;
@@ -150,22 +150,28 @@ void qmp_guest_set_time(int64_t time_ns, Error **errp)
Error *local_err = NULL;
struct timeval tv;
- /* year-2038 will overflow in case time_t is 32bit */
- if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
- error_setg(errp, "Time %" PRId64 " is too large", time_ns);
- return;
- }
+ /* If user has passed a time, validate and set it. */
+ if (has_time) {
+ /* year-2038 will overflow in case time_t is 32bit */
+ if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
+ error_setg(errp, "Time %" PRId64 " is too large", time_ns);
+ return;
+ }
- tv.tv_sec = time_ns / 1000000000;
- tv.tv_usec = (time_ns % 1000000000) / 1000;
+ tv.tv_sec = time_ns / 1000000000;
+ tv.tv_usec = (time_ns % 1000000000) / 1000;
- ret = settimeofday(&tv, NULL);
- if (ret < 0) {
- error_setg_errno(errp, errno, "Failed to set time to guest");
- return;
+ ret = settimeofday(&tv, NULL);
+ if (ret < 0) {
+ error_setg_errno(errp, errno, "Failed to set time to guest");
+ return;
+ }
}
- /* Set the Hardware Clock to the current System Time. */
+ /* Now, if user has passed a time to set and the system time is set, we
+ * just need to synchronize the hardware clock. However, if no time was
+ * passed, user is requesting the opposite: set the system time from the
+ * hardware clock. */
pid = fork();
if (pid == 0) {
setsid();
@@ -173,7 +179,10 @@ void qmp_guest_set_time(int64_t time_ns, Error **errp)
reopen_fd_to_null(1);
reopen_fd_to_null(2);
- execle("/sbin/hwclock", "hwclock", "-w", NULL, environ);
+ /* Use '/sbin/hwclock -w' to set RTC from the system time,
+ * or '/sbin/hwclock -s' to set the system time from RTC. */
+ execle("/sbin/hwclock", "hwclock", has_time ? "-w" : "-s",
+ NULL, environ);
_exit(EXIT_FAILURE);
} else if (pid < 0) {
error_setg_errno(errp, errno, "failed to create child process");
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 50094dd..0ee07b6 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -370,25 +370,37 @@ int64_t qmp_guest_get_time(Error **errp)
return time_ns;
}
-void qmp_guest_set_time(int64_t time_ns, Error **errp)
+void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
{
SYSTEMTIME ts;
FILETIME tf;
LONGLONG time;
- if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
- error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
- return;
- }
+ if (has_time) {
+ /* Okay, user passed a time to set. Validate it. */
+ if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
+ error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
+ return;
+ }
- time = time_ns / 100 + W32_FT_OFFSET;
+ time = time_ns / 100 + W32_FT_OFFSET;
- tf.dwLowDateTime = (DWORD) time;
- tf.dwHighDateTime = (DWORD) (time >> 32);
+ tf.dwLowDateTime = (DWORD) time;
+ tf.dwHighDateTime = (DWORD) (time >> 32);
- if (!FileTimeToSystemTime(&tf, &ts)) {
- error_setg(errp, "Failed to convert system time %d", (int)GetLastError());
- return;
+ if (!FileTimeToSystemTime(&tf, &ts)) {
+ error_setg(errp, "Failed to convert system time %d",
+ (int)GetLastError());
+ return;
+ }
+ } else {
+ /* Otherwise read the time from RTC which contains the correct value.
+ * Hopefully. */
+ GetSystemTime(&ts);
+ if (ts.wYear < 1601 || ts.wYear > 30827) {
+ error_setg(errp, "Failed to get time");
+ return;
+ }
}
acquire_privilege(SE_SYSTEMTIME_NAME, errp);
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 245f968..80edca1 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -120,17 +120,18 @@
# This command tries to set guest time to the given value,
# then sets the Hardware Clock to the current System Time.
# This will make it easier for a guest to resynchronize
-# without waiting for NTP.
+# without waiting for NTP. If no @time is specified, then
+# the time to set is read from RTC.
#
-# @time: time of nanoseconds, relative to the Epoch of
-# 1970-01-01 in UTC.
+# @time: #optional time of nanoseconds, relative to the Epoch
+# of 1970-01-01 in UTC.
#
# Returns: Nothing on success.
#
# Since: 1.5
##
{ 'command': 'guest-set-time',
- 'data': { 'time': 'int' } }
+ 'data': { '*time': 'int' } }
##
# @GuestAgentCommandInfo: