diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-02-25 12:30:01 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-02-25 12:30:01 +0000 |
commit | 0459650d94d18218808fcabc8c3227d2ee99af39 (patch) | |
tree | 89b1f02e7e4784c444faf91506ca7fcfd8bb7e7b | |
parent | 05fd3bf2a1c9fc26414d3cf608732c40d0d9eb23 (diff) | |
parent | a749f42da5129bbfadea6926964d9a213ed4bc5f (diff) | |
download | qemu-0459650d94d18218808fcabc8c3227d2ee99af39.tar.gz qemu-0459650d94d18218808fcabc8c3227d2ee99af39.tar.bz2 qemu-0459650d94d18218808fcabc8c3227d2ee99af39.zip |
Merge remote-tracking branch 'remotes/mdroth/qga-pull-2014-02-24' into staging
* remotes/mdroth/qga-pull-2014-02-24:
qemu-ga: isa-serial support on Windows
qga: Fix memory allocation pasto
qga: Don't require 'time' argument in guest-set-time command
qga: vss-win32: Fix interference with snapshot deletion by other VSS request
qga: vss-win32: Fix interference with snapshot creation by other VSS requesters
qga: vss-win32: Use NULL as an invalid pointer for OpenEvent and CreateEvent
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | qga/channel-win32.c | 20 | ||||
-rw-r--r-- | qga/commands-posix.c | 39 | ||||
-rw-r--r-- | qga/commands-win32.c | 34 | ||||
-rw-r--r-- | qga/main.c | 17 | ||||
-rw-r--r-- | qga/qapi-schema.json | 9 | ||||
-rw-r--r-- | qga/vss-win32/provider.cpp | 21 | ||||
-rw-r--r-- | qga/vss-win32/requester.cpp | 70 |
7 files changed, 132 insertions, 78 deletions
diff --git a/qga/channel-win32.c b/qga/channel-win32.c index 8a303f35ec..0d5e5f511f 100644 --- a/qga/channel-win32.c +++ b/qga/channel-win32.c @@ -287,12 +287,22 @@ GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size) static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method, const gchar *path) { - if (method != GA_CHANNEL_VIRTIO_SERIAL) { + COMMTIMEOUTS comTimeOut = {0}; + gchar newpath[MAXPATHLEN] = {0}; + comTimeOut.ReadIntervalTimeout = 1; + + if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) { g_critical("unsupported communication method"); return false; } - c->handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, + if (method == GA_CHANNEL_ISA_SERIAL){ + snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path); + }else { + g_strlcpy(newpath, path, sizeof(newpath)); + } + + c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); if (c->handle == INVALID_HANDLE_VALUE) { @@ -300,6 +310,12 @@ static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method, return false; } + if (method == GA_CHANNEL_ISA_SERIAL && !SetCommTimeouts(c->handle,&comTimeOut)) { + g_critical("error setting timeout for com port: %lu",GetLastError()); + CloseHandle(c->handle); + return false; + } + return true; } diff --git a/qga/commands-posix.c b/qga/commands-posix.c index cae41716ca..6b5f11f83f 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"); @@ -525,7 +534,7 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, if (ret == -1) { error_setg_errno(err, errno, "failed to seek file"); } else { - seek_data = g_malloc0(sizeof(GuestFileRead)); + seek_data = g_new0(GuestFileSeek, 1); seek_data->position = ftell(fh); seek_data->eof = feof(fh); } diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 50094ddfd3..0ee07b6e23 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/main.c b/qga/main.c index c58b26a9a0..cfca291b43 100644 --- a/qga/main.c +++ b/qga/main.c @@ -47,9 +47,11 @@ #ifndef _WIN32 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0" #define QGA_STATE_RELATIVE_DIR "run" +#define QGA_SERIAL_PATH_DEFAULT "/dev/ttyS0" #else #define QGA_VIRTIO_PATH_DEFAULT "\\\\.\\Global\\org.qemu.guest_agent.0" #define QGA_STATE_RELATIVE_DIR "qemu-ga" +#define QGA_SERIAL_PATH_DEFAULT "COM1" #endif #ifdef CONFIG_FSFREEZE #define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook" @@ -189,6 +191,8 @@ static void usage(const char *cmd) " -m, --method transport method: one of unix-listen, virtio-serial, or\n" " isa-serial (virtio-serial is the default)\n" " -p, --path device/socket path (the default for virtio-serial is:\n" +" %s,\n" +" the default for isa-serial is:\n" " %s)\n" " -l, --logfile set logfile path, logs to stderr by default\n" " -f, --pidfile specify pidfile (default is %s)\n" @@ -215,7 +219,8 @@ static void usage(const char *cmd) " -h, --help display this help and exit\n" "\n" "Report bugs to <mdroth@linux.vnet.ibm.com>\n" - , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, dfl_pathnames.pidfile, + , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT, + dfl_pathnames.pidfile, #ifdef CONFIG_FSFREEZE QGA_FSFREEZE_HOOK_DEFAULT, #endif @@ -659,12 +664,16 @@ static gboolean channel_init(GAState *s, const gchar *method, const gchar *path) } if (path == NULL) { - if (strcmp(method, "virtio-serial") != 0) { + if (strcmp(method, "virtio-serial") == 0 ) { + /* try the default path for the virtio-serial port */ + path = QGA_VIRTIO_PATH_DEFAULT; + } else if (strcmp(method, "isa-serial") == 0){ + /* try the default path for the serial port - COM1 */ + path = QGA_SERIAL_PATH_DEFAULT; + } else { g_critical("must specify a path for this channel"); return false; } - /* try the default path for the virtio-serial port */ - path = QGA_VIRTIO_PATH_DEFAULT; } if (strcmp(method, "virtio-serial") == 0) { diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 245f968bc2..80edca143a 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: diff --git a/qga/vss-win32/provider.cpp b/qga/vss-win32/provider.cpp index bf42b5e95f..d5129f8f65 100644 --- a/qga/vss-win32/provider.cpp +++ b/qga/vss-win32/provider.cpp @@ -278,7 +278,9 @@ STDMETHODIMP CQGAVssProvider::DeleteSnapshots( VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType, BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID) { - return E_NOTIMPL; + *plDeletedSnapshots = 0; + *pNondeletedSnapshotID = SourceObjectId; + return S_OK; } STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot( @@ -291,8 +293,17 @@ STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot( STDMETHODIMP CQGAVssProvider::IsVolumeSupported( VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider) { - *pbSupportedByThisProvider = TRUE; + HANDLE hEventFrozen; + /* Check if a requester is qemu-ga by whether an event is created */ + hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN); + if (!hEventFrozen) { + *pbSupportedByThisProvider = FALSE; + return S_OK; + } + CloseHandle(hEventFrozen); + + *pbSupportedByThisProvider = TRUE; return S_OK; } @@ -342,18 +353,18 @@ STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId) HANDLE hEventFrozen, hEventThaw, hEventTimeout; hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN); - if (hEventFrozen == INVALID_HANDLE_VALUE) { + if (!hEventFrozen) { return E_FAIL; } hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW); - if (hEventThaw == INVALID_HANDLE_VALUE) { + if (!hEventThaw) { CloseHandle(hEventFrozen); return E_FAIL; } hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT); - if (hEventTimeout == INVALID_HANDLE_VALUE) { + if (!hEventTimeout) { CloseHandle(hEventFrozen); CloseHandle(hEventThaw); return E_FAIL; diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index 1e8dd3dfa8..922e74ddfc 100644 --- a/qga/vss-win32/requester.cpp +++ b/qga/vss-win32/requester.cpp @@ -50,10 +50,6 @@ static struct QGAVSSContext { STDAPI requester_init(void) { - vss_ctx.hEventFrozen = INVALID_HANDLE_VALUE; - vss_ctx.hEventThaw = INVALID_HANDLE_VALUE; - vss_ctx.hEventTimeout = INVALID_HANDLE_VALUE; - COMInitializer initializer; /* to call CoInitializeSecurity */ HRESULT hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, @@ -94,17 +90,17 @@ STDAPI requester_init(void) static void requester_cleanup(void) { - if (vss_ctx.hEventFrozen != INVALID_HANDLE_VALUE) { + if (vss_ctx.hEventFrozen) { CloseHandle(vss_ctx.hEventFrozen); - vss_ctx.hEventFrozen = INVALID_HANDLE_VALUE; + vss_ctx.hEventFrozen = NULL; } - if (vss_ctx.hEventThaw != INVALID_HANDLE_VALUE) { + if (vss_ctx.hEventThaw) { CloseHandle(vss_ctx.hEventThaw); - vss_ctx.hEventThaw = INVALID_HANDLE_VALUE; + vss_ctx.hEventThaw = NULL; } - if (vss_ctx.hEventTimeout != INVALID_HANDLE_VALUE) { + if (vss_ctx.hEventTimeout) { CloseHandle(vss_ctx.hEventTimeout); - vss_ctx.hEventTimeout = INVALID_HANDLE_VALUE; + vss_ctx.hEventTimeout = NULL; } if (vss_ctx.pAsyncSnapshot) { vss_ctx.pAsyncSnapshot->Release(); @@ -256,6 +252,32 @@ void requester_freeze(int *num_vols, ErrorSet *errset) CoInitialize(NULL); + /* Allow unrestricted access to events */ + InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = &sd; + sa.bInheritHandle = FALSE; + + vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); + if (!vss_ctx.hEventFrozen) { + err_set(errset, GetLastError(), "failed to create event %s", + EVENT_NAME_FROZEN); + goto out; + } + vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); + if (!vss_ctx.hEventThaw) { + err_set(errset, GetLastError(), "failed to create event %s", + EVENT_NAME_THAW); + goto out; + } + vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); + if (!vss_ctx.hEventTimeout) { + err_set(errset, GetLastError(), "failed to create event %s", + EVENT_NAME_TIMEOUT); + goto out; + } + assert(pCreateVssBackupComponents != NULL); hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); if (FAILED(hr)) { @@ -366,32 +388,6 @@ void requester_freeze(int *num_vols, ErrorSet *errset) goto out; } - /* Allow unrestricted access to events */ - InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); - SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = &sd; - sa.bInheritHandle = FALSE; - - vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); - if (vss_ctx.hEventFrozen == INVALID_HANDLE_VALUE) { - err_set(errset, GetLastError(), "failed to create event %s", - EVENT_NAME_FROZEN); - goto out; - } - vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); - if (vss_ctx.hEventThaw == INVALID_HANDLE_VALUE) { - err_set(errset, GetLastError(), "failed to create event %s", - EVENT_NAME_THAW); - goto out; - } - vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); - if (vss_ctx.hEventTimeout == INVALID_HANDLE_VALUE) { - err_set(errset, GetLastError(), "failed to create event %s", - EVENT_NAME_TIMEOUT); - goto out; - } - /* * Start VSS quiescing operations. * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen @@ -443,7 +439,7 @@ void requester_thaw(int *num_vols, ErrorSet *errset) { COMPointer<IVssAsync> pAsync; - if (vss_ctx.hEventThaw == INVALID_HANDLE_VALUE) { + if (!vss_ctx.hEventThaw) { /* * In this case, DoSnapshotSet is aborted or not started, * and no volumes must be frozen. We return without an error. |