qemu-ga: add win32 guest-suspend-disk command.
Implement guest-suspend-disk RPC for Windows. Functionally this should be equivalent to the posix implementation. Signed-off-by: Gal Hammer <ghammer@redhat.com>
This commit is contained in:
		
							parent
							
								
									95f4f404e1
								
							
						
					
					
						commit
						aa59637ea1
					
				
							
								
								
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@ -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=""
 | 
			
		||||
 | 
			
		||||
@ -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"
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -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)) {
 | 
			
		||||
@ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user