2 * QEMU Guest Agent win32-specific command implementations
4 * Copyright IBM Corp. 2012
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
8 * Gal Hammer <ghammer@redhat.com>
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.
13 #include "qemu/osdep.h"
21 #ifdef CONFIG_QGA_NTDDSCSI
31 #include "guest-agent-core.h"
32 #include "vss-win32.h"
33 #include "qga-qapi-commands.h"
34 #include "qapi/error.h"
35 #include "qapi/qmp/qerror.h"
36 #include "qemu/queue.h"
37 #include "qemu/host-utils.h"
38 #include "qemu/base64.h"
40 #ifndef SHTDN_REASON_FLAG_PLANNED
41 #define SHTDN_REASON_FLAG_PLANNED 0x80000000
44 /* multiple of 100 nanoseconds elapsed between windows baseline
45 * (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */
46 #define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \
47 (365 * (1970 - 1601) + \
48 (1970 - 1601) / 4 - 3))
50 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
52 typedef struct GuestFileHandle
{
55 QTAILQ_ENTRY(GuestFileHandle
) next
;
59 QTAILQ_HEAD(, GuestFileHandle
) filehandles
;
60 } guest_file_state
= {
61 .filehandles
= QTAILQ_HEAD_INITIALIZER(guest_file_state
.filehandles
),
64 #define FILE_GENERIC_APPEND (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA)
66 typedef struct OpenFlags
{
69 DWORD creation_disposition
;
71 static OpenFlags guest_file_open_modes
[] = {
72 {"r", GENERIC_READ
, OPEN_EXISTING
},
73 {"rb", GENERIC_READ
, OPEN_EXISTING
},
74 {"w", GENERIC_WRITE
, CREATE_ALWAYS
},
75 {"wb", GENERIC_WRITE
, CREATE_ALWAYS
},
76 {"a", FILE_GENERIC_APPEND
, OPEN_ALWAYS
},
77 {"r+", GENERIC_WRITE
|GENERIC_READ
, OPEN_EXISTING
},
78 {"rb+", GENERIC_WRITE
|GENERIC_READ
, OPEN_EXISTING
},
79 {"r+b", GENERIC_WRITE
|GENERIC_READ
, OPEN_EXISTING
},
80 {"w+", GENERIC_WRITE
|GENERIC_READ
, CREATE_ALWAYS
},
81 {"wb+", GENERIC_WRITE
|GENERIC_READ
, CREATE_ALWAYS
},
82 {"w+b", GENERIC_WRITE
|GENERIC_READ
, CREATE_ALWAYS
},
83 {"a+", FILE_GENERIC_APPEND
|GENERIC_READ
, OPEN_ALWAYS
},
84 {"ab+", FILE_GENERIC_APPEND
|GENERIC_READ
, OPEN_ALWAYS
},
85 {"a+b", FILE_GENERIC_APPEND
|GENERIC_READ
, OPEN_ALWAYS
}
88 #define debug_error(msg) do { \
89 char *suffix = g_win32_error_message(GetLastError()); \
90 g_debug("%s: %s", (msg), suffix); \
94 static OpenFlags
*find_open_flag(const char *mode_str
)
99 for (mode
= 0; mode
< ARRAY_SIZE(guest_file_open_modes
); ++mode
) {
100 OpenFlags
*flags
= guest_file_open_modes
+ mode
;
102 if (strcmp(flags
->forms
, mode_str
) == 0) {
107 error_setg(errp
, "invalid file open mode '%s'", mode_str
);
111 static int64_t guest_file_handle_add(HANDLE fh
, Error
**errp
)
113 GuestFileHandle
*gfh
;
116 handle
= ga_get_fd_handle(ga_state
, errp
);
120 gfh
= g_new0(GuestFileHandle
, 1);
123 QTAILQ_INSERT_TAIL(&guest_file_state
.filehandles
, gfh
, next
);
128 static GuestFileHandle
*guest_file_handle_find(int64_t id
, Error
**errp
)
130 GuestFileHandle
*gfh
;
131 QTAILQ_FOREACH(gfh
, &guest_file_state
.filehandles
, next
) {
136 error_setg(errp
, "handle '%" PRId64
"' has not been found", id
);
140 static void handle_set_nonblocking(HANDLE fh
)
142 DWORD file_type
, pipe_state
;
143 file_type
= GetFileType(fh
);
144 if (file_type
!= FILE_TYPE_PIPE
) {
147 /* If file_type == FILE_TYPE_PIPE, according to MSDN
148 * the specified file is socket or named pipe */
149 if (!GetNamedPipeHandleState(fh
, &pipe_state
, NULL
,
150 NULL
, NULL
, NULL
, 0)) {
153 /* The fd is named pipe fd */
154 if (pipe_state
& PIPE_NOWAIT
) {
158 pipe_state
|= PIPE_NOWAIT
;
159 SetNamedPipeHandleState(fh
, &pipe_state
, NULL
, NULL
);
162 int64_t qmp_guest_file_open(const char *path
, bool has_mode
,
163 const char *mode
, Error
**errp
)
167 HANDLE templ_file
= NULL
;
168 DWORD share_mode
= FILE_SHARE_READ
;
169 DWORD flags_and_attr
= FILE_ATTRIBUTE_NORMAL
;
170 LPSECURITY_ATTRIBUTES sa_attr
= NULL
;
171 OpenFlags
*guest_flags
;
173 wchar_t *w_path
= NULL
;
178 slog("guest-file-open called, filepath: %s, mode: %s", path
, mode
);
179 guest_flags
= find_open_flag(mode
);
180 if (guest_flags
== NULL
) {
181 error_setg(errp
, "invalid file open mode");
185 w_path
= g_utf8_to_utf16(path
, -1, NULL
, NULL
, &gerr
);
190 fh
= CreateFileW(w_path
, guest_flags
->desired_access
, share_mode
, sa_attr
,
191 guest_flags
->creation_disposition
, flags_and_attr
,
193 if (fh
== INVALID_HANDLE_VALUE
) {
194 error_setg_win32(errp
, GetLastError(), "failed to open file '%s'",
199 /* set fd non-blocking to avoid common use cases (like reading from a
200 * named pipe) from hanging the agent
202 handle_set_nonblocking(fh
);
204 fd
= guest_file_handle_add(fh
, errp
);
207 error_setg(errp
, "failed to add handle to qmp handle table");
211 slog("guest-file-open, handle: % " PRId64
, fd
);
215 error_setg(errp
, QERR_QGA_COMMAND_FAILED
, gerr
->message
);
222 void qmp_guest_file_close(int64_t handle
, Error
**errp
)
225 GuestFileHandle
*gfh
= guest_file_handle_find(handle
, errp
);
226 slog("guest-file-close called, handle: %" PRId64
, handle
);
230 ret
= CloseHandle(gfh
->fh
);
232 error_setg_win32(errp
, GetLastError(), "failed close handle");
236 QTAILQ_REMOVE(&guest_file_state
.filehandles
, gfh
, next
);
240 static void acquire_privilege(const char *name
, Error
**errp
)
243 TOKEN_PRIVILEGES priv
;
244 Error
*local_err
= NULL
;
246 if (OpenProcessToken(GetCurrentProcess(),
247 TOKEN_ADJUST_PRIVILEGES
|TOKEN_QUERY
, &token
))
249 if (!LookupPrivilegeValue(NULL
, name
, &priv
.Privileges
[0].Luid
)) {
250 error_setg(&local_err
, QERR_QGA_COMMAND_FAILED
,
251 "no luid for requested privilege");
255 priv
.PrivilegeCount
= 1;
256 priv
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
258 if (!AdjustTokenPrivileges(token
, FALSE
, &priv
, 0, NULL
, 0)) {
259 error_setg(&local_err
, QERR_QGA_COMMAND_FAILED
,
260 "unable to acquire requested privilege");
265 error_setg(&local_err
, QERR_QGA_COMMAND_FAILED
,
266 "failed to open privilege token");
273 error_propagate(errp
, local_err
);
276 static void execute_async(DWORD
WINAPI (*func
)(LPVOID
), LPVOID opaque
,
279 Error
*local_err
= NULL
;
281 HANDLE thread
= CreateThread(NULL
, 0, func
, opaque
, 0, NULL
);
283 error_setg(&local_err
, QERR_QGA_COMMAND_FAILED
,
284 "failed to dispatch asynchronous command");
285 error_propagate(errp
, local_err
);
289 void qmp_guest_shutdown(bool has_mode
, const char *mode
, Error
**errp
)
291 Error
*local_err
= NULL
;
292 UINT shutdown_flag
= EWX_FORCE
;
294 slog("guest-shutdown called, mode: %s", mode
);
296 if (!has_mode
|| strcmp(mode
, "powerdown") == 0) {
297 shutdown_flag
|= EWX_POWEROFF
;
298 } else if (strcmp(mode
, "halt") == 0) {
299 shutdown_flag
|= EWX_SHUTDOWN
;
300 } else if (strcmp(mode
, "reboot") == 0) {
301 shutdown_flag
|= EWX_REBOOT
;
303 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, "mode",
304 "halt|powerdown|reboot");
308 /* Request a shutdown privilege, but try to shut down the system
310 acquire_privilege(SE_SHUTDOWN_NAME
, &local_err
);
312 error_propagate(errp
, local_err
);
316 if (!ExitWindowsEx(shutdown_flag
, SHTDN_REASON_FLAG_PLANNED
)) {
317 slog("guest-shutdown failed: %lu", GetLastError());
318 error_setg(errp
, QERR_UNDEFINED_ERROR
);
322 GuestFileRead
*qmp_guest_file_read(int64_t handle
, bool has_count
,
323 int64_t count
, Error
**errp
)
325 GuestFileRead
*read_data
= NULL
;
330 GuestFileHandle
*gfh
= guest_file_handle_find(handle
, errp
);
336 count
= QGA_READ_COUNT_DEFAULT
;
337 } else if (count
< 0 || count
>= UINT32_MAX
) {
338 error_setg(errp
, "value '%" PRId64
339 "' is invalid for argument count", count
);
344 buf
= g_malloc0(count
+1);
345 is_ok
= ReadFile(fh
, buf
, count
, &read_count
, NULL
);
347 error_setg_win32(errp
, GetLastError(), "failed to read file");
348 slog("guest-file-read failed, handle %" PRId64
, handle
);
351 read_data
= g_new0(GuestFileRead
, 1);
352 read_data
->count
= (size_t)read_count
;
353 read_data
->eof
= read_count
== 0;
355 if (read_count
!= 0) {
356 read_data
->buf_b64
= g_base64_encode(buf
, read_count
);
364 GuestFileWrite
*qmp_guest_file_write(int64_t handle
, const char *buf_b64
,
365 bool has_count
, int64_t count
,
368 GuestFileWrite
*write_data
= NULL
;
373 GuestFileHandle
*gfh
= guest_file_handle_find(handle
, errp
);
380 buf
= qbase64_decode(buf_b64
, -1, &buf_len
, errp
);
387 } else if (count
< 0 || count
> buf_len
) {
388 error_setg(errp
, "value '%" PRId64
389 "' is invalid for argument count", count
);
393 is_ok
= WriteFile(fh
, buf
, count
, &write_count
, NULL
);
395 error_setg_win32(errp
, GetLastError(), "failed to write to file");
396 slog("guest-file-write-failed, handle: %" PRId64
, handle
);
398 write_data
= g_new0(GuestFileWrite
, 1);
399 write_data
->count
= (size_t) write_count
;
407 GuestFileSeek
*qmp_guest_file_seek(int64_t handle
, int64_t offset
,
408 GuestFileWhence
*whence_code
,
411 GuestFileHandle
*gfh
;
412 GuestFileSeek
*seek_data
;
414 LARGE_INTEGER new_pos
, off_pos
;
415 off_pos
.QuadPart
= offset
;
420 gfh
= guest_file_handle_find(handle
, errp
);
425 /* We stupidly exposed 'whence':'int' in our qapi */
426 whence
= ga_parse_whence(whence_code
, &err
);
428 error_propagate(errp
, err
);
433 res
= SetFilePointerEx(fh
, off_pos
, &new_pos
, whence
);
435 error_setg_win32(errp
, GetLastError(), "failed to seek file");
438 seek_data
= g_new0(GuestFileSeek
, 1);
439 seek_data
->position
= new_pos
.QuadPart
;
443 void qmp_guest_file_flush(int64_t handle
, Error
**errp
)
446 GuestFileHandle
*gfh
= guest_file_handle_find(handle
, errp
);
452 if (!FlushFileBuffers(fh
)) {
453 error_setg_win32(errp
, GetLastError(), "failed to flush file");
457 #ifdef CONFIG_QGA_NTDDSCSI
459 static STORAGE_BUS_TYPE win2qemu
[] = {
460 [BusTypeUnknown
] = GUEST_DISK_BUS_TYPE_UNKNOWN
,
461 [BusTypeScsi
] = GUEST_DISK_BUS_TYPE_SCSI
,
462 [BusTypeAtapi
] = GUEST_DISK_BUS_TYPE_IDE
,
463 [BusTypeAta
] = GUEST_DISK_BUS_TYPE_IDE
,
464 [BusType1394
] = GUEST_DISK_BUS_TYPE_IEEE1394
,
465 [BusTypeSsa
] = GUEST_DISK_BUS_TYPE_SSA
,
466 [BusTypeFibre
] = GUEST_DISK_BUS_TYPE_SSA
,
467 [BusTypeUsb
] = GUEST_DISK_BUS_TYPE_USB
,
468 [BusTypeRAID
] = GUEST_DISK_BUS_TYPE_RAID
,
469 [BusTypeiScsi
] = GUEST_DISK_BUS_TYPE_ISCSI
,
470 [BusTypeSas
] = GUEST_DISK_BUS_TYPE_SAS
,
471 [BusTypeSata
] = GUEST_DISK_BUS_TYPE_SATA
,
472 [BusTypeSd
] = GUEST_DISK_BUS_TYPE_SD
,
473 [BusTypeMmc
] = GUEST_DISK_BUS_TYPE_MMC
,
474 #if (_WIN32_WINNT >= 0x0601)
475 [BusTypeVirtual
] = GUEST_DISK_BUS_TYPE_VIRTUAL
,
476 [BusTypeFileBackedVirtual
] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL
,
480 static GuestDiskBusType
find_bus_type(STORAGE_BUS_TYPE bus
)
482 if (bus
>= ARRAY_SIZE(win2qemu
) || (int)bus
< 0) {
483 return GUEST_DISK_BUS_TYPE_UNKNOWN
;
485 return win2qemu
[(int)bus
];
488 /* XXX: The following function is BROKEN!
490 * It does not work and probably has never worked. When we query for list of
491 * disks we get cryptic names like "\Device\0000001d" instead of
492 * "\PhysicalDriveX" or "\HarddiskX". Whether the names can be translated one
493 * way or the other for comparison is an open question.
495 * When we query volume names (the original version) we are able to match those
496 * but then the property queries report error "Invalid function". (duh!)
500 DEFINE_GUID(GUID_DEVINTERFACE_VOLUME,
501 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2,
502 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
504 DEFINE_GUID(GUID_DEVINTERFACE_DISK
,
505 0x53f56307L
, 0xb6bf, 0x11d0, 0x94, 0xf2,
506 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
509 static GuestPCIAddress
*get_pci_info(char *guid
, Error
**errp
)
512 SP_DEVINFO_DATA dev_info_data
;
515 char dev_name
[MAX_PATH
];
517 GuestPCIAddress
*pci
= NULL
;
519 bool partial_pci
= false;
520 pci
= g_malloc0(sizeof(*pci
));
526 if (g_str_has_prefix(guid
, "\\\\.\\") ||
527 g_str_has_prefix(guid
, "\\\\?\\")) {
528 name
= g_strdup(guid
+ 4);
530 name
= g_strdup(guid
);
533 if (!QueryDosDevice(name
, dev_name
, ARRAY_SIZE(dev_name
))) {
534 error_setg_win32(errp
, GetLastError(), "failed to get dos device name");
538 dev_info
= SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK
, 0, 0,
539 DIGCF_PRESENT
| DIGCF_DEVICEINTERFACE
);
540 if (dev_info
== INVALID_HANDLE_VALUE
) {
541 error_setg_win32(errp
, GetLastError(), "failed to get devices tree");
545 g_debug("enumerating devices");
546 dev_info_data
.cbSize
= sizeof(SP_DEVINFO_DATA
);
547 for (i
= 0; SetupDiEnumDeviceInfo(dev_info
, i
, &dev_info_data
); i
++) {
548 DWORD addr
, bus
, slot
, data
, size2
;
550 while (!SetupDiGetDeviceRegistryProperty(dev_info
, &dev_info_data
,
551 SPDRP_PHYSICAL_DEVICE_OBJECT_NAME
,
552 &data
, (PBYTE
)buffer
, size
,
554 size
= MAX(size
, size2
);
555 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
557 /* Double the size to avoid problems on
558 * W2k MBCS systems per KB 888609.
559 * https://support.microsoft.com/en-us/kb/259695 */
560 buffer
= g_malloc(size
* 2);
562 error_setg_win32(errp
, GetLastError(),
563 "failed to get device name");
568 if (g_strcmp0(buffer
, dev_name
)) {
571 g_debug("found device %s", dev_name
);
573 /* There is no need to allocate buffer in the next functions. The size
574 * is known and ULONG according to
575 * https://support.microsoft.com/en-us/kb/253232
576 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
578 if (!SetupDiGetDeviceRegistryProperty(dev_info
, &dev_info_data
,
579 SPDRP_BUSNUMBER
, &data
, (PBYTE
)&bus
, size
, NULL
)) {
580 debug_error("failed to get bus");
585 /* The function retrieves the device's address. This value will be
586 * transformed into device function and number */
587 if (!SetupDiGetDeviceRegistryProperty(dev_info
, &dev_info_data
,
588 SPDRP_ADDRESS
, &data
, (PBYTE
)&addr
, size
, NULL
)) {
589 debug_error("failed to get address");
594 /* This call returns UINumber of DEVICE_CAPABILITIES structure.
595 * This number is typically a user-perceived slot number. */
596 if (!SetupDiGetDeviceRegistryProperty(dev_info
, &dev_info_data
,
597 SPDRP_UI_NUMBER
, &data
, (PBYTE
)&slot
, size
, NULL
)) {
598 debug_error("failed to get slot");
603 /* SetupApi gives us the same information as driver with
604 * IoGetDeviceProperty. According to Microsoft
605 * https://support.microsoft.com/en-us/kb/253232
606 * FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
607 * DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
608 * SPDRP_ADDRESS is propertyAddress, so we do the same.*/
616 func
= ((int) addr
== -1) ? -1 : addr
& 0x0000FFFF;
617 dev
= ((int) addr
== -1) ? -1 : (addr
>> 16) & 0x0000FFFF;
619 pci
->slot
= (int) slot
;
620 pci
->function
= func
;
621 pci
->bus
= (int) bus
;
627 SetupDiDestroyDeviceInfoList(dev_info
);
634 static void get_disk_properties(HANDLE vol_h
, GuestDiskAddress
*disk
,
637 STORAGE_PROPERTY_QUERY query
;
638 STORAGE_DEVICE_DESCRIPTOR
*dev_desc
, buf
;
640 ULONG size
= sizeof(buf
);
643 query
.PropertyId
= StorageDeviceProperty
;
644 query
.QueryType
= PropertyStandardQuery
;
646 if (!DeviceIoControl(vol_h
, IOCTL_STORAGE_QUERY_PROPERTY
, &query
,
647 sizeof(STORAGE_PROPERTY_QUERY
), dev_desc
,
648 size
, &received
, NULL
)) {
649 error_setg_win32(errp
, GetLastError(), "failed to get bus type");
652 disk
->bus_type
= find_bus_type(dev_desc
->BusType
);
653 g_debug("bus type %d", disk
->bus_type
);
655 /* Query once more. Now with long enough buffer. */
656 size
= dev_desc
->Size
;
657 dev_desc
= g_malloc0(size
);
658 if (!DeviceIoControl(vol_h
, IOCTL_STORAGE_QUERY_PROPERTY
, &query
,
659 sizeof(STORAGE_PROPERTY_QUERY
), dev_desc
,
660 size
, &received
, NULL
)) {
661 error_setg_win32(errp
, GetLastError(), "failed to get serial number");
662 g_debug("failed to get serial number");
665 if (dev_desc
->SerialNumberOffset
> 0) {
669 if (dev_desc
->SerialNumberOffset
>= received
) {
670 error_setg(errp
, "failed to get serial number: offset outside the buffer");
671 g_debug("serial number offset outside the buffer");
674 serial
= (char *)dev_desc
+ dev_desc
->SerialNumberOffset
;
675 len
= received
- dev_desc
->SerialNumberOffset
;
676 g_debug("serial number \"%s\"", serial
);
678 disk
->serial
= g_strndup(serial
, len
);
679 disk
->has_serial
= true;
688 static void get_single_disk_info(GuestDiskAddress
*disk
, Error
**errp
)
690 SCSI_ADDRESS addr
, *scsi_ad
;
693 Error
*local_err
= NULL
;
697 g_debug("getting disk info for: %s", disk
->dev
);
698 disk_h
= CreateFile(disk
->dev
, 0, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
,
700 if (disk_h
== INVALID_HANDLE_VALUE
) {
701 error_setg_win32(errp
, GetLastError(), "failed to open disk");
705 get_disk_properties(disk_h
, disk
, &local_err
);
707 error_propagate(errp
, local_err
);
711 g_debug("bus type %d", disk
->bus_type
);
712 /* always set pci_controller as required by schema. get_pci_info() should
713 * report -1 values for non-PCI buses rather than fail. fail the command
714 * if that doesn't hold since that suggests some other unexpected
717 disk
->pci_controller
= get_pci_info(disk
->dev
, &local_err
);
719 error_propagate(errp
, local_err
);
722 if (disk
->bus_type
== GUEST_DISK_BUS_TYPE_SCSI
723 || disk
->bus_type
== GUEST_DISK_BUS_TYPE_IDE
724 || disk
->bus_type
== GUEST_DISK_BUS_TYPE_RAID
725 /* This bus type is not supported before Windows Server 2003 SP1 */
726 || disk
->bus_type
== GUEST_DISK_BUS_TYPE_SAS
728 /* We are able to use the same ioctls for different bus types
729 * according to Microsoft docs
730 * https://technet.microsoft.com/en-us/library/ee851589(v=ws.10).aspx */
731 g_debug("getting pci-controller info");
732 if (DeviceIoControl(disk_h
, IOCTL_SCSI_GET_ADDRESS
, NULL
, 0, scsi_ad
,
733 sizeof(SCSI_ADDRESS
), &len
, NULL
)) {
734 disk
->unit
= addr
.Lun
;
735 disk
->target
= addr
.TargetId
;
736 disk
->bus
= addr
.PathId
;
738 /* We do not set error in this case, because we still have enough
739 * information about volume. */
747 /* VSS provider works with volumes, thus there is no difference if
748 * the volume consist of spanned disks. Info about the first disk in the
749 * volume is returned for the spanned disk group (LVM) */
750 static GuestDiskAddressList
*build_guest_disk_info(char *guid
, Error
**errp
)
752 Error
*local_err
= NULL
;
753 GuestDiskAddressList
*list
= NULL
, *cur_item
= NULL
;
754 GuestDiskAddress
*disk
= NULL
;
758 PVOLUME_DISK_EXTENTS extents
= NULL
;
760 /* strip final backslash */
761 char *name
= g_strdup(guid
);
762 if (g_str_has_suffix(name
, "\\")) {
763 name
[strlen(name
) - 1] = 0;
766 g_debug("opening %s", name
);
767 vol_h
= CreateFile(name
, 0, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
,
769 if (vol_h
== INVALID_HANDLE_VALUE
) {
770 error_setg_win32(errp
, GetLastError(), "failed to open volume");
774 /* Get list of extents */
775 g_debug("getting disk extents");
776 size
= sizeof(VOLUME_DISK_EXTENTS
);
777 extents
= g_malloc0(size
);
778 if (!DeviceIoControl(vol_h
, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
, NULL
,
779 0, extents
, size
, NULL
, NULL
)) {
780 DWORD last_err
= GetLastError();
781 if (last_err
== ERROR_MORE_DATA
) {
782 /* Try once more with big enough buffer */
783 size
= sizeof(VOLUME_DISK_EXTENTS
)
784 + extents
->NumberOfDiskExtents
*sizeof(DISK_EXTENT
);
786 extents
= g_malloc0(size
);
787 if (!DeviceIoControl(
788 vol_h
, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
, NULL
,
789 0, extents
, size
, NULL
, NULL
)) {
790 error_setg_win32(errp
, GetLastError(),
791 "failed to get disk extents");
794 } else if (last_err
== ERROR_INVALID_FUNCTION
) {
795 /* Possibly CD-ROM or a shared drive. Try to pass the volume */
796 g_debug("volume not on disk");
797 disk
= g_malloc0(sizeof(GuestDiskAddress
));
798 disk
->has_dev
= true;
799 disk
->dev
= g_strdup(name
);
800 get_single_disk_info(disk
, &local_err
);
802 g_debug("failed to get disk info, ignoring error: %s",
803 error_get_pretty(local_err
));
804 error_free(local_err
);
807 list
= g_malloc0(sizeof(*list
));
813 error_setg_win32(errp
, GetLastError(),
814 "failed to get disk extents");
818 g_debug("Number of extents: %lu", extents
->NumberOfDiskExtents
);
820 /* Go through each extent */
821 for (i
= 0; i
< extents
->NumberOfDiskExtents
; i
++) {
822 disk
= g_malloc0(sizeof(GuestDiskAddress
));
824 /* Disk numbers directly correspond to numbers used in UNCs
826 * See documentation for DISK_EXTENT:
827 * https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
829 * See also Naming Files, Paths and Namespaces:
830 * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
832 disk
->has_dev
= true;
833 disk
->dev
= g_strdup_printf("\\\\.\\PhysicalDrive%lu",
834 extents
->Extents
[i
].DiskNumber
);
836 get_single_disk_info(disk
, &local_err
);
838 error_propagate(errp
, local_err
);
841 cur_item
= g_malloc0(sizeof(*list
));
842 cur_item
->value
= disk
;
844 cur_item
->next
= list
;
850 if (vol_h
!= INVALID_HANDLE_VALUE
) {
853 qapi_free_GuestDiskAddress(disk
);
862 static GuestDiskAddressList
*build_guest_disk_info(char *guid
, Error
**errp
)
867 #endif /* CONFIG_QGA_NTDDSCSI */
869 static GuestFilesystemInfo
*build_guest_fsinfo(char *guid
, Error
**errp
)
872 char mnt
, *mnt_point
;
874 char vol_info
[MAX_PATH
+1];
876 uint64_t i64FreeBytesToCaller
, i64TotalBytes
, i64FreeBytes
;
877 GuestFilesystemInfo
*fs
= NULL
;
879 GetVolumePathNamesForVolumeName(guid
, (LPCH
)&mnt
, 0, &info_size
);
880 if (GetLastError() != ERROR_MORE_DATA
) {
881 error_setg_win32(errp
, GetLastError(), "failed to get volume name");
885 mnt_point
= g_malloc(info_size
+ 1);
886 if (!GetVolumePathNamesForVolumeName(guid
, mnt_point
, info_size
,
888 error_setg_win32(errp
, GetLastError(), "failed to get volume name");
892 len
= strlen(mnt_point
);
893 mnt_point
[len
] = '\\';
894 mnt_point
[len
+1] = 0;
895 if (!GetVolumeInformation(mnt_point
, vol_info
, sizeof(vol_info
), NULL
, NULL
,
896 NULL
, (LPSTR
)&fs_name
, sizeof(fs_name
))) {
897 if (GetLastError() != ERROR_NOT_READY
) {
898 error_setg_win32(errp
, GetLastError(), "failed to get volume info");
903 fs_name
[sizeof(fs_name
) - 1] = 0;
904 fs
= g_malloc(sizeof(*fs
));
905 fs
->name
= g_strdup(guid
);
906 fs
->has_total_bytes
= false;
907 fs
->has_used_bytes
= false;
909 fs
->mountpoint
= g_strdup("System Reserved");
911 fs
->mountpoint
= g_strndup(mnt_point
, len
);
912 if (GetDiskFreeSpaceEx(fs
->mountpoint
,
913 (PULARGE_INTEGER
) & i64FreeBytesToCaller
,
914 (PULARGE_INTEGER
) & i64TotalBytes
,
915 (PULARGE_INTEGER
) & i64FreeBytes
)) {
916 fs
->used_bytes
= i64TotalBytes
- i64FreeBytes
;
917 fs
->total_bytes
= i64TotalBytes
;
918 fs
->has_total_bytes
= true;
919 fs
->has_used_bytes
= true;
922 fs
->type
= g_strdup(fs_name
);
923 fs
->disk
= build_guest_disk_info(guid
, errp
);
929 GuestFilesystemInfoList
*qmp_guest_get_fsinfo(Error
**errp
)
932 GuestFilesystemInfoList
*new, *ret
= NULL
;
935 vol_h
= FindFirstVolume(guid
, sizeof(guid
));
936 if (vol_h
== INVALID_HANDLE_VALUE
) {
937 error_setg_win32(errp
, GetLastError(), "failed to find any volume");
942 GuestFilesystemInfo
*info
= build_guest_fsinfo(guid
, errp
);
946 new = g_malloc(sizeof(*ret
));
950 } while (FindNextVolume(vol_h
, guid
, sizeof(guid
)));
952 if (GetLastError() != ERROR_NO_MORE_FILES
) {
953 error_setg_win32(errp
, GetLastError(), "failed to find next volume");
956 FindVolumeClose(vol_h
);
961 * Return status of freeze/thaw
963 GuestFsfreezeStatus
qmp_guest_fsfreeze_status(Error
**errp
)
965 if (!vss_initialized()) {
966 error_setg(errp
, QERR_UNSUPPORTED
);
970 if (ga_is_frozen(ga_state
)) {
971 return GUEST_FSFREEZE_STATUS_FROZEN
;
974 return GUEST_FSFREEZE_STATUS_THAWED
;
978 * Freeze local file systems using Volume Shadow-copy Service.
979 * The frozen state is limited for up to 10 seconds by VSS.
981 int64_t qmp_guest_fsfreeze_freeze(Error
**errp
)
983 return qmp_guest_fsfreeze_freeze_list(false, NULL
, errp
);
986 int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints
,
987 strList
*mountpoints
,
991 Error
*local_err
= NULL
;
993 if (!vss_initialized()) {
994 error_setg(errp
, QERR_UNSUPPORTED
);
998 slog("guest-fsfreeze called");
1000 /* cannot risk guest agent blocking itself on a write in this state */
1001 ga_set_frozen(ga_state
);
1003 qga_vss_fsfreeze(&i
, true, mountpoints
, &local_err
);
1005 error_propagate(errp
, local_err
);
1013 qmp_guest_fsfreeze_thaw(&local_err
);
1015 g_debug("cleanup thaw: %s", error_get_pretty(local_err
));
1016 error_free(local_err
);
1022 * Thaw local file systems using Volume Shadow-copy Service.
1024 int64_t qmp_guest_fsfreeze_thaw(Error
**errp
)
1028 if (!vss_initialized()) {
1029 error_setg(errp
, QERR_UNSUPPORTED
);
1033 qga_vss_fsfreeze(&i
, false, NULL
, errp
);
1035 ga_unset_frozen(ga_state
);
1039 static void guest_fsfreeze_cleanup(void)
1043 if (!vss_initialized()) {
1047 if (ga_is_frozen(ga_state
) == GUEST_FSFREEZE_STATUS_FROZEN
) {
1048 qmp_guest_fsfreeze_thaw(&err
);
1050 slog("failed to clean up frozen filesystems: %s",
1051 error_get_pretty(err
));
1060 * Walk list of mounted file systems in the guest, and discard unused
1063 GuestFilesystemTrimResponse
*
1064 qmp_guest_fstrim(bool has_minimum
, int64_t minimum
, Error
**errp
)
1066 GuestFilesystemTrimResponse
*resp
;
1068 WCHAR guid
[MAX_PATH
] = L
"";
1072 ZeroMemory(&osvi
, sizeof(OSVERSIONINFO
));
1073 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
1074 GetVersionEx(&osvi
);
1075 win8_or_later
= (osvi
.dwMajorVersion
> 6 ||
1076 ((osvi
.dwMajorVersion
== 6) &&
1077 (osvi
.dwMinorVersion
>= 2)));
1078 if (!win8_or_later
) {
1079 error_setg(errp
, "fstrim is only supported for Win8+");
1083 handle
= FindFirstVolumeW(guid
, ARRAYSIZE(guid
));
1084 if (handle
== INVALID_HANDLE_VALUE
) {
1085 error_setg_win32(errp
, GetLastError(), "failed to find any volume");
1089 resp
= g_new0(GuestFilesystemTrimResponse
, 1);
1092 GuestFilesystemTrimResult
*res
;
1093 GuestFilesystemTrimResultList
*list
;
1095 DWORD char_count
= 0;
1097 GError
*gerr
= NULL
;
1100 GetVolumePathNamesForVolumeNameW(guid
, NULL
, 0, &char_count
);
1102 if (GetLastError() != ERROR_MORE_DATA
) {
1105 if (GetDriveTypeW(guid
) != DRIVE_FIXED
) {
1109 uc_path
= g_malloc(sizeof(WCHAR
) * char_count
);
1110 if (!GetVolumePathNamesForVolumeNameW(guid
, uc_path
, char_count
,
1111 &char_count
) || !*uc_path
) {
1112 /* strange, but this condition could be faced even with size == 2 */
1117 res
= g_new0(GuestFilesystemTrimResult
, 1);
1119 path
= g_utf16_to_utf8(uc_path
, char_count
, NULL
, NULL
, &gerr
);
1124 res
->has_error
= true;
1125 res
->error
= g_strdup(gerr
->message
);
1132 list
= g_new0(GuestFilesystemTrimResultList
, 1);
1134 list
->next
= resp
->paths
;
1138 memset(argv
, 0, sizeof(argv
));
1139 argv
[0] = (gchar
*)"defrag.exe";
1140 argv
[1] = (gchar
*)"/L";
1143 if (!g_spawn_sync(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
,
1144 &out
/* stdout */, NULL
/* stdin */,
1146 res
->has_error
= true;
1147 res
->error
= g_strdup(gerr
->message
);
1150 /* defrag.exe is UGLY. Exit code is ALWAYS zero.
1151 Error is reported in the output with something like
1152 (x89000020) etc code in the stdout */
1155 gchar
**lines
= g_strsplit(out
, "\r\n", 0);
1158 for (i
= 0; lines
[i
] != NULL
; i
++) {
1159 if (g_strstr_len(lines
[i
], -1, "(0x") == NULL
) {
1162 res
->has_error
= true;
1163 res
->error
= g_strdup(lines
[i
]);
1168 } while (FindNextVolumeW(handle
, guid
, ARRAYSIZE(guid
)));
1170 FindVolumeClose(handle
);
1175 GUEST_SUSPEND_MODE_DISK
,
1176 GUEST_SUSPEND_MODE_RAM
1179 static void check_suspend_mode(GuestSuspendMode mode
, Error
**errp
)
1181 SYSTEM_POWER_CAPABILITIES sys_pwr_caps
;
1182 Error
*local_err
= NULL
;
1184 ZeroMemory(&sys_pwr_caps
, sizeof(sys_pwr_caps
));
1185 if (!GetPwrCapabilities(&sys_pwr_caps
)) {
1186 error_setg(&local_err
, QERR_QGA_COMMAND_FAILED
,
1187 "failed to determine guest suspend capabilities");
1192 case GUEST_SUSPEND_MODE_DISK
:
1193 if (!sys_pwr_caps
.SystemS4
) {
1194 error_setg(&local_err
, QERR_QGA_COMMAND_FAILED
,
1195 "suspend-to-disk not supported by OS");
1198 case GUEST_SUSPEND_MODE_RAM
:
1199 if (!sys_pwr_caps
.SystemS3
) {
1200 error_setg(&local_err
, QERR_QGA_COMMAND_FAILED
,
1201 "suspend-to-ram not supported by OS");
1205 error_setg(&local_err
, QERR_INVALID_PARAMETER_VALUE
, "mode",
1206 "GuestSuspendMode");
1210 error_propagate(errp
, local_err
);
1213 static DWORD WINAPI
do_suspend(LPVOID opaque
)
1215 GuestSuspendMode
*mode
= opaque
;
1218 if (!SetSuspendState(*mode
== GUEST_SUSPEND_MODE_DISK
, TRUE
, TRUE
)) {
1219 slog("failed to suspend guest, %lu", GetLastError());
1226 void qmp_guest_suspend_disk(Error
**errp
)
1228 Error
*local_err
= NULL
;
1229 GuestSuspendMode
*mode
= g_new(GuestSuspendMode
, 1);
1231 *mode
= GUEST_SUSPEND_MODE_DISK
;
1232 check_suspend_mode(*mode
, &local_err
);
1233 acquire_privilege(SE_SHUTDOWN_NAME
, &local_err
);
1234 execute_async(do_suspend
, mode
, &local_err
);
1237 error_propagate(errp
, local_err
);
1242 void qmp_guest_suspend_ram(Error
**errp
)
1244 Error
*local_err
= NULL
;
1245 GuestSuspendMode
*mode
= g_new(GuestSuspendMode
, 1);
1247 *mode
= GUEST_SUSPEND_MODE_RAM
;
1248 check_suspend_mode(*mode
, &local_err
);
1249 acquire_privilege(SE_SHUTDOWN_NAME
, &local_err
);
1250 execute_async(do_suspend
, mode
, &local_err
);
1253 error_propagate(errp
, local_err
);
1258 void qmp_guest_suspend_hybrid(Error
**errp
)
1260 error_setg(errp
, QERR_UNSUPPORTED
);
1263 static IP_ADAPTER_ADDRESSES
*guest_get_adapters_addresses(Error
**errp
)
1265 IP_ADAPTER_ADDRESSES
*adptr_addrs
= NULL
;
1266 ULONG adptr_addrs_len
= 0;
1269 /* Call the first time to get the adptr_addrs_len. */
1270 GetAdaptersAddresses(AF_UNSPEC
, GAA_FLAG_INCLUDE_PREFIX
,
1271 NULL
, adptr_addrs
, &adptr_addrs_len
);
1273 adptr_addrs
= g_malloc(adptr_addrs_len
);
1274 ret
= GetAdaptersAddresses(AF_UNSPEC
, GAA_FLAG_INCLUDE_PREFIX
,
1275 NULL
, adptr_addrs
, &adptr_addrs_len
);
1276 if (ret
!= ERROR_SUCCESS
) {
1277 error_setg_win32(errp
, ret
, "failed to get adapters addresses");
1278 g_free(adptr_addrs
);
1284 static char *guest_wctomb_dup(WCHAR
*wstr
)
1289 i
= wcslen(wstr
) + 1;
1291 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
,
1292 wstr
, -1, str
, i
, NULL
, NULL
);
1296 static char *guest_addr_to_str(IP_ADAPTER_UNICAST_ADDRESS
*ip_addr
,
1299 char addr_str
[INET6_ADDRSTRLEN
+ INET_ADDRSTRLEN
];
1303 if (ip_addr
->Address
.lpSockaddr
->sa_family
== AF_INET
||
1304 ip_addr
->Address
.lpSockaddr
->sa_family
== AF_INET6
) {
1305 len
= sizeof(addr_str
);
1306 ret
= WSAAddressToString(ip_addr
->Address
.lpSockaddr
,
1307 ip_addr
->Address
.iSockaddrLength
,
1312 error_setg_win32(errp
, WSAGetLastError(),
1313 "failed address presentation form conversion");
1316 return g_strdup(addr_str
);
1321 static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS
*ip_addr
)
1323 /* For Windows Vista/2008 and newer, use the OnLinkPrefixLength
1324 * field to obtain the prefix.
1326 return ip_addr
->OnLinkPrefixLength
;
1329 #define INTERFACE_PATH_BUF_SZ 512
1331 static DWORD
get_interface_index(const char *guid
)
1335 wchar_t wbuf
[INTERFACE_PATH_BUF_SZ
];
1336 snwprintf(wbuf
, INTERFACE_PATH_BUF_SZ
, L
"\\device\\tcpip_%s", guid
);
1337 wbuf
[INTERFACE_PATH_BUF_SZ
- 1] = 0;
1338 status
= GetAdapterIndex (wbuf
, &index
);
1339 if (status
!= NO_ERROR
) {
1346 typedef NETIOAPI_API (WINAPI
*GetIfEntry2Func
)(PMIB_IF_ROW2 Row
);
1348 static int guest_get_network_stats(const char *name
,
1349 GuestNetworkInterfaceStat
*stats
)
1351 OSVERSIONINFO os_ver
;
1353 os_ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
1354 GetVersionEx(&os_ver
);
1355 if (os_ver
.dwMajorVersion
>= 6) {
1356 MIB_IF_ROW2 a_mid_ifrow
;
1357 GetIfEntry2Func getifentry2_ex
;
1359 HMODULE module
= GetModuleHandle("iphlpapi");
1360 PVOID func
= GetProcAddress(module
, "GetIfEntry2");
1366 getifentry2_ex
= (GetIfEntry2Func
)func
;
1367 if_index
= get_interface_index(name
);
1368 if (if_index
== (DWORD
)~0) {
1372 memset(&a_mid_ifrow
, 0, sizeof(a_mid_ifrow
));
1373 a_mid_ifrow
.InterfaceIndex
= if_index
;
1374 if (NO_ERROR
== getifentry2_ex(&a_mid_ifrow
)) {
1375 stats
->rx_bytes
= a_mid_ifrow
.InOctets
;
1376 stats
->rx_packets
= a_mid_ifrow
.InUcastPkts
;
1377 stats
->rx_errs
= a_mid_ifrow
.InErrors
;
1378 stats
->rx_dropped
= a_mid_ifrow
.InDiscards
;
1379 stats
->tx_bytes
= a_mid_ifrow
.OutOctets
;
1380 stats
->tx_packets
= a_mid_ifrow
.OutUcastPkts
;
1381 stats
->tx_errs
= a_mid_ifrow
.OutErrors
;
1382 stats
->tx_dropped
= a_mid_ifrow
.OutDiscards
;
1389 GuestNetworkInterfaceList
*qmp_guest_network_get_interfaces(Error
**errp
)
1391 IP_ADAPTER_ADDRESSES
*adptr_addrs
, *addr
;
1392 IP_ADAPTER_UNICAST_ADDRESS
*ip_addr
= NULL
;
1393 GuestNetworkInterfaceList
*head
= NULL
, *cur_item
= NULL
;
1394 GuestIpAddressList
*head_addr
, *cur_addr
;
1395 GuestNetworkInterfaceList
*info
;
1396 GuestNetworkInterfaceStat
*interface_stat
= NULL
;
1397 GuestIpAddressList
*address_item
= NULL
;
1398 unsigned char *mac_addr
;
1404 adptr_addrs
= guest_get_adapters_addresses(errp
);
1405 if (adptr_addrs
== NULL
) {
1409 /* Make WSA APIs available. */
1410 wsa_version
= MAKEWORD(2, 2);
1411 ret
= WSAStartup(wsa_version
, &wsa_data
);
1413 error_setg_win32(errp
, ret
, "failed socket startup");
1417 for (addr
= adptr_addrs
; addr
; addr
= addr
->Next
) {
1418 info
= g_malloc0(sizeof(*info
));
1420 if (cur_item
== NULL
) {
1421 head
= cur_item
= info
;
1423 cur_item
->next
= info
;
1427 info
->value
= g_malloc0(sizeof(*info
->value
));
1428 info
->value
->name
= guest_wctomb_dup(addr
->FriendlyName
);
1430 if (addr
->PhysicalAddressLength
!= 0) {
1431 mac_addr
= addr
->PhysicalAddress
;
1433 info
->value
->hardware_address
=
1434 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1435 (int) mac_addr
[0], (int) mac_addr
[1],
1436 (int) mac_addr
[2], (int) mac_addr
[3],
1437 (int) mac_addr
[4], (int) mac_addr
[5]);
1439 info
->value
->has_hardware_address
= true;
1444 for (ip_addr
= addr
->FirstUnicastAddress
;
1446 ip_addr
= ip_addr
->Next
) {
1447 addr_str
= guest_addr_to_str(ip_addr
, errp
);
1448 if (addr_str
== NULL
) {
1452 address_item
= g_malloc0(sizeof(*address_item
));
1455 head_addr
= cur_addr
= address_item
;
1457 cur_addr
->next
= address_item
;
1458 cur_addr
= address_item
;
1461 address_item
->value
= g_malloc0(sizeof(*address_item
->value
));
1462 address_item
->value
->ip_address
= addr_str
;
1463 address_item
->value
->prefix
= guest_ip_prefix(ip_addr
);
1464 if (ip_addr
->Address
.lpSockaddr
->sa_family
== AF_INET
) {
1465 address_item
->value
->ip_address_type
=
1466 GUEST_IP_ADDRESS_TYPE_IPV4
;
1467 } else if (ip_addr
->Address
.lpSockaddr
->sa_family
== AF_INET6
) {
1468 address_item
->value
->ip_address_type
=
1469 GUEST_IP_ADDRESS_TYPE_IPV6
;
1473 info
->value
->has_ip_addresses
= true;
1474 info
->value
->ip_addresses
= head_addr
;
1476 if (!info
->value
->has_statistics
) {
1477 interface_stat
= g_malloc0(sizeof(*interface_stat
));
1478 if (guest_get_network_stats(addr
->AdapterName
,
1479 interface_stat
) == -1) {
1480 info
->value
->has_statistics
= false;
1481 g_free(interface_stat
);
1483 info
->value
->statistics
= interface_stat
;
1484 info
->value
->has_statistics
= true;
1490 g_free(adptr_addrs
);
1494 int64_t qmp_guest_get_time(Error
**errp
)
1496 SYSTEMTIME ts
= {0};
1500 if (ts
.wYear
< 1601 || ts
.wYear
> 30827) {
1501 error_setg(errp
, "Failed to get time");
1505 if (!SystemTimeToFileTime(&ts
, &tf
)) {
1506 error_setg(errp
, "Failed to convert system time: %d", (int)GetLastError());
1510 return ((((int64_t)tf
.dwHighDateTime
<< 32) | tf
.dwLowDateTime
)
1511 - W32_FT_OFFSET
) * 100;
1514 void qmp_guest_set_time(bool has_time
, int64_t time_ns
, Error
**errp
)
1516 Error
*local_err
= NULL
;
1522 /* Unfortunately, Windows libraries don't provide an easy way to access
1525 * https://msdn.microsoft.com/en-us/library/aa908981.aspx
1527 * Instead, a workaround is to use the Windows win32tm command to
1528 * resync the time using the Windows Time service.
1533 HRESULT hr
= system("w32tm /resync /nowait");
1535 if (GetLastError() != 0) {
1536 strerror_s((LPTSTR
) & msg_buffer
, 0, errno
);
1537 error_setg(errp
, "system(...) failed: %s", (LPCTSTR
)msg_buffer
);
1538 } else if (hr
!= 0) {
1539 if (hr
== HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE
)) {
1540 error_setg(errp
, "Windows Time service not running on the "
1543 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
1544 FORMAT_MESSAGE_FROM_SYSTEM
|
1545 FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
,
1546 (DWORD
)hr
, MAKELANGID(LANG_NEUTRAL
,
1547 SUBLANG_DEFAULT
), (LPTSTR
) & msg_buffer
, 0,
1549 error_setg(errp
, "w32tm failed with error (0x%lx), couldn'"
1550 "t retrieve error message", hr
);
1552 error_setg(errp
, "w32tm failed with error (0x%lx): %s", hr
,
1553 (LPCTSTR
)msg_buffer
);
1554 LocalFree(msg_buffer
);
1557 } else if (!InternetGetConnectedState(&ret_flags
, 0)) {
1558 error_setg(errp
, "No internet connection on guest, sync not "
1564 /* Validate time passed by user. */
1565 if (time_ns
< 0 || time_ns
/ 100 > INT64_MAX
- W32_FT_OFFSET
) {
1566 error_setg(errp
, "Time %" PRId64
"is invalid", time_ns
);
1570 time
= time_ns
/ 100 + W32_FT_OFFSET
;
1572 tf
.dwLowDateTime
= (DWORD
) time
;
1573 tf
.dwHighDateTime
= (DWORD
) (time
>> 32);
1575 if (!FileTimeToSystemTime(&tf
, &ts
)) {
1576 error_setg(errp
, "Failed to convert system time %d",
1577 (int)GetLastError());
1581 acquire_privilege(SE_SYSTEMTIME_NAME
, &local_err
);
1583 error_propagate(errp
, local_err
);
1587 if (!SetSystemTime(&ts
)) {
1588 error_setg(errp
, "Failed to set time to guest: %d", (int)GetLastError());
1593 GuestLogicalProcessorList
*qmp_guest_get_vcpus(Error
**errp
)
1595 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pslpi
, ptr
;
1597 GuestLogicalProcessorList
*head
, **link
;
1598 Error
*local_err
= NULL
;
1607 if ((GetLogicalProcessorInformation(pslpi
, &length
) == FALSE
) &&
1608 (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) &&
1609 (length
> sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
))) {
1610 ptr
= pslpi
= g_malloc0(length
);
1611 if (GetLogicalProcessorInformation(pslpi
, &length
) == FALSE
) {
1612 error_setg(&local_err
, "Failed to get processor information: %d",
1613 (int)GetLastError());
1616 error_setg(&local_err
,
1617 "Failed to get processor information buffer length: %d",
1618 (int)GetLastError());
1621 while ((local_err
== NULL
) && (length
> 0)) {
1622 if (pslpi
->Relationship
== RelationProcessorCore
) {
1623 ULONG_PTR cpu_bits
= pslpi
->ProcessorMask
;
1625 while (cpu_bits
> 0) {
1626 if (!!(cpu_bits
& 1)) {
1627 GuestLogicalProcessor
*vcpu
;
1628 GuestLogicalProcessorList
*entry
;
1630 vcpu
= g_malloc0(sizeof *vcpu
);
1631 vcpu
->logical_id
= current
++;
1632 vcpu
->online
= true;
1633 vcpu
->has_can_offline
= true;
1635 entry
= g_malloc0(sizeof *entry
);
1636 entry
->value
= vcpu
;
1639 link
= &entry
->next
;
1644 length
-= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
);
1645 pslpi
++; /* next entry */
1650 if (local_err
== NULL
) {
1654 /* there's no guest with zero VCPUs */
1655 error_setg(&local_err
, "Guest reported zero VCPUs");
1658 qapi_free_GuestLogicalProcessorList(head
);
1659 error_propagate(errp
, local_err
);
1663 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList
*vcpus
, Error
**errp
)
1665 error_setg(errp
, QERR_UNSUPPORTED
);
1670 get_net_error_message(gint error
)
1672 HMODULE module
= NULL
;
1673 gchar
*retval
= NULL
;
1674 wchar_t *msg
= NULL
;
1678 flags
= FORMAT_MESSAGE_ALLOCATE_BUFFER
|
1679 FORMAT_MESSAGE_IGNORE_INSERTS
|
1680 FORMAT_MESSAGE_FROM_SYSTEM
;
1682 if (error
>= NERR_BASE
&& error
<= MAX_NERR
) {
1683 module
= LoadLibraryExW(L
"netmsg.dll", NULL
, LOAD_LIBRARY_AS_DATAFILE
);
1685 if (module
!= NULL
) {
1686 flags
|= FORMAT_MESSAGE_FROM_HMODULE
;
1690 FormatMessageW(flags
, module
, error
, 0, (LPWSTR
)&msg
, 0, NULL
);
1693 nchars
= wcslen(msg
);
1696 msg
[nchars
- 1] == L
'\n' &&
1697 msg
[nchars
- 2] == L
'\r') {
1698 msg
[nchars
- 2] = L
'\0';
1701 retval
= g_utf16_to_utf8(msg
, -1, NULL
, NULL
, NULL
);
1706 if (module
!= NULL
) {
1707 FreeLibrary(module
);
1713 void qmp_guest_set_user_password(const char *username
,
1714 const char *password
,
1719 char *rawpasswddata
= NULL
;
1720 size_t rawpasswdlen
;
1721 wchar_t *user
= NULL
, *wpass
= NULL
;
1722 USER_INFO_1003 pi1003
= { 0, };
1723 GError
*gerr
= NULL
;
1726 error_setg(errp
, QERR_UNSUPPORTED
);
1730 rawpasswddata
= (char *)qbase64_decode(password
, -1, &rawpasswdlen
, errp
);
1731 if (!rawpasswddata
) {
1734 rawpasswddata
= g_renew(char, rawpasswddata
, rawpasswdlen
+ 1);
1735 rawpasswddata
[rawpasswdlen
] = '\0';
1737 user
= g_utf8_to_utf16(username
, -1, NULL
, NULL
, &gerr
);
1742 wpass
= g_utf8_to_utf16(rawpasswddata
, -1, NULL
, NULL
, &gerr
);
1747 pi1003
.usri1003_password
= wpass
;
1748 nas
= NetUserSetInfo(NULL
, user
,
1749 1003, (LPBYTE
)&pi1003
,
1752 if (nas
!= NERR_Success
) {
1753 gchar
*msg
= get_net_error_message(nas
);
1754 error_setg(errp
, "failed to set password: %s", msg
);
1760 error_setg(errp
, QERR_QGA_COMMAND_FAILED
, gerr
->message
);
1765 g_free(rawpasswddata
);
1768 GuestMemoryBlockList
*qmp_guest_get_memory_blocks(Error
**errp
)
1770 error_setg(errp
, QERR_UNSUPPORTED
);
1774 GuestMemoryBlockResponseList
*
1775 qmp_guest_set_memory_blocks(GuestMemoryBlockList
*mem_blks
, Error
**errp
)
1777 error_setg(errp
, QERR_UNSUPPORTED
);
1781 GuestMemoryBlockInfo
*qmp_guest_get_memory_block_info(Error
**errp
)
1783 error_setg(errp
, QERR_UNSUPPORTED
);
1787 /* add unsupported commands to the blacklist */
1788 GList
*ga_command_blacklist_init(GList
*blacklist
)
1790 const char *list_unsupported
[] = {
1791 "guest-suspend-hybrid",
1793 "guest-get-memory-blocks", "guest-set-memory-blocks",
1794 "guest-get-memory-block-size",
1796 char **p
= (char **)list_unsupported
;
1799 blacklist
= g_list_append(blacklist
, g_strdup(*p
++));
1802 if (!vss_init(true)) {
1803 g_debug("vss_init failed, vss commands are going to be disabled");
1804 const char *list
[] = {
1805 "guest-get-fsinfo", "guest-fsfreeze-status",
1806 "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL
};
1810 blacklist
= g_list_append(blacklist
, g_strdup(*p
++));
1817 /* register init/cleanup routines for stateful command groups */
1818 void ga_command_state_init(GAState
*s
, GACommandState
*cs
)
1820 if (!vss_initialized()) {
1821 ga_command_state_add(cs
, NULL
, guest_fsfreeze_cleanup
);
1825 /* MINGW is missing two fields: IncomingFrames & OutgoingFrames */
1826 typedef struct _GA_WTSINFOA
{
1827 WTS_CONNECTSTATE_CLASS State
;
1829 DWORD IncomingBytes
;
1830 DWORD OutgoingBytes
;
1831 DWORD IncomingFrames
;
1832 DWORD OutgoingFrames
;
1833 DWORD IncomingCompressedBytes
;
1834 DWORD OutgoingCompressedBy
;
1835 CHAR WinStationName
[WINSTATIONNAME_LENGTH
];
1836 CHAR Domain
[DOMAIN_LENGTH
];
1837 CHAR UserName
[USERNAME_LENGTH
+ 1];
1838 LARGE_INTEGER ConnectTime
;
1839 LARGE_INTEGER DisconnectTime
;
1840 LARGE_INTEGER LastInputTime
;
1841 LARGE_INTEGER LogonTime
;
1842 LARGE_INTEGER CurrentTime
;
1846 GuestUserList
*qmp_guest_get_users(Error
**err
)
1848 #define QGA_NANOSECONDS 10000000
1850 GHashTable
*cache
= NULL
;
1851 GuestUserList
*head
= NULL
, *cur_item
= NULL
;
1853 DWORD buffer_size
= 0, count
= 0, i
= 0;
1854 GA_WTSINFOA
*info
= NULL
;
1855 WTS_SESSION_INFOA
*entries
= NULL
;
1856 GuestUserList
*item
= NULL
;
1857 GuestUser
*user
= NULL
;
1858 gpointer value
= NULL
;
1860 double login_time
= 0;
1862 cache
= g_hash_table_new(g_str_hash
, g_str_equal
);
1864 if (WTSEnumerateSessionsA(NULL
, 0, 1, &entries
, &count
)) {
1865 for (i
= 0; i
< count
; ++i
) {
1868 if (WTSQuerySessionInformationA(
1870 entries
[i
].SessionId
,
1876 if (strlen(info
->UserName
) == 0) {
1877 WTSFreeMemory(info
);
1881 login
= info
->LogonTime
.QuadPart
;
1882 login
-= W32_FT_OFFSET
;
1883 login_time
= ((double)login
) / QGA_NANOSECONDS
;
1885 if (g_hash_table_contains(cache
, info
->UserName
)) {
1886 value
= g_hash_table_lookup(cache
, info
->UserName
);
1887 user
= (GuestUser
*)value
;
1888 if (user
->login_time
> login_time
) {
1889 user
->login_time
= login_time
;
1892 item
= g_new0(GuestUserList
, 1);
1893 item
->value
= g_new0(GuestUser
, 1);
1895 item
->value
->user
= g_strdup(info
->UserName
);
1896 item
->value
->domain
= g_strdup(info
->Domain
);
1897 item
->value
->has_domain
= true;
1899 item
->value
->login_time
= login_time
;
1901 g_hash_table_add(cache
, item
->value
->user
);
1904 head
= cur_item
= item
;
1906 cur_item
->next
= item
;
1911 WTSFreeMemory(info
);
1913 WTSFreeMemory(entries
);
1915 g_hash_table_destroy(cache
);
1919 typedef struct _ga_matrix_lookup_t
{
1922 char const *version
;
1923 char const *version_id
;
1924 } ga_matrix_lookup_t
;
1926 static ga_matrix_lookup_t
const WIN_VERSION_MATRIX
[2][8] = {
1928 /* Desktop editions */
1929 { 5, 0, "Microsoft Windows 2000", "2000"},
1930 { 5, 1, "Microsoft Windows XP", "xp"},
1931 { 6, 0, "Microsoft Windows Vista", "vista"},
1932 { 6, 1, "Microsoft Windows 7" "7"},
1933 { 6, 2, "Microsoft Windows 8", "8"},
1934 { 6, 3, "Microsoft Windows 8.1", "8.1"},
1935 {10, 0, "Microsoft Windows 10", "10"},
1938 /* Server editions */
1939 { 5, 2, "Microsoft Windows Server 2003", "2003"},
1940 { 6, 0, "Microsoft Windows Server 2008", "2008"},
1941 { 6, 1, "Microsoft Windows Server 2008 R2", "2008r2"},
1942 { 6, 2, "Microsoft Windows Server 2012", "2012"},
1943 { 6, 3, "Microsoft Windows Server 2012 R2", "2012r2"},
1944 {10, 0, "Microsoft Windows Server 2016", "2016"},
1950 static void ga_get_win_version(RTL_OSVERSIONINFOEXW
*info
, Error
**errp
)
1952 typedef NTSTATUS(WINAPI
* rtl_get_version_t
)(
1953 RTL_OSVERSIONINFOEXW
*os_version_info_ex
);
1955 info
->dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
1957 HMODULE module
= GetModuleHandle("ntdll");
1958 PVOID fun
= GetProcAddress(module
, "RtlGetVersion");
1960 error_setg(errp
, QERR_QGA_COMMAND_FAILED
,
1961 "Failed to get address of RtlGetVersion");
1965 rtl_get_version_t rtl_get_version
= (rtl_get_version_t
)fun
;
1966 rtl_get_version(info
);
1970 static char *ga_get_win_name(OSVERSIONINFOEXW
const *os_version
, bool id
)
1972 DWORD major
= os_version
->dwMajorVersion
;
1973 DWORD minor
= os_version
->dwMinorVersion
;
1974 int tbl_idx
= (os_version
->wProductType
!= VER_NT_WORKSTATION
);
1975 ga_matrix_lookup_t
const *table
= WIN_VERSION_MATRIX
[tbl_idx
];
1976 while (table
->version
!= NULL
) {
1977 if (major
== table
->major
&& minor
== table
->minor
) {
1979 return g_strdup(table
->version_id
);
1981 return g_strdup(table
->version
);
1986 slog("failed to lookup Windows version: major=%lu, minor=%lu",
1988 return g_strdup("N/A");
1991 static char *ga_get_win_product_name(Error
**errp
)
1995 char *result
= g_malloc0(size
);
1996 LONG err
= ERROR_SUCCESS
;
1998 err
= RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1999 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
2001 if (err
!= ERROR_SUCCESS
) {
2002 error_setg_win32(errp
, err
, "failed to open registry key");
2006 err
= RegQueryValueExA(key
, "ProductName", NULL
, NULL
,
2007 (LPBYTE
)result
, &size
);
2008 if (err
== ERROR_MORE_DATA
) {
2009 slog("ProductName longer than expected (%lu bytes), retrying",
2014 result
= g_malloc0(size
);
2015 err
= RegQueryValueExA(key
, "ProductName", NULL
, NULL
,
2016 (LPBYTE
)result
, &size
);
2019 if (err
!= ERROR_SUCCESS
) {
2020 error_setg_win32(errp
, err
, "failed to retrive ProductName");
2031 static char *ga_get_current_arch(void)
2034 GetNativeSystemInfo(&info
);
2035 char *result
= NULL
;
2036 switch (info
.wProcessorArchitecture
) {
2037 case PROCESSOR_ARCHITECTURE_AMD64
:
2038 result
= g_strdup("x86_64");
2040 case PROCESSOR_ARCHITECTURE_ARM
:
2041 result
= g_strdup("arm");
2043 case PROCESSOR_ARCHITECTURE_IA64
:
2044 result
= g_strdup("ia64");
2046 case PROCESSOR_ARCHITECTURE_INTEL
:
2047 result
= g_strdup("x86");
2049 case PROCESSOR_ARCHITECTURE_UNKNOWN
:
2051 slog("unknown processor architecture 0x%0x",
2052 info
.wProcessorArchitecture
);
2053 result
= g_strdup("unknown");
2059 GuestOSInfo
*qmp_guest_get_osinfo(Error
**errp
)
2061 Error
*local_err
= NULL
;
2062 OSVERSIONINFOEXW os_version
= {0};
2067 ga_get_win_version(&os_version
, &local_err
);
2069 error_propagate(errp
, local_err
);
2073 server
= os_version
.wProductType
!= VER_NT_WORKSTATION
;
2074 product_name
= ga_get_win_product_name(&local_err
);
2075 if (product_name
== NULL
) {
2076 error_propagate(errp
, local_err
);
2080 info
= g_new0(GuestOSInfo
, 1);
2082 info
->has_kernel_version
= true;
2083 info
->kernel_version
= g_strdup_printf("%lu.%lu",
2084 os_version
.dwMajorVersion
,
2085 os_version
.dwMinorVersion
);
2086 info
->has_kernel_release
= true;
2087 info
->kernel_release
= g_strdup_printf("%lu",
2088 os_version
.dwBuildNumber
);
2089 info
->has_machine
= true;
2090 info
->machine
= ga_get_current_arch();
2092 info
->has_id
= true;
2093 info
->id
= g_strdup("mswindows");
2094 info
->has_name
= true;
2095 info
->name
= g_strdup("Microsoft Windows");
2096 info
->has_pretty_name
= true;
2097 info
->pretty_name
= product_name
;
2098 info
->has_version
= true;
2099 info
->version
= ga_get_win_name(&os_version
, false);
2100 info
->has_version_id
= true;
2101 info
->version_id
= ga_get_win_name(&os_version
, true);
2102 info
->has_variant
= true;
2103 info
->variant
= g_strdup(server
? "server" : "client");
2104 info
->has_variant_id
= true;
2105 info
->variant_id
= g_strdup(server
? "server" : "client");