From: Marc-André Lureau <marcandre.lur...@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> --- configure | 1 + qga/commands-win32.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 2 deletions(-)
diff --git a/configure b/configure index c5c4b82..82ee185 100755 --- a/configure +++ b/configure @@ -734,6 +734,7 @@ if test "$mingw32" = "yes" ; then local_statedir= confsuffix="" libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi -lnetapi32 $libs_qga" + libs_qga="-lole32 -loleaut32 -lwbemuuid -lpsapi $libs_qga" fi werror="" diff --git a/qga/commands-win32.c b/qga/commands-win32.c index bf9cd93..be11221 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -27,6 +27,8 @@ #include <initguid.h> #endif #include <lm.h> +#include <wbemcli.h> +#include <psapi.h> #include "qga/guest-agent-core.h" #include "qga/vss-win32.h" @@ -1333,8 +1335,166 @@ void ga_command_state_init(GAState *s, GACommandState *cs) ga_command_state_add(cs, guest_file_init, NULL); } +#define chk(msg) \ + do { \ + if (FAILED(hr)) { \ + gchar *emsg = g_win32_error_message(GetLastError()); \ + slog("Failed to %s: %s", (msg), emsg); \ + g_free(emsg); \ + goto out; \ + } \ + } while (0) + +static gboolean get_memory_wmi_info(GuestMemoryInfo *info) +{ + HRESULT hr = 0; + IWbemLocator *locator = NULL; + IWbemServices *services = NULL; + IEnumWbemClassObject *results = NULL; + BSTR resource, language, query_perf, query_swap; + gboolean success = FALSE; + + g_return_val_if_fail(info != NULL, FALSE); + + resource = SysAllocString(L"ROOT\\CIMV2"); + language = SysAllocString(L"WQL"); + query_perf = SysAllocString(L"SELECT * FROM " + "Win32_PerfFormattedData_PerfOS_Memory"); + query_swap = SysAllocString(L"SELECT * FROM " + "Win32_PageFileUsage"); + + /* initialize COM */ + hr = CoInitializeEx(0, COINIT_MULTITHREADED); + chk("initialize COM"); + + hr = CoInitializeSecurity(NULL, -1, NULL, NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, EOAC_NONE, NULL); + chk("initialize COM security"); + + /* connect to WMI */ + hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, + &IID_IWbemLocator, (LPVOID *) &locator); + chk("create WbemLocator instance"); + + hr = locator->lpVtbl->ConnectServer(locator, resource, NULL, NULL, NULL, 0, + NULL, NULL, &services); + chk("connect to CIMV2 server"); + + /* issue a WMI perf query */ + hr = services->lpVtbl->ExecQuery(services, language, query_perf, + WBEM_FLAG_BIDIRECTIONAL, NULL, &results); + chk("execute perf query"); + + if (results != NULL) { + IWbemClassObject *result = NULL; + ULONG returnedCount = 0; + + /* enumerate the retrieved objects */ + while ((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1, + &result, &returnedCount)) == S_OK) { + VARIANT pages_in, pages_out, pf, pfr; + + hr = result->lpVtbl->Get(result, L"PagesInputPersec", 0, + &pages_in, 0, 0); + hr = result->lpVtbl->Get(result, L"PagesOutputPersec", 0, + &pages_out, 0, 0); + hr = result->lpVtbl->Get(result, L"PageFaultsPersec", 0, + &pf, 0, 0); + hr = result->lpVtbl->Get(result, L"PageReadsPersec", 0, + &pfr, 0, 0); + + info->swap_in += pages_in.ulVal; + info->swap_out += pages_out.ulVal; + info->pf_minor += pf.ulVal - pfr.ulVal; + info->pf_major += pfr.ulVal; + + result->lpVtbl->Release(result); + } + + results->lpVtbl->Release(results); + } + + /* issue a WMI swap query */ + hr = services->lpVtbl->ExecQuery(services, language, query_swap, + WBEM_FLAG_BIDIRECTIONAL, NULL, &results); + chk("execute swap query"); + + if (results != NULL) { + IWbemClassObject *result = NULL; + ULONG returnedCount = 0; + + /* enumerate the retrieved objects */ + while ((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1, + &result, &returnedCount)) == S_OK) { + VARIANT usage, alloc; + + hr = result->lpVtbl->Get(result, L"AllocatedBaseSize", 0, + &alloc, 0, 0); + hr = result->lpVtbl->Get(result, L"CurrentUsage", 0, + &usage, 0, 0); + + /* MiB to kiB */ + info->swap_total += alloc.ulVal * 1024; + info->swap_free += (alloc.ulVal - usage.ulVal) * 1024; + + result->lpVtbl->Release(result); + } + + results->lpVtbl->Release(results); + } + + success = TRUE; + +out: + /* release WMI COM interfaces */ + if (services) { + services->lpVtbl->Release(services); + } + if (locator) { + locator->lpVtbl->Release(locator); + } + + /* unwind everything else we've allocated */ + CoUninitialize(); + + if (query_perf) { + SysFreeString(query_perf); + } + if (query_swap) { + SysFreeString(query_swap); + } + if (language) { + SysFreeString(language); + } + if (resource) { + SysFreeString(resource); + } + + return success; +} + GuestMemoryInfo *qmp_guest_get_memory_info(Error **errp) { - error_setg(errp, QERR_UNSUPPORTED); - return NULL; + GuestMemoryInfo *info = g_new0(GuestMemoryInfo, 1); + PERFORMANCE_INFORMATION perf = { .cb = sizeof(PERFORMANCE_INFORMATION) }; + + if (!get_memory_wmi_info(info)) { + error_setg(errp, "Failed to get WMI info"); + g_free(info); + return NULL; + } + + if (!GetPerformanceInfo(&perf, perf.cb)) { + error_setg(errp, "Failed to get performance info"); + g_free(info); + return NULL; + } + + info->mem_total = (perf.PhysicalTotal * perf.PageSize) / 1024; + info->mem_free = (perf.PhysicalAvailable * perf.PageSize) / 1024; + info->mem_cached = (perf.SystemCache * perf.PageSize) / 1024; + + return info; } -- 2.4.3