aboutsummaryrefslogtreecommitdiff
path: root/qga/commands-win32.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2017-04-28 16:12:11 +0100
committerStefan Hajnoczi <stefanha@redhat.com>2017-04-28 16:12:19 +0100
commit7ad691ec988dd0ca1c3674018f6aede8ed18128b (patch)
tree9ea5883ab18b0a0e4389875840057519bb364e1e /qga/commands-win32.c
parent81b2d5ceb0cfb4cdc2163492e3169ed714b0cda9 (diff)
parent53c58e64d0a27c59d763778faa2b5a522c544719 (diff)
Merge remote-tracking branch 'mdroth/tags/qga-pull-2017-04-25-v2-tag' into staging
qemu-ga patch queue * new commands: guest-get-timezone, guest-get-users, guest-get-host-name * fix hang on w32 when stopping qemu-ga service while fs frozen * fix missing setting of can-offline in guest-get-vcpus * make qemu-ga VSS w32 service on-demand rather than on-startup * fix unecessary errors to EventLog on w32 * improvements to fsfreeze documentation v2: * document 'zone' field of guest-get-timezone as informational-only (Daniel, Eric) * fix build error for glib < 2.32 (Peter) # gpg: Signature made Thu 27 Apr 2017 06:43:42 AM BST # gpg: using RSA key 0x3353C9CEF108B584 # gpg: Good signature from "Michael Roth <flukshun@gmail.com>" # gpg: aka "Michael Roth <mdroth@utexas.edu>" # gpg: aka "Michael Roth <mdroth@linux.vnet.ibm.com>" # Primary key fingerprint: CEAC C9E1 5534 EBAB B82D 3FA0 3353 C9CE F108 B584 * mdroth/tags/qga-pull-2017-04-25-v2-tag: qga: Add `guest-get-timezone` command qga: Add 'guest-get-users' command qga: improve fsfreeze documentations qga: Add 'guest-get-host-name' command qga-win: Fix Event Viewer errors caused by qemu-ga qga-win: Fix a bug where qemu-ga service is stuck during stop operation qga-win: Enable 'can-offline' field in 'guest-get-vcpus' reply qemu-ga: Make QGA VSS provider service run only when needed Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'qga/commands-win32.c')
-rw-r--r--qga/commands-win32.c105
1 files changed, 104 insertions, 1 deletions
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 04026eedbf..439d229225 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -11,6 +11,9 @@
* See the COPYING file in the top-level directory.
*/
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0600
+#endif
#include "qemu/osdep.h"
#include <wtypes.h>
#include <powrprof.h>
@@ -25,6 +28,7 @@
#include <initguid.h>
#endif
#include <lm.h>
+#include <wtsapi32.h>
#include "qga/guest-agent-core.h"
#include "qga/vss-win32.h"
@@ -1344,7 +1348,7 @@ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
vcpu = g_malloc0(sizeof *vcpu);
vcpu->logical_id = current++;
vcpu->online = true;
- vcpu->has_can_offline = false;
+ vcpu->has_can_offline = true;
entry = g_malloc0(sizeof *entry);
entry->value = vcpu;
@@ -1536,3 +1540,102 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
}
}
+
+/* MINGW is missing two fields: IncomingFrames & OutgoingFrames */
+typedef struct _GA_WTSINFOA {
+ WTS_CONNECTSTATE_CLASS State;
+ DWORD SessionId;
+ DWORD IncomingBytes;
+ DWORD OutgoingBytes;
+ DWORD IncomingFrames;
+ DWORD OutgoingFrames;
+ DWORD IncomingCompressedBytes;
+ DWORD OutgoingCompressedBy;
+ CHAR WinStationName[WINSTATIONNAME_LENGTH];
+ CHAR Domain[DOMAIN_LENGTH];
+ CHAR UserName[USERNAME_LENGTH + 1];
+ LARGE_INTEGER ConnectTime;
+ LARGE_INTEGER DisconnectTime;
+ LARGE_INTEGER LastInputTime;
+ LARGE_INTEGER LogonTime;
+ LARGE_INTEGER CurrentTime;
+
+} GA_WTSINFOA;
+
+GuestUserList *qmp_guest_get_users(Error **err)
+{
+#if (_WIN32_WINNT >= 0x0600)
+#define QGA_NANOSECONDS 10000000
+
+ GHashTable *cache = NULL;
+ GuestUserList *head = NULL, *cur_item = NULL;
+
+ DWORD buffer_size = 0, count = 0, i = 0;
+ GA_WTSINFOA *info = NULL;
+ WTS_SESSION_INFOA *entries = NULL;
+ GuestUserList *item = NULL;
+ GuestUser *user = NULL;
+ gpointer value = NULL;
+ INT64 login = 0;
+ double login_time = 0;
+
+ cache = g_hash_table_new(g_str_hash, g_str_equal);
+
+ if (WTSEnumerateSessionsA(NULL, 0, 1, &entries, &count)) {
+ for (i = 0; i < count; ++i) {
+ buffer_size = 0;
+ info = NULL;
+ if (WTSQuerySessionInformationA(
+ NULL,
+ entries[i].SessionId,
+ WTSSessionInfo,
+ (LPSTR *)&info,
+ &buffer_size
+ )) {
+
+ if (strlen(info->UserName) == 0) {
+ WTSFreeMemory(info);
+ continue;
+ }
+
+ login = info->LogonTime.QuadPart;
+ login -= W32_FT_OFFSET;
+ login_time = ((double)login) / QGA_NANOSECONDS;
+
+ if (g_hash_table_contains(cache, info->UserName)) {
+ value = g_hash_table_lookup(cache, info->UserName);
+ user = (GuestUser *)value;
+ if (user->login_time > login_time) {
+ user->login_time = login_time;
+ }
+ } else {
+ item = g_new0(GuestUserList, 1);
+ item->value = g_new0(GuestUser, 1);
+
+ item->value->user = g_strdup(info->UserName);
+ item->value->domain = g_strdup(info->Domain);
+ item->value->has_domain = true;
+
+ item->value->login_time = login_time;
+
+ g_hash_table_add(cache, item->value->user);
+
+ if (!cur_item) {
+ head = cur_item = item;
+ } else {
+ cur_item->next = item;
+ cur_item = item;
+ }
+ }
+ }
+ WTSFreeMemory(info);
+ }
+ WTSFreeMemory(entries);
+ }
+ g_hash_table_destroy(cache);
+ return head;
+#else
+ error_setg(err, QERR_UNSUPPORTED);
+ return NULL;
+#endif
+}