void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) { int ret; int status; pid_t pid; Error *local_err = NULL; struct timeval tv; /* 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; g_date_set_time_t(&date, tv.tv_sec); if (date.year < 1970 || date.year >= 2070) { error_setg_errno(errp, errno, "Invalid time"); return; } ret = settimeofday(&tv, NULL); if (ret < 0) { error_setg_errno(errp, errno, "Failed to set time to guest"); return; } } /* 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 (RTC). */ pid = fork(); if (pid == 0) { setsid(); reopen_fd_to_null(0); reopen_fd_to_null(1); reopen_fd_to_null(2); /* 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"); return; } ga_wait_child(pid, &status, &local_err); if (local_err) { error_propagate(errp, local_err); return; } if (!WIFEXITED(status)) { error_setg(errp, "child process has terminated abnormally"); return; } if (WEXITSTATUS(status)) { error_setg(errp, "hwclock failed to set hardware clock to system time"); return; } }