--- src/vbox/vbox_common.c | 1076 ++++++++++++++++++++++++++++++++++- src/vbox/vbox_common.h | 9 + src/vbox/vbox_tmpl.c | 1261 +---------------------------------------- src/vbox/vbox_uniformed_api.h | 1 + 4 files changed, 1094 insertions(+), 1253 deletions(-) diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index 24d2ddb..fa9c0b0 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -109,7 +109,6 @@ if (!data->vboxObj) {\ #define ARRAY_GET_MACHINES \ (gVBoxAPI.UArray.handleGetMachines(data->vboxObj)) - /* global vbox API, used for all common codes. */ static vboxUniformedAPI gVBoxAPI; @@ -277,6 +276,66 @@ static bool vboxGetDeviceDetails(const char *deviceName, return true; } +/** + * function to generate the name for medium, + * for e.g: hda, sda, etc + * + * @returns null terminated string with device name or NULL + * for failures + * @param conn Input Connection Pointer + * @param storageBus Input storage bus type + * @param deviceInst Input device instance number + * @param devicePort Input port number + * @param deviceSlot Input slot number + * @param aMaxPortPerInst Input array of max port per device instance + * @param aMaxSlotPerPort Input array of max slot per device port + * + */ +static char *vboxGenerateMediumName(PRUint32 storageBus, + PRInt32 deviceInst, + PRInt32 devicePort, + PRInt32 deviceSlot, + PRUint32 *aMaxPortPerInst, + PRUint32 *aMaxSlotPerPort) +{ + const char *prefix = NULL; + char *name = NULL; + int total = 0; + PRUint32 maxPortPerInst = 0; + PRUint32 maxSlotPerPort = 0; + + if (!aMaxPortPerInst || + !aMaxSlotPerPort) + return NULL; + + if ((storageBus < StorageBus_IDE) || + (storageBus > StorageBus_Floppy)) + return NULL; + + maxPortPerInst = aMaxPortPerInst[storageBus]; + maxSlotPerPort = aMaxSlotPerPort[storageBus]; + total = (deviceInst * maxPortPerInst * maxSlotPerPort) + + (devicePort * maxSlotPerPort) + + deviceSlot; + + if (storageBus == StorageBus_IDE) { + prefix = "hd"; + } else if ((storageBus == StorageBus_SATA) || + (storageBus == StorageBus_SCSI)) { + prefix = "sd"; + } else if (storageBus == StorageBus_Floppy) { + prefix = "fd"; + } + + name = virIndexToDiskName(total, prefix); + + VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, " + "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u", + NULLSTR(name), total, storageBus, deviceInst, devicePort, + deviceSlot, maxPortPerInst, maxSlotPerPort); + return name; +} + static virDomainDefParserConfig vboxDomainDefParserConfig = { .macPrefix = { 0x08, 0x00, 0x27 }, }; @@ -2860,3 +2919,1018 @@ int vboxDomainGetMaxVcpus(virDomainPtr dom) return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)); } + +static void +vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine) +{ + IUSBCommon *USBCommon = NULL; + PRBool enabled = PR_FALSE; + vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER; + size_t i; + PRUint32 USBFilterCount = 0; + + def->nhostdevs = 0; + + gVBoxAPI.UIMachine.GetUSBCommon(machine, &USBCommon); + if (!USBCommon) + return; + + gVBoxAPI.UIUSBCommon.GetEnabled(USBCommon, &enabled); + if (!enabled) + goto release_controller; + + gVBoxAPI.UArray.vboxArrayGet(&deviceFilters, USBCommon, + gVBoxAPI.UArray.handleUSBGetDeviceFilters(USBCommon)); + + if (deviceFilters.count <= 0) + goto release_filters; + + /* check if the filters are active and then only + * alloc mem and set def->nhostdevs + */ + + for (i = 0; i < deviceFilters.count; i++) { + PRBool active = PR_FALSE; + IUSBDeviceFilter *deviceFilter = deviceFilters.items[i]; + + gVBoxAPI.UIUSBDeviceFilter.GetActive(deviceFilter, &active); + if (active) { + def->nhostdevs++; + } + } + + if (def->nhostdevs == 0) + goto release_filters; + + /* Alloc mem needed for the filters now */ + if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) < 0) + goto release_filters; + + for (i = 0; i < def->nhostdevs; i++) { + def->hostdevs[i] = virDomainHostdevDefAlloc(); + if (!def->hostdevs[i]) + goto release_hostdevs; + } + + for (i = 0; i < deviceFilters.count; i++) { + PRBool active = PR_FALSE; + IUSBDeviceFilter *deviceFilter = deviceFilters.items[i]; + PRUnichar *vendorIdUtf16 = NULL; + char *vendorIdUtf8 = NULL; + unsigned vendorId = 0; + PRUnichar *productIdUtf16 = NULL; + char *productIdUtf8 = NULL; + unsigned productId = 0; + char *endptr = NULL; + + gVBoxAPI.UIUSBDeviceFilter.GetActive(deviceFilter, &active); + if (!active) + continue; + + def->hostdevs[USBFilterCount]->mode = + VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + def->hostdevs[USBFilterCount]->source.subsys.type = + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB; + + gVBoxAPI.UIUSBDeviceFilter.GetVendorId(deviceFilter, &vendorIdUtf16); + gVBoxAPI.UIUSBDeviceFilter.GetProductId(deviceFilter, &productIdUtf16); + + VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8); + VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8); + + ignore_value(virStrToLong_ui(vendorIdUtf8, &endptr, 16, &vendorId)); + ignore_value(virStrToLong_ui(productIdUtf8, &endptr, 16, &productId)); + + def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor = vendorId; + def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId; + + VBOX_UTF16_FREE(vendorIdUtf16); + VBOX_UTF8_FREE(vendorIdUtf8); + + VBOX_UTF16_FREE(productIdUtf16); + VBOX_UTF8_FREE(productIdUtf8); + + USBFilterCount++; + } + + release_filters: + gVBoxAPI.UArray.vboxArrayRelease(&deviceFilters); + release_controller: + VBOX_RELEASE(USBCommon); + return; + + release_hostdevs: + for (i = 0; i < def->nhostdevs; i++) + virDomainHostdevDefFree(def->hostdevs[i]); + VIR_FREE(def->hostdevs); + + goto release_filters; +} + +static void +vboxDumpIDEHDDsNew(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine) +{ + /* dump IDE hdds if present */ + vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; + bool error = false; + int diskCount = 0; + size_t i; + PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; + PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; + + if (gVBoxAPI.oldMediumInterface) + VIR_WARN("This function may not work in current vbox version"); + + def->ndisks = 0; + gVBoxAPI.UArray.vboxArrayGet(&mediumAttachments, machine, + gVBoxAPI.UArray.handleMachineGetMediumAttachments(machine)); + + /* get the number of attachments */ + for (i = 0; i < mediumAttachments.count; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + if (imediumattach) { + IMedium *medium = NULL; + + gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &medium); + if (medium) { + def->ndisks++; + VBOX_RELEASE(medium); + } + } + } + + /* Allocate mem, if fails return error */ + if (VIR_ALLOC_N(def->disks, def->ndisks) >= 0) { + for (i = 0; i < def->ndisks; i++) { + virDomainDiskDefPtr disk = virDomainDiskDefNew(); + if (!disk) { + error = true; + break; + } + def->disks[i] = disk; + } + } else { + error = true; + } + + if (!error) + error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort); + + /* get the attachment details here */ + for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + IStorageController *storageController = NULL; + PRUnichar *storageControllerName = NULL; + PRUint32 deviceType = DeviceType_Null; + PRUint32 storageBus = StorageBus_Null; + PRBool readOnly = PR_FALSE; + IMedium *medium = NULL; + PRUnichar *mediumLocUtf16 = NULL; + char *mediumLocUtf8 = NULL; + PRUint32 deviceInst = 0; + PRInt32 devicePort = 0; + PRInt32 deviceSlot = 0; + + if (!imediumattach) + continue; + + gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &medium); + if (!medium) + continue; + + gVBoxAPI.UIMediumAttachment.GetController(imediumattach, &storageControllerName); + if (!storageControllerName) { + VBOX_RELEASE(medium); + continue; + } + + gVBoxAPI.UIMachine.GetStorageControllerByName(machine, + storageControllerName, + &storageController); + VBOX_UTF16_FREE(storageControllerName); + if (!storageController) { + VBOX_RELEASE(medium); + continue; + } + + gVBoxAPI.UIMedium.GetLocation(medium, &mediumLocUtf16); + VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8); + VBOX_UTF16_FREE(mediumLocUtf16); + ignore_value(virDomainDiskSetSource(def->disks[diskCount], + mediumLocUtf8)); + VBOX_UTF8_FREE(mediumLocUtf8); + + if (!virDomainDiskGetSource(def->disks[diskCount])) { + VBOX_RELEASE(medium); + VBOX_RELEASE(storageController); + error = true; + break; + } + + gVBoxAPI.UIStorageController.GetBus(storageController, &storageBus); + if (storageBus == StorageBus_IDE) { + def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE; + } else if (storageBus == StorageBus_SATA) { + def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA; + } else if (storageBus == StorageBus_SCSI) { + def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI; + } else if (storageBus == StorageBus_Floppy) { + def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC; + } + + gVBoxAPI.UIMediumAttachment.GetType(imediumattach, &deviceType); + if (deviceType == DeviceType_HardDisk) + def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK; + else if (deviceType == DeviceType_Floppy) + def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; + else if (deviceType == DeviceType_DVD) + def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + + gVBoxAPI.UIMediumAttachment.GetPort(imediumattach, &devicePort); + gVBoxAPI.UIMediumAttachment.GetDevice(imediumattach, &deviceSlot); + def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus, + deviceInst, + devicePort, + deviceSlot, + maxPortPerInst, + maxSlotPerPort); + if (!def->disks[diskCount]->dst) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not generate medium name for the disk " + "at: controller instance:%u, port:%d, slot:%d"), + deviceInst, devicePort, deviceSlot); + VBOX_RELEASE(medium); + VBOX_RELEASE(storageController); + error = true; + break; + } + + gVBoxAPI.UIMedium.GetReadOnly(medium, &readOnly); + if (readOnly == PR_TRUE) + def->disks[diskCount]->src->readonly = true; + + virDomainDiskSetType(def->disks[diskCount], + VIR_STORAGE_TYPE_FILE); + + VBOX_RELEASE(medium); + VBOX_RELEASE(storageController); + diskCount++; + } + + gVBoxAPI.UArray.vboxArrayRelease(&mediumAttachments); + + /* cleanup on error */ + if (error) { + for (i = 0; i < def->ndisks; i++) { + VIR_FREE(def->disks[i]); + } + VIR_FREE(def->disks); + def->ndisks = 0; + } +} + +static void +vboxDumpVideo(virDomainDefPtr def, vboxGlobalData *data ATTRIBUTE_UNUSED, + IMachine *machine) +{ + /* dump video options vram/2d/3d/directx/etc. */ + /* Currently supports only one graphics card */ + def->nvideos = 1; + if (VIR_ALLOC_N(def->videos, def->nvideos) >= 0) { + if (VIR_ALLOC(def->videos[0]) >= 0) { + /* the default is: vram is 8MB, One monitor, 3dAccel Off */ + PRUint32 VRAMSize = 8; + PRUint32 monitorCount = 1; + PRBool accelerate3DEnabled = PR_FALSE; + PRBool accelerate2DEnabled = PR_FALSE; + + gVBoxAPI.UIMachine.GetVRAMSize(machine, &VRAMSize); + gVBoxAPI.UIMachine.GetMonitorCount(machine, &monitorCount); + gVBoxAPI.UIMachine.GetAccelerate3DEnabled(machine, &accelerate3DEnabled); + if (gVBoxAPI.accelerate2DVideo) + gVBoxAPI.UIMachine.GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled); + + def->videos[0]->type = VIR_DOMAIN_VIDEO_TYPE_VBOX; + def->videos[0]->vram = VRAMSize * 1024; + def->videos[0]->heads = monitorCount; + if (VIR_ALLOC(def->videos[0]->accel) >= 0) { + def->videos[0]->accel->support3d = accelerate3DEnabled; + def->videos[0]->accel->support2d = accelerate2DEnabled; + } + } + } +} + +static void +vboxDumpDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine) +{ + /* dump display options vrdp/gui/sdl */ + int vrdpPresent = 0; + int sdlPresent = 0; + int guiPresent = 0; + int totalPresent = 0; + char *guiDisplay = NULL; + char *sdlDisplay = NULL; + PRUnichar *keyTypeUtf16 = NULL; + PRUnichar *valueTypeUtf16 = NULL; + char *valueTypeUtf8 = NULL; + IVRDxServer *VRDxServer = NULL; + PRBool VRDxEnabled = PR_FALSE; + + def->ngraphics = 0; + + VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16); + gVBoxAPI.UIMachine.GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16); + VBOX_UTF16_FREE(keyTypeUtf16); + + if (valueTypeUtf16) { + VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8); + VBOX_UTF16_FREE(valueTypeUtf16); + + if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) { + PRUnichar *keyDislpayUtf16 = NULL; + PRUnichar *valueDisplayUtf16 = NULL; + char *valueDisplayUtf8 = NULL; + + VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16); + gVBoxAPI.UIMachine.GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16); + VBOX_UTF16_FREE(keyDislpayUtf16); + + if (valueDisplayUtf16) { + VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8); + VBOX_UTF16_FREE(valueDisplayUtf16); + + if (strlen(valueDisplayUtf8) <= 0) + VBOX_UTF8_FREE(valueDisplayUtf8); + } + + if (STREQ(valueTypeUtf8, "sdl")) { + sdlPresent = 1; + if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) { + /* just don't go to cleanup yet as it is ok to have + * sdlDisplay as NULL and we check it below if it + * exist and then only use it there + */ + } + totalPresent++; + } + + if (STREQ(valueTypeUtf8, "gui")) { + guiPresent = 1; + if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) { + /* just don't go to cleanup yet as it is ok to have + * guiDisplay as NULL and we check it below if it + * exist and then only use it there + */ + } + totalPresent++; + } + VBOX_UTF8_FREE(valueDisplayUtf8); + } + + if (STREQ(valueTypeUtf8, "vrdp")) + vrdpPresent = 1; + + VBOX_UTF8_FREE(valueTypeUtf8); + } + + if ((totalPresent > 0) && (VIR_ALLOC_N(def->graphics, totalPresent) >= 0)) { + if ((guiPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) { + def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP; + if (guiDisplay) + def->graphics[def->ngraphics]->data.desktop.display = guiDisplay; + def->ngraphics++; + } + + if ((sdlPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) { + def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL; + if (sdlDisplay) + def->graphics[def->ngraphics]->data.sdl.display = sdlDisplay; + def->ngraphics++; + } + } else if ((vrdpPresent != 1) && (totalPresent == 0) && (VIR_ALLOC_N(def->graphics, 1) >= 0)) { + if (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0) { + const char *tmp; + def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP; + tmp = virGetEnvBlockSUID("DISPLAY"); + if (VIR_STRDUP(def->graphics[def->ngraphics]->data.desktop.display, tmp) < 0) { + /* just don't go to cleanup yet as it is ok to have + * display as NULL + */ + } + totalPresent++; + def->ngraphics++; + } + } + + gVBoxAPI.UIMachine.GetVRDxServer(machine, &VRDxServer); + if (VRDxServer) { + gVBoxAPI.UIVRDxServer.GetEnabled(VRDxServer, &VRDxEnabled); + if (VRDxEnabled) { + + totalPresent++; + + if ((VIR_REALLOC_N(def->graphics, totalPresent) >= 0) && + (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) { + PRUnichar *netAddressUtf16 = NULL; + char *netAddressUtf8 = NULL; + PRBool allowMultiConnection = PR_FALSE; + PRBool reuseSingleConnection = PR_FALSE; + + gVBoxAPI.UIVRDxServer.GetPorts(data, VRDxServer, def->graphics[def->ngraphics]); + + def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP; + + gVBoxAPI.UIVRDxServer.GetNetAddress(data, VRDxServer, &netAddressUtf16); + if (netAddressUtf16) { + VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8); + if (STRNEQ(netAddressUtf8, "")) + virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0, + netAddressUtf8, -1, true); + VBOX_UTF16_FREE(netAddressUtf16); + VBOX_UTF8_FREE(netAddressUtf8); + } + + gVBoxAPI.UIVRDxServer.GetAllowMultiConnection(VRDxServer, &allowMultiConnection); + if (allowMultiConnection) { + def->graphics[def->ngraphics]->data.rdp.multiUser = true; + } + + gVBoxAPI.UIVRDxServer.GetReuseSingleConnection(VRDxServer, &reuseSingleConnection); + if (reuseSingleConnection) { + def->graphics[def->ngraphics]->data.rdp.replaceUser = true; + } + + def->ngraphics++; + } else + virReportOOMError(); + } + VBOX_RELEASE(VRDxServer); + } +} + +static void +vboxDumpSharedFolders(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine) +{ + /* shared folders */ + vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER; + size_t i = 0; + + def->nfss = 0; + + gVBoxAPI.UArray.vboxArrayGet(&sharedFolders, machine, + gVBoxAPI.UArray.handleMachineGetSharedFolders(machine)); + + if (sharedFolders.count <= 0) + goto sharedFoldersCleanup; + + if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0) + goto sharedFoldersCleanup; + + for (i = 0; i < sharedFolders.count; i++) { + ISharedFolder *sharedFolder = sharedFolders.items[i]; + PRUnichar *nameUtf16 = NULL; + char *name = NULL; + PRUnichar *hostPathUtf16 = NULL; + char *hostPath = NULL; + PRBool writable = PR_FALSE; + + if (VIR_ALLOC(def->fss[i]) < 0) + goto sharedFoldersCleanup; + + def->fss[i]->type = VIR_DOMAIN_FS_TYPE_MOUNT; + + gVBoxAPI.UISharedFolder.GetHostPath(sharedFolder, &hostPathUtf16); + VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath); + if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) { + VBOX_UTF8_FREE(hostPath); + VBOX_UTF16_FREE(hostPathUtf16); + goto sharedFoldersCleanup; + } + VBOX_UTF8_FREE(hostPath); + VBOX_UTF16_FREE(hostPathUtf16); + + gVBoxAPI.UISharedFolder.GetName(sharedFolder, &nameUtf16); + VBOX_UTF16_TO_UTF8(nameUtf16, &name); + if (VIR_STRDUP(def->fss[i]->dst, name) < 0) { + VBOX_UTF8_FREE(name); + VBOX_UTF16_FREE(nameUtf16); + goto sharedFoldersCleanup; + } + VBOX_UTF8_FREE(name); + VBOX_UTF16_FREE(nameUtf16); + + gVBoxAPI.UISharedFolder.GetWritable(sharedFolder, &writable); + def->fss[i]->readonly = !writable; + + ++def->nfss; + } + + sharedFoldersCleanup: + gVBoxAPI.UArray.vboxArrayRelease(&sharedFolders); +} + +static void +vboxDumpNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine, PRUint32 networkAdapterCount) +{ + PRUint32 netAdpIncCnt = 0; + size_t i = 0; + /* dump network cards if present */ + def->nnets = 0; + /* Get which network cards are enabled */ + for (i = 0; i < networkAdapterCount; i++) { + INetworkAdapter *adapter = NULL; + + gVBoxAPI.UIMachine.GetNetworkAdapter(machine, i, &adapter); + if (adapter) { + PRBool enabled = PR_FALSE; + + gVBoxAPI.UINetworkAdapter.GetEnabled(adapter, &enabled); + if (enabled) { + def->nnets++; + } + + VBOX_RELEASE(adapter); + } + } + + /* Allocate memory for the networkcards which are enabled */ + if ((def->nnets > 0) && (VIR_ALLOC_N(def->nets, def->nnets) >= 0)) { + for (i = 0; i < def->nnets; i++) { + ignore_value(VIR_ALLOC(def->nets[i])); + } + } + + /* Now get the details about the network cards here */ + for (i = 0; netAdpIncCnt < def->nnets && i < networkAdapterCount; i++) { + INetworkAdapter *adapter = NULL; + + gVBoxAPI.UIMachine.GetNetworkAdapter(machine, i, &adapter); + if (adapter) { + PRBool enabled = PR_FALSE; + + gVBoxAPI.UINetworkAdapter.GetEnabled(adapter, &enabled); + if (enabled) { + PRUint32 attachmentType = NetworkAttachmentType_Null; + PRUint32 adapterType = NetworkAdapterType_Null; + PRUnichar *MACAddressUtf16 = NULL; + char *MACAddress = NULL; + char macaddr[VIR_MAC_STRING_BUFLEN] = {0}; + + gVBoxAPI.UINetworkAdapter.GetAttachmentType(adapter, &attachmentType); + if (attachmentType == NetworkAttachmentType_NAT) { + + def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER; + + } else if (attachmentType == NetworkAttachmentType_Bridged) { + PRUnichar *hostIntUtf16 = NULL; + char *hostInt = NULL; + + def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + + gVBoxAPI.UINetworkAdapter.GetBridgedInterface(adapter, &hostIntUtf16); + + VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt); + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt)); + + VBOX_UTF8_FREE(hostInt); + VBOX_UTF16_FREE(hostIntUtf16); + + } else if (attachmentType == NetworkAttachmentType_Internal) { + PRUnichar *intNetUtf16 = NULL; + char *intNet = NULL; + + def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL; + + gVBoxAPI.UINetworkAdapter.GetInternalNetwork(adapter, &intNetUtf16); + + VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet); + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet)); + + VBOX_UTF8_FREE(intNet); + VBOX_UTF16_FREE(intNetUtf16); + + } else if (attachmentType == NetworkAttachmentType_HostOnly) { + PRUnichar *hostIntUtf16 = NULL; + char *hostInt = NULL; + + def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_NETWORK; + + gVBoxAPI.UINetworkAdapter.GetHostOnlyInterface(adapter, &hostIntUtf16); + + VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt); + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt)); + + VBOX_UTF8_FREE(hostInt); + VBOX_UTF16_FREE(hostIntUtf16); + + } else { + /* default to user type i.e. NAT in VirtualBox if this + * dump is ever used to create a machine. + */ + def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER; + } + + gVBoxAPI.UINetworkAdapter.GetAdapterType(adapter, &adapterType); + if (adapterType == NetworkAdapterType_Am79C970A) { + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A")); + } else if (adapterType == NetworkAdapterType_Am79C973) { + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973")); + } else if (adapterType == NetworkAdapterType_I82540EM) { + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM")); + } else if (adapterType == NetworkAdapterType_I82545EM) { + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM")); + } else if (adapterType == NetworkAdapterType_I82543GC) { + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC")); + } else if (gVBoxAPI.APIVersion >= 3000051 && + adapterType == NetworkAdapterType_Virtio) { + /* Only vbox 3.1 and later support NetworkAdapterType_Virto */ + ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio")); + } + + gVBoxAPI.UINetworkAdapter.GetMACAddress(adapter, &MACAddressUtf16); + VBOX_UTF16_TO_UTF8(MACAddressUtf16, &MACAddress); + snprintf(macaddr, VIR_MAC_STRING_BUFLEN, + "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c", + MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], + MACAddress[4], MACAddress[5], MACAddress[6], MACAddress[7], + MACAddress[8], MACAddress[9], MACAddress[10], MACAddress[11]); + + /* XXX some real error handling here some day ... */ + if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0) + {} + + netAdpIncCnt++; + + VBOX_UTF16_FREE(MACAddressUtf16); + VBOX_UTF8_FREE(MACAddress); + } + + VBOX_RELEASE(adapter); + } + } +} + +static void +vboxDumpAudio(virDomainDefPtr def, vboxGlobalData *data ATTRIBUTE_UNUSED, + IMachine *machine) +{ + /* dump sound card if active */ + + /* Set def->nsounds to one as VirtualBox currently supports + * only one sound card + */ + IAudioAdapter *audioAdapter = NULL; + + gVBoxAPI.UIMachine.GetAudioAdapter(machine, &audioAdapter); + if (audioAdapter) { + PRBool enabled = PR_FALSE; + + gVBoxAPI.UIAudioAdapter.GetEnabled(audioAdapter, &enabled); + if (enabled) { + PRUint32 audioController = AudioControllerType_AC97; + + def->nsounds = 1; + if (VIR_ALLOC_N(def->sounds, def->nsounds) >= 0) { + if (VIR_ALLOC(def->sounds[0]) >= 0) { + gVBoxAPI.UIAudioAdapter.GetAudioController(audioAdapter, &audioController); + if (audioController == AudioControllerType_SB16) { + def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16; + } else if (audioController == AudioControllerType_AC97) { + def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97; + } + } else { + VIR_FREE(def->sounds); + def->nsounds = 0; + } + } else { + def->nsounds = 0; + } + } + VBOX_RELEASE(audioAdapter); + } +} + +static void +vboxDumpSerial(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine, PRUint32 serialPortCount) +{ + PRUint32 serialPortIncCount = 0; + size_t i = 0; + /* dump serial port if active */ + def->nserials = 0; + /* Get which serial ports are enabled/active */ + for (i = 0; i < serialPortCount; i++) { + ISerialPort *serialPort = NULL; + + gVBoxAPI.UIMachine.GetSerialPort(machine, i, &serialPort); + if (serialPort) { + PRBool enabled = PR_FALSE; + + gVBoxAPI.UISerialPort.GetEnabled(serialPort, &enabled); + if (enabled) { + def->nserials++; + } + + VBOX_RELEASE(serialPort); + } + } + + /* Allocate memory for the serial ports which are enabled */ + if ((def->nserials > 0) && (VIR_ALLOC_N(def->serials, def->nserials) >= 0)) { + for (i = 0; i < def->nserials; i++) { + ignore_value(VIR_ALLOC(def->serials[i])); + } + } + + /* Now get the details about the serial ports here */ + for (i = 0; + serialPortIncCount < def->nserials && i < serialPortCount; + i++) { + ISerialPort *serialPort = NULL; + + gVBoxAPI.UIMachine.GetSerialPort(machine, i, &serialPort); + if (serialPort) { + PRBool enabled = PR_FALSE; + + gVBoxAPI.UISerialPort.GetEnabled(serialPort, &enabled); + if (enabled) { + PRUint32 hostMode = PortMode_Disconnected; + PRUint32 IOBase = 0; + PRUint32 IRQ = 0; + PRUnichar *pathUtf16 = NULL; + char *path = NULL; + + gVBoxAPI.UISerialPort.GetHostMode(serialPort, &hostMode); + if (hostMode == PortMode_HostPipe) { + def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE; + } else if (hostMode == PortMode_HostDevice) { + def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV; + } else if (gVBoxAPI.APIVersion >= 2002051 && + hostMode == PortMode_RawFile) { + /* PortMode RawFile is used for vbox 3.0 or later */ + def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE; + } else { + def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL; + } + + def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + + gVBoxAPI.UISerialPort.GetIRQ(serialPort, &IRQ); + gVBoxAPI.UISerialPort.GetIOBase(serialPort, &IOBase); + if ((IRQ == 4) && (IOBase == 1016)) { + def->serials[serialPortIncCount]->target.port = 0; + } else if ((IRQ == 3) && (IOBase == 760)) { + def->serials[serialPortIncCount]->target.port = 1; + } + + gVBoxAPI.UISerialPort.GetPath(serialPort, &pathUtf16); + + if (pathUtf16) { + VBOX_UTF16_TO_UTF8(pathUtf16, &path); + ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path)); + } + + serialPortIncCount++; + + VBOX_UTF16_FREE(pathUtf16); + VBOX_UTF8_FREE(path); + } + + VBOX_RELEASE(serialPort); + } + } +} + +static void +vboxDumpParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine, PRUint32 parallelPortCount) +{ + PRUint32 parallelPortIncCount = 0; + size_t i = 0; + /* dump parallel ports if active */ + def->nparallels = 0; + /* Get which parallel ports are enabled/active */ + for (i = 0; i < parallelPortCount; i++) { + IParallelPort *parallelPort = NULL; + + gVBoxAPI.UIMachine.GetParallelPort(machine, i, ¶llelPort); + if (parallelPort) { + PRBool enabled = PR_FALSE; + + gVBoxAPI.UIParallelPort.GetEnabled(parallelPort, &enabled); + if (enabled) { + def->nparallels++; + } + + VBOX_RELEASE(parallelPort); + } + } + + /* Allocate memory for the parallel ports which are enabled */ + if ((def->nparallels > 0) && (VIR_ALLOC_N(def->parallels, def->nparallels) >= 0)) { + for (i = 0; i < def->nparallels; i++) { + ignore_value(VIR_ALLOC(def->parallels[i])); + } + } + + /* Now get the details about the parallel ports here */ + for (i = 0; + parallelPortIncCount < def->nparallels && + i < parallelPortCount; + i++) { + IParallelPort *parallelPort = NULL; + + gVBoxAPI.UIMachine.GetParallelPort(machine, i, ¶llelPort); + if (parallelPort) { + PRBool enabled = PR_FALSE; + + gVBoxAPI.UIParallelPort.GetEnabled(parallelPort, &enabled); + if (enabled) { + PRUint32 IOBase = 0; + PRUint32 IRQ = 0; + PRUnichar *pathUtf16 = NULL; + char *path = NULL; + + gVBoxAPI.UIParallelPort.GetIRQ(parallelPort, &IRQ); + gVBoxAPI.UIParallelPort.GetIOBase(parallelPort, &IOBase); + if ((IRQ == 7) && (IOBase == 888)) { + def->parallels[parallelPortIncCount]->target.port = 0; + } else if ((IRQ == 5) && (IOBase == 632)) { + def->parallels[parallelPortIncCount]->target.port = 1; + } + + def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE; + def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL; + + gVBoxAPI.UIParallelPort.GetPath(parallelPort, &pathUtf16); + + VBOX_UTF16_TO_UTF8(pathUtf16, &path); + ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path)); + + parallelPortIncCount++; + + VBOX_UTF16_FREE(pathUtf16); + VBOX_UTF8_FREE(path); + } + + VBOX_RELEASE(parallelPort); + } + } +} + +char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) +{ + VBOX_OBJECT_CHECK(dom->conn, char *, NULL); + virDomainDefPtr def = NULL; + IMachine *machine = NULL; + vboxIIDUnion iid; + PRBool accessible = PR_FALSE; + size_t i = 0; + PRBool PAEEnabled = PR_FALSE; + PRBool ACPIEnabled = PR_FALSE; + PRBool IOAPICEnabled = PR_FALSE; + PRUint32 CPUCount = 0; + PRUint32 memorySize = 0; + PRUint32 networkAdapterCount = 0; + PRUint32 maxMemorySize = 4 * 1024; + PRUint32 maxBootPosition = 0; + PRUint32 serialPortCount = 0; + PRUint32 parallelPortCount = 0; + IBIOSSettings *bios = NULL; + PRUint32 chipsetType = ChipsetType_Null; + ISystemProperties *systemProperties = NULL; + + /* Flags checked by virDomainDefFormat */ + + if (openSessionForMachine(data, dom->uuid, &iid, &machine, false) < 0) + goto cleanup; + + if (VIR_ALLOC(def) < 0) + goto cleanup; + + gVBoxAPI.UIMachine.GetAccessible(machine, &accessible); + if (!accessible) + goto cleanup; + + def->virtType = VIR_DOMAIN_VIRT_VBOX; + def->id = dom->id; + memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN); + if (VIR_STRDUP(def->name, dom->name) < 0) + goto cleanup; + + gVBoxAPI.UIMachine.GetMemorySize(machine, &memorySize); + def->mem.cur_balloon = memorySize * 1024; + + if (gVBoxAPI.chipsetType) + gVBoxAPI.UIMachine.GetChipsetType(machine, &chipsetType); + + gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties); + if (systemProperties) { + gVBoxAPI.UISystemProperties.GetMaxGuestRAM(systemProperties, &maxMemorySize); + gVBoxAPI.UISystemProperties.GetMaxBootPosition(systemProperties, &maxBootPosition); + gVBoxAPI.UISystemProperties.GetMaxNetworkAdapters(systemProperties, chipsetType, &networkAdapterCount); + gVBoxAPI.UISystemProperties.GetSerialPortCount(systemProperties, &serialPortCount); + gVBoxAPI.UISystemProperties.GetParallelPortCount(systemProperties, ¶llelPortCount); + VBOX_RELEASE(systemProperties); + systemProperties = NULL; + } + /* Currently setting memory and maxMemory as same, cause + * the notation here seems to be inconsistent while + * reading and while dumping xml + */ + /* def->mem.max_balloon = maxMemorySize * 1024; */ + def->mem.max_balloon = memorySize * 1024; + + gVBoxAPI.UIMachine.GetCPUCount(machine, &CPUCount); + def->maxvcpus = def->vcpus = CPUCount; + + /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */ + + if (VIR_STRDUP(def->os.type, "hvm") < 0) + goto cleanup; + + def->os.arch = virArchFromHost(); + + def->os.nBootDevs = 0; + for (i = 0; (i < VIR_DOMAIN_BOOT_LAST) && (i < maxBootPosition); i++) { + PRUint32 device = DeviceType_Null; + + gVBoxAPI.UIMachine.GetBootOrder(machine, i+1, &device); + + if (device == DeviceType_Floppy) { + def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY; + def->os.nBootDevs++; + } else if (device == DeviceType_DVD) { + def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM; + def->os.nBootDevs++; + } else if (device == DeviceType_HardDisk) { + def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK; + def->os.nBootDevs++; + } else if (device == DeviceType_Network) { + def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET; + def->os.nBootDevs++; + } else if (device == DeviceType_USB) { + /* Not supported by libvirt yet */ + } else if (device == DeviceType_SharedFolder) { + /* Not supported by libvirt yet */ + /* Can VirtualBox really boot from a shared folder? */ + } + } + + gVBoxAPI.UIMachine.GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled); + if (PAEEnabled) + def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON; + + gVBoxAPI.UIMachine.GetBIOSSettings(machine, &bios); + if (bios) { + gVBoxAPI.UIBIOSSettings.GetACPIEnabled(bios, &ACPIEnabled); + if (ACPIEnabled) + def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON; + + gVBoxAPI.UIBIOSSettings.GetIOAPICEnabled(bios, &IOAPICEnabled); + if (IOAPICEnabled) + def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON; + + VBOX_RELEASE(bios); + } + + /* Currently VirtualBox always uses locatime + * so locatime is always true here */ + def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME; + + vboxDumpVideo(def, data, machine); + vboxDumpDisplay(def, data, machine); + + /* As the medium interface changed from 3.0 to 3.1. + * There are two totally different implementations. + * The old one would be version specified, while the + * new one is using the vboxUniformedAPI and be put + * into the common code. + */ + if (gVBoxAPI.oldMediumInterface) + gVBoxAPI.dumpIDEHDDsOld(def, data, machine); + else + vboxDumpIDEHDDsNew(def, data, machine); + + vboxDumpSharedFolders(def, data, machine); + vboxDumpNetwork(def, data, machine, networkAdapterCount); + vboxDumpAudio(def, data, machine); + + if (gVBoxAPI.oldMediumInterface) { + gVBoxAPI.dumpDVD(def, data, machine); + gVBoxAPI.dumpFloppy(def, data, machine); + } + + vboxDumpSerial(def, data, machine, serialPortCount); + vboxDumpParallel(def, data, machine, parallelPortCount); + + /* dump USB devices/filters if active */ + vboxHostDeviceGetXMLDesc(data, def, machine); + + ret = virDomainDefFormat(def, flags); + + cleanup: + VBOX_RELEASE(machine); + vboxIIDUnalloc(&iid); + virDomainDefFree(def); + return ret; +} diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h index c4e7ae5..434689b 100644 --- a/src/vbox/vbox_common.h +++ b/src/vbox/vbox_common.h @@ -196,6 +196,15 @@ enum NetworkAdapterType NetworkAdapterType_Virtio = 6 }; +enum NetworkAttachmentType +{ + NetworkAttachmentType_Null = 0, + NetworkAttachmentType_NAT = 1, + NetworkAttachmentType_Bridged = 2, + NetworkAttachmentType_Internal = 3, + NetworkAttachmentType_HostOnly = 4 +}; + enum PortMode { PortMode_Disconnected = 0, diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 803b0cc..f017840 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -676,7 +676,6 @@ _vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu, #endif /* !(VBOX_API_VERSION == 2002000) */ -#if VBOX_API_VERSION >= 3001000 /** * function to generate the name for medium, @@ -693,6 +692,9 @@ _vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu, * @param aMaxSlotPerPort Input array of max slot per device port * */ +/* This functions is used for 4.2 and later only since vboxDomainGetXMLDesc + * is rewritten. */ +#if VBOX_API_VERSION >= 4002000 static char *vboxGenerateMediumName(PRUint32 storageBus, PRInt32 deviceInst, PRInt32 devicePort, @@ -737,6 +739,7 @@ static char *vboxGenerateMediumName(PRUint32 storageBus, deviceSlot, maxPortPerInst, maxSlotPerPort); return name; } +#endif /* VBOX_API_VERSION >= 4002000 */ /** * function to get the StorageBus, Port number @@ -754,6 +757,7 @@ static char *vboxGenerateMediumName(PRUint32 storageBus, * @param deviceSlot Output slot number * */ +#if VBOX_API_VERSION >= 3001000 # if VBOX_API_VERSION < 4000000 /* Only 3.x will use this function. */ static bool vboxGetDeviceDetails(const char *deviceName, @@ -813,6 +817,9 @@ static bool vboxGetDeviceDetails(const char *deviceName, * */ +/* This function would not be used in 4.0 and 4.1 since + * vboxDomainGetXMLDesc is written*/ +# if VBOX_API_VERSION >= 4002000 || VBOX_API_VERSION < 4000000 static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox, PRUint32 *maxPortPerInst, PRUint32 *maxSlotPerPort) @@ -857,6 +864,7 @@ static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox, return true; } +# endif /* VBOX_API_VERSION >= 4002000 || VBOX_API_VERSION < 4000000 */ /** * Converts Utf-16 string to int @@ -958,1257 +966,6 @@ static virDomainState _vboxConvertState(PRUint32 state) } } -static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine) -{ -#if VBOX_API_VERSION < 4003000 - IUSBController *USBController = NULL; - PRBool enabled = PR_FALSE; -#else - IUSBDeviceFilters *USBDeviceFilters = NULL; -#endif - vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER; - size_t i; - PRUint32 USBFilterCount = 0; - - def->nhostdevs = 0; - -#if VBOX_API_VERSION < 4003000 - machine->vtbl->GetUSBController(machine, &USBController); - - if (!USBController) - return; - - USBController->vtbl->GetEnabled(USBController, &enabled); - if (!enabled) - goto release_controller; - - vboxArrayGet(&deviceFilters, USBController, - USBController->vtbl->GetDeviceFilters); - -#else - machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters); - - if (!USBDeviceFilters) - return; - - vboxArrayGet(&deviceFilters, USBDeviceFilters, - USBDeviceFilters->vtbl->GetDeviceFilters); -#endif - - if (deviceFilters.count <= 0) - goto release_filters; - - /* check if the filters are active and then only - * alloc mem and set def->nhostdevs - */ - - for (i = 0; i < deviceFilters.count; i++) { - PRBool active = PR_FALSE; - IUSBDeviceFilter *deviceFilter = deviceFilters.items[i]; - - deviceFilter->vtbl->GetActive(deviceFilter, &active); - if (active) { - def->nhostdevs++; - } - } - - if (def->nhostdevs == 0) - goto release_filters; - - /* Alloc mem needed for the filters now */ - if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) < 0) - goto release_filters; - - for (i = 0; i < def->nhostdevs; i++) { - def->hostdevs[i] = virDomainHostdevDefAlloc(); - if (!def->hostdevs[i]) - goto release_hostdevs; - } - - for (i = 0; i < deviceFilters.count; i++) { - PRBool active = PR_FALSE; - IUSBDeviceFilter *deviceFilter = deviceFilters.items[i]; - PRUnichar *vendorIdUtf16 = NULL; - char *vendorIdUtf8 = NULL; - unsigned vendorId = 0; - PRUnichar *productIdUtf16 = NULL; - char *productIdUtf8 = NULL; - unsigned productId = 0; - char *endptr = NULL; - - deviceFilter->vtbl->GetActive(deviceFilter, &active); - if (!active) - continue; - - def->hostdevs[USBFilterCount]->mode = - VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; - def->hostdevs[USBFilterCount]->source.subsys.type = - VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB; - - deviceFilter->vtbl->GetVendorId(deviceFilter, &vendorIdUtf16); - deviceFilter->vtbl->GetProductId(deviceFilter, &productIdUtf16); - - VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8); - VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8); - - ignore_value(virStrToLong_ui(vendorIdUtf8, &endptr, 16, &vendorId)); - ignore_value(virStrToLong_ui(productIdUtf8, &endptr, 16, &productId)); - - def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor = vendorId; - def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId; - - VBOX_UTF16_FREE(vendorIdUtf16); - VBOX_UTF8_FREE(vendorIdUtf8); - - VBOX_UTF16_FREE(productIdUtf16); - VBOX_UTF8_FREE(productIdUtf8); - - USBFilterCount++; - } - - release_filters: - vboxArrayRelease(&deviceFilters); -#if VBOX_API_VERSION < 4003000 - release_controller: - VBOX_RELEASE(USBController); -#else - VBOX_RELEASE(USBDeviceFilters); -#endif - - return; - - release_hostdevs: - for (i = 0; i < def->nhostdevs; i++) - virDomainHostdevDefFree(def->hostdevs[i]); - VIR_FREE(def->hostdevs); - - goto release_filters; -} - -static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) { - VBOX_OBJECT_CHECK(dom->conn, char *, NULL); - virDomainDefPtr def = NULL; - IMachine *machine = NULL; - vboxIID iid = VBOX_IID_INITIALIZER; - int gotAllABoutDef = -1; - nsresult rc; - - /* Flags checked by virDomainDefFormat */ - - if (VIR_ALLOC(def) < 0) - goto cleanup; - - vboxIIDFromUUID(&iid, dom->uuid); - rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); - if (NS_SUCCEEDED(rc)) { - PRBool accessible = PR_FALSE; - - machine->vtbl->GetAccessible(machine, &accessible); - if (accessible) { - size_t i = 0; - PRBool PAEEnabled = PR_FALSE; - PRBool ACPIEnabled = PR_FALSE; - PRBool IOAPICEnabled = PR_FALSE; - PRBool VRDxEnabled = PR_FALSE; - PRUint32 CPUCount = 0; - PRUint32 memorySize = 0; - PRUint32 netAdpCnt = 0; - PRUint32 netAdpIncCnt = 0; - PRUint32 maxMemorySize = 4 * 1024; - PRUint32 maxBootPosition = 0; - PRUint32 serialPortCount = 0; - PRUint32 serialPortIncCount = 0; - PRUint32 parallelPortCount = 0; - PRUint32 parallelPortIncCount = 0; - IBIOSSettings *bios = NULL; -#if VBOX_API_VERSION < 3001000 - PRInt32 hddNum = 0; - IDVDDrive *dvdDrive = NULL; - IHardDisk *hardDiskPM = NULL; - IHardDisk *hardDiskPS = NULL; - IHardDisk *hardDiskSS = NULL; - const char *hddBus = "IDE"; - PRUnichar *hddBusUtf16 = NULL; - IFloppyDrive *floppyDrive = NULL; -#else /* VBOX_API_VERSION >= 3001000 */ - vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; -#endif /* VBOX_API_VERSION >= 3001000 */ -#if VBOX_API_VERSION < 4000000 - IVRDPServer *VRDxServer = NULL; -#else /* VBOX_API_VERSION >= 4000000 */ - IVRDEServer *VRDxServer = NULL; -#endif /* VBOX_API_VERSION >= 4000000 */ - IAudioAdapter *audioAdapter = NULL; -#if VBOX_API_VERSION >= 4001000 - PRUint32 chipsetType = ChipsetType_Null; -#endif /* VBOX_API_VERSION >= 4001000 */ - ISystemProperties *systemProperties = NULL; - - - def->virtType = VIR_DOMAIN_VIRT_VBOX; - def->id = dom->id; - memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN); - if (VIR_STRDUP(def->name, dom->name) < 0) - goto cleanup; - - machine->vtbl->GetMemorySize(machine, &memorySize); - def->mem.cur_balloon = memorySize * 1024; - -#if VBOX_API_VERSION >= 4001000 - machine->vtbl->GetChipsetType(machine, &chipsetType); -#endif /* VBOX_API_VERSION >= 4001000 */ - - data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties); - if (systemProperties) { - systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize); - systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition); -#if VBOX_API_VERSION < 4001000 - systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt); -#else /* VBOX_API_VERSION >= 4000000 */ - systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt); -#endif /* VBOX_API_VERSION >= 4000000 */ - systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount); - systemProperties->vtbl->GetParallelPortCount(systemProperties, ¶llelPortCount); - VBOX_RELEASE(systemProperties); - systemProperties = NULL; - } - /* Currently setting memory and maxMemory as same, cause - * the notation here seems to be inconsistent while - * reading and while dumping xml - */ - /* def->mem.max_balloon = maxMemorySize * 1024; */ - def->mem.max_balloon = memorySize * 1024; - - machine->vtbl->GetCPUCount(machine, &CPUCount); - def->maxvcpus = def->vcpus = CPUCount; - - /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */ - - if (VIR_STRDUP(def->os.type, "hvm") < 0) - goto cleanup; - - def->os.arch = virArchFromHost(); - - def->os.nBootDevs = 0; - for (i = 0; (i < VIR_DOMAIN_BOOT_LAST) && (i < maxBootPosition); i++) { - PRUint32 device = DeviceType_Null; - - machine->vtbl->GetBootOrder(machine, i+1, &device); - - if (device == DeviceType_Floppy) { - def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY; - def->os.nBootDevs++; - } else if (device == DeviceType_DVD) { - def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM; - def->os.nBootDevs++; - } else if (device == DeviceType_HardDisk) { - def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK; - def->os.nBootDevs++; - } else if (device == DeviceType_Network) { - def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET; - def->os.nBootDevs++; - } else if (device == DeviceType_USB) { - /* Not supported by libvirt yet */ - } else if (device == DeviceType_SharedFolder) { - /* Not supported by libvirt yet */ - /* Can VirtualBox really boot from a shared folder? */ - } - } - -#if VBOX_API_VERSION < 3001000 - machine->vtbl->GetPAEEnabled(machine, &PAEEnabled); -#elif VBOX_API_VERSION == 3001000 - machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled); -#elif VBOX_API_VERSION >= 3002000 - machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled); -#endif - if (PAEEnabled) - def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON; - - machine->vtbl->GetBIOSSettings(machine, &bios); - if (bios) { - bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled); - if (ACPIEnabled) - def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON; - - bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled); - if (IOAPICEnabled) - def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON; - - VBOX_RELEASE(bios); - } - - /* Currently VirtualBox always uses locatime - * so locatime is always true here */ - def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME; - - /* dump video options vram/2d/3d/directx/etc. */ - { - /* Currently supports only one graphics card */ - def->nvideos = 1; - if (VIR_ALLOC_N(def->videos, def->nvideos) >= 0) { - if (VIR_ALLOC(def->videos[0]) >= 0) { - /* the default is: vram is 8MB, One monitor, 3dAccel Off */ - PRUint32 VRAMSize = 8; - PRUint32 monitorCount = 1; - PRBool accelerate3DEnabled = PR_FALSE; - PRBool accelerate2DEnabled = PR_FALSE; - - machine->vtbl->GetVRAMSize(machine, &VRAMSize); - machine->vtbl->GetMonitorCount(machine, &monitorCount); - machine->vtbl->GetAccelerate3DEnabled(machine, &accelerate3DEnabled); -#if VBOX_API_VERSION >= 3001000 - machine->vtbl->GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled); -#endif /* VBOX_API_VERSION >= 3001000 */ - - def->videos[0]->type = VIR_DOMAIN_VIDEO_TYPE_VBOX; - def->videos[0]->vram = VRAMSize * 1024; - def->videos[0]->heads = monitorCount; - if (VIR_ALLOC(def->videos[0]->accel) >= 0) { - def->videos[0]->accel->support3d = accelerate3DEnabled; - def->videos[0]->accel->support2d = accelerate2DEnabled; - } - } - } - } - - /* dump display options vrdp/gui/sdl */ - { - int vrdpPresent = 0; - int sdlPresent = 0; - int guiPresent = 0; - int totalPresent = 0; - char *guiDisplay = NULL; - char *sdlDisplay = NULL; - PRUnichar *keyTypeUtf16 = NULL; - PRUnichar *valueTypeUtf16 = NULL; - char *valueTypeUtf8 = NULL; - - def->ngraphics = 0; - - VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16); - machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16); - VBOX_UTF16_FREE(keyTypeUtf16); - - if (valueTypeUtf16) { - VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8); - VBOX_UTF16_FREE(valueTypeUtf16); - - if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) { - PRUnichar *keyDislpayUtf16 = NULL; - PRUnichar *valueDisplayUtf16 = NULL; - char *valueDisplayUtf8 = NULL; - - VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16); - machine->vtbl->GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16); - VBOX_UTF16_FREE(keyDislpayUtf16); - - if (valueDisplayUtf16) { - VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8); - VBOX_UTF16_FREE(valueDisplayUtf16); - - if (strlen(valueDisplayUtf8) <= 0) - VBOX_UTF8_FREE(valueDisplayUtf8); - } - - if (STREQ(valueTypeUtf8, "sdl")) { - sdlPresent = 1; - if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) { - /* just don't go to cleanup yet as it is ok to have - * sdlDisplay as NULL and we check it below if it - * exist and then only use it there - */ - } - totalPresent++; - } - - if (STREQ(valueTypeUtf8, "gui")) { - guiPresent = 1; - if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) { - /* just don't go to cleanup yet as it is ok to have - * guiDisplay as NULL and we check it below if it - * exist and then only use it there - */ - } - totalPresent++; - } - VBOX_UTF8_FREE(valueDisplayUtf8); - } - - if (STREQ(valueTypeUtf8, "vrdp")) - vrdpPresent = 1; - - VBOX_UTF8_FREE(valueTypeUtf8); - } - - if ((totalPresent > 0) && (VIR_ALLOC_N(def->graphics, totalPresent) >= 0)) { - if ((guiPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) { - def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP; - if (guiDisplay) - def->graphics[def->ngraphics]->data.desktop.display = guiDisplay; - def->ngraphics++; - } - - if ((sdlPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) { - def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL; - if (sdlDisplay) - def->graphics[def->ngraphics]->data.sdl.display = sdlDisplay; - def->ngraphics++; - } - } else if ((vrdpPresent != 1) && (totalPresent == 0) && (VIR_ALLOC_N(def->graphics, 1) >= 0)) { - if (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0) { - const char *tmp; - def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP; - tmp = virGetEnvBlockSUID("DISPLAY"); - if (VIR_STRDUP(def->graphics[def->ngraphics]->data.desktop.display, tmp) < 0) { - /* just don't go to cleanup yet as it is ok to have - * display as NULL - */ - } - totalPresent++; - def->ngraphics++; - } - } - -#if VBOX_API_VERSION < 4000000 - machine->vtbl->GetVRDPServer(machine, &VRDxServer); -#else /* VBOX_API_VERSION >= 4000000 */ - machine->vtbl->GetVRDEServer(machine, &VRDxServer); -#endif /* VBOX_API_VERSION >= 4000000 */ - if (VRDxServer) { - VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled); - if (VRDxEnabled) { - - totalPresent++; - - if ((VIR_REALLOC_N(def->graphics, totalPresent) >= 0) && - (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) { - PRUnichar *netAddressUtf16 = NULL; - char *netAddressUtf8 = NULL; - PRBool allowMultiConnection = PR_FALSE; - PRBool reuseSingleConnection = PR_FALSE; -#if VBOX_API_VERSION < 3001000 - PRUint32 VRDPport = 0; - VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport); - if (VRDPport) { - def->graphics[def->ngraphics]->data.rdp.port = VRDPport; - } else { - def->graphics[def->ngraphics]->data.rdp.autoport = true; - } -#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */ - PRUnichar *VRDPport = NULL; - VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport); - if (VRDPport) { - /* even if vbox supports mutilpe ports, single port for now here */ - def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDPport); - VBOX_UTF16_FREE(VRDPport); - } else { - def->graphics[def->ngraphics]->data.rdp.autoport = true; - } -#else /* VBOX_API_VERSION >= 4000000 */ - PRUnichar *VRDEPortsKey = NULL; - PRUnichar *VRDEPortsValue = NULL; - VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey); - VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDEPortsKey, &VRDEPortsValue); - VBOX_UTF16_FREE(VRDEPortsKey); - if (VRDEPortsValue) { - /* even if vbox supports mutilpe ports, single port for now here */ - def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDEPortsValue); - VBOX_UTF16_FREE(VRDEPortsValue); - } else { - def->graphics[def->ngraphics]->data.rdp.autoport = true; - } -#endif /* VBOX_API_VERSION >= 4000000 */ - - def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP; - -#if VBOX_API_VERSION >= 4000000 - PRUnichar *VRDENetAddressKey = NULL; - VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey); - VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16); - VBOX_UTF16_FREE(VRDENetAddressKey); -#else /* VBOX_API_VERSION < 4000000 */ - VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16); -#endif /* VBOX_API_VERSION < 4000000 */ - if (netAddressUtf16) { - VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8); - if (STRNEQ(netAddressUtf8, "")) - virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0, - netAddressUtf8, -1, true); - VBOX_UTF16_FREE(netAddressUtf16); - VBOX_UTF8_FREE(netAddressUtf8); - } - - VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection); - if (allowMultiConnection) { - def->graphics[def->ngraphics]->data.rdp.multiUser = true; - } - - VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection); - if (reuseSingleConnection) { - def->graphics[def->ngraphics]->data.rdp.replaceUser = true; - } - - def->ngraphics++; - } else - virReportOOMError(); - } - VBOX_RELEASE(VRDxServer); - } - } - -#if VBOX_API_VERSION < 3001000 - /* dump IDE hdds if present */ - VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16); - - def->ndisks = 0; - machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0, &hardDiskPM); - if (hardDiskPM) - def->ndisks++; - - machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1, &hardDiskPS); - if (hardDiskPS) - def->ndisks++; - - machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1, &hardDiskSS); - if (hardDiskSS) - def->ndisks++; - - VBOX_UTF16_FREE(hddBusUtf16); - - if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) { - for (i = 0; i < def->ndisks; i++) { - if ((def->disks[i] = virDomainDiskDefNew())) { - def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK; - def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE; - virDomainDiskSetType(def->disks[i], - VIR_STORAGE_TYPE_FILE); - } - } - } - - if (hardDiskPM) { - PRUnichar *hddlocationUtf16 = NULL; - char *hddlocation = NULL; - PRUint32 hddType = HardDiskType_Normal; - - hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16); - VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation); - - hardDiskPM->vtbl->GetType(hardDiskPM, &hddType); - - if (hddType == HardDiskType_Immutable) - def->disks[hddNum]->src->readonly = true; - ignore_value(virDomainDiskSetSource(def->disks[hddNum], - hddlocation)); - ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda")); - hddNum++; - - VBOX_UTF8_FREE(hddlocation); - VBOX_UTF16_FREE(hddlocationUtf16); - VBOX_MEDIUM_RELEASE(hardDiskPM); - } - - if (hardDiskPS) { - PRUnichar *hddlocationUtf16 = NULL; - char *hddlocation = NULL; - PRUint32 hddType = HardDiskType_Normal; - - hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16); - VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation); - - hardDiskPS->vtbl->GetType(hardDiskPS, &hddType); - - if (hddType == HardDiskType_Immutable) - def->disks[hddNum]->src->readonly = true; - ignore_value(virDomainDiskSetSource(def->disks[hddNum], - hddlocation)); - ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb")); - hddNum++; - - VBOX_UTF8_FREE(hddlocation); - VBOX_UTF16_FREE(hddlocationUtf16); - VBOX_MEDIUM_RELEASE(hardDiskPS); - } - - if (hardDiskSS) { - PRUnichar *hddlocationUtf16 = NULL; - char *hddlocation = NULL; - PRUint32 hddType = HardDiskType_Normal; - - hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16); - VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation); - - hardDiskSS->vtbl->GetType(hardDiskSS, &hddType); - - if (hddType == HardDiskType_Immutable) - def->disks[hddNum]->src->readonly = true; - ignore_value(virDomainDiskSetSource(def->disks[hddNum], - hddlocation)); - ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd")); - hddNum++; - - VBOX_UTF8_FREE(hddlocation); - VBOX_UTF16_FREE(hddlocationUtf16); - VBOX_MEDIUM_RELEASE(hardDiskSS); - } -#else /* VBOX_API_VERSION >= 3001000 */ - /* dump IDE hdds if present */ - - bool error = false; - int diskCount = 0; - PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; - PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; - def->ndisks = 0; - vboxArrayGet(&mediumAttachments, machine, machine->vtbl->GetMediumAttachments); - - /* get the number of attachments */ - for (i = 0; i < mediumAttachments.count; i++) { - IMediumAttachment *imediumattach = mediumAttachments.items[i]; - if (imediumattach) { - IMedium *medium = NULL; - - imediumattach->vtbl->GetMedium(imediumattach, &medium); - if (medium) { - def->ndisks++; - VBOX_RELEASE(medium); - } - } - } - - /* Allocate mem, if fails return error */ - if (VIR_ALLOC_N(def->disks, def->ndisks) >= 0) { - for (i = 0; i < def->ndisks; i++) { - virDomainDiskDefPtr disk = virDomainDiskDefNew(); - if (!disk) { - error = true; - break; - } - def->disks[i] = disk; - } - } else { - error = true; - } - - if (!error) - error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort); - - /* get the attachment details here */ - for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) { - IMediumAttachment *imediumattach = mediumAttachments.items[i]; - IStorageController *storageController = NULL; - PRUnichar *storageControllerName = NULL; - PRUint32 deviceType = DeviceType_Null; - PRUint32 storageBus = StorageBus_Null; - PRBool readOnly = PR_FALSE; - IMedium *medium = NULL; - PRUnichar *mediumLocUtf16 = NULL; - char *mediumLocUtf8 = NULL; - PRUint32 deviceInst = 0; - PRInt32 devicePort = 0; - PRInt32 deviceSlot = 0; - - if (!imediumattach) - continue; - - imediumattach->vtbl->GetMedium(imediumattach, &medium); - if (!medium) - continue; - - imediumattach->vtbl->GetController(imediumattach, &storageControllerName); - if (!storageControllerName) { - VBOX_RELEASE(medium); - continue; - } - - machine->vtbl->GetStorageControllerByName(machine, - storageControllerName, - &storageController); - VBOX_UTF16_FREE(storageControllerName); - if (!storageController) { - VBOX_RELEASE(medium); - continue; - } - - medium->vtbl->GetLocation(medium, &mediumLocUtf16); - VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8); - VBOX_UTF16_FREE(mediumLocUtf16); - ignore_value(virDomainDiskSetSource(def->disks[diskCount], - mediumLocUtf8)); - VBOX_UTF8_FREE(mediumLocUtf8); - - if (!virDomainDiskGetSource(def->disks[diskCount])) { - VBOX_RELEASE(medium); - VBOX_RELEASE(storageController); - error = true; - break; - } - - storageController->vtbl->GetBus(storageController, &storageBus); - if (storageBus == StorageBus_IDE) { - def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE; - } else if (storageBus == StorageBus_SATA) { - def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA; - } else if (storageBus == StorageBus_SCSI) { - def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI; - } else if (storageBus == StorageBus_Floppy) { - def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC; - } - - imediumattach->vtbl->GetType(imediumattach, &deviceType); - if (deviceType == DeviceType_HardDisk) - def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK; - else if (deviceType == DeviceType_Floppy) - def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; - else if (deviceType == DeviceType_DVD) - def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM; - - imediumattach->vtbl->GetPort(imediumattach, &devicePort); - imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot); - def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus, - deviceInst, - devicePort, - deviceSlot, - maxPortPerInst, - maxSlotPerPort); - if (!def->disks[diskCount]->dst) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not generate medium name for the disk " - "at: controller instance:%u, port:%d, slot:%d"), - deviceInst, devicePort, deviceSlot); - VBOX_RELEASE(medium); - VBOX_RELEASE(storageController); - error = true; - break; - } - - medium->vtbl->GetReadOnly(medium, &readOnly); - if (readOnly == PR_TRUE) - def->disks[diskCount]->src->readonly = true; - - virDomainDiskSetType(def->disks[diskCount], - VIR_STORAGE_TYPE_FILE); - - VBOX_RELEASE(medium); - VBOX_RELEASE(storageController); - diskCount++; - } - - vboxArrayRelease(&mediumAttachments); - - /* cleanup on error */ - if (error) { - for (i = 0; i < def->ndisks; i++) { - VIR_FREE(def->disks[i]); - } - VIR_FREE(def->disks); - def->ndisks = 0; - } - -#endif /* VBOX_API_VERSION >= 3001000 */ - - /* shared folders */ - vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER; - - def->nfss = 0; - - vboxArrayGet(&sharedFolders, machine, - machine->vtbl->GetSharedFolders); - - if (sharedFolders.count > 0) { - if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0) - goto sharedFoldersCleanup; - - for (i = 0; i < sharedFolders.count; i++) { - ISharedFolder *sharedFolder = sharedFolders.items[i]; - PRUnichar *nameUtf16 = NULL; - char *name = NULL; - PRUnichar *hostPathUtf16 = NULL; - char *hostPath = NULL; - PRBool writable = PR_FALSE; - - if (VIR_ALLOC(def->fss[i]) < 0) - goto sharedFoldersCleanup; - - def->fss[i]->type = VIR_DOMAIN_FS_TYPE_MOUNT; - - sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16); - VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath); - if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) { - VBOX_UTF8_FREE(hostPath); - VBOX_UTF16_FREE(hostPathUtf16); - goto sharedFoldersCleanup; - } - VBOX_UTF8_FREE(hostPath); - VBOX_UTF16_FREE(hostPathUtf16); - - sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16); - VBOX_UTF16_TO_UTF8(nameUtf16, &name); - if (VIR_STRDUP(def->fss[i]->dst, name) < 0) { - VBOX_UTF8_FREE(name); - VBOX_UTF16_FREE(nameUtf16); - goto sharedFoldersCleanup; - } - VBOX_UTF8_FREE(name); - VBOX_UTF16_FREE(nameUtf16); - - sharedFolder->vtbl->GetWritable(sharedFolder, &writable); - def->fss[i]->readonly = !writable; - - ++def->nfss; - } - } - - sharedFoldersCleanup: - vboxArrayRelease(&sharedFolders); - - /* dump network cards if present */ - def->nnets = 0; - /* Get which network cards are enabled */ - for (i = 0; i < netAdpCnt; i++) { - INetworkAdapter *adapter = NULL; - - machine->vtbl->GetNetworkAdapter(machine, i, &adapter); - if (adapter) { - PRBool enabled = PR_FALSE; - - adapter->vtbl->GetEnabled(adapter, &enabled); - if (enabled) { - def->nnets++; - } - - VBOX_RELEASE(adapter); - } - } - - /* Allocate memory for the networkcards which are enabled */ - if ((def->nnets > 0) && (VIR_ALLOC_N(def->nets, def->nnets) >= 0)) { - for (i = 0; i < def->nnets; i++) { - ignore_value(VIR_ALLOC(def->nets[i])); - } - } - - /* Now get the details about the network cards here */ - for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) { - INetworkAdapter *adapter = NULL; - - machine->vtbl->GetNetworkAdapter(machine, i, &adapter); - if (adapter) { - PRBool enabled = PR_FALSE; - - adapter->vtbl->GetEnabled(adapter, &enabled); - if (enabled) { - PRUint32 attachmentType = NetworkAttachmentType_Null; - PRUint32 adapterType = NetworkAdapterType_Null; - PRUnichar *MACAddressUtf16 = NULL; - char *MACAddress = NULL; - char macaddr[VIR_MAC_STRING_BUFLEN] = {0}; - - adapter->vtbl->GetAttachmentType(adapter, &attachmentType); - if (attachmentType == NetworkAttachmentType_NAT) { - - def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER; - - } else if (attachmentType == NetworkAttachmentType_Bridged) { - PRUnichar *hostIntUtf16 = NULL; - char *hostInt = NULL; - - def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; - -#if VBOX_API_VERSION < 4001000 - adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16); -#else /* VBOX_API_VERSION >= 4001000 */ - adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16); -#endif /* VBOX_API_VERSION >= 4001000 */ - - VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt); - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt)); - - VBOX_UTF8_FREE(hostInt); - VBOX_UTF16_FREE(hostIntUtf16); - - } else if (attachmentType == NetworkAttachmentType_Internal) { - PRUnichar *intNetUtf16 = NULL; - char *intNet = NULL; - - def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL; - - adapter->vtbl->GetInternalNetwork(adapter, &intNetUtf16); - - VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet); - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet)); - - VBOX_UTF8_FREE(intNet); - VBOX_UTF16_FREE(intNetUtf16); - - } else if (attachmentType == NetworkAttachmentType_HostOnly) { - PRUnichar *hostIntUtf16 = NULL; - char *hostInt = NULL; - - def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_NETWORK; - -#if VBOX_API_VERSION < 4001000 - adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16); -#else /* VBOX_API_VERSION >= 4001000 */ - adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16); -#endif /* VBOX_API_VERSION >= 4001000 */ - - VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt); - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt)); - - VBOX_UTF8_FREE(hostInt); - VBOX_UTF16_FREE(hostIntUtf16); - - } else { - /* default to user type i.e. NAT in VirtualBox if this - * dump is ever used to create a machine. - */ - def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER; - } - - adapter->vtbl->GetAdapterType(adapter, &adapterType); - if (adapterType == NetworkAdapterType_Am79C970A) { - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A")); - } else if (adapterType == NetworkAdapterType_Am79C973) { - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973")); - } else if (adapterType == NetworkAdapterType_I82540EM) { - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM")); - } else if (adapterType == NetworkAdapterType_I82545EM) { - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM")); - } else if (adapterType == NetworkAdapterType_I82543GC) { - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC")); -#if VBOX_API_VERSION >= 3001000 - } else if (adapterType == NetworkAdapterType_Virtio) { - ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio")); -#endif /* VBOX_API_VERSION >= 3001000 */ - } - - adapter->vtbl->GetMACAddress(adapter, &MACAddressUtf16); - VBOX_UTF16_TO_UTF8(MACAddressUtf16, &MACAddress); - snprintf(macaddr, VIR_MAC_STRING_BUFLEN, - "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c", - MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], - MACAddress[4], MACAddress[5], MACAddress[6], MACAddress[7], - MACAddress[8], MACAddress[9], MACAddress[10], MACAddress[11]); - - /* XXX some real error handling here some day ... */ - if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0) - {} - - netAdpIncCnt++; - - VBOX_UTF16_FREE(MACAddressUtf16); - VBOX_UTF8_FREE(MACAddress); - } - - VBOX_RELEASE(adapter); - } - } - - /* dump sound card if active */ - - /* Set def->nsounds to one as VirtualBox currently supports - * only one sound card - */ - - machine->vtbl->GetAudioAdapter(machine, &audioAdapter); - if (audioAdapter) { - PRBool enabled = PR_FALSE; - - audioAdapter->vtbl->GetEnabled(audioAdapter, &enabled); - if (enabled) { - PRUint32 audioController = AudioControllerType_AC97; - - def->nsounds = 1; - if (VIR_ALLOC_N(def->sounds, def->nsounds) >= 0) { - if (VIR_ALLOC(def->sounds[0]) >= 0) { - audioAdapter->vtbl->GetAudioController(audioAdapter, &audioController); - if (audioController == AudioControllerType_SB16) { - def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16; - } else if (audioController == AudioControllerType_AC97) { - def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97; - } - } else { - VIR_FREE(def->sounds); - def->nsounds = 0; - } - } else { - def->nsounds = 0; - } - } - VBOX_RELEASE(audioAdapter); - } - -#if VBOX_API_VERSION < 3001000 - /* dump CDROM/DVD if the drive is attached and has DVD/CD in it */ - machine->vtbl->GetDVDDrive(machine, &dvdDrive); - if (dvdDrive) { - PRUint32 state = DriveState_Null; - - dvdDrive->vtbl->GetState(dvdDrive, &state); - if (state == DriveState_ImageMounted) { - IDVDImage *dvdImage = NULL; - - dvdDrive->vtbl->GetImage(dvdDrive, &dvdImage); - if (dvdImage) { - PRUnichar *locationUtf16 = NULL; - char *location = NULL; - - dvdImage->vtbl->imedium.GetLocation((IMedium *)dvdImage, &locationUtf16); - VBOX_UTF16_TO_UTF8(locationUtf16, &location); - - def->ndisks++; - if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) { - if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) { - def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM; - def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE; - virDomainDiskSetType(def->disks[def->ndisks - 1], - VIR_STORAGE_TYPE_FILE); - def->disks[def->ndisks - 1]->src->readonly = true; - ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location)); - ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc")); - def->ndisks--; - } else { - def->ndisks--; - } - } else { - def->ndisks--; - } - - VBOX_UTF8_FREE(location); - VBOX_UTF16_FREE(locationUtf16); - VBOX_MEDIUM_RELEASE(dvdImage); - } - } - VBOX_RELEASE(dvdDrive); - } - - /* dump Floppy if the drive is attached and has floppy in it */ - machine->vtbl->GetFloppyDrive(machine, &floppyDrive); - if (floppyDrive) { - PRBool enabled = PR_FALSE; - - floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled); - if (enabled) { - PRUint32 state = DriveState_Null; - - floppyDrive->vtbl->GetState(floppyDrive, &state); - if (state == DriveState_ImageMounted) { - IFloppyImage *floppyImage = NULL; - - floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage); - if (floppyImage) { - PRUnichar *locationUtf16 = NULL; - char *location = NULL; - - floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16); - VBOX_UTF16_TO_UTF8(locationUtf16, &location); - - def->ndisks++; - if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) { - if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) { - def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; - def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC; - virDomainDiskSetType(def->disks[def->ndisks - 1], - VIR_STORAGE_TYPE_FILE); - def->disks[def->ndisks - 1]->src->readonly = false; - ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location)); - ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda")); - def->ndisks--; - } else { - def->ndisks--; - } - } else { - def->ndisks--; - } - - VBOX_UTF8_FREE(location); - VBOX_UTF16_FREE(locationUtf16); - VBOX_MEDIUM_RELEASE(floppyImage); - } - } - } - - VBOX_RELEASE(floppyDrive); - } -#else /* VBOX_API_VERSION >= 3001000 */ -#endif /* VBOX_API_VERSION >= 3001000 */ - - /* dump serial port if active */ - def->nserials = 0; - /* Get which serial ports are enabled/active */ - for (i = 0; i < serialPortCount; i++) { - ISerialPort *serialPort = NULL; - - machine->vtbl->GetSerialPort(machine, i, &serialPort); - if (serialPort) { - PRBool enabled = PR_FALSE; - - serialPort->vtbl->GetEnabled(serialPort, &enabled); - if (enabled) { - def->nserials++; - } - - VBOX_RELEASE(serialPort); - } - } - - /* Allocate memory for the serial ports which are enabled */ - if ((def->nserials > 0) && (VIR_ALLOC_N(def->serials, def->nserials) >= 0)) { - for (i = 0; i < def->nserials; i++) { - ignore_value(VIR_ALLOC(def->serials[i])); - } - } - - /* Now get the details about the serial ports here */ - for (i = 0; - serialPortIncCount < def->nserials && i < serialPortCount; - i++) { - ISerialPort *serialPort = NULL; - - machine->vtbl->GetSerialPort(machine, i, &serialPort); - if (serialPort) { - PRBool enabled = PR_FALSE; - - serialPort->vtbl->GetEnabled(serialPort, &enabled); - if (enabled) { - PRUint32 hostMode = PortMode_Disconnected; - PRUint32 IOBase = 0; - PRUint32 IRQ = 0; - PRUnichar *pathUtf16 = NULL; - char *path = NULL; - - serialPort->vtbl->GetHostMode(serialPort, &hostMode); - if (hostMode == PortMode_HostPipe) { - def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE; - } else if (hostMode == PortMode_HostDevice) { - def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV; -#if VBOX_API_VERSION >= 3000000 - } else if (hostMode == PortMode_RawFile) { - def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE; -#endif /* VBOX_API_VERSION >= 3000000 */ - } else { - def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL; - } - - def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - - serialPort->vtbl->GetIRQ(serialPort, &IRQ); - serialPort->vtbl->GetIOBase(serialPort, &IOBase); - if ((IRQ == 4) && (IOBase == 1016)) { - def->serials[serialPortIncCount]->target.port = 0; - } else if ((IRQ == 3) && (IOBase == 760)) { - def->serials[serialPortIncCount]->target.port = 1; - } - - serialPort->vtbl->GetPath(serialPort, &pathUtf16); - - if (pathUtf16) { - VBOX_UTF16_TO_UTF8(pathUtf16, &path); - ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path)); - } - - serialPortIncCount++; - - VBOX_UTF16_FREE(pathUtf16); - VBOX_UTF8_FREE(path); - } - - VBOX_RELEASE(serialPort); - } - } - - /* dump parallel ports if active */ - def->nparallels = 0; - /* Get which parallel ports are enabled/active */ - for (i = 0; i < parallelPortCount; i++) { - IParallelPort *parallelPort = NULL; - - machine->vtbl->GetParallelPort(machine, i, ¶llelPort); - if (parallelPort) { - PRBool enabled = PR_FALSE; - - parallelPort->vtbl->GetEnabled(parallelPort, &enabled); - if (enabled) { - def->nparallels++; - } - - VBOX_RELEASE(parallelPort); - } - } - - /* Allocate memory for the parallel ports which are enabled */ - if ((def->nparallels > 0) && (VIR_ALLOC_N(def->parallels, def->nparallels) >= 0)) { - for (i = 0; i < def->nparallels; i++) { - ignore_value(VIR_ALLOC(def->parallels[i])); - } - } - - /* Now get the details about the parallel ports here */ - for (i = 0; - parallelPortIncCount < def->nparallels && - i < parallelPortCount; - i++) { - IParallelPort *parallelPort = NULL; - - machine->vtbl->GetParallelPort(machine, i, ¶llelPort); - if (parallelPort) { - PRBool enabled = PR_FALSE; - - parallelPort->vtbl->GetEnabled(parallelPort, &enabled); - if (enabled) { - PRUint32 IOBase = 0; - PRUint32 IRQ = 0; - PRUnichar *pathUtf16 = NULL; - char *path = NULL; - - parallelPort->vtbl->GetIRQ(parallelPort, &IRQ); - parallelPort->vtbl->GetIOBase(parallelPort, &IOBase); - if ((IRQ == 7) && (IOBase == 888)) { - def->parallels[parallelPortIncCount]->target.port = 0; - } else if ((IRQ == 5) && (IOBase == 632)) { - def->parallels[parallelPortIncCount]->target.port = 1; - } - - def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE; - def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL; - - parallelPort->vtbl->GetPath(parallelPort, &pathUtf16); - - VBOX_UTF16_TO_UTF8(pathUtf16, &path); - ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path)); - - parallelPortIncCount++; - - VBOX_UTF16_FREE(pathUtf16); - VBOX_UTF8_FREE(path); - } - - VBOX_RELEASE(parallelPort); - } - } - - /* dump USB devices/filters if active */ - vboxHostDeviceGetXMLDesc(data, def, machine); - - /* all done so set gotAllABoutDef and pass def to virDomainDefFormat - * to generate XML for it - */ - gotAllABoutDef = 0; - } - VBOX_RELEASE(machine); - machine = NULL; - } - - if (gotAllABoutDef == 0) - ret = virDomainDefFormat(def, flags); - - cleanup: - vboxIIDUnalloc(&iid); - virDomainDefFree(def); - return ret; -} - static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) { VBOX_OBJECT_CHECK(conn, int, -1); vboxArray machines = VBOX_ARRAY_INITIALIZER; diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h index f72d03f..518dd2a 100644 --- a/src/vbox/vbox_uniformed_api.h +++ b/src/vbox/vbox_uniformed_api.h @@ -516,6 +516,7 @@ int vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, int vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus); int vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags); int vboxDomainGetMaxVcpus(virDomainPtr dom); +char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags); /* Version specified functions for installing uniformed API */ void vbox22InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI); -- 1.7.9.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list