Loading configure +1 −1 Original line number Diff line number Diff line Loading @@ -525,7 +525,7 @@ EOF bindir="\${prefix}" sysconfdir="\${prefix}" confsuffix="" libs_qga="-lws2_32 -lwinmm $lib_qga" libs_qga="-lws2_32 -lwinmm -lpowrprof $lib_qga" fi werror="" Loading qga/commands-win32.c +120 −12 Original line number Diff line number Diff line Loading @@ -5,12 +5,15 @@ * * Authors: * Michael Roth <mdroth@linux.vnet.ibm.com> * Gal Hammer <ghammer@redhat.com> * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ #include <glib.h> #include <wtypes.h> #include <powrprof.h> #include "qga/guest-agent-core.h" #include "qga-qmp-commands.h" #include "qerror.h" Loading @@ -19,10 +22,63 @@ #define SHTDN_REASON_FLAG_PLANNED 0x80000000 #endif void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) static void acquire_privilege(const char *name, Error **err) { HANDLE token; TOKEN_PRIVILEGES priv; Error *local_err = NULL; if (error_is_set(err)) { return; } if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token)) { if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "no luid for requested privilege"); goto out; } priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "unable to acquire requested privilege"); goto out; } CloseHandle(token); } else { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "failed to open privilege token"); } out: if (local_err) { error_propagate(err, local_err); } } static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, Error **err) { Error *local_err = NULL; if (error_is_set(err)) { return; } HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL); if (!thread) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "failed to dispatch asynchronous command"); error_propagate(err, local_err); } } void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) { UINT shutdown_flag = EWX_FORCE; slog("guest-shutdown called, mode: %s", mode); Loading @@ -41,16 +97,9 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) /* Request a shutdown privilege, but try to shut down the system anyway. */ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token)) { LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &priv.Privileges[0].Luid); priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0); acquire_privilege(SE_SHUTDOWN_NAME, err); if (error_is_set(err)) { return; } if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) { Loading Loading @@ -124,9 +173,68 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) return 0; } typedef enum { GUEST_SUSPEND_MODE_DISK } GuestSuspendMode; static void check_suspend_mode(GuestSuspendMode mode, Error **err) { SYSTEM_POWER_CAPABILITIES sys_pwr_caps; Error *local_err = NULL; if (error_is_set(err)) { return; } ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps)); if (!GetPwrCapabilities(&sys_pwr_caps)) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "failed to determine guest suspend capabilities"); goto out; } if (mode == GUEST_SUSPEND_MODE_DISK) { if (sys_pwr_caps.SystemS4) { return; } } else { error_set(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode", "GuestSuspendMode"); goto out; } error_set(&local_err, QERR_QGA_COMMAND_FAILED, "suspend mode not supported by OS"); out: if (local_err) { error_propagate(err, local_err); } } static DWORD WINAPI do_suspend(LPVOID opaque) { GuestSuspendMode *mode = opaque; DWORD ret = 0; if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) { slog("failed to suspend guest, %s", GetLastError()); ret = -1; } g_free(mode); return ret; } void qmp_guest_suspend_disk(Error **err) { error_set(err, QERR_UNSUPPORTED); GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); *mode = GUEST_SUSPEND_MODE_DISK; check_suspend_mode(*mode, err); acquire_privilege(SE_SHUTDOWN_NAME, err); execute_async(do_suspend, mode, err); if (error_is_set(err)) { g_free(mode); } } void qmp_guest_suspend_ram(Error **err) Loading Loading
configure +1 −1 Original line number Diff line number Diff line Loading @@ -525,7 +525,7 @@ EOF bindir="\${prefix}" sysconfdir="\${prefix}" confsuffix="" libs_qga="-lws2_32 -lwinmm $lib_qga" libs_qga="-lws2_32 -lwinmm -lpowrprof $lib_qga" fi werror="" Loading
qga/commands-win32.c +120 −12 Original line number Diff line number Diff line Loading @@ -5,12 +5,15 @@ * * Authors: * Michael Roth <mdroth@linux.vnet.ibm.com> * Gal Hammer <ghammer@redhat.com> * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ #include <glib.h> #include <wtypes.h> #include <powrprof.h> #include "qga/guest-agent-core.h" #include "qga-qmp-commands.h" #include "qerror.h" Loading @@ -19,10 +22,63 @@ #define SHTDN_REASON_FLAG_PLANNED 0x80000000 #endif void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) static void acquire_privilege(const char *name, Error **err) { HANDLE token; TOKEN_PRIVILEGES priv; Error *local_err = NULL; if (error_is_set(err)) { return; } if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token)) { if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "no luid for requested privilege"); goto out; } priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "unable to acquire requested privilege"); goto out; } CloseHandle(token); } else { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "failed to open privilege token"); } out: if (local_err) { error_propagate(err, local_err); } } static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, Error **err) { Error *local_err = NULL; if (error_is_set(err)) { return; } HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL); if (!thread) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "failed to dispatch asynchronous command"); error_propagate(err, local_err); } } void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) { UINT shutdown_flag = EWX_FORCE; slog("guest-shutdown called, mode: %s", mode); Loading @@ -41,16 +97,9 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) /* Request a shutdown privilege, but try to shut down the system anyway. */ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token)) { LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &priv.Privileges[0].Luid); priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0); acquire_privilege(SE_SHUTDOWN_NAME, err); if (error_is_set(err)) { return; } if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) { Loading Loading @@ -124,9 +173,68 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) return 0; } typedef enum { GUEST_SUSPEND_MODE_DISK } GuestSuspendMode; static void check_suspend_mode(GuestSuspendMode mode, Error **err) { SYSTEM_POWER_CAPABILITIES sys_pwr_caps; Error *local_err = NULL; if (error_is_set(err)) { return; } ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps)); if (!GetPwrCapabilities(&sys_pwr_caps)) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "failed to determine guest suspend capabilities"); goto out; } if (mode == GUEST_SUSPEND_MODE_DISK) { if (sys_pwr_caps.SystemS4) { return; } } else { error_set(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode", "GuestSuspendMode"); goto out; } error_set(&local_err, QERR_QGA_COMMAND_FAILED, "suspend mode not supported by OS"); out: if (local_err) { error_propagate(err, local_err); } } static DWORD WINAPI do_suspend(LPVOID opaque) { GuestSuspendMode *mode = opaque; DWORD ret = 0; if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) { slog("failed to suspend guest, %s", GetLastError()); ret = -1; } g_free(mode); return ret; } void qmp_guest_suspend_disk(Error **err) { error_set(err, QERR_UNSUPPORTED); GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); *mode = GUEST_SUSPEND_MODE_DISK; check_suspend_mode(*mode, err); acquire_privilege(SE_SHUTDOWN_NAME, err); execute_async(do_suspend, mode, err); if (error_is_set(err)) { g_free(mode); } } void qmp_guest_suspend_ram(Error **err) Loading