Patchwork [v3,8/8] qemu-ga: add win32 guest-shutdown command

login
register
mail settings
Submitter Michael Roth
Date Feb. 14, 2012, 3:15 p.m.
Message ID <1329232542-30251-9-git-send-email-mdroth@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/141183/
State New
Headers show

Comments

Michael Roth - Feb. 14, 2012, 3:15 p.m.
Implement guest-shutdown RPC for Windows. Functionally this should be
equivalent to the posix implementation.

Original patch by Gal Hammer <ghammer@redhat.com>

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/commands-win32.c |   41 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 40 insertions(+), 1 deletions(-)

Patch

diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index d96f1ad..4aa0f0d 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -15,9 +15,48 @@ 
 #include "qga-qmp-commands.h"
 #include "qerror.h"
 
+#ifndef SHTDN_REASON_FLAG_PLANNED
+#define SHTDN_REASON_FLAG_PLANNED 0x80000000
+#endif
+
 void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
 {
-    error_set(err, QERR_UNSUPPORTED);
+    HANDLE token;
+    TOKEN_PRIVILEGES priv;
+    UINT shutdown_flag = EWX_FORCE;
+
+    slog("guest-shutdown called, mode: %s", mode);
+
+    if (!has_mode || strcmp(mode, "powerdown") == 0) {
+        shutdown_flag |= EWX_POWEROFF;
+    } else if (strcmp(mode, "halt") == 0) {
+        shutdown_flag |= EWX_SHUTDOWN;
+    } else if (strcmp(mode, "reboot") == 0) {
+        shutdown_flag |= EWX_REBOOT;
+    } else {
+        error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
+                  "halt|powerdown|reboot");
+        return;
+    }
+
+    /* 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);
+    }
+
+    if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) {
+        slog("guest-shutdown failed: %d", GetLastError());
+        error_set(err, QERR_UNDEFINED_ERROR);
+    }
 }
 
 int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)