|
|
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.