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