|
|
1.1 root 1: /*
2: * QEMU Guest Agent win32-specific command implementations
3: *
4: * Copyright IBM Corp. 2012
5: *
6: * Authors:
7: * Michael Roth <[email protected]>
8: * Gal Hammer <[email protected]>
9: *
10: * This work is licensed under the terms of the GNU GPL, version 2 or later.
11: * See the COPYING file in the top-level directory.
12: */
13:
14: #include <glib.h>
15: #include <wtypes.h>
16: #include <powrprof.h>
17: #include "qga/guest-agent-core.h"
18: #include "qga-qmp-commands.h"
19: #include "qerror.h"
20:
21: #ifndef SHTDN_REASON_FLAG_PLANNED
22: #define SHTDN_REASON_FLAG_PLANNED 0x80000000
23: #endif
24:
25: static void acquire_privilege(const char *name, Error **err)
26: {
27: HANDLE token;
28: TOKEN_PRIVILEGES priv;
29: Error *local_err = NULL;
30:
31: if (error_is_set(err)) {
32: return;
33: }
34:
35: if (OpenProcessToken(GetCurrentProcess(),
36: TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
37: {
38: if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) {
39: error_set(&local_err, QERR_QGA_COMMAND_FAILED,
40: "no luid for requested privilege");
41: goto out;
42: }
43:
44: priv.PrivilegeCount = 1;
45: priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
46:
47: if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) {
48: error_set(&local_err, QERR_QGA_COMMAND_FAILED,
49: "unable to acquire requested privilege");
50: goto out;
51: }
52:
53: CloseHandle(token);
54: } else {
55: error_set(&local_err, QERR_QGA_COMMAND_FAILED,
56: "failed to open privilege token");
57: }
58:
59: out:
60: if (local_err) {
61: error_propagate(err, local_err);
62: }
63: }
64:
65: static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, Error **err)
66: {
67: Error *local_err = NULL;
68:
69: if (error_is_set(err)) {
70: return;
71: }
72: HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL);
73: if (!thread) {
74: error_set(&local_err, QERR_QGA_COMMAND_FAILED,
75: "failed to dispatch asynchronous command");
76: error_propagate(err, local_err);
77: }
78: }
79:
80: void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
81: {
82: UINT shutdown_flag = EWX_FORCE;
83:
84: slog("guest-shutdown called, mode: %s", mode);
85:
86: if (!has_mode || strcmp(mode, "powerdown") == 0) {
87: shutdown_flag |= EWX_POWEROFF;
88: } else if (strcmp(mode, "halt") == 0) {
89: shutdown_flag |= EWX_SHUTDOWN;
90: } else if (strcmp(mode, "reboot") == 0) {
91: shutdown_flag |= EWX_REBOOT;
92: } else {
93: error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
94: "halt|powerdown|reboot");
95: return;
96: }
97:
98: /* Request a shutdown privilege, but try to shut down the system
99: anyway. */
100: acquire_privilege(SE_SHUTDOWN_NAME, err);
101: if (error_is_set(err)) {
102: return;
103: }
104:
105: if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) {
106: slog("guest-shutdown failed: %d", GetLastError());
107: error_set(err, QERR_UNDEFINED_ERROR);
108: }
109: }
110:
111: int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
112: {
113: error_set(err, QERR_UNSUPPORTED);
114: return 0;
115: }
116:
117: void qmp_guest_file_close(int64_t handle, Error **err)
118: {
119: error_set(err, QERR_UNSUPPORTED);
120: }
121:
122: GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
123: int64_t count, Error **err)
124: {
125: error_set(err, QERR_UNSUPPORTED);
126: return 0;
127: }
128:
129: GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
130: bool has_count, int64_t count, Error **err)
131: {
132: error_set(err, QERR_UNSUPPORTED);
133: return 0;
134: }
135:
136: GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
137: int64_t whence, Error **err)
138: {
139: error_set(err, QERR_UNSUPPORTED);
140: return 0;
141: }
142:
143: void qmp_guest_file_flush(int64_t handle, Error **err)
144: {
145: error_set(err, QERR_UNSUPPORTED);
146: }
147:
148: /*
149: * Return status of freeze/thaw
150: */
151: GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
152: {
153: error_set(err, QERR_UNSUPPORTED);
154: return 0;
155: }
156:
157: /*
158: * Walk list of mounted file systems in the guest, and freeze the ones which
159: * are real local file systems.
160: */
161: int64_t qmp_guest_fsfreeze_freeze(Error **err)
162: {
163: error_set(err, QERR_UNSUPPORTED);
164: return 0;
165: }
166:
167: /*
168: * Walk list of frozen file systems in the guest, and thaw them.
169: */
170: int64_t qmp_guest_fsfreeze_thaw(Error **err)
171: {
172: error_set(err, QERR_UNSUPPORTED);
173: return 0;
174: }
175:
176: typedef enum {
177: GUEST_SUSPEND_MODE_DISK,
178: GUEST_SUSPEND_MODE_RAM
179: } GuestSuspendMode;
180:
181: static void check_suspend_mode(GuestSuspendMode mode, Error **err)
182: {
183: SYSTEM_POWER_CAPABILITIES sys_pwr_caps;
184: Error *local_err = NULL;
185:
186: if (error_is_set(err)) {
187: return;
188: }
189: ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps));
190: if (!GetPwrCapabilities(&sys_pwr_caps)) {
191: error_set(&local_err, QERR_QGA_COMMAND_FAILED,
192: "failed to determine guest suspend capabilities");
193: goto out;
194: }
195:
196: switch (mode) {
197: case GUEST_SUSPEND_MODE_DISK:
198: if (!sys_pwr_caps.SystemS4) {
199: error_set(&local_err, QERR_QGA_COMMAND_FAILED,
200: "suspend-to-disk not supported by OS");
201: }
202: break;
203: case GUEST_SUSPEND_MODE_RAM:
204: if (!sys_pwr_caps.SystemS3) {
205: error_set(&local_err, QERR_QGA_COMMAND_FAILED,
206: "suspend-to-ram not supported by OS");
207: }
208: break;
209: default:
210: error_set(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode",
211: "GuestSuspendMode");
212: }
213:
214: out:
215: if (local_err) {
216: error_propagate(err, local_err);
217: }
218: }
219:
220: static DWORD WINAPI do_suspend(LPVOID opaque)
221: {
222: GuestSuspendMode *mode = opaque;
223: DWORD ret = 0;
224:
225: if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) {
226: slog("failed to suspend guest, %s", GetLastError());
227: ret = -1;
228: }
229: g_free(mode);
230: return ret;
231: }
232:
233: void qmp_guest_suspend_disk(Error **err)
234: {
235: GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode));
236:
237: *mode = GUEST_SUSPEND_MODE_DISK;
238: check_suspend_mode(*mode, err);
239: acquire_privilege(SE_SHUTDOWN_NAME, err);
240: execute_async(do_suspend, mode, err);
241:
242: if (error_is_set(err)) {
243: g_free(mode);
244: }
245: }
246:
247: void qmp_guest_suspend_ram(Error **err)
248: {
249: GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode));
250:
251: *mode = GUEST_SUSPEND_MODE_RAM;
252: check_suspend_mode(*mode, err);
253: acquire_privilege(SE_SHUTDOWN_NAME, err);
254: execute_async(do_suspend, mode, err);
255:
256: if (error_is_set(err)) {
257: g_free(mode);
258: }
259: }
260:
261: void qmp_guest_suspend_hybrid(Error **err)
262: {
263: error_set(err, QERR_UNSUPPORTED);
264: }
265:
266: GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **err)
267: {
268: error_set(err, QERR_UNSUPPORTED);
269: return NULL;
270: }
271:
272: /* register init/cleanup routines for stateful command groups */
273: void ga_command_state_init(GAState *s, GACommandState *cs)
274: {
275: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.