xref: /openbmc/qemu/qga/commands-win32.c (revision ac1d8878)
1 /*
2  * QEMU Guest Agent win32-specific command implementations
3  *
4  * Copyright IBM Corp. 2012
5  *
6  * Authors:
7  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
8  *  Gal Hammer        <ghammer@redhat.com>
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 <stdio.h>
18 #include <string.h>
19 #include <winsock2.h>
20 #include <ws2tcpip.h>
21 #include <iptypes.h>
22 #include <iphlpapi.h>
23 #ifdef CONFIG_QGA_NTDDSCSI
24 #include <winioctl.h>
25 #include <ntddscsi.h>
26 #include <setupapi.h>
27 #include <initguid.h>
28 #endif
29 #include <lm.h>
30 
31 #include "qga/guest-agent-core.h"
32 #include "qga/vss-win32.h"
33 #include "qga-qmp-commands.h"
34 #include "qapi/qmp/qerror.h"
35 #include "qemu/queue.h"
36 #include "qemu/host-utils.h"
37 #include "qemu/base64.h"
38 
39 #ifndef SHTDN_REASON_FLAG_PLANNED
40 #define SHTDN_REASON_FLAG_PLANNED 0x80000000
41 #endif
42 
43 /* multiple of 100 nanoseconds elapsed between windows baseline
44  *    (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */
45 #define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \
46                        (365 * (1970 - 1601) +       \
47                         (1970 - 1601) / 4 - 3))
48 
49 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
50 
51 typedef struct GuestFileHandle {
52     int64_t id;
53     HANDLE fh;
54     QTAILQ_ENTRY(GuestFileHandle) next;
55 } GuestFileHandle;
56 
57 static struct {
58     QTAILQ_HEAD(, GuestFileHandle) filehandles;
59 } guest_file_state = {
60     .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles),
61 };
62 
63 #define FILE_GENERIC_APPEND (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA)
64 
65 typedef struct OpenFlags {
66     const char *forms;
67     DWORD desired_access;
68     DWORD creation_disposition;
69 } OpenFlags;
70 static OpenFlags guest_file_open_modes[] = {
71     {"r",   GENERIC_READ,                     OPEN_EXISTING},
72     {"rb",  GENERIC_READ,                     OPEN_EXISTING},
73     {"w",   GENERIC_WRITE,                    CREATE_ALWAYS},
74     {"wb",  GENERIC_WRITE,                    CREATE_ALWAYS},
75     {"a",   FILE_GENERIC_APPEND,              OPEN_ALWAYS  },
76     {"r+",  GENERIC_WRITE|GENERIC_READ,       OPEN_EXISTING},
77     {"rb+", GENERIC_WRITE|GENERIC_READ,       OPEN_EXISTING},
78     {"r+b", GENERIC_WRITE|GENERIC_READ,       OPEN_EXISTING},
79     {"w+",  GENERIC_WRITE|GENERIC_READ,       CREATE_ALWAYS},
80     {"wb+", GENERIC_WRITE|GENERIC_READ,       CREATE_ALWAYS},
81     {"w+b", GENERIC_WRITE|GENERIC_READ,       CREATE_ALWAYS},
82     {"a+",  FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS  },
83     {"ab+", FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS  },
84     {"a+b", FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS  }
85 };
86 
87 static OpenFlags *find_open_flag(const char *mode_str)
88 {
89     int mode;
90     Error **errp = NULL;
91 
92     for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
93         OpenFlags *flags = guest_file_open_modes + mode;
94 
95         if (strcmp(flags->forms, mode_str) == 0) {
96             return flags;
97         }
98     }
99 
100     error_setg(errp, "invalid file open mode '%s'", mode_str);
101     return NULL;
102 }
103 
104 static int64_t guest_file_handle_add(HANDLE fh, Error **errp)
105 {
106     GuestFileHandle *gfh;
107     int64_t handle;
108 
109     handle = ga_get_fd_handle(ga_state, errp);
110     if (handle < 0) {
111         return -1;
112     }
113     gfh = g_new0(GuestFileHandle, 1);
114     gfh->id = handle;
115     gfh->fh = fh;
116     QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
117 
118     return handle;
119 }
120 
121 static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
122 {
123     GuestFileHandle *gfh;
124     QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) {
125         if (gfh->id == id) {
126             return gfh;
127         }
128     }
129     error_setg(errp, "handle '%" PRId64 "' has not been found", id);
130     return NULL;
131 }
132 
133 static void handle_set_nonblocking(HANDLE fh)
134 {
135     DWORD file_type, pipe_state;
136     file_type = GetFileType(fh);
137     if (file_type != FILE_TYPE_PIPE) {
138         return;
139     }
140     /* If file_type == FILE_TYPE_PIPE, according to MSDN
141      * the specified file is socket or named pipe */
142     if (!GetNamedPipeHandleState(fh, &pipe_state, NULL,
143                                  NULL, NULL, NULL, 0)) {
144         return;
145     }
146     /* The fd is named pipe fd */
147     if (pipe_state & PIPE_NOWAIT) {
148         return;
149     }
150 
151     pipe_state |= PIPE_NOWAIT;
152     SetNamedPipeHandleState(fh, &pipe_state, NULL, NULL);
153 }
154 
155 int64_t qmp_guest_file_open(const char *path, bool has_mode,
156                             const char *mode, Error **errp)
157 {
158     int64_t fd;
159     HANDLE fh;
160     HANDLE templ_file = NULL;
161     DWORD share_mode = FILE_SHARE_READ;
162     DWORD flags_and_attr = FILE_ATTRIBUTE_NORMAL;
163     LPSECURITY_ATTRIBUTES sa_attr = NULL;
164     OpenFlags *guest_flags;
165 
166     if (!has_mode) {
167         mode = "r";
168     }
169     slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
170     guest_flags = find_open_flag(mode);
171     if (guest_flags == NULL) {
172         error_setg(errp, "invalid file open mode");
173         return -1;
174     }
175 
176     fh = CreateFile(path, guest_flags->desired_access, share_mode, sa_attr,
177                     guest_flags->creation_disposition, flags_and_attr,
178                     templ_file);
179     if (fh == INVALID_HANDLE_VALUE) {
180         error_setg_win32(errp, GetLastError(), "failed to open file '%s'",
181                          path);
182         return -1;
183     }
184 
185     /* set fd non-blocking to avoid common use cases (like reading from a
186      * named pipe) from hanging the agent
187      */
188     handle_set_nonblocking(fh);
189 
190     fd = guest_file_handle_add(fh, errp);
191     if (fd < 0) {
192         CloseHandle(fh);
193         error_setg(errp, "failed to add handle to qmp handle table");
194         return -1;
195     }
196 
197     slog("guest-file-open, handle: % " PRId64, fd);
198     return fd;
199 }
200 
201 void qmp_guest_file_close(int64_t handle, Error **errp)
202 {
203     bool ret;
204     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
205     slog("guest-file-close called, handle: %" PRId64, handle);
206     if (gfh == NULL) {
207         return;
208     }
209     ret = CloseHandle(gfh->fh);
210     if (!ret) {
211         error_setg_win32(errp, GetLastError(), "failed close handle");
212         return;
213     }
214 
215     QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
216     g_free(gfh);
217 }
218 
219 static void acquire_privilege(const char *name, Error **errp)
220 {
221     HANDLE token = NULL;
222     TOKEN_PRIVILEGES priv;
223     Error *local_err = NULL;
224 
225     if (OpenProcessToken(GetCurrentProcess(),
226         TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
227     {
228         if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) {
229             error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
230                        "no luid for requested privilege");
231             goto out;
232         }
233 
234         priv.PrivilegeCount = 1;
235         priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
236 
237         if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) {
238             error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
239                        "unable to acquire requested privilege");
240             goto out;
241         }
242 
243     } else {
244         error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
245                    "failed to open privilege token");
246     }
247 
248 out:
249     if (token) {
250         CloseHandle(token);
251     }
252     if (local_err) {
253         error_propagate(errp, local_err);
254     }
255 }
256 
257 static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque,
258                           Error **errp)
259 {
260     Error *local_err = NULL;
261 
262     HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL);
263     if (!thread) {
264         error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
265                    "failed to dispatch asynchronous command");
266         error_propagate(errp, local_err);
267     }
268 }
269 
270 void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp)
271 {
272     Error *local_err = NULL;
273     UINT shutdown_flag = EWX_FORCE;
274 
275     slog("guest-shutdown called, mode: %s", mode);
276 
277     if (!has_mode || strcmp(mode, "powerdown") == 0) {
278         shutdown_flag |= EWX_POWEROFF;
279     } else if (strcmp(mode, "halt") == 0) {
280         shutdown_flag |= EWX_SHUTDOWN;
281     } else if (strcmp(mode, "reboot") == 0) {
282         shutdown_flag |= EWX_REBOOT;
283     } else {
284         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "mode",
285                    "halt|powerdown|reboot");
286         return;
287     }
288 
289     /* Request a shutdown privilege, but try to shut down the system
290        anyway. */
291     acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
292     if (local_err) {
293         error_propagate(errp, local_err);
294         return;
295     }
296 
297     if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) {
298         slog("guest-shutdown failed: %lu", GetLastError());
299         error_setg(errp, QERR_UNDEFINED_ERROR);
300     }
301 }
302 
303 GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
304                                    int64_t count, Error **errp)
305 {
306     GuestFileRead *read_data = NULL;
307     guchar *buf;
308     HANDLE fh;
309     bool is_ok;
310     DWORD read_count;
311     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
312 
313     if (!gfh) {
314         return NULL;
315     }
316     if (!has_count) {
317         count = QGA_READ_COUNT_DEFAULT;
318     } else if (count < 0) {
319         error_setg(errp, "value '%" PRId64
320                    "' is invalid for argument count", count);
321         return NULL;
322     }
323 
324     fh = gfh->fh;
325     buf = g_malloc0(count+1);
326     is_ok = ReadFile(fh, buf, count, &read_count, NULL);
327     if (!is_ok) {
328         error_setg_win32(errp, GetLastError(), "failed to read file");
329         slog("guest-file-read failed, handle %" PRId64, handle);
330     } else {
331         buf[read_count] = 0;
332         read_data = g_new0(GuestFileRead, 1);
333         read_data->count = (size_t)read_count;
334         read_data->eof = read_count == 0;
335 
336         if (read_count != 0) {
337             read_data->buf_b64 = g_base64_encode(buf, read_count);
338         }
339     }
340     g_free(buf);
341 
342     return read_data;
343 }
344 
345 GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
346                                      bool has_count, int64_t count,
347                                      Error **errp)
348 {
349     GuestFileWrite *write_data = NULL;
350     guchar *buf;
351     gsize buf_len;
352     bool is_ok;
353     DWORD write_count;
354     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
355     HANDLE fh;
356 
357     if (!gfh) {
358         return NULL;
359     }
360     fh = gfh->fh;
361     buf = qbase64_decode(buf_b64, -1, &buf_len, errp);
362     if (!buf) {
363         return NULL;
364     }
365 
366     if (!has_count) {
367         count = buf_len;
368     } else if (count < 0 || count > buf_len) {
369         error_setg(errp, "value '%" PRId64
370                    "' is invalid for argument count", count);
371         goto done;
372     }
373 
374     is_ok = WriteFile(fh, buf, count, &write_count, NULL);
375     if (!is_ok) {
376         error_setg_win32(errp, GetLastError(), "failed to write to file");
377         slog("guest-file-write-failed, handle: %" PRId64, handle);
378     } else {
379         write_data = g_new0(GuestFileWrite, 1);
380         write_data->count = (size_t) write_count;
381     }
382 
383 done:
384     g_free(buf);
385     return write_data;
386 }
387 
388 GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
389                                    int64_t whence_code, Error **errp)
390 {
391     GuestFileHandle *gfh;
392     GuestFileSeek *seek_data;
393     HANDLE fh;
394     LARGE_INTEGER new_pos, off_pos;
395     off_pos.QuadPart = offset;
396     BOOL res;
397     int whence;
398 
399     gfh = guest_file_handle_find(handle, errp);
400     if (!gfh) {
401         return NULL;
402     }
403 
404     /* We stupidly exposed 'whence':'int' in our qapi */
405     switch (whence_code) {
406     case QGA_SEEK_SET:
407         whence = SEEK_SET;
408         break;
409     case QGA_SEEK_CUR:
410         whence = SEEK_CUR;
411         break;
412     case QGA_SEEK_END:
413         whence = SEEK_END;
414         break;
415     default:
416         error_setg(errp, "invalid whence code %"PRId64, whence_code);
417         return NULL;
418     }
419 
420     fh = gfh->fh;
421     res = SetFilePointerEx(fh, off_pos, &new_pos, whence);
422     if (!res) {
423         error_setg_win32(errp, GetLastError(), "failed to seek file");
424         return NULL;
425     }
426     seek_data = g_new0(GuestFileSeek, 1);
427     seek_data->position = new_pos.QuadPart;
428     return seek_data;
429 }
430 
431 void qmp_guest_file_flush(int64_t handle, Error **errp)
432 {
433     HANDLE fh;
434     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
435     if (!gfh) {
436         return;
437     }
438 
439     fh = gfh->fh;
440     if (!FlushFileBuffers(fh)) {
441         error_setg_win32(errp, GetLastError(), "failed to flush file");
442     }
443 }
444 
445 #ifdef CONFIG_QGA_NTDDSCSI
446 
447 static STORAGE_BUS_TYPE win2qemu[] = {
448     [BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN,
449     [BusTypeScsi] = GUEST_DISK_BUS_TYPE_SCSI,
450     [BusTypeAtapi] = GUEST_DISK_BUS_TYPE_IDE,
451     [BusTypeAta] = GUEST_DISK_BUS_TYPE_IDE,
452     [BusType1394] = GUEST_DISK_BUS_TYPE_IEEE1394,
453     [BusTypeSsa] = GUEST_DISK_BUS_TYPE_SSA,
454     [BusTypeFibre] = GUEST_DISK_BUS_TYPE_SSA,
455     [BusTypeUsb] = GUEST_DISK_BUS_TYPE_USB,
456     [BusTypeRAID] = GUEST_DISK_BUS_TYPE_RAID,
457 #if (_WIN32_WINNT >= 0x0600)
458     [BusTypeiScsi] = GUEST_DISK_BUS_TYPE_ISCSI,
459     [BusTypeSas] = GUEST_DISK_BUS_TYPE_SAS,
460     [BusTypeSata] = GUEST_DISK_BUS_TYPE_SATA,
461     [BusTypeSd] =  GUEST_DISK_BUS_TYPE_SD,
462     [BusTypeMmc] = GUEST_DISK_BUS_TYPE_MMC,
463 #endif
464 #if (_WIN32_WINNT >= 0x0601)
465     [BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL,
466     [BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL,
467 #endif
468 };
469 
470 static GuestDiskBusType find_bus_type(STORAGE_BUS_TYPE bus)
471 {
472     if (bus > ARRAY_SIZE(win2qemu) || (int)bus < 0) {
473         return GUEST_DISK_BUS_TYPE_UNKNOWN;
474     }
475     return win2qemu[(int)bus];
476 }
477 
478 DEFINE_GUID(GUID_DEVINTERFACE_VOLUME,
479         0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2,
480         0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
481 
482 static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
483 {
484     HDEVINFO dev_info;
485     SP_DEVINFO_DATA dev_info_data;
486     DWORD size = 0;
487     int i;
488     char dev_name[MAX_PATH];
489     char *buffer = NULL;
490     GuestPCIAddress *pci = NULL;
491     char *name = g_strdup(&guid[4]);
492 
493     if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) {
494         error_setg_win32(errp, GetLastError(), "failed to get dos device name");
495         goto out;
496     }
497 
498     dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0,
499                                    DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
500     if (dev_info == INVALID_HANDLE_VALUE) {
501         error_setg_win32(errp, GetLastError(), "failed to get devices tree");
502         goto out;
503     }
504 
505     dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
506     for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
507         DWORD addr, bus, slot, func, dev, data, size2;
508         while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
509                                             SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
510                                             &data, (PBYTE)buffer, size,
511                                             &size2)) {
512             size = MAX(size, size2);
513             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
514                 g_free(buffer);
515                 /* Double the size to avoid problems on
516                  * W2k MBCS systems per KB 888609.
517                  * https://support.microsoft.com/en-us/kb/259695 */
518                 buffer = g_malloc(size * 2);
519             } else {
520                 error_setg_win32(errp, GetLastError(),
521                         "failed to get device name");
522                 goto out;
523             }
524         }
525 
526         if (g_strcmp0(buffer, dev_name)) {
527             continue;
528         }
529 
530         /* There is no need to allocate buffer in the next functions. The size
531          * is known and ULONG according to
532          * https://support.microsoft.com/en-us/kb/253232
533          * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
534          */
535         if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
536                    SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) {
537             break;
538         }
539 
540         /* The function retrieves the device's address. This value will be
541          * transformed into device function and number */
542         if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
543                    SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) {
544             break;
545         }
546 
547         /* This call returns UINumber of DEVICE_CAPABILITIES structure.
548          * This number is typically a user-perceived slot number. */
549         if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
550                    SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) {
551             break;
552         }
553 
554         /* SetupApi gives us the same information as driver with
555          * IoGetDeviceProperty. According to Microsoft
556          * https://support.microsoft.com/en-us/kb/253232
557          * FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
558          * DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
559          * SPDRP_ADDRESS is propertyAddress, so we do the same.*/
560 
561         func = addr & 0x0000FFFF;
562         dev = (addr >> 16) & 0x0000FFFF;
563         pci = g_malloc0(sizeof(*pci));
564         pci->domain = dev;
565         pci->slot = slot;
566         pci->function = func;
567         pci->bus = bus;
568         break;
569     }
570 out:
571     g_free(buffer);
572     g_free(name);
573     return pci;
574 }
575 
576 static int get_disk_bus_type(HANDLE vol_h, Error **errp)
577 {
578     STORAGE_PROPERTY_QUERY query;
579     STORAGE_DEVICE_DESCRIPTOR *dev_desc, buf;
580     DWORD received;
581 
582     dev_desc = &buf;
583     dev_desc->Size = sizeof(buf);
584     query.PropertyId = StorageDeviceProperty;
585     query.QueryType = PropertyStandardQuery;
586 
587     if (!DeviceIoControl(vol_h, IOCTL_STORAGE_QUERY_PROPERTY, &query,
588                          sizeof(STORAGE_PROPERTY_QUERY), dev_desc,
589                          dev_desc->Size, &received, NULL)) {
590         error_setg_win32(errp, GetLastError(), "failed to get bus type");
591         return -1;
592     }
593 
594     return dev_desc->BusType;
595 }
596 
597 /* VSS provider works with volumes, thus there is no difference if
598  * the volume consist of spanned disks. Info about the first disk in the
599  * volume is returned for the spanned disk group (LVM) */
600 static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
601 {
602     GuestDiskAddressList *list = NULL;
603     GuestDiskAddress *disk;
604     SCSI_ADDRESS addr, *scsi_ad;
605     DWORD len;
606     int bus;
607     HANDLE vol_h;
608 
609     scsi_ad = &addr;
610     char *name = g_strndup(guid, strlen(guid)-1);
611 
612     vol_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
613                        0, NULL);
614     if (vol_h == INVALID_HANDLE_VALUE) {
615         error_setg_win32(errp, GetLastError(), "failed to open volume");
616         goto out_free;
617     }
618 
619     bus = get_disk_bus_type(vol_h, errp);
620     if (bus < 0) {
621         goto out_close;
622     }
623 
624     disk = g_malloc0(sizeof(*disk));
625     disk->bus_type = find_bus_type(bus);
626     if (bus == BusTypeScsi || bus == BusTypeAta || bus == BusTypeRAID
627 #if (_WIN32_WINNT >= 0x0600)
628             /* This bus type is not supported before Windows Server 2003 SP1 */
629             || bus == BusTypeSas
630 #endif
631         ) {
632         /* We are able to use the same ioctls for different bus types
633          * according to Microsoft docs
634          * https://technet.microsoft.com/en-us/library/ee851589(v=ws.10).aspx */
635         if (DeviceIoControl(vol_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_ad,
636                             sizeof(SCSI_ADDRESS), &len, NULL)) {
637             disk->unit = addr.Lun;
638             disk->target = addr.TargetId;
639             disk->bus = addr.PathId;
640             disk->pci_controller = get_pci_info(name, errp);
641         }
642         /* We do not set error in this case, because we still have enough
643          * information about volume. */
644     } else {
645          disk->pci_controller = NULL;
646     }
647 
648     list = g_malloc0(sizeof(*list));
649     list->value = disk;
650     list->next = NULL;
651 out_close:
652     CloseHandle(vol_h);
653 out_free:
654     g_free(name);
655     return list;
656 }
657 
658 #else
659 
660 static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
661 {
662     return NULL;
663 }
664 
665 #endif /* CONFIG_QGA_NTDDSCSI */
666 
667 static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)
668 {
669     DWORD info_size;
670     char mnt, *mnt_point;
671     char fs_name[32];
672     char vol_info[MAX_PATH+1];
673     size_t len;
674     GuestFilesystemInfo *fs = NULL;
675 
676     GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size);
677     if (GetLastError() != ERROR_MORE_DATA) {
678         error_setg_win32(errp, GetLastError(), "failed to get volume name");
679         return NULL;
680     }
681 
682     mnt_point = g_malloc(info_size + 1);
683     if (!GetVolumePathNamesForVolumeName(guid, mnt_point, info_size,
684                                          &info_size)) {
685         error_setg_win32(errp, GetLastError(), "failed to get volume name");
686         goto free;
687     }
688 
689     len = strlen(mnt_point);
690     mnt_point[len] = '\\';
691     mnt_point[len+1] = 0;
692     if (!GetVolumeInformation(mnt_point, vol_info, sizeof(vol_info), NULL, NULL,
693                               NULL, (LPSTR)&fs_name, sizeof(fs_name))) {
694         if (GetLastError() != ERROR_NOT_READY) {
695             error_setg_win32(errp, GetLastError(), "failed to get volume info");
696         }
697         goto free;
698     }
699 
700     fs_name[sizeof(fs_name) - 1] = 0;
701     fs = g_malloc(sizeof(*fs));
702     fs->name = g_strdup(guid);
703     if (len == 0) {
704         fs->mountpoint = g_strdup("System Reserved");
705     } else {
706         fs->mountpoint = g_strndup(mnt_point, len);
707     }
708     fs->type = g_strdup(fs_name);
709     fs->disk = build_guest_disk_info(guid, errp);
710 free:
711     g_free(mnt_point);
712     return fs;
713 }
714 
715 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
716 {
717     HANDLE vol_h;
718     GuestFilesystemInfoList *new, *ret = NULL;
719     char guid[256];
720 
721     vol_h = FindFirstVolume(guid, sizeof(guid));
722     if (vol_h == INVALID_HANDLE_VALUE) {
723         error_setg_win32(errp, GetLastError(), "failed to find any volume");
724         return NULL;
725     }
726 
727     do {
728         GuestFilesystemInfo *info = build_guest_fsinfo(guid, errp);
729         if (info == NULL) {
730             continue;
731         }
732         new = g_malloc(sizeof(*ret));
733         new->value = info;
734         new->next = ret;
735         ret = new;
736     } while (FindNextVolume(vol_h, guid, sizeof(guid)));
737 
738     if (GetLastError() != ERROR_NO_MORE_FILES) {
739         error_setg_win32(errp, GetLastError(), "failed to find next volume");
740     }
741 
742     FindVolumeClose(vol_h);
743     return ret;
744 }
745 
746 /*
747  * Return status of freeze/thaw
748  */
749 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
750 {
751     if (!vss_initialized()) {
752         error_setg(errp, QERR_UNSUPPORTED);
753         return 0;
754     }
755 
756     if (ga_is_frozen(ga_state)) {
757         return GUEST_FSFREEZE_STATUS_FROZEN;
758     }
759 
760     return GUEST_FSFREEZE_STATUS_THAWED;
761 }
762 
763 /*
764  * Freeze local file systems using Volume Shadow-copy Service.
765  * The frozen state is limited for up to 10 seconds by VSS.
766  */
767 int64_t qmp_guest_fsfreeze_freeze(Error **errp)
768 {
769     int i;
770     Error *local_err = NULL;
771 
772     if (!vss_initialized()) {
773         error_setg(errp, QERR_UNSUPPORTED);
774         return 0;
775     }
776 
777     slog("guest-fsfreeze called");
778 
779     /* cannot risk guest agent blocking itself on a write in this state */
780     ga_set_frozen(ga_state);
781 
782     qga_vss_fsfreeze(&i, &local_err, true);
783     if (local_err) {
784         error_propagate(errp, local_err);
785         goto error;
786     }
787 
788     return i;
789 
790 error:
791     local_err = NULL;
792     qmp_guest_fsfreeze_thaw(&local_err);
793     if (local_err) {
794         g_debug("cleanup thaw: %s", error_get_pretty(local_err));
795         error_free(local_err);
796     }
797     return 0;
798 }
799 
800 int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
801                                        strList *mountpoints,
802                                        Error **errp)
803 {
804     error_setg(errp, QERR_UNSUPPORTED);
805 
806     return 0;
807 }
808 
809 /*
810  * Thaw local file systems using Volume Shadow-copy Service.
811  */
812 int64_t qmp_guest_fsfreeze_thaw(Error **errp)
813 {
814     int i;
815 
816     if (!vss_initialized()) {
817         error_setg(errp, QERR_UNSUPPORTED);
818         return 0;
819     }
820 
821     qga_vss_fsfreeze(&i, errp, false);
822 
823     ga_unset_frozen(ga_state);
824     return i;
825 }
826 
827 static void guest_fsfreeze_cleanup(void)
828 {
829     Error *err = NULL;
830 
831     if (!vss_initialized()) {
832         return;
833     }
834 
835     if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
836         qmp_guest_fsfreeze_thaw(&err);
837         if (err) {
838             slog("failed to clean up frozen filesystems: %s",
839                  error_get_pretty(err));
840             error_free(err);
841         }
842     }
843 
844     vss_deinit(true);
845 }
846 
847 /*
848  * Walk list of mounted file systems in the guest, and discard unused
849  * areas.
850  */
851 GuestFilesystemTrimResponse *
852 qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
853 {
854     error_setg(errp, QERR_UNSUPPORTED);
855     return NULL;
856 }
857 
858 typedef enum {
859     GUEST_SUSPEND_MODE_DISK,
860     GUEST_SUSPEND_MODE_RAM
861 } GuestSuspendMode;
862 
863 static void check_suspend_mode(GuestSuspendMode mode, Error **errp)
864 {
865     SYSTEM_POWER_CAPABILITIES sys_pwr_caps;
866     Error *local_err = NULL;
867 
868     ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps));
869     if (!GetPwrCapabilities(&sys_pwr_caps)) {
870         error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
871                    "failed to determine guest suspend capabilities");
872         goto out;
873     }
874 
875     switch (mode) {
876     case GUEST_SUSPEND_MODE_DISK:
877         if (!sys_pwr_caps.SystemS4) {
878             error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
879                        "suspend-to-disk not supported by OS");
880         }
881         break;
882     case GUEST_SUSPEND_MODE_RAM:
883         if (!sys_pwr_caps.SystemS3) {
884             error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
885                        "suspend-to-ram not supported by OS");
886         }
887         break;
888     default:
889         error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode",
890                    "GuestSuspendMode");
891     }
892 
893 out:
894     if (local_err) {
895         error_propagate(errp, local_err);
896     }
897 }
898 
899 static DWORD WINAPI do_suspend(LPVOID opaque)
900 {
901     GuestSuspendMode *mode = opaque;
902     DWORD ret = 0;
903 
904     if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) {
905         slog("failed to suspend guest, %lu", GetLastError());
906         ret = -1;
907     }
908     g_free(mode);
909     return ret;
910 }
911 
912 void qmp_guest_suspend_disk(Error **errp)
913 {
914     Error *local_err = NULL;
915     GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
916 
917     *mode = GUEST_SUSPEND_MODE_DISK;
918     check_suspend_mode(*mode, &local_err);
919     acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
920     execute_async(do_suspend, mode, &local_err);
921 
922     if (local_err) {
923         error_propagate(errp, local_err);
924         g_free(mode);
925     }
926 }
927 
928 void qmp_guest_suspend_ram(Error **errp)
929 {
930     Error *local_err = NULL;
931     GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
932 
933     *mode = GUEST_SUSPEND_MODE_RAM;
934     check_suspend_mode(*mode, &local_err);
935     acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
936     execute_async(do_suspend, mode, &local_err);
937 
938     if (local_err) {
939         error_propagate(errp, local_err);
940         g_free(mode);
941     }
942 }
943 
944 void qmp_guest_suspend_hybrid(Error **errp)
945 {
946     error_setg(errp, QERR_UNSUPPORTED);
947 }
948 
949 static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp)
950 {
951     IP_ADAPTER_ADDRESSES *adptr_addrs = NULL;
952     ULONG adptr_addrs_len = 0;
953     DWORD ret;
954 
955     /* Call the first time to get the adptr_addrs_len. */
956     GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
957                          NULL, adptr_addrs, &adptr_addrs_len);
958 
959     adptr_addrs = g_malloc(adptr_addrs_len);
960     ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
961                                NULL, adptr_addrs, &adptr_addrs_len);
962     if (ret != ERROR_SUCCESS) {
963         error_setg_win32(errp, ret, "failed to get adapters addresses");
964         g_free(adptr_addrs);
965         adptr_addrs = NULL;
966     }
967     return adptr_addrs;
968 }
969 
970 static char *guest_wctomb_dup(WCHAR *wstr)
971 {
972     char *str;
973     size_t i;
974 
975     i = wcslen(wstr) + 1;
976     str = g_malloc(i);
977     WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
978                         wstr, -1, str, i, NULL, NULL);
979     return str;
980 }
981 
982 static char *guest_addr_to_str(IP_ADAPTER_UNICAST_ADDRESS *ip_addr,
983                                Error **errp)
984 {
985     char addr_str[INET6_ADDRSTRLEN + INET_ADDRSTRLEN];
986     DWORD len;
987     int ret;
988 
989     if (ip_addr->Address.lpSockaddr->sa_family == AF_INET ||
990             ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
991         len = sizeof(addr_str);
992         ret = WSAAddressToString(ip_addr->Address.lpSockaddr,
993                                  ip_addr->Address.iSockaddrLength,
994                                  NULL,
995                                  addr_str,
996                                  &len);
997         if (ret != 0) {
998             error_setg_win32(errp, WSAGetLastError(),
999                 "failed address presentation form conversion");
1000             return NULL;
1001         }
1002         return g_strdup(addr_str);
1003     }
1004     return NULL;
1005 }
1006 
1007 #if (_WIN32_WINNT >= 0x0600)
1008 static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
1009 {
1010     /* For Windows Vista/2008 and newer, use the OnLinkPrefixLength
1011      * field to obtain the prefix.
1012      */
1013     return ip_addr->OnLinkPrefixLength;
1014 }
1015 #else
1016 /* When using the Windows XP and 2003 build environment, do the best we can to
1017  * figure out the prefix.
1018  */
1019 static IP_ADAPTER_INFO *guest_get_adapters_info(void)
1020 {
1021     IP_ADAPTER_INFO *adptr_info = NULL;
1022     ULONG adptr_info_len = 0;
1023     DWORD ret;
1024 
1025     /* Call the first time to get the adptr_info_len. */
1026     GetAdaptersInfo(adptr_info, &adptr_info_len);
1027 
1028     adptr_info = g_malloc(adptr_info_len);
1029     ret = GetAdaptersInfo(adptr_info, &adptr_info_len);
1030     if (ret != ERROR_SUCCESS) {
1031         g_free(adptr_info);
1032         adptr_info = NULL;
1033     }
1034     return adptr_info;
1035 }
1036 
1037 static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
1038 {
1039     int64_t prefix = -1; /* Use for AF_INET6 and unknown/undetermined values. */
1040     IP_ADAPTER_INFO *adptr_info, *info;
1041     IP_ADDR_STRING *ip;
1042     struct in_addr *p;
1043 
1044     if (ip_addr->Address.lpSockaddr->sa_family != AF_INET) {
1045         return prefix;
1046     }
1047     adptr_info = guest_get_adapters_info();
1048     if (adptr_info == NULL) {
1049         return prefix;
1050     }
1051 
1052     /* Match up the passed in ip_addr with one found in adaptr_info.
1053      * The matching one in adptr_info will have the netmask.
1054      */
1055     p = &((struct sockaddr_in *)ip_addr->Address.lpSockaddr)->sin_addr;
1056     for (info = adptr_info; info; info = info->Next) {
1057         for (ip = &info->IpAddressList; ip; ip = ip->Next) {
1058             if (p->S_un.S_addr == inet_addr(ip->IpAddress.String)) {
1059                 prefix = ctpop32(inet_addr(ip->IpMask.String));
1060                 goto out;
1061             }
1062         }
1063     }
1064 out:
1065     g_free(adptr_info);
1066     return prefix;
1067 }
1068 #endif
1069 
1070 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1071 {
1072     IP_ADAPTER_ADDRESSES *adptr_addrs, *addr;
1073     IP_ADAPTER_UNICAST_ADDRESS *ip_addr = NULL;
1074     GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
1075     GuestIpAddressList *head_addr, *cur_addr;
1076     GuestNetworkInterfaceList *info;
1077     GuestIpAddressList *address_item = NULL;
1078     unsigned char *mac_addr;
1079     char *addr_str;
1080     WORD wsa_version;
1081     WSADATA wsa_data;
1082     int ret;
1083 
1084     adptr_addrs = guest_get_adapters_addresses(errp);
1085     if (adptr_addrs == NULL) {
1086         return NULL;
1087     }
1088 
1089     /* Make WSA APIs available. */
1090     wsa_version = MAKEWORD(2, 2);
1091     ret = WSAStartup(wsa_version, &wsa_data);
1092     if (ret != 0) {
1093         error_setg_win32(errp, ret, "failed socket startup");
1094         goto out;
1095     }
1096 
1097     for (addr = adptr_addrs; addr; addr = addr->Next) {
1098         info = g_malloc0(sizeof(*info));
1099 
1100         if (cur_item == NULL) {
1101             head = cur_item = info;
1102         } else {
1103             cur_item->next = info;
1104             cur_item = info;
1105         }
1106 
1107         info->value = g_malloc0(sizeof(*info->value));
1108         info->value->name = guest_wctomb_dup(addr->FriendlyName);
1109 
1110         if (addr->PhysicalAddressLength != 0) {
1111             mac_addr = addr->PhysicalAddress;
1112 
1113             info->value->hardware_address =
1114                 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1115                                 (int) mac_addr[0], (int) mac_addr[1],
1116                                 (int) mac_addr[2], (int) mac_addr[3],
1117                                 (int) mac_addr[4], (int) mac_addr[5]);
1118 
1119             info->value->has_hardware_address = true;
1120         }
1121 
1122         head_addr = NULL;
1123         cur_addr = NULL;
1124         for (ip_addr = addr->FirstUnicastAddress;
1125                 ip_addr;
1126                 ip_addr = ip_addr->Next) {
1127             addr_str = guest_addr_to_str(ip_addr, errp);
1128             if (addr_str == NULL) {
1129                 continue;
1130             }
1131 
1132             address_item = g_malloc0(sizeof(*address_item));
1133 
1134             if (!cur_addr) {
1135                 head_addr = cur_addr = address_item;
1136             } else {
1137                 cur_addr->next = address_item;
1138                 cur_addr = address_item;
1139             }
1140 
1141             address_item->value = g_malloc0(sizeof(*address_item->value));
1142             address_item->value->ip_address = addr_str;
1143             address_item->value->prefix = guest_ip_prefix(ip_addr);
1144             if (ip_addr->Address.lpSockaddr->sa_family == AF_INET) {
1145                 address_item->value->ip_address_type =
1146                     GUEST_IP_ADDRESS_TYPE_IPV4;
1147             } else if (ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
1148                 address_item->value->ip_address_type =
1149                     GUEST_IP_ADDRESS_TYPE_IPV6;
1150             }
1151         }
1152         if (head_addr) {
1153             info->value->has_ip_addresses = true;
1154             info->value->ip_addresses = head_addr;
1155         }
1156     }
1157     WSACleanup();
1158 out:
1159     g_free(adptr_addrs);
1160     return head;
1161 }
1162 
1163 int64_t qmp_guest_get_time(Error **errp)
1164 {
1165     SYSTEMTIME ts = {0};
1166     int64_t time_ns;
1167     FILETIME tf;
1168 
1169     GetSystemTime(&ts);
1170     if (ts.wYear < 1601 || ts.wYear > 30827) {
1171         error_setg(errp, "Failed to get time");
1172         return -1;
1173     }
1174 
1175     if (!SystemTimeToFileTime(&ts, &tf)) {
1176         error_setg(errp, "Failed to convert system time: %d", (int)GetLastError());
1177         return -1;
1178     }
1179 
1180     time_ns = ((((int64_t)tf.dwHighDateTime << 32) | tf.dwLowDateTime)
1181                 - W32_FT_OFFSET) * 100;
1182 
1183     return time_ns;
1184 }
1185 
1186 void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
1187 {
1188     Error *local_err = NULL;
1189     SYSTEMTIME ts;
1190     FILETIME tf;
1191     LONGLONG time;
1192 
1193     if (!has_time) {
1194         /* Unfortunately, Windows libraries don't provide an easy way to access
1195          * RTC yet:
1196          *
1197          * https://msdn.microsoft.com/en-us/library/aa908981.aspx
1198          */
1199         error_setg(errp, "Time argument is required on this platform");
1200         return;
1201     }
1202 
1203     /* Validate time passed by user. */
1204     if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
1205         error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
1206         return;
1207     }
1208 
1209     time = time_ns / 100 + W32_FT_OFFSET;
1210 
1211     tf.dwLowDateTime = (DWORD) time;
1212     tf.dwHighDateTime = (DWORD) (time >> 32);
1213 
1214     if (!FileTimeToSystemTime(&tf, &ts)) {
1215         error_setg(errp, "Failed to convert system time %d",
1216                    (int)GetLastError());
1217         return;
1218     }
1219 
1220     acquire_privilege(SE_SYSTEMTIME_NAME, &local_err);
1221     if (local_err) {
1222         error_propagate(errp, local_err);
1223         return;
1224     }
1225 
1226     if (!SetSystemTime(&ts)) {
1227         error_setg(errp, "Failed to set time to guest: %d", (int)GetLastError());
1228         return;
1229     }
1230 }
1231 
1232 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1233 {
1234     error_setg(errp, QERR_UNSUPPORTED);
1235     return NULL;
1236 }
1237 
1238 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1239 {
1240     error_setg(errp, QERR_UNSUPPORTED);
1241     return -1;
1242 }
1243 
1244 static gchar *
1245 get_net_error_message(gint error)
1246 {
1247     HMODULE module = NULL;
1248     gchar *retval = NULL;
1249     wchar_t *msg = NULL;
1250     int flags, nchars;
1251 
1252     flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
1253         |FORMAT_MESSAGE_IGNORE_INSERTS
1254         |FORMAT_MESSAGE_FROM_SYSTEM;
1255 
1256     if (error >= NERR_BASE && error <= MAX_NERR) {
1257         module = LoadLibraryExW(L"netmsg.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
1258 
1259         if (module != NULL) {
1260             flags |= FORMAT_MESSAGE_FROM_HMODULE;
1261         }
1262     }
1263 
1264     FormatMessageW(flags, module, error, 0, (LPWSTR)&msg, 0, NULL);
1265 
1266     if (msg != NULL) {
1267         nchars = wcslen(msg);
1268 
1269         if (nchars > 2 && msg[nchars-1] == '\n' && msg[nchars-2] == '\r') {
1270             msg[nchars-2] = '\0';
1271         }
1272 
1273         retval = g_utf16_to_utf8(msg, -1, NULL, NULL, NULL);
1274 
1275         LocalFree(msg);
1276     }
1277 
1278     if (module != NULL) {
1279         FreeLibrary(module);
1280     }
1281 
1282     return retval;
1283 }
1284 
1285 void qmp_guest_set_user_password(const char *username,
1286                                  const char *password,
1287                                  bool crypted,
1288                                  Error **errp)
1289 {
1290     NET_API_STATUS nas;
1291     char *rawpasswddata = NULL;
1292     size_t rawpasswdlen;
1293     wchar_t *user, *wpass;
1294     USER_INFO_1003 pi1003 = { 0, };
1295 
1296     if (crypted) {
1297         error_setg(errp, QERR_UNSUPPORTED);
1298         return;
1299     }
1300 
1301     rawpasswddata = (char *)qbase64_decode(password, -1, &rawpasswdlen, errp);
1302     if (!rawpasswddata) {
1303         return;
1304     }
1305     rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
1306     rawpasswddata[rawpasswdlen] = '\0';
1307 
1308     user = g_utf8_to_utf16(username, -1, NULL, NULL, NULL);
1309     wpass = g_utf8_to_utf16(rawpasswddata, -1, NULL, NULL, NULL);
1310 
1311     pi1003.usri1003_password = wpass;
1312     nas = NetUserSetInfo(NULL, user,
1313                          1003, (LPBYTE)&pi1003,
1314                          NULL);
1315 
1316     if (nas != NERR_Success) {
1317         gchar *msg = get_net_error_message(nas);
1318         error_setg(errp, "failed to set password: %s", msg);
1319         g_free(msg);
1320     }
1321 
1322     g_free(user);
1323     g_free(wpass);
1324     g_free(rawpasswddata);
1325 }
1326 
1327 GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
1328 {
1329     error_setg(errp, QERR_UNSUPPORTED);
1330     return NULL;
1331 }
1332 
1333 GuestMemoryBlockResponseList *
1334 qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
1335 {
1336     error_setg(errp, QERR_UNSUPPORTED);
1337     return NULL;
1338 }
1339 
1340 GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
1341 {
1342     error_setg(errp, QERR_UNSUPPORTED);
1343     return NULL;
1344 }
1345 
1346 /* add unsupported commands to the blacklist */
1347 GList *ga_command_blacklist_init(GList *blacklist)
1348 {
1349     const char *list_unsupported[] = {
1350         "guest-suspend-hybrid",
1351         "guest-get-vcpus", "guest-set-vcpus",
1352         "guest-get-memory-blocks", "guest-set-memory-blocks",
1353         "guest-get-memory-block-size",
1354         "guest-fsfreeze-freeze-list",
1355         "guest-fstrim", NULL};
1356     char **p = (char **)list_unsupported;
1357 
1358     while (*p) {
1359         blacklist = g_list_append(blacklist, g_strdup(*p++));
1360     }
1361 
1362     if (!vss_init(true)) {
1363         g_debug("vss_init failed, vss commands are going to be disabled");
1364         const char *list[] = {
1365             "guest-get-fsinfo", "guest-fsfreeze-status",
1366             "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
1367         p = (char **)list;
1368 
1369         while (*p) {
1370             blacklist = g_list_append(blacklist, g_strdup(*p++));
1371         }
1372     }
1373 
1374     return blacklist;
1375 }
1376 
1377 /* register init/cleanup routines for stateful command groups */
1378 void ga_command_state_init(GAState *s, GACommandState *cs)
1379 {
1380     if (!vss_initialized()) {
1381         ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
1382     }
1383 }
1384