/** @file vbox_tmpl.c * Template File to support multiple versions of VirtualBox * at runtime :). * * IMPORTANT: * Please dont include this file in the src/Makefile.am, it * is automatically include by other files. */ /* * Copyright (C) 2010-2014 Red Hat, Inc. * Copyright (C) 2008-2009 Sun Microsystems, Inc. * * This file is part of a free software library; you can redistribute * it and/or modify it under the terms of the GNU Lesser General * Public License version 2.1 as published by the Free Software * Foundation and shipped in the "COPYING.LESSER" file with this library. * The library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY of any kind. * * Sun LGPL Disclaimer: For the avoidance of doubt, except that if * any license choice other than GPL or LGPL is available it will * apply instead, Sun elects to use only the Lesser General Public * License version 2.1 (LGPLv2) at this time for any software where * a choice of LGPL license versions is made available with the * language indicating that LGPLv2 or any later version may be used, * or where a choice of which version of the LGPL is applied is * otherwise unspecified. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 USA or visit http://www.sun.com if you need * additional information or have any questions. */ #include #include #include #include #include #include "internal.h" #include "datatypes.h" #include "domain_conf.h" #include "snapshot_conf.h" #include "vbox_snapshot_conf.h" #include "network_conf.h" #include "virerror.h" #include "domain_event.h" #include "storage_conf.h" #include "virstoragefile.h" #include "viruuid.h" #include "viralloc.h" #include "nodeinfo.h" #include "virlog.h" #include "vbox_driver.h" #include "configmake.h" #include "virfile.h" #include "fdstream.h" #include "viruri.h" #include "virstring.h" #include "virtime.h" #include "virutil.h" /* This one changes from version to version. */ #if VBOX_API_VERSION == 2002000 # include "vbox_CAPI_v2_2.h" #elif VBOX_API_VERSION == 3000000 # include "vbox_CAPI_v3_0.h" #elif VBOX_API_VERSION == 3001000 # include "vbox_CAPI_v3_1.h" #elif VBOX_API_VERSION == 3002000 # include "vbox_CAPI_v3_2.h" #elif VBOX_API_VERSION == 4000000 # include "vbox_CAPI_v4_0.h" #elif VBOX_API_VERSION == 4001000 # include "vbox_CAPI_v4_1.h" #elif VBOX_API_VERSION == 4002000 # include "vbox_CAPI_v4_2.h" #elif VBOX_API_VERSION == 4002020 # include "vbox_CAPI_v4_2_20.h" #elif VBOX_API_VERSION == 4003000 # include "vbox_CAPI_v4_3.h" #elif VBOX_API_VERSION == 4003004 # include "vbox_CAPI_v4_3_4.h" #else # error "Unsupport VBOX_API_VERSION" #endif /* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */ #include "vbox_glue.h" #if VBOX_API_VERSION < 4000000 typedef IVRDPServer IVRDxServer; #else /* VBOX_API_VERSION >= 4000000 */ typedef IVRDEServer IVRDxServer; #endif /* VBOX_API_VERSION >= 4000000 */ #if VBOX_API_VERSION < 4003000 typedef IUSBController IUSBCommon; #else /* VBOX_API_VERSION >= 4003000 */ typedef IUSBDeviceFilters IUSBCommon; #endif /* VBOX_API_VERSION >= 4003000 */ #include "vbox_uniformed_api.h" #define VIR_FROM_THIS VIR_FROM_VBOX VIR_LOG_INIT("vbox.vbox_tmpl"); #define vboxUnsupported() \ VIR_WARN("No %s in current vbox version %d.", __FUNCTION__, VBOX_API_VERSION); #define VBOX_UTF16_FREE(arg) \ do { \ if (arg) { \ data->pFuncs->pfnUtf16Free(arg); \ (arg) = NULL; \ } \ } while (0) #define VBOX_UTF8_FREE(arg) \ do { \ if (arg) { \ data->pFuncs->pfnUtf8Free(arg); \ (arg) = NULL; \ } \ } while (0) #define VBOX_COM_UNALLOC_MEM(arg) \ do { \ if (arg) { \ data->pFuncs->pfnComUnallocMem(arg); \ (arg) = NULL; \ } \ } while (0) #define VBOX_UTF16_TO_UTF8(arg1, arg2) data->pFuncs->pfnUtf16ToUtf8(arg1, arg2) #define VBOX_UTF8_TO_UTF16(arg1, arg2) data->pFuncs->pfnUtf8ToUtf16(arg1, arg2) #define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg)) #define VBOX_RELEASE(arg) \ do { \ if (arg) { \ (arg)->vtbl->nsisupports.Release((nsISupports *)(arg)); \ (arg) = NULL; \ } \ } while (0) #define VBOX_OBJECT_CHECK(conn, type, value) \ vboxGlobalData *data = conn->privateData;\ type ret = value;\ if (!data->vboxObj) {\ return ret;\ } #define VBOX_OBJECT_HOST_CHECK(conn, type, value) \ vboxGlobalData *data = conn->privateData;\ type ret = value;\ IHost *host = NULL;\ if (!data->vboxObj) {\ return ret;\ }\ data->vboxObj->vtbl->GetHost(data->vboxObj, &host);\ if (!host) {\ return ret;\ } #if VBOX_API_VERSION < 3001000 # define VBOX_MEDIUM_RELEASE(arg) \ if (arg)\ (arg)->vtbl->imedium.nsisupports.Release((nsISupports *)(arg)) # define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \ (object)->vtbl->imedium.func((IMedium *)(object), arg1) # define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \ (object)->vtbl->imedium.func((IMedium *)(object), arg1, arg2) #else /* VBOX_API_VERSION >= 3001000 */ typedef IMedium IHardDisk; typedef IMediumAttachment IHardDiskAttachment; # define MediaState_Inaccessible MediumState_Inaccessible # define HardDiskVariant_Standard MediumVariant_Standard # define HardDiskVariant_Fixed MediumVariant_Fixed # define VBOX_MEDIUM_RELEASE(arg) VBOX_RELEASE(arg) # define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \ (object)->vtbl->func(object, arg1) # define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \ (object)->vtbl->func(object, arg1, arg2) #endif /* VBOX_API_VERSION >= 3001000 */ #define DEBUGPRUnichar(msg, strUtf16) \ if (strUtf16) {\ char *strUtf8 = NULL;\ \ g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);\ if (strUtf8) {\ VIR_DEBUG("%s: %s", msg, strUtf8);\ g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);\ }\ } #define DEBUGUUID(msg, iid) \ {\ VIR_DEBUG("%s: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", msg,\ (unsigned)(iid)->m0,\ (unsigned)(iid)->m1,\ (unsigned)(iid)->m2,\ (unsigned)(iid)->m3[0],\ (unsigned)(iid)->m3[1],\ (unsigned)(iid)->m3[2],\ (unsigned)(iid)->m3[3],\ (unsigned)(iid)->m3[4],\ (unsigned)(iid)->m3[5],\ (unsigned)(iid)->m3[6],\ (unsigned)(iid)->m3[7]);\ }\ #if VBOX_API_VERSION > 2002000 /* g_pVBoxGlobalData has to be global variable, * there is no other way to make the callbacks * work other then having g_pVBoxGlobalData as * global, because the functions namely AddRef, * Release, etc consider it as global and you * can't change the function definition as it * is XPCOM nsISupport::* function and it expects * them that way */ static vboxGlobalData *g_pVBoxGlobalData = NULL; #endif /* !(VBOX_API_VERSION == 2002000) */ #if VBOX_API_VERSION < 4000000 # define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \ data->vboxObj->vtbl->GetMachine(data->vboxObj, iid_value, machine) # define VBOX_SESSION_OPEN(/* in */ iid_value, /* unused */ machine) \ data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid_value) # define VBOX_SESSION_OPEN_EXISTING(/* in */ iid_value, /* unused */ machine) \ data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid_value) # define VBOX_SESSION_CLOSE() \ data->vboxSession->vtbl->Close(data->vboxSession) #else /* VBOX_API_VERSION >= 4000000 */ # define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \ data->vboxObj->vtbl->FindMachine(data->vboxObj, iid_value, machine) # define VBOX_SESSION_OPEN(/* unused */ iid_value, /* in */ machine) \ machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Write) # define VBOX_SESSION_OPEN_EXISTING(/* unused */ iid_value, /* in */ machine) \ machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared) # define VBOX_SESSION_CLOSE() \ data->vboxSession->vtbl->UnlockMachine(data->vboxSession) #endif /* VBOX_API_VERSION >= 4000000 */ #if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000 /* Since vboxConnectGetCapabilities has been rewritten, * vboxDriverLock and vboxDriverUnlock only be used in code for * 3.x release. */ static void vboxDriverLock(vboxGlobalData *data) { virMutexLock(&data->lock); } static void vboxDriverUnlock(vboxGlobalData *data) { virMutexUnlock(&data->lock); } #endif #if VBOX_API_VERSION == 2002000 static void nsIDtoChar(unsigned char *uuid, const nsID *iid) { char uuidstrsrc[VIR_UUID_STRING_BUFLEN]; char uuidstrdst[VIR_UUID_STRING_BUFLEN]; unsigned char uuidinterim[VIR_UUID_BUFLEN]; size_t i; memcpy(uuidinterim, iid, VIR_UUID_BUFLEN); virUUIDFormat(uuidinterim, uuidstrsrc); uuidstrdst[0] = uuidstrsrc[6]; uuidstrdst[1] = uuidstrsrc[7]; uuidstrdst[2] = uuidstrsrc[4]; uuidstrdst[3] = uuidstrsrc[5]; uuidstrdst[4] = uuidstrsrc[2]; uuidstrdst[5] = uuidstrsrc[3]; uuidstrdst[6] = uuidstrsrc[0]; uuidstrdst[7] = uuidstrsrc[1]; uuidstrdst[8] = uuidstrsrc[8]; uuidstrdst[9] = uuidstrsrc[11]; uuidstrdst[10] = uuidstrsrc[12]; uuidstrdst[11] = uuidstrsrc[9]; uuidstrdst[12] = uuidstrsrc[10]; uuidstrdst[13] = uuidstrsrc[13]; uuidstrdst[14] = uuidstrsrc[16]; uuidstrdst[15] = uuidstrsrc[17]; uuidstrdst[16] = uuidstrsrc[14]; uuidstrdst[17] = uuidstrsrc[15]; for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) { uuidstrdst[i] = uuidstrsrc[i]; } uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0'; ignore_value(virUUIDParse(uuidstrdst, uuid)); } static void nsIDFromChar(nsID *iid, const unsigned char *uuid) { char uuidstrsrc[VIR_UUID_STRING_BUFLEN]; char uuidstrdst[VIR_UUID_STRING_BUFLEN]; unsigned char uuidinterim[VIR_UUID_BUFLEN]; size_t i; virUUIDFormat(uuid, uuidstrsrc); uuidstrdst[0] = uuidstrsrc[6]; uuidstrdst[1] = uuidstrsrc[7]; uuidstrdst[2] = uuidstrsrc[4]; uuidstrdst[3] = uuidstrsrc[5]; uuidstrdst[4] = uuidstrsrc[2]; uuidstrdst[5] = uuidstrsrc[3]; uuidstrdst[6] = uuidstrsrc[0]; uuidstrdst[7] = uuidstrsrc[1]; uuidstrdst[8] = uuidstrsrc[8]; uuidstrdst[9] = uuidstrsrc[11]; uuidstrdst[10] = uuidstrsrc[12]; uuidstrdst[11] = uuidstrsrc[9]; uuidstrdst[12] = uuidstrsrc[10]; uuidstrdst[13] = uuidstrsrc[13]; uuidstrdst[14] = uuidstrsrc[16]; uuidstrdst[15] = uuidstrsrc[17]; uuidstrdst[16] = uuidstrsrc[14]; uuidstrdst[17] = uuidstrsrc[15]; for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) { uuidstrdst[i] = uuidstrsrc[i]; } uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0'; ignore_value(virUUIDParse(uuidstrdst, uuidinterim)); memcpy(iid, uuidinterim, VIR_UUID_BUFLEN); } # ifdef WIN32 typedef struct _vboxIID_v2_x_WIN32 vboxIID; typedef struct _vboxIID_v2_x_WIN32 vboxIID_v2_x_WIN32; # define VBOX_IID_INITIALIZER { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } } # define IID_MEMBER(name) (iidu->vboxIID_v2_x_WIN32.name) static void vboxIIDUnalloc_v2_x_WIN32(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIID_v2_x_WIN32 *iid ATTRIBUTE_UNUSED) { /* Nothing to free */ } static void _vboxIIDUnalloc(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iid ATTRIBUTE_UNUSED) { /* Nothing to free */ } static void vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid) { nsIDtoChar(uuid, (nsID *)&iid->value); } static void _vboxIIDToUUID(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iidu, unsigned char *uuid) { vboxIIDToUUID_v2_x_WIN32(&iidu->vboxIID_v2_x_WIN32, uuid); } static void vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid, const unsigned char *uuid) { vboxIIDUnalloc_v2_x_WIN32(data, iid); nsIDFromChar((nsID *)&iid->value, uuid); } static void _vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu, const unsigned char *uuid) { vboxIIDFromUUID_v2_x_WIN32(data, &iidu->vboxIID_v2_x_WIN32, uuid); } static bool vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2) { return memcmp(&iid1->value, &iid2->value, sizeof(GUID)) == 0; } static bool _vboxIIDIsEqual(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iidu1, vboxIIDUnion *iidu2) { return vboxIIDIsEqual_v2_x_WIN32(&iidu1->vboxIID_v2_x_WIN32, &iidu2->vboxIID_v2_x_WIN32); } static void vboxIIDFromArrayItem_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid, vboxArray *array, int idx) { GUID *items = (GUID *)array->items; vboxIIDUnalloc_v2_x_WIN32(data, iid); memcpy(&iid->value, &items[idx], sizeof(GUID)); } static void _vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu, vboxArray *array, int idx) { vboxIIDFromArrayItem_v2_x_WIN32(data, &iidu->vboxIID_v2_x_WIN32, array, idx); } # define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x_WIN32(data, iid) # define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x_WIN32(iid, uuid) # define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x_WIN32(data, iid, uuid) # define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x_WIN32(iid1, iid2) # define vboxIIDFromArrayItem(iid, array, idx) \ vboxIIDFromArrayItem_v2_x_WIN32(data, iid, array, idx) # define DEBUGIID(msg, iid) DEBUGUUID(msg, (nsID *)&(iid)) # else /* !WIN32 */ typedef struct _vboxIID_v2_x vboxIID; typedef struct _vboxIID_v2_x vboxIID_v2_x; # define VBOX_IID_INITIALIZER { NULL, { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } } # define IID_MEMBER(name) (iidu->vboxIID_v2_x.name) static void vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid) { if (iid->value == NULL) { return; } if (iid->value != &iid->backing) { data->pFuncs->pfnComUnallocMem(iid->value); } iid->value = NULL; } static void _vboxIIDUnalloc(vboxGlobalData *data, vboxIIDUnion *iidu) { vboxIIDUnalloc_v2_x(data, &iidu->vboxIID_v2_x); } static void vboxIIDToUUID_v2_x(vboxIID_v2_x *iid, unsigned char *uuid) { nsIDtoChar(uuid, iid->value); } static void _vboxIIDToUUID(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iidu, unsigned char *uuid) { vboxIIDToUUID_v2_x(&iidu->vboxIID_v2_x, uuid); } static void vboxIIDFromUUID_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid, const unsigned char *uuid) { vboxIIDUnalloc_v2_x(data, iid); iid->value = &iid->backing; sa_assert(iid->value); nsIDFromChar(iid->value, uuid); } static void _vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu, const unsigned char *uuid) { vboxIIDFromUUID_v2_x(data, &iidu->vboxIID_v2_x, uuid); } static bool vboxIIDIsEqual_v2_x(vboxIID_v2_x *iid1, vboxIID_v2_x *iid2) { return memcmp(iid1->value, iid2->value, sizeof(nsID)) == 0; } static bool _vboxIIDIsEqual(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iidu1, vboxIIDUnion *iidu2) { return vboxIIDIsEqual_v2_x(&iidu1->vboxIID_v2_x, &iidu2->vboxIID_v2_x); } static void vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid, vboxArray *array, int idx) { vboxIIDUnalloc_v2_x(data, iid); iid->value = &iid->backing; memcpy(iid->value, array->items[idx], sizeof(nsID)); } static void _vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu, vboxArray *array, int idx) { vboxIIDFromArrayItem_v2_x(data, &iidu->vboxIID_v2_x, array, idx); } # define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x(data, iid) # define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x(iid, uuid) # define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x(data, iid, uuid) # define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x(iid1, iid2) # define vboxIIDFromArrayItem(iid, array, idx) \ vboxIIDFromArrayItem_v2_x(data, iid, array, idx) # define DEBUGIID(msg, iid) DEBUGUUID(msg, iid) # endif /* !WIN32 */ #else /* VBOX_API_VERSION != 2002000 */ typedef struct _vboxIID_v3_x vboxIID; typedef struct _vboxIID_v3_x vboxIID_v3_x; # define VBOX_IID_INITIALIZER { NULL, true } # define IID_MEMBER(name) (iidu->vboxIID_v3_x.name) static void vboxIIDUnalloc_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid) { if (iid->value != NULL && iid->owner) { data->pFuncs->pfnUtf16Free(iid->value); } iid->value = NULL; iid->owner = true; } static void _vboxIIDUnalloc(vboxGlobalData *data, vboxIIDUnion *iidu) { vboxIIDUnalloc_v3_x(data, &iidu->vboxIID_v3_x); } static void vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid, unsigned char *uuid) { char *utf8 = NULL; data->pFuncs->pfnUtf16ToUtf8(iid->value, &utf8); ignore_value(virUUIDParse(utf8, uuid)); data->pFuncs->pfnUtf8Free(utf8); } static void _vboxIIDToUUID(vboxGlobalData *data, vboxIIDUnion *iidu, unsigned char *uuid) { vboxIIDToUUID_v3_x(data, &iidu->vboxIID_v3_x, uuid); } static void vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid, const unsigned char *uuid) { char utf8[VIR_UUID_STRING_BUFLEN]; vboxIIDUnalloc_v3_x(data, iid); virUUIDFormat(uuid, utf8); data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value); } static void _vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu, const unsigned char *uuid) { vboxIIDFromUUID_v3_x(data, &iidu->vboxIID_v3_x, uuid); } static bool vboxIIDIsEqual_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid1, vboxIID_v3_x *iid2) { unsigned char uuid1[VIR_UUID_BUFLEN]; unsigned char uuid2[VIR_UUID_BUFLEN]; /* Note: we can't directly compare the utf8 strings here * cause the two UUID's may have separators as space or '-' * or mixture of both and we don't want to fail here by * using direct string comparison. Here virUUIDParse() takes * care of these cases. */ vboxIIDToUUID_v3_x(data, iid1, uuid1); vboxIIDToUUID_v3_x(data, iid2, uuid2); return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0; } static bool _vboxIIDIsEqual(vboxGlobalData *data, vboxIIDUnion *iidu1, vboxIIDUnion *iidu2) { return vboxIIDIsEqual_v3_x(data, &iidu1->vboxIID_v3_x, &iidu2->vboxIID_v3_x); } static void vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid, vboxArray *array, int idx) { vboxIIDUnalloc_v3_x(data, iid); iid->value = array->items[idx]; iid->owner = false; } static void _vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu, vboxArray *array, int idx) { vboxIIDFromArrayItem_v3_x(data, &iidu->vboxIID_v3_x, array, idx); } # define vboxIIDUnalloc(iid) vboxIIDUnalloc_v3_x(data, iid) # define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v3_x(data, iid, uuid) # define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v3_x(data, iid, uuid) # define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v3_x(data, iid1, iid2) # define vboxIIDFromArrayItem(iid, array, idx) \ vboxIIDFromArrayItem_v3_x(data, iid, array, idx) # define DEBUGIID(msg, strUtf16) DEBUGPRUnichar(msg, strUtf16) #endif /* !(VBOX_API_VERSION == 2002000) */ #if VBOX_API_VERSION >= 3001000 /** * 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; } /** * function to get the StorageBus, Port number * and Device number for the given devicename * e.g: hda has StorageBus = IDE, port = 0, * device = 0 * * @returns true on Success, false on failure. * @param deviceName Input device name * @param aMaxPortPerInst Input array of max port per device instance * @param aMaxSlotPerPort Input array of max slot per device port * @param storageBus Input storage bus type * @param deviceInst Output device instance number * @param devicePort Output port number * @param deviceSlot Output slot number * */ # if VBOX_API_VERSION < 4000000 /* Only 3.x will use this function. */ static bool vboxGetDeviceDetails(const char *deviceName, PRUint32 *aMaxPortPerInst, PRUint32 *aMaxSlotPerPort, PRUint32 storageBus, PRInt32 *deviceInst, PRInt32 *devicePort, PRInt32 *deviceSlot) { int total = 0; PRUint32 maxPortPerInst = 0; PRUint32 maxSlotPerPort = 0; if (!deviceName || !deviceInst || !devicePort || !deviceSlot || !aMaxPortPerInst || !aMaxSlotPerPort) return false; if ((storageBus < StorageBus_IDE) || (storageBus > StorageBus_Floppy)) return false; total = virDiskNameToIndex(deviceName); maxPortPerInst = aMaxPortPerInst[storageBus]; maxSlotPerPort = aMaxSlotPerPort[storageBus]; if (!maxPortPerInst || !maxSlotPerPort || (total < 0)) return false; *deviceInst = total / (maxPortPerInst * maxSlotPerPort); *devicePort = (total % (maxPortPerInst * maxSlotPerPort)) / maxSlotPerPort; *deviceSlot = (total % (maxPortPerInst * maxSlotPerPort)) % maxSlotPerPort; VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, " "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u", deviceName, total, storageBus, *deviceInst, *devicePort, *deviceSlot, maxPortPerInst, maxSlotPerPort); return true; } # endif /* VBOX_API_VERSION < 4000000 */ /** * function to get the values for max port per * instance and max slots per port for the devices * * @returns true on Success, false on failure. * @param vbox Input IVirtualBox pointer * @param maxPortPerInst Output array of max port per instance * @param maxSlotPerPort Output array of max slot per port * */ static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox, PRUint32 *maxPortPerInst, PRUint32 *maxSlotPerPort) { ISystemProperties *sysProps = NULL; if (!vbox) return false; vbox->vtbl->GetSystemProperties(vbox, &sysProps); if (!sysProps) return false; sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps, StorageBus_IDE, &maxPortPerInst[StorageBus_IDE]); sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps, StorageBus_SATA, &maxPortPerInst[StorageBus_SATA]); sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps, StorageBus_SCSI, &maxPortPerInst[StorageBus_SCSI]); sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps, StorageBus_Floppy, &maxPortPerInst[StorageBus_Floppy]); sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps, StorageBus_IDE, &maxSlotPerPort[StorageBus_IDE]); sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps, StorageBus_SATA, &maxSlotPerPort[StorageBus_SATA]); sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps, StorageBus_SCSI, &maxSlotPerPort[StorageBus_SCSI]); sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps, StorageBus_Floppy, &maxSlotPerPort[StorageBus_Floppy]); VBOX_RELEASE(sysProps); return true; } /** * Converts Utf-16 string to int */ static int PRUnicharToInt(PRUnichar *strUtf16) { char *strUtf8 = NULL; int ret = 0; if (!strUtf16) return -1; g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8); if (!strUtf8) return -1; if (virStrToLong_i(strUtf8, NULL, 10, &ret) < 0) ret = -1; g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8); return ret; } /** * Converts int to Utf-16 string */ static PRUnichar *PRUnicharFromInt(int n) { PRUnichar *strUtf16 = NULL; char s[24]; snprintf(s, sizeof(s), "%d", n); g_pVBoxGlobalData->pFuncs->pfnUtf8ToUtf16(s, &strUtf16); return strUtf16; } #endif /* VBOX_API_VERSION >= 3001000 */ static PRUnichar * vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr) { char *utf8 = NULL; PRUnichar *utf16 = NULL; utf8 = virSocketAddrFormat(addr); if (utf8 == NULL) { return NULL; } VBOX_UTF8_TO_UTF16(utf8, &utf16); VIR_FREE(utf8); return utf16; } static int vboxSocketParseAddrUtf16(vboxGlobalData *data, const PRUnichar *utf16, virSocketAddrPtr addr) { int result = -1; char *utf8 = NULL; VBOX_UTF16_TO_UTF8(utf16, &utf8); if (virSocketAddrParse(addr, utf8, AF_UNSPEC) < 0) { goto cleanup; } result = 0; cleanup: VBOX_UTF8_FREE(utf8); return result; } static int vboxDomainIsPersistent(virDomainPtr dom ATTRIBUTE_UNUSED) { /* All domains are persistent. However, we do want to check for * existence. */ VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; nsresult rc; vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } ret = 1; cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED) { /* VBox domains never have a persistent state that differs from * current state. However, we do want to check for existence. */ VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; nsresult rc; vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } ret = 0; cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainSuspend(virDomainPtr dom) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; IConsole *console = NULL; PRBool isAccessible = PR_FALSE; PRUint32 state; nsresult rc; vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching id %d"), dom->id); goto cleanup; } if (!machine) goto cleanup; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if (state == MachineState_Running) { /* set state pause */ VBOX_SESSION_OPEN_EXISTING(iid.value, machine); data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (console) { console->vtbl->Pause(console); VBOX_RELEASE(console); ret = 0; } else { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("error while suspending the domain")); goto cleanup; } VBOX_SESSION_CLOSE(); } else { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("machine not in running state to suspend it")); goto cleanup; } } cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainResume(virDomainPtr dom) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; IConsole *console = NULL; PRUint32 state = MachineState_Null; nsresult rc; PRBool isAccessible = PR_FALSE; vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching id %d"), dom->id); goto cleanup; } if (!machine) goto cleanup; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if (state == MachineState_Paused) { /* resume the machine here */ VBOX_SESSION_OPEN_EXISTING(iid.value, machine); data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (console) { console->vtbl->Resume(console); VBOX_RELEASE(console); ret = 0; } else { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("error while resuming the domain")); goto cleanup; } VBOX_SESSION_CLOSE(); } else { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("machine not paused, so can't resume it")); goto cleanup; } } cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainShutdownFlags(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; IConsole *console = NULL; PRUint32 state = MachineState_Null; PRBool isAccessible = PR_FALSE; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching id %d"), dom->id); goto cleanup; } if (!machine) goto cleanup; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if (state == MachineState_Paused) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("machine paused, so can't power it down")); goto cleanup; } else if (state == MachineState_PoweredOff) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("machine already powered down")); goto cleanup; } VBOX_SESSION_OPEN_EXISTING(iid.value, machine); data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (console) { console->vtbl->PowerButton(console); VBOX_RELEASE(console); ret = 0; } VBOX_SESSION_CLOSE(); } cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainShutdown(virDomainPtr dom) { return vboxDomainShutdownFlags(dom, 0); } static int vboxDomainReboot(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; IConsole *console = NULL; PRUint32 state = MachineState_Null; PRBool isAccessible = PR_FALSE; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching id %d"), dom->id); goto cleanup; } if (!machine) goto cleanup; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if (state == MachineState_Running) { VBOX_SESSION_OPEN_EXISTING(iid.value, machine); data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (console) { console->vtbl->Reset(console); VBOX_RELEASE(console); ret = 0; } VBOX_SESSION_CLOSE(); } else { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("machine not running, so can't reboot it")); goto cleanup; } } cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainDestroyFlags(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; IConsole *console = NULL; PRUint32 state = MachineState_Null; PRBool isAccessible = PR_FALSE; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching id %d"), dom->id); goto cleanup; } if (!machine) goto cleanup; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if (state == MachineState_PoweredOff) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("machine already powered down")); goto cleanup; } VBOX_SESSION_OPEN_EXISTING(iid.value, machine); data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (console) { #if VBOX_API_VERSION == 2002000 console->vtbl->PowerDown(console); #else IProgress *progress = NULL; console->vtbl->PowerDown(console, &progress); if (progress) { progress->vtbl->WaitForCompletion(progress, -1); VBOX_RELEASE(progress); } #endif VBOX_RELEASE(console); dom->id = -1; ret = 0; } VBOX_SESSION_CLOSE(); } cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainDestroy(virDomainPtr dom) { return vboxDomainDestroyFlags(dom, 0); } static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) { /* Returning "hvm" always as suggested on list, cause * this functions seems to be badly named and it * is supposed to pass the ABI name and not the domain * operating system driver as I had imagined ;) */ char *osType; ignore_value(VIR_STRDUP(osType, "hvm")); return osType; } static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; PRUint32 state = MachineState_Null; PRBool isAccessible = PR_FALSE; nsresult rc; vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching id %d"), dom->id); goto cleanup; } if (!machine) goto cleanup; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if (state != MachineState_PoweredOff) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("memory size can't be changed unless domain is powered down")); goto cleanup; } rc = VBOX_SESSION_OPEN(iid.value, machine); if (NS_SUCCEEDED(rc)) { rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine); if (NS_SUCCEEDED(rc) && machine) { rc = machine->vtbl->SetMemorySize(machine, VIR_DIV_UP(memory, 1024)); if (NS_SUCCEEDED(rc)) { machine->vtbl->SaveSettings(machine); ret = 0; } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not set the memory size of the " "domain to: %lu Kb, rc=%08x"), memory, (unsigned)rc); } } VBOX_SESSION_CLOSE(); } } cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static virDomainState vboxConvertState(enum MachineState state) { switch (state) { case MachineState_Running: return VIR_DOMAIN_RUNNING; case MachineState_Stuck: return VIR_DOMAIN_BLOCKED; case MachineState_Paused: return VIR_DOMAIN_PAUSED; case MachineState_Stopping: return VIR_DOMAIN_SHUTDOWN; case MachineState_PoweredOff: case MachineState_Saved: return VIR_DOMAIN_SHUTOFF; case MachineState_Aborted: return VIR_DOMAIN_CRASHED; case MachineState_Null: default: return VIR_DOMAIN_NOSTATE; } } static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxArray machines = VBOX_ARRAY_INITIALIZER; char *machineName = NULL; PRUnichar *machineNameUtf16 = NULL; nsresult rc; size_t i = 0; rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of machines, rc=%08x"), (unsigned)rc); goto cleanup; } info->nrVirtCpu = 0; for (i = 0; i < machines.count; ++i) { IMachine *machine = machines.items[i]; PRBool isAccessible = PR_FALSE; if (!machine) continue; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetName(machine, &machineNameUtf16); VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); if (STREQ(dom->name, machineName)) { /* Get the Machine State (also match it with * virDomainState). Get the Machine memory and * for time being set max_balloon and cur_balloon to same * Also since there is no direct way of checking * the cputime required (one condition being the * VM is remote), return zero for cputime. Get the * number of CPU. */ PRUint32 CPUCount = 0; PRUint32 memorySize = 0; PRUint32 state = MachineState_Null; PRUint32 maxMemorySize = 4 * 1024; ISystemProperties *systemProperties = NULL; data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties); if (systemProperties) { systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize); VBOX_RELEASE(systemProperties); systemProperties = NULL; } machine->vtbl->GetCPUCount(machine, &CPUCount); machine->vtbl->GetMemorySize(machine, &memorySize); machine->vtbl->GetState(machine, &state); info->cpuTime = 0; info->nrVirtCpu = CPUCount; info->memory = memorySize * 1024; info->maxMem = maxMemorySize * 1024; info->state = vboxConvertState(state); ret = 0; } VBOX_UTF8_FREE(machineName); VBOX_COM_UNALLOC_MEM(machineNameUtf16); if (info->nrVirtCpu) break; } } vboxArrayRelease(&machines); cleanup: return ret; } static int vboxDomainGetState(virDomainPtr dom, int *state, int *reason, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID domiid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; PRUint32 mstate = MachineState_Null; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } machine->vtbl->GetState(machine, &mstate); *state = vboxConvertState(mstate); if (reason) *reason = 0; ret = 0; cleanup: vboxIIDUnalloc(&domiid); return ret; } static int vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; PRUint32 CPUCount = nvcpus; nsresult rc; if (flags != VIR_DOMAIN_AFFECT_LIVE) { virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); return -1; } vboxIIDFromUUID(&iid, dom->uuid); #if VBOX_API_VERSION >= 4000000 /* Get machine for the call to VBOX_SESSION_OPEN */ rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); return -1; } #endif rc = VBOX_SESSION_OPEN(iid.value, machine); if (NS_SUCCEEDED(rc)) { data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine); if (machine) { rc = machine->vtbl->SetCPUCount(machine, CPUCount); if (NS_SUCCEEDED(rc)) { machine->vtbl->SaveSettings(machine); ret = 0; } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not set the number of cpus of the domain " "to: %u, rc=%08x"), CPUCount, (unsigned)rc); } VBOX_RELEASE(machine); } else { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching id %d"), dom->id); } } else { virReportError(VIR_ERR_NO_DOMAIN, _("can't open session to the domain with id %d"), dom->id); } VBOX_SESSION_CLOSE(); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) { return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE); } static int vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); ISystemProperties *systemProperties = NULL; PRUint32 maxCPUCount = 0; if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); return -1; } /* Currently every domain supports the same number of max cpus * as that supported by vbox and thus take it directly from * the systemproperties. */ data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties); if (systemProperties) { systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount); VBOX_RELEASE(systemProperties); } if (maxCPUCount > 0) ret = maxCPUCount; return ret; } static int vboxDomainGetMaxVcpus(virDomainPtr dom) { return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)); } 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; char *machineName = NULL; PRUnichar *machineNameUtf16 = NULL; PRUint32 state; nsresult rc; size_t i, j; rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of Defined Domains, rc=%08x"), (unsigned)rc); goto cleanup; } memset(names, 0, sizeof(names[i]) * maxnames); ret = 0; for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) { IMachine *machine = machines.items[i]; if (machine) { PRBool isAccessible = PR_FALSE; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if ((state < MachineState_FirstOnline) || (state > MachineState_LastOnline)) { machine->vtbl->GetName(machine, &machineNameUtf16); VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); if (VIR_STRDUP(names[j], machineName) < 0) { VBOX_UTF16_FREE(machineNameUtf16); VBOX_UTF8_FREE(machineName); for (j = 0; j < maxnames; j++) VIR_FREE(names[j]); ret = -1; goto cleanup; } VBOX_UTF16_FREE(machineNameUtf16); VBOX_UTF8_FREE(machineName); j++; ret++; } } } } cleanup: vboxArrayRelease(&machines); return ret; } static int vboxConnectNumOfDefinedDomains(virConnectPtr conn) { VBOX_OBJECT_CHECK(conn, int, -1); vboxArray machines = VBOX_ARRAY_INITIALIZER; PRUint32 state = MachineState_Null; nsresult rc; size_t i; rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get number of Defined Domains, rc=%08x"), (unsigned)rc); goto cleanup; } ret = 0; for (i = 0; i < machines.count; ++i) { IMachine *machine = machines.items[i]; if (machine) { PRBool isAccessible = PR_FALSE; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if ((state < MachineState_FirstOnline) || (state > MachineState_LastOnline)) { ret++; } } } } cleanup: vboxArrayRelease(&machines); return ret; } #if VBOX_API_VERSION < 3001000 static void _vboxAttachDrivesOld(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine) { size_t i; nsresult rc; if (def->ndisks == 0) return; for (i = 0; i < def->ndisks; i++) { const char *src = virDomainDiskGetSource(def->disks[i]); int type = virDomainDiskGetType(def->disks[i]); int format = virDomainDiskGetFormat(def->disks[i]); VIR_DEBUG("disk(%zu) type: %d", i, type); VIR_DEBUG("disk(%zu) device: %d", i, def->disks[i]->device); VIR_DEBUG("disk(%zu) bus: %d", i, def->disks[i]->bus); VIR_DEBUG("disk(%zu) src: %s", i, src); VIR_DEBUG("disk(%zu) dst: %s", i, def->disks[i]->dst); VIR_DEBUG("disk(%zu) driverName: %s", i, virDomainDiskGetDriver(def->disks[i])); VIR_DEBUG("disk(%zu) driverType: %s", i, virStorageFileFormatTypeToString(format)); VIR_DEBUG("disk(%zu) cachemode: %d", i, def->disks[i]->cachemode); VIR_DEBUG("disk(%zu) readonly: %s", i, (def->disks[i]->src->readonly ? "True" : "False")); VIR_DEBUG("disk(%zu) shared: %s", i, (def->disks[i]->src->shared ? "True" : "False")); if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { if (type == VIR_STORAGE_TYPE_FILE && src) { IDVDDrive *dvdDrive = NULL; /* Currently CDROM/DVD Drive is always IDE * Secondary Master so neglecting the following * parameters: * def->disks[i]->bus * def->disks[i]->dst */ machine->vtbl->GetDVDDrive(machine, &dvdDrive); if (dvdDrive) { IDVDImage *dvdImage = NULL; PRUnichar *dvdfileUtf16 = NULL; vboxIID dvduuid = VBOX_IID_INITIALIZER; vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER; VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16); data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage); if (!dvdImage) { data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage); } if (dvdImage) { rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("can't get the uuid of the file to " "be attached to cdrom: %s, rc=%08x"), src, (unsigned)rc); } else { rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach the file to cdrom: %s, rc=%08x"), src, (unsigned)rc); } else { DEBUGIID("CD/DVDImage UUID:", dvduuid.value); } } VBOX_MEDIUM_RELEASE(dvdImage); } vboxIIDUnalloc(&dvduuid); VBOX_UTF16_FREE(dvdfileUtf16); VBOX_RELEASE(dvdDrive); } } else if (type == VIR_STORAGE_TYPE_BLOCK) { } } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) { if (type == VIR_STORAGE_TYPE_FILE && src) { IHardDisk *hardDisk = NULL; PRUnichar *hddfileUtf16 = NULL; vboxIID hdduuid = VBOX_IID_INITIALIZER; PRUnichar *hddEmpty = NULL; /* Current Limitation: Harddisk can't be connected to * Secondary Master as Secondary Master is always used * for CD/DVD Drive, so don't connect the harddisk if it * is requested to be connected to Secondary master */ VBOX_UTF8_TO_UTF16(src, &hddfileUtf16); VBOX_UTF8_TO_UTF16("", &hddEmpty); data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16, &hardDisk); if (!hardDisk) { # if VBOX_API_VERSION == 2002000 data->vboxObj->vtbl->OpenHardDisk(data->vboxObj, hddfileUtf16, AccessMode_ReadWrite, &hardDisk); # else data->vboxObj->vtbl->OpenHardDisk(data->vboxObj, hddfileUtf16, AccessMode_ReadWrite, 0, hddEmpty, 0, hddEmpty, &hardDisk); # endif } if (hardDisk) { rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk, &hdduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("can't get the uuid of the file to be " "attached as harddisk: %s, rc=%08x"), src, (unsigned)rc); } else { if (def->disks[i]->src->readonly) { hardDisk->vtbl->SetType(hardDisk, HardDiskType_Immutable); VIR_DEBUG("setting harddisk to readonly"); } else if (!def->disks[i]->src->readonly) { hardDisk->vtbl->SetType(hardDisk, HardDiskType_Normal); VIR_DEBUG("setting harddisk type to normal"); } if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) { if (STREQ(def->disks[i]->dst, "hdc")) { VIR_DEBUG("Not connecting harddisk to hdc as hdc" " is taken by CD/DVD Drive"); } else { PRInt32 channel = 0; PRInt32 device = 0; PRUnichar *hddcnameUtf16 = NULL; char *hddcname; ignore_value(VIR_STRDUP(hddcname, "IDE")); VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16); VIR_FREE(hddcname); if (STREQ(def->disks[i]->dst, "hda")) { channel = 0; device = 0; } else if (STREQ(def->disks[i]->dst, "hdb")) { channel = 0; device = 1; } else if (STREQ(def->disks[i]->dst, "hdd")) { channel = 1; device = 1; } rc = machine->vtbl->AttachHardDisk(machine, hdduuid.value, hddcnameUtf16, channel, device); VBOX_UTF16_FREE(hddcnameUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach the file as " "harddisk: %s, rc=%08x"), src, (unsigned)rc); } else { DEBUGIID("Attached HDD with UUID", hdduuid.value); } } } } VBOX_MEDIUM_RELEASE(hardDisk); } vboxIIDUnalloc(&hdduuid); VBOX_UTF16_FREE(hddEmpty); VBOX_UTF16_FREE(hddfileUtf16); } else if (type == VIR_STORAGE_TYPE_BLOCK) { } } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { if (type == VIR_STORAGE_TYPE_FILE && src) { IFloppyDrive *floppyDrive; machine->vtbl->GetFloppyDrive(machine, &floppyDrive); if (floppyDrive) { rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1); if (NS_SUCCEEDED(rc)) { IFloppyImage *floppyImage = NULL; PRUnichar *fdfileUtf16 = NULL; vboxIID fduuid = VBOX_IID_INITIALIZER; vboxIID fdemptyuuid = VBOX_IID_INITIALIZER; VBOX_UTF8_TO_UTF16(src, &fdfileUtf16); rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj, fdfileUtf16, &floppyImage); if (!floppyImage) { data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj, fdfileUtf16, fdemptyuuid.value, &floppyImage); } if (floppyImage) { rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("can't get the uuid of the file to " "be attached to floppy drive: %s, rc=%08x"), src, (unsigned)rc); } else { rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach the file to " "floppy drive: %s, rc=%08x"), src, (unsigned)rc); } else { DEBUGIID("floppyImage UUID", fduuid.value); } } VBOX_MEDIUM_RELEASE(floppyImage); } vboxIIDUnalloc(&fduuid); VBOX_UTF16_FREE(fdfileUtf16); } VBOX_RELEASE(floppyDrive); } } else if (type == VIR_STORAGE_TYPE_BLOCK) { } } } } #elif VBOX_API_VERSION < 4000000 static void _vboxAttachDrivesOld(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine) { size_t i; nsresult rc; PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; PRUnichar *storageCtlName = NULL; bool error = false; /* get the max port/slots/etc for the given storage bus */ error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort); /* add a storage controller for the mediums to be attached */ /* this needs to change when multiple controller are supported for * ver > 3.1 */ { IStorageController *storageCtl = NULL; PRUnichar *sName = NULL; VBOX_UTF8_TO_UTF16("IDE Controller", &sName); machine->vtbl->AddStorageController(machine, sName, StorageBus_IDE, &storageCtl); VBOX_UTF16_FREE(sName); VBOX_RELEASE(storageCtl); VBOX_UTF8_TO_UTF16("SATA Controller", &sName); machine->vtbl->AddStorageController(machine, sName, StorageBus_SATA, &storageCtl); VBOX_UTF16_FREE(sName); VBOX_RELEASE(storageCtl); VBOX_UTF8_TO_UTF16("SCSI Controller", &sName); machine->vtbl->AddStorageController(machine, sName, StorageBus_SCSI, &storageCtl); VBOX_UTF16_FREE(sName); VBOX_RELEASE(storageCtl); VBOX_UTF8_TO_UTF16("Floppy Controller", &sName); machine->vtbl->AddStorageController(machine, sName, StorageBus_Floppy, &storageCtl); VBOX_UTF16_FREE(sName); VBOX_RELEASE(storageCtl); } for (i = 0; i < def->ndisks && !error; i++) { const char *src = virDomainDiskGetSource(def->disks[i]); int type = virDomainDiskGetType(def->disks[i]); int format = virDomainDiskGetFormat(def->disks[i]); VIR_DEBUG("disk(%zu) type: %d", i, type); VIR_DEBUG("disk(%zu) device: %d", i, def->disks[i]->device); VIR_DEBUG("disk(%zu) bus: %d", i, def->disks[i]->bus); VIR_DEBUG("disk(%zu) src: %s", i, src); VIR_DEBUG("disk(%zu) dst: %s", i, def->disks[i]->dst); VIR_DEBUG("disk(%zu) driverName: %s", i, virDomainDiskGetDriver(def->disks[i])); VIR_DEBUG("disk(%zu) driverType: %s", i, virStorageFileFormatTypeToString(format)); VIR_DEBUG("disk(%zu) cachemode: %d", i, def->disks[i]->cachemode); VIR_DEBUG("disk(%zu) readonly: %s", i, (def->disks[i]->src->readonly ? "True" : "False")); VIR_DEBUG("disk(%zu) shared: %s", i, (def->disks[i]->src->shared ? "True" : "False")); if (type == VIR_STORAGE_TYPE_FILE && src) { IMedium *medium = NULL; PRUnichar *mediumUUID = NULL; PRUnichar *mediumFileUtf16 = NULL; PRUint32 storageBus = StorageBus_Null; PRUint32 deviceType = DeviceType_Null; PRInt32 deviceInst = 0; PRInt32 devicePort = 0; PRInt32 deviceSlot = 0; VBOX_UTF8_TO_UTF16(src, &mediumFileUtf16); if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) { deviceType = DeviceType_HardDisk; data->vboxObj->vtbl->FindHardDisk(data->vboxObj, mediumFileUtf16, &medium); } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { deviceType = DeviceType_DVD; data->vboxObj->vtbl->FindDVDImage(data->vboxObj, mediumFileUtf16, &medium); } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { deviceType = DeviceType_Floppy; data->vboxObj->vtbl->FindFloppyImage(data->vboxObj, mediumFileUtf16, &medium); } else { VBOX_UTF16_FREE(mediumFileUtf16); continue; } if (!medium) { PRUnichar *mediumEmpty = NULL; VBOX_UTF8_TO_UTF16("", &mediumEmpty); if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) { rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj, mediumFileUtf16, AccessMode_ReadWrite, false, mediumEmpty, false, mediumEmpty, &medium); } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, mediumFileUtf16, mediumEmpty, &medium); } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj, mediumFileUtf16, mediumEmpty, &medium); } else { rc = 0; } VBOX_UTF16_FREE(mediumEmpty); } if (!medium) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to attach the following disk/dvd/floppy " "to the machine: %s, rc=%08x"), src, (unsigned)rc); VBOX_UTF16_FREE(mediumFileUtf16); continue; } rc = medium->vtbl->GetId(medium, &mediumUUID); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("can't get the uuid of the file to be attached " "as harddisk/dvd/floppy: %s, rc=%08x"), src, (unsigned)rc); VBOX_RELEASE(medium); VBOX_UTF16_FREE(mediumFileUtf16); continue; } if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) { if (def->disks[i]->src->readonly) { medium->vtbl->SetType(medium, MediumType_Immutable); VIR_DEBUG("setting harddisk to immutable"); } else if (!def->disks[i]->src->readonly) { medium->vtbl->SetType(medium, MediumType_Normal); VIR_DEBUG("setting harddisk type to normal"); } } if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) { VBOX_UTF8_TO_UTF16("IDE Controller", &storageCtlName); storageBus = StorageBus_IDE; } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SATA) { VBOX_UTF8_TO_UTF16("SATA Controller", &storageCtlName); storageBus = StorageBus_SATA; } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SCSI) { VBOX_UTF8_TO_UTF16("SCSI Controller", &storageCtlName); storageBus = StorageBus_SCSI; } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_FDC) { VBOX_UTF8_TO_UTF16("Floppy Controller", &storageCtlName); storageBus = StorageBus_Floppy; } /* get the device details i.e instance, port and slot */ if (!vboxGetDeviceDetails(def->disks[i]->dst, maxPortPerInst, maxSlotPerPort, storageBus, &deviceInst, &devicePort, &deviceSlot)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("can't get the port/slot number of " "harddisk/dvd/floppy to be attached: " "%s, rc=%08x"), src, (unsigned)rc); VBOX_RELEASE(medium); VBOX_UTF16_FREE(mediumUUID); VBOX_UTF16_FREE(mediumFileUtf16); continue; } /* attach the harddisk/dvd/Floppy to the storage controller */ rc = machine->vtbl->AttachDevice(machine, storageCtlName, devicePort, deviceSlot, deviceType, mediumUUID); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach the file as " "harddisk/dvd/floppy: %s, rc=%08x"), src, (unsigned)rc); } else { DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID); } VBOX_RELEASE(medium); VBOX_UTF16_FREE(mediumUUID); VBOX_UTF16_FREE(mediumFileUtf16); VBOX_UTF16_FREE(storageCtlName); } } } #else /* VBOX_API_VERSION >= 4000000 */ static void _vboxAttachDrivesOld(virDomainDefPtr def ATTRIBUTE_UNUSED, vboxGlobalData *data ATTRIBUTE_UNUSED, IMachine *machine ATTRIBUTE_UNUSED) { vboxUnsupported(); } #endif /* VBOX_API_VERSION >= 4000000 */ static int vboxDomainUndefine(virDomainPtr dom) { return vboxDomainUndefineFlags(dom, 0); } static int vboxDomainAttachDeviceImpl(virDomainPtr dom, const char *xml, int mediaChangeOnly ATTRIBUTE_UNUSED) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; PRUint32 state = MachineState_Null; virDomainDefPtr def = NULL; virDomainDeviceDefPtr dev = NULL; nsresult rc; if (VIR_ALLOC(def) < 0) return ret; if (VIR_STRDUP(def->os.type, "hvm") < 0) goto cleanup; dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt, VIR_DOMAIN_XML_INACTIVE); if (dev == NULL) goto cleanup; vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); goto cleanup; } if (machine) { machine->vtbl->GetState(machine, &state); if ((state == MachineState_Running) || (state == MachineState_Paused)) { rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine); } else { rc = VBOX_SESSION_OPEN(iid.value, machine); } if (NS_SUCCEEDED(rc)) { rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine); if (NS_SUCCEEDED(rc) && machine) { if (dev->type == VIR_DOMAIN_DEVICE_DISK) { #if VBOX_API_VERSION < 3001000 const char *src = virDomainDiskGetSource(dev->data.disk); int type = virDomainDiskGetType(dev->data.disk); if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { if (type == VIR_STORAGE_TYPE_FILE && src) { IDVDDrive *dvdDrive = NULL; /* Currently CDROM/DVD Drive is always IDE * Secondary Master so neglecting the following * parameter dev->data.disk->bus */ machine->vtbl->GetDVDDrive(machine, &dvdDrive); if (dvdDrive) { IDVDImage *dvdImage = NULL; PRUnichar *dvdfileUtf16 = NULL; vboxIID dvduuid = VBOX_IID_INITIALIZER; vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER; VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16); data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage); if (!dvdImage) { data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage); } if (dvdImage) { rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("can't get the uuid of the file to " "be attached to cdrom: %s, rc=%08x"), src, (unsigned)rc); } else { /* unmount the previous mounted image */ dvdDrive->vtbl->Unmount(dvdDrive); rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach the file to cdrom: %s, rc=%08x"), src, (unsigned)rc); } else { ret = 0; DEBUGIID("CD/DVD Image UUID:", dvduuid.value); } } VBOX_MEDIUM_RELEASE(dvdImage); } vboxIIDUnalloc(&dvduuid); VBOX_UTF16_FREE(dvdfileUtf16); VBOX_RELEASE(dvdDrive); } } else if (type == VIR_STORAGE_TYPE_BLOCK) { } } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { if (type == VIR_STORAGE_TYPE_FILE && src) { IFloppyDrive *floppyDrive; machine->vtbl->GetFloppyDrive(machine, &floppyDrive); if (floppyDrive) { rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1); if (NS_SUCCEEDED(rc)) { IFloppyImage *floppyImage = NULL; PRUnichar *fdfileUtf16 = NULL; vboxIID fduuid = VBOX_IID_INITIALIZER; vboxIID fdemptyuuid = VBOX_IID_INITIALIZER; VBOX_UTF8_TO_UTF16(src, &fdfileUtf16); rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj, fdfileUtf16, &floppyImage); if (!floppyImage) { data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj, fdfileUtf16, fdemptyuuid.value, &floppyImage); } if (floppyImage) { rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("can't get the uuid of the file to be " "attached to floppy drive: %s, rc=%08x"), src, (unsigned)rc); } else { rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach the file to floppy drive: %s, rc=%08x"), src, (unsigned)rc); } else { ret = 0; DEBUGIID("attached floppy, UUID:", fduuid.value); } } VBOX_MEDIUM_RELEASE(floppyImage); } vboxIIDUnalloc(&fduuid); VBOX_UTF16_FREE(fdfileUtf16); } VBOX_RELEASE(floppyDrive); } } else if (type == VIR_STORAGE_TYPE_BLOCK) { } } #else /* VBOX_API_VERSION >= 3001000 */ #endif /* VBOX_API_VERSION >= 3001000 */ } else if (dev->type == VIR_DOMAIN_DEVICE_NET) { } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) { if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { } } } else if (dev->type == VIR_DOMAIN_DEVICE_FS && dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) { PRUnichar *nameUtf16; PRUnichar *hostPathUtf16; PRBool writable; VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16); VBOX_UTF8_TO_UTF16(dev->data.fs->src, &hostPathUtf16); writable = !dev->data.fs->readonly; #if VBOX_API_VERSION < 4000000 rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16, writable); #else /* VBOX_API_VERSION >= 4000000 */ rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16, writable, PR_FALSE); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach shared folder '%s', rc=%08x"), dev->data.fs->dst, (unsigned)rc); } else { ret = 0; } VBOX_UTF16_FREE(nameUtf16); VBOX_UTF16_FREE(hostPathUtf16); } machine->vtbl->SaveSettings(machine); VBOX_RELEASE(machine); } VBOX_SESSION_CLOSE(); } } cleanup: vboxIIDUnalloc(&iid); virDomainDefFree(def); virDomainDeviceDefFree(dev); return ret; } static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) { return vboxDomainAttachDeviceImpl(dom, xml, 0); } static int vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml, unsigned int flags) { virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); if (flags & VIR_DOMAIN_AFFECT_CONFIG) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot modify the persistent configuration of a domain")); return -1; } return vboxDomainAttachDeviceImpl(dom, xml, 0); } static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml, unsigned int flags) { virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT | VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); if (flags & VIR_DOMAIN_AFFECT_CONFIG) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot modify the persistent configuration of a domain")); return -1; } return vboxDomainAttachDeviceImpl(dom, xml, 1); } static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; PRUint32 state = MachineState_Null; virDomainDefPtr def = NULL; virDomainDeviceDefPtr dev = NULL; nsresult rc; if (VIR_ALLOC(def) < 0) return ret; if (VIR_STRDUP(def->os.type, "hvm") < 0) goto cleanup; dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt, VIR_DOMAIN_XML_INACTIVE); if (dev == NULL) goto cleanup; vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); goto cleanup; } if (machine) { machine->vtbl->GetState(machine, &state); if ((state == MachineState_Running) || (state == MachineState_Paused)) { rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine); } else { rc = VBOX_SESSION_OPEN(iid.value, machine); } if (NS_SUCCEEDED(rc)) { rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine); if (NS_SUCCEEDED(rc) && machine) { if (dev->type == VIR_DOMAIN_DEVICE_DISK) { #if VBOX_API_VERSION < 3001000 int type = virDomainDiskGetType(dev->data.disk); if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { if (type == VIR_STORAGE_TYPE_FILE) { IDVDDrive *dvdDrive = NULL; /* Currently CDROM/DVD Drive is always IDE * Secondary Master so neglecting the following * parameter dev->data.disk->bus */ machine->vtbl->GetDVDDrive(machine, &dvdDrive); if (dvdDrive) { rc = dvdDrive->vtbl->Unmount(dvdDrive); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not de-attach the mounted ISO, rc=%08x"), (unsigned)rc); } else { ret = 0; } VBOX_RELEASE(dvdDrive); } } else if (type == VIR_STORAGE_TYPE_BLOCK) { } } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { if (type == VIR_STORAGE_TYPE_FILE) { IFloppyDrive *floppyDrive; machine->vtbl->GetFloppyDrive(machine, &floppyDrive); if (floppyDrive) { PRBool enabled = PR_FALSE; floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled); if (enabled) { rc = floppyDrive->vtbl->Unmount(floppyDrive); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not attach the file " "to floppy drive, rc=%08x"), (unsigned)rc); } else { ret = 0; } } else { /* If you are here means floppy drive is already unmounted * so don't flag error, just say everything is fine and quit */ ret = 0; } VBOX_RELEASE(floppyDrive); } } else if (type == VIR_STORAGE_TYPE_BLOCK) { } } #else /* VBOX_API_VERSION >= 3001000 */ #endif /* VBOX_API_VERSION >= 3001000 */ } else if (dev->type == VIR_DOMAIN_DEVICE_NET) { } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) { if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { } } } else if (dev->type == VIR_DOMAIN_DEVICE_FS && dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) { PRUnichar *nameUtf16; VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16); rc = machine->vtbl->RemoveSharedFolder(machine, nameUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not detach shared folder '%s', rc=%08x"), dev->data.fs->dst, (unsigned)rc); } else { ret = 0; } VBOX_UTF16_FREE(nameUtf16); } machine->vtbl->SaveSettings(machine); VBOX_RELEASE(machine); } VBOX_SESSION_CLOSE(); } } cleanup: vboxIIDUnalloc(&iid); virDomainDefFree(def); virDomainDeviceDefFree(dev); return ret; } static int vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml, unsigned int flags) { virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); if (flags & VIR_DOMAIN_AFFECT_CONFIG) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot modify the persistent configuration of a domain")); return -1; } return vboxDomainDetachDevice(dom, xml); } static int vboxDomainSnapshotGetAll(virDomainPtr dom, IMachine *machine, ISnapshot ***snapshots) { vboxIID empty = VBOX_IID_INITIALIZER; ISnapshot **list = NULL; PRUint32 count; nsresult rc; unsigned int next; unsigned int top; rc = machine->vtbl->GetSnapshotCount(machine, &count); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get snapshot count for domain %s"), dom->name); goto error; } if (count == 0) goto out; if (VIR_ALLOC_N(list, count) < 0) goto error; #if VBOX_API_VERSION < 4000000 rc = machine->vtbl->GetSnapshot(machine, empty.value, list); #else /* VBOX_API_VERSION >= 4000000 */ rc = machine->vtbl->FindSnapshot(machine, empty.value, list); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_FAILED(rc) || !list[0]) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get root snapshot for domain %s"), dom->name); goto error; } /* BFS walk through snapshot tree */ top = 1; for (next = 0; next < count; next++) { vboxArray children = VBOX_ARRAY_INITIALIZER; size_t i; if (!list[next]) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected number of snapshots < %u"), count); goto error; } rc = vboxArrayGet(&children, list[next], list[next]->vtbl->GetChildren); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get children snapshots")); goto error; } for (i = 0; i < children.count; i++) { ISnapshot *child = children.items[i]; if (!child) continue; if (top == count) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected number of snapshots > %u"), count); vboxArrayRelease(&children); goto error; } VBOX_ADDREF(child); list[top++] = child; } vboxArrayRelease(&children); } out: *snapshots = list; return count; error: if (list) { for (next = 0; next < count; next++) VBOX_RELEASE(list[next]); } VIR_FREE(list); return -1; } static ISnapshot * vboxDomainSnapshotGet(vboxGlobalData *data, virDomainPtr dom, IMachine *machine, const char *name) { ISnapshot **snapshots = NULL; ISnapshot *snapshot = NULL; nsresult rc; int count = 0; size_t i; if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0) goto cleanup; for (i = 0; i < count; i++) { PRUnichar *nameUtf16; char *nameUtf8; rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16); if (NS_FAILED(rc) || !nameUtf16) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get snapshot name")); goto cleanup; } VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); VBOX_UTF16_FREE(nameUtf16); if (STREQ(name, nameUtf8)) snapshot = snapshots[i]; VBOX_UTF8_FREE(nameUtf8); if (snapshot) break; } if (!snapshot) { virReportError(VIR_ERR_OPERATION_INVALID, _("domain %s has no snapshots with name %s"), dom->name, name); goto cleanup; } cleanup: if (count > 0) { for (i = 0; i < count; i++) { if (snapshots[i] != snapshot) VBOX_RELEASE(snapshots[i]); } } VIR_FREE(snapshots); return snapshot; } #if VBOX_API_VERSION >= 4002000 static int vboxCloseDisksRecursively(virDomainPtr dom, char *location) { VBOX_OBJECT_CHECK(dom->conn, int, -1); nsresult rc; size_t i = 0; PRUnichar *locationUtf = NULL; IMedium *medium = NULL; IMedium **children = NULL; PRUint32 childrenSize = 0; VBOX_UTF8_TO_UTF16(location, &locationUtf); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf, DeviceType_HardDisk, AccessMode_ReadWrite, false, &medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } rc = medium->vtbl->GetChildren(medium, &childrenSize, &children); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s" , _("Unable to get disk children")); goto cleanup; } for (i = 0; i < childrenSize; i++) { IMedium *childMedium = children[i]; if (childMedium) { PRUnichar *childLocationUtf = NULL; char *childLocation = NULL; rc = childMedium->vtbl->GetLocation(childMedium, &childLocationUtf); VBOX_UTF16_TO_UTF8(childLocationUtf, &childLocation); VBOX_UTF16_FREE(childLocationUtf); if (vboxCloseDisksRecursively(dom, childLocation) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s" , _("Unable to close disk children")); goto cleanup; } VIR_FREE(childLocation); } } rc = medium->vtbl->Close(medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to close HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } ret = 0; cleanup: VBOX_UTF16_FREE(locationUtf); return ret; } static int vboxSnapshotRedefine(virDomainPtr dom, virDomainSnapshotDefPtr def, bool isCurrent) { /* * If your snapshot has a parent, * it will only be redefined if you have already * redefined the parent. * * The general algorithm of this function is below : * First of all, we are going to create our vboxSnapshotXmlMachinePtr struct from * the machine settings path. * Then, if the machine current snapshot xml file is saved in the machine location, * it means that this snapshot was previously modified by us and has fake disks. * Fake disks are added when the flag VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT was not set * yet, in order to not corrupt read-only disks. The first thing to do is to remove those * disks and restore the read-write disks, if any, in the vboxSnapshotXmlMachinePtr struct. * We also delete the current snapshot xml file. * * After that, we are going to register the snapshot read-only disks that we want to redefine, * if they are not in the media registry struct. * * The next step is to unregister the machine and close all disks. * * Then, we check if the flag VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE has already been set. * If this flag was set, we just add read-write disks to the media registry * struct. Otherwise, we save the snapshot xml file into the machine location in order * to recover the read-write disks during the next redefine and we create differential disks * from the snapshot read-only disks and add them to the media registry struct. * * Finally, we register the machine with the new virtualbox description file. */ VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID domiid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; nsresult rc; PRUnichar *settingsFilePath = NULL; char *settingsFilePath_Utf8 = NULL; virVBoxSnapshotConfMachinePtr snapshotMachineDesc = NULL; char *currentSnapshotXmlFilePath = NULL; PRUnichar *machineNameUtf16 = NULL; char *machineName = NULL; char **realReadWriteDisksPath = NULL; int realReadWriteDisksPathSize = 0; char **realReadOnlyDisksPath = NULL; int realReadOnlyDisksPathSize = 0; virVBoxSnapshotConfSnapshotPtr newSnapshotPtr = NULL; unsigned char snapshotUuid[VIR_UUID_BUFLEN]; int it = 0; int jt = 0; PRUint32 aMediaSize = 0; IMedium **aMedia = NULL; char *machineLocationPath = NULL; char *nameTmpUse = NULL; bool snapshotFileExists = false; bool needToChangeStorageController = false; vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } rc = machine->vtbl->SaveSettings(machine); /*It may failed when the machine is not mutable.*/ rc = machine->vtbl->GetSettingsFilePath(machine, &settingsFilePath); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get settings file path")); goto cleanup; } VBOX_UTF16_TO_UTF8(settingsFilePath, &settingsFilePath_Utf8); /*Getting the machine name to retrieve the machine location path.*/ rc = machine->vtbl->GetName(machine, &machineNameUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get machine name")); goto cleanup; } VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); if (virAsprintf(&nameTmpUse, "%s.vbox", machineName) < 0) goto cleanup; machineLocationPath = virStringReplace(settingsFilePath_Utf8, nameTmpUse, ""); if (machineLocationPath == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get the machine location path")); goto cleanup; } /*We create the xml struct with the settings file path.*/ snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilePath_Utf8, machineLocationPath); if (snapshotMachineDesc == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot create a vboxSnapshotXmlPtr")); goto cleanup; } if (snapshotMachineDesc->currentSnapshot != NULL) { if (virAsprintf(¤tSnapshotXmlFilePath, "%s%s.xml", machineLocationPath, snapshotMachineDesc->currentSnapshot) < 0) goto cleanup; snapshotFileExists = virFileExists(currentSnapshotXmlFilePath); } if (snapshotFileExists) { /* * We have created fake disks, so we have to remove them and replace them with * the read-write disks if there are any. The fake disks will be closed during * the machine unregistration. */ if (virVBoxSnapshotConfRemoveFakeDisks(snapshotMachineDesc) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to remove Fake Disks")); goto cleanup; } realReadWriteDisksPathSize = virVBoxSnapshotConfGetRWDisksPathsFromLibvirtXML(currentSnapshotXmlFilePath, &realReadWriteDisksPath); realReadOnlyDisksPathSize = virVBoxSnapshotConfGetRODisksPathsFromLibvirtXML(currentSnapshotXmlFilePath, &realReadOnlyDisksPath); /*The read-only disk number is necessarily greater or equal to the *read-write disk number*/ if (realReadOnlyDisksPathSize < realReadWriteDisksPathSize) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("The read only disk number must be greater or equal to the " " read write disk number")); goto cleanup; } for (it = 0; it < realReadWriteDisksPathSize; it++) { virVBoxSnapshotConfHardDiskPtr readWriteDisk = NULL; PRUnichar *locationUtf = NULL; IMedium *readWriteMedium = NULL; PRUnichar *uuidUtf = NULL; char *uuid = NULL; PRUnichar *formatUtf = NULL; char *format = NULL; const char *parentUuid = NULL; VBOX_UTF8_TO_UTF16(realReadWriteDisksPath[it], &locationUtf); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf, DeviceType_HardDisk, AccessMode_ReadWrite, false, &readWriteMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); VBOX_UTF16_FREE(locationUtf); goto cleanup; } VBOX_UTF16_FREE(locationUtf); rc = readWriteMedium->vtbl->GetId(readWriteMedium, &uuidUtf); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get the read write medium id")); goto cleanup; } VBOX_UTF16_TO_UTF8(uuidUtf, &uuid); VBOX_UTF16_FREE(uuidUtf); rc = readWriteMedium->vtbl->GetFormat(readWriteMedium, &formatUtf); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get the read write medium format")); VIR_FREE(uuid); goto cleanup; } VBOX_UTF16_TO_UTF8(formatUtf, &format); VBOX_UTF16_FREE(formatUtf); if (VIR_ALLOC(readWriteDisk) < 0) { VIR_FREE(uuid); VIR_FREE(formatUtf); goto cleanup; } readWriteDisk->format = format; readWriteDisk->uuid = uuid; readWriteDisk->location = realReadWriteDisksPath[it]; /* * We get the current snapshot's read-only disk uuid in order to add the * read-write disk to the media registry as it's child. The read-only disk * is already in the media registry because it is the fake disk's parent. */ parentUuid = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, realReadOnlyDisksPath[it]); if (parentUuid == NULL) { VIR_FREE(readWriteDisk); goto cleanup; } if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readWriteDisk, snapshotMachineDesc->mediaRegistry, parentUuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to add hard disk to media Registry")); VIR_FREE(readWriteDisk); goto cleanup; } rc = readWriteMedium->vtbl->Close(readWriteMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to close HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } } /* * Now we have done this swap, we remove the snapshot xml file from the * current machine location. */ if (unlink(currentSnapshotXmlFilePath) < 0) { virReportSystemError(errno, _("Unable to delete file %s"), currentSnapshotXmlFilePath); goto cleanup; } } /* * Before unregistering the machine, while all disks are still open, ensure that all * read-only disks are in the redefined snapshot's media registry (the disks need to * be open to query their uuid). */ for (it = 0; it < def->dom->ndisks; it++) { int diskInMediaRegistry = 0; IMedium *readOnlyMedium = NULL; PRUnichar *locationUtf = NULL; PRUnichar *uuidUtf = NULL; char *uuid = NULL; PRUnichar *formatUtf = NULL; char *format = NULL; PRUnichar *parentUuidUtf = NULL; char *parentUuid = NULL; virVBoxSnapshotConfHardDiskPtr readOnlyDisk = NULL; diskInMediaRegistry = virVBoxSnapshotConfDiskIsInMediaRegistry(snapshotMachineDesc, def->dom->disks[it]->src->path); if (diskInMediaRegistry == -1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to know if disk is in media registry")); goto cleanup; } if (diskInMediaRegistry == 1) /*Nothing to do.*/ continue; /*The read only disk is not in the media registry*/ VBOX_UTF8_TO_UTF16(def->dom->disks[it]->src->path, &locationUtf); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf, DeviceType_HardDisk, AccessMode_ReadWrite, false, &readOnlyMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); VBOX_UTF16_FREE(locationUtf); goto cleanup; } VBOX_UTF16_FREE(locationUtf); rc = readOnlyMedium->vtbl->GetId(readOnlyMedium, &uuidUtf); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get hard disk id")); goto cleanup; } VBOX_UTF16_TO_UTF8(uuidUtf, &uuid); VBOX_UTF16_FREE(uuidUtf); rc = readOnlyMedium->vtbl->GetFormat(readOnlyMedium, &formatUtf); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get hard disk format")); VIR_FREE(uuid); goto cleanup; } VBOX_UTF16_TO_UTF8(formatUtf, &format); VBOX_UTF16_FREE(formatUtf); /*This disk is already in the media registry*/ IMedium *parentReadOnlyMedium = NULL; rc = readOnlyMedium->vtbl->GetParent(readOnlyMedium, &parentReadOnlyMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get parent hard disk")); VIR_FREE(uuid); goto cleanup; } rc = parentReadOnlyMedium->vtbl->GetId(parentReadOnlyMedium, &parentUuidUtf); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to get hard disk id, rc=%08x"), (unsigned)rc); VIR_FREE(uuid); goto cleanup; } VBOX_UTF16_TO_UTF8(parentUuidUtf, &parentUuid); VBOX_UTF16_FREE(parentUuidUtf); rc = readOnlyMedium->vtbl->Close(readOnlyMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to close HardDisk, rc=%08x"), (unsigned)rc); VIR_FREE(uuid); VIR_FREE(parentUuid); goto cleanup; } if (VIR_ALLOC(readOnlyDisk) < 0) { VIR_FREE(uuid); VIR_FREE(parentUuid); goto cleanup; } readOnlyDisk->format = format; readOnlyDisk->uuid = uuid; if (VIR_STRDUP(readOnlyDisk->location, def->dom->disks[it]->src->path) < 0) { VIR_FREE(readOnlyDisk); goto cleanup; } if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readOnlyDisk, snapshotMachineDesc->mediaRegistry, parentUuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to add hard disk to media registry")); VIR_FREE(readOnlyDisk); goto cleanup; } } /*Now, we can unregister the machine*/ rc = machine->vtbl->Unregister(machine, CleanupMode_DetachAllReturnHardDisksOnly, &aMediaSize, &aMedia); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to unregister machine, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_RELEASE(machine); /* * Unregister the machine, and then close all disks returned by the unregister method. * Some close operations will fail because some disks that need to be closed will not * be returned by virtualbox. We will close them just after. We have to use this * solution because it is the only way to delete fake disks. */ for (it = 0; it < aMediaSize; it++) { IMedium *medium = aMedia[it]; if (medium) { PRUnichar *locationUtf16 = NULL; char *locationUtf8 = NULL; rc = medium->vtbl->GetLocation(medium, &locationUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get medium location")); goto cleanup; } VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8); VBOX_UTF16_FREE(locationUtf16); if (strstr(locationUtf8, "fake") != NULL) { /*we delete the fake disk because we don't need it anymore*/ IProgress *progress = NULL; PRInt32 resultCode = -1; rc = medium->vtbl->DeleteStorage(medium, &progress); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to delete medium, rc=%08x"), (unsigned)rc); VIR_FREE(locationUtf8); goto cleanup; } progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &resultCode); if (NS_FAILED(resultCode)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Error while closing medium, rc=%08x"), (unsigned)resultCode); VIR_FREE(locationUtf8); goto cleanup; } VBOX_RELEASE(progress); } else { /* * This a comment from vboxmanage code in the handleUnregisterVM * function in VBoxManageMisc.cpp : * Note that the IMachine::Unregister method will return the medium * reference in a sane order, which means that closing will normally * succeed, unless there is still another machine which uses the * medium. No harm done if we ignore the error. */ rc = medium->vtbl->Close(medium); } VBOX_UTF8_FREE(locationUtf8); } } /*Close all disks that failed to close normally.*/ for (it = 0; it < snapshotMachineDesc->mediaRegistry->ndisks; it++) { if (vboxCloseDisksRecursively(dom, snapshotMachineDesc->mediaRegistry->disks[it]->location) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to close recursively all disks")); goto cleanup; } } /*Here, all disks are closed or deleted*/ /*We are now going to create and fill the Snapshot xml struct*/ if (VIR_ALLOC(newSnapshotPtr) < 0) goto cleanup; if (virUUIDGenerate(snapshotUuid) < 0) goto cleanup; char uuidtmp[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(snapshotUuid, uuidtmp); if (VIR_STRDUP(newSnapshotPtr->uuid, uuidtmp) < 0) goto cleanup; VIR_DEBUG("New snapshot UUID: %s", newSnapshotPtr->uuid); if (VIR_STRDUP(newSnapshotPtr->name, def->name) < 0) goto cleanup; newSnapshotPtr->timeStamp = virTimeStringThen(def->creationTime * 1000); if (VIR_STRDUP(newSnapshotPtr->description, def->description) < 0) goto cleanup; if (VIR_STRDUP(newSnapshotPtr->hardware, snapshotMachineDesc->hardware) < 0) goto cleanup; if (VIR_STRDUP(newSnapshotPtr->storageController, snapshotMachineDesc->storageController) < 0) goto cleanup; /*We get the parent disk uuid from the parent disk location to correctly fill the storage controller.*/ for (it = 0; it < def->dom->ndisks; it++) { char *location = NULL; const char *uuidReplacing = NULL; char **searchResultTab = NULL; ssize_t resultSize = 0; char *tmp = NULL; location = def->dom->disks[it]->src->path; if (!location) goto cleanup; /*Replacing the uuid*/ uuidReplacing = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, location); if (uuidReplacing == NULL) goto cleanup; resultSize = virStringSearch(newSnapshotPtr->storageController, VBOX_UUID_REGEX, it + 1, &searchResultTab); if (resultSize != it + 1) goto cleanup; tmp = virStringReplace(newSnapshotPtr->storageController, searchResultTab[it], uuidReplacing); virStringFreeList(searchResultTab); VIR_FREE(newSnapshotPtr->storageController); if (!tmp) goto cleanup; if (VIR_STRDUP(newSnapshotPtr->storageController, tmp) < 0) goto cleanup; VIR_FREE(tmp); } if (virVBoxSnapshotConfAddSnapshotToXmlMachine(newSnapshotPtr, snapshotMachineDesc, def->parent) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to add the snapshot to the machine description")); goto cleanup; } /* * We change the current snapshot only if there is no current snapshot or if the * snapshotFile exists, otherwise, it means that the correct current snapshot is * already set. */ if (snapshotMachineDesc->currentSnapshot == NULL || snapshotFileExists) { snapshotMachineDesc->currentSnapshot = newSnapshotPtr->uuid; needToChangeStorageController = true; } /* * Open the snapshot's read-write disk's full ancestry to allow opening the * read-write disk itself. */ for (it = 0; it < def->dom->ndisks; it++) { char *location = NULL; virVBoxSnapshotConfHardDiskPtr *hardDiskToOpen = NULL; size_t hardDiskToOpenSize = 0; location = def->dom->disks[it]->src->path; if (!location) goto cleanup; hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc, &hardDiskToOpen, location); for (jt = hardDiskToOpenSize -1; jt >= 0; jt--) { IMedium *medium = NULL; PRUnichar *locationUtf16 = NULL; VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->location, &locationUtf16); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf16, DeviceType_HardDisk, AccessMode_ReadWrite, false, &medium); VBOX_UTF16_FREE(locationUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } } } if (isCurrent || !needToChangeStorageController) { /* We don't create a differential hard disk because either the current snapshot * has already been defined or the snapshot to redefine is the current snapshot. * If the snapshot to redefine is the current snapshot, we add read-write disks in * the machine storage controllers. */ for (it = 0; it < def->ndisks; it++) { IMedium *medium = NULL; PRUnichar *locationUtf16 = NULL; virVBoxSnapshotConfHardDiskPtr disk = NULL; PRUnichar *formatUtf16 = NULL; char *format = NULL; PRUnichar *uuidUtf16 = NULL; char *uuid = NULL; IMedium *parentDisk = NULL; PRUnichar *parentUuidUtf16 = NULL; char *parentUuid = NULL; VBOX_UTF8_TO_UTF16(def->disks[it].src->path, &locationUtf16); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf16, DeviceType_HardDisk, AccessMode_ReadWrite, false, &medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_UTF16_FREE(locationUtf16); if (VIR_ALLOC(disk) < 0) goto cleanup; rc = medium->vtbl->GetFormat(medium, &formatUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get disk format")); VIR_FREE(disk); goto cleanup; } VBOX_UTF16_TO_UTF8(formatUtf16, &format); disk->format = format; VBOX_UTF16_FREE(formatUtf16); if (VIR_STRDUP(disk->location, def->disks[it].src->path) < 0) { VIR_FREE(disk); goto cleanup; } rc = medium->vtbl->GetId(medium, &uuidUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get disk uuid")); VIR_FREE(disk); goto cleanup; } VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid); disk->uuid = uuid; VBOX_UTF16_FREE(uuidUtf16); rc = medium->vtbl->GetParent(medium, &parentDisk); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get disk parent")); VIR_FREE(disk); goto cleanup; } parentDisk->vtbl->GetId(parentDisk, &parentUuidUtf16); VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid); VBOX_UTF16_FREE(parentUuidUtf16); if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk, snapshotMachineDesc->mediaRegistry, parentUuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to add hard disk to the media registry")); VIR_FREE(disk); goto cleanup; } if (needToChangeStorageController) { /*We need to append this disk in the storage controller*/ char **searchResultTab = NULL; ssize_t resultSize = 0; char *tmp = NULL; resultSize = virStringSearch(snapshotMachineDesc->storageController, VBOX_UUID_REGEX, it + 1, &searchResultTab); if (resultSize != it + 1) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find UUID %s"), searchResultTab[it]); goto cleanup; } tmp = virStringReplace(snapshotMachineDesc->storageController, searchResultTab[it], disk->uuid); virStringFreeList(searchResultTab); VIR_FREE(snapshotMachineDesc->storageController); if (!tmp) goto cleanup; if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) goto cleanup; VIR_FREE(tmp); } /*Close disk*/ rc = medium->vtbl->Close(medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to close HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } } } else { /*Create a "fake" disk to avoid corrupting children snapshot disks.*/ for (it = 0; it < def->dom->ndisks; it++) { IMedium *medium = NULL; PRUnichar *locationUtf16 = NULL; PRUnichar *parentUuidUtf16 = NULL; char *parentUuid = NULL; IMedium *newMedium = NULL; PRUnichar *formatUtf16 = NULL; PRUnichar *newLocation = NULL; char *newLocationUtf8 = NULL; PRInt32 resultCode = -1; virVBoxSnapshotConfHardDiskPtr disk = NULL; PRUnichar *uuidUtf16 = NULL; char *uuid = NULL; char *format = NULL; char **searchResultTab = NULL; ssize_t resultSize = 0; char *tmp = NULL; VBOX_UTF8_TO_UTF16(def->dom->disks[it]->src->path, &locationUtf16); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf16, DeviceType_HardDisk, AccessMode_ReadWrite, false, &medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); VBOX_UTF16_FREE(locationUtf16); goto cleanup; } VBOX_UTF16_FREE(locationUtf16); rc = medium->vtbl->GetId(medium, &parentUuidUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to get hardDisk Id, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid); VBOX_UTF16_FREE(parentUuidUtf16); VBOX_UTF8_TO_UTF16("VDI", &formatUtf16); if (virAsprintf(&newLocationUtf8, "%sfakedisk-%d.vdi", machineLocationPath, it) < 0) goto cleanup; VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation); rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, formatUtf16, newLocation, &newMedium); VBOX_UTF16_FREE(newLocation); VBOX_UTF16_FREE(formatUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to create HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } IProgress *progress = NULL; # if VBOX_API_VERSION < 4003000 medium->vtbl->CreateDiffStorage(medium, newMedium, MediumVariant_Diff, &progress); # else PRUint32 tab[1]; tab[0] = MediumVariant_Diff; medium->vtbl->CreateDiffStorage(medium, newMedium, 1, tab, &progress); # endif progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &resultCode); if (NS_FAILED(resultCode)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Error while creating diff storage, rc=%08x"), (unsigned)resultCode); goto cleanup; } VBOX_RELEASE(progress); /* * The differential disk is created, we add it to the media registry and the * machine storage controllers. */ if (VIR_ALLOC(disk) < 0) goto cleanup; rc = newMedium->vtbl->GetId(newMedium, &uuidUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to get medium uuid, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid); disk->uuid = uuid; VBOX_UTF16_FREE(uuidUtf16); if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) goto cleanup; rc = newMedium->vtbl->GetFormat(newMedium, &formatUtf16); VBOX_UTF16_TO_UTF8(formatUtf16, &format); disk->format = format; VBOX_UTF16_FREE(formatUtf16); if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk, snapshotMachineDesc->mediaRegistry, parentUuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to add hard disk to the media registry")); goto cleanup; } /*Adding the fake disk to the machine storage controllers*/ resultSize = virStringSearch(snapshotMachineDesc->storageController, VBOX_UUID_REGEX, it + 1, &searchResultTab); if (resultSize != it + 1) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find UUID %s"), searchResultTab[it]); goto cleanup; } tmp = virStringReplace(snapshotMachineDesc->storageController, searchResultTab[it], disk->uuid); virStringFreeList(searchResultTab); VIR_FREE(snapshotMachineDesc->storageController); if (!tmp) goto cleanup; if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) goto cleanup; VIR_FREE(tmp); /*Closing the "fake" disk*/ rc = newMedium->vtbl->Close(newMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to close the new medium, rc=%08x"), (unsigned)rc); goto cleanup; } } /* * We save the snapshot xml file to retrieve the real read-write disk during the * next define. This file is saved as "'machineLocation'/snapshot-'uuid'.xml" */ VIR_FREE(currentSnapshotXmlFilePath); if (virAsprintf(¤tSnapshotXmlFilePath, "%s%s.xml", machineLocationPath, snapshotMachineDesc->currentSnapshot) < 0) goto cleanup; char *snapshotContent = virDomainSnapshotDefFormat(NULL, def, VIR_DOMAIN_XML_SECURE, 0); if (snapshotContent == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get snapshot content")); goto cleanup; } if (virFileWriteStr(currentSnapshotXmlFilePath, snapshotContent, 0644) < 0) { virReportSystemError(errno, "%s", _("Unable to save new snapshot xml file")); goto cleanup; } VIR_FREE(snapshotContent); } /* * All the snapshot structure manipulation is done, we close the disks we have * previously opened. */ for (it = 0; it < def->dom->ndisks; it++) { char *location = def->dom->disks[it]->src->path; if (!location) goto cleanup; virVBoxSnapshotConfHardDiskPtr *hardDiskToOpen = NULL; size_t hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc, &hardDiskToOpen, location); for (jt = 0; jt < hardDiskToOpenSize; jt++) { IMedium *medium = NULL; PRUnichar *locationUtf16 = NULL; VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->location, &locationUtf16); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf16, DeviceType_HardDisk, AccessMode_ReadWrite, false, &medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } rc = medium->vtbl->Close(medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to close HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_UTF16_FREE(locationUtf16); } } /*Now, we rewrite the 'machineName'.vbox file to redefine the machine.*/ if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilePath_Utf8) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to serialize the machine description")); goto cleanup; } rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj, settingsFilePath, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open Machine, rc=%08x"), (unsigned)rc); goto cleanup; } rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to register Machine, rc=%08x"), (unsigned)rc); goto cleanup; } ret = 0; cleanup: VBOX_RELEASE(machine); VBOX_UTF16_FREE(settingsFilePath); VBOX_UTF8_FREE(settingsFilePath_Utf8); VIR_FREE(snapshotMachineDesc); VIR_FREE(currentSnapshotXmlFilePath); VBOX_UTF16_FREE(machineNameUtf16); VBOX_UTF8_FREE(machineName); virStringFreeList(realReadOnlyDisksPath); virStringFreeList(realReadWriteDisksPath); VIR_FREE(newSnapshotPtr); VIR_FREE(machineLocationPath); VIR_FREE(nameTmpUse); return ret; } #endif static virDomainSnapshotPtr vboxDomainSnapshotCreateXML(virDomainPtr dom, const char *xmlDesc, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL); virDomainSnapshotDefPtr def = NULL; vboxIID domiid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; IConsole *console = NULL; IProgress *progress = NULL; ISnapshot *snapshot = NULL; PRUnichar *name = NULL; PRUnichar *description = NULL; PRUint32 state; nsresult rc; #if VBOX_API_VERSION == 2002000 nsresult result; #else PRInt32 result; #endif #if VBOX_API_VERSION >= 4002000 bool isCurrent = false; #endif /* VBox has no snapshot metadata, so this flag is trivial. */ virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA | VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE | VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT, NULL); if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps, data->xmlopt, -1, VIR_DOMAIN_SNAPSHOT_PARSE_DISKS | VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE))) goto cleanup; vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } #if VBOX_API_VERSION >= 4002000 isCurrent = flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT; if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) { if (vboxSnapshotRedefine(dom, def, isCurrent) < 0) goto cleanup; ret = virGetDomainSnapshot(dom, def->name); goto cleanup; } #endif rc = machine->vtbl->GetState(machine, &state); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get domain state")); goto cleanup; } if ((state >= MachineState_FirstOnline) && (state <= MachineState_LastOnline)) { rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine); } else { rc = VBOX_SESSION_OPEN(domiid.value, machine); } if (NS_SUCCEEDED(rc)) rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not open VirtualBox session with domain %s"), dom->name); goto cleanup; } VBOX_UTF8_TO_UTF16(def->name, &name); if (!name) { virReportOOMError(); goto cleanup; } if (def->description) { VBOX_UTF8_TO_UTF16(def->description, &description); if (!description) { virReportOOMError(); goto cleanup; } } rc = console->vtbl->TakeSnapshot(console, name, description, &progress); if (NS_FAILED(rc) || !progress) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not take snapshot of domain %s"), dom->name); goto cleanup; } progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &result); if (NS_FAILED(result)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not take snapshot of domain %s"), dom->name); goto cleanup; } rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get current snapshot of domain %s"), dom->name); goto cleanup; } ret = virGetDomainSnapshot(dom, def->name); cleanup: VBOX_RELEASE(progress); VBOX_UTF16_FREE(description); VBOX_UTF16_FREE(name); VBOX_RELEASE(console); VBOX_SESSION_CLOSE(); VBOX_RELEASE(machine); vboxIIDUnalloc(&domiid); virDomainSnapshotDefFree(def); return ret; } #if VBOX_API_VERSION >=4002000 static int vboxSnapshotGetReadWriteDisks(virDomainSnapshotDefPtr def, virDomainSnapshotPtr snapshot) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID domiid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snap = NULL; IMachine *snapMachine = NULL; vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; int diskCount = 0; nsresult rc; vboxIID snapIid = VBOX_IID_INITIALIZER; char *snapshotUuidStr = NULL; size_t i = 0; vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no domain with matching UUID")); goto cleanup; } if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) goto cleanup; rc = snap->vtbl->GetId(snap, &snapIid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get snapshot id")); goto cleanup; } VBOX_UTF16_TO_UTF8(snapIid.value, &snapshotUuidStr); rc = snap->vtbl->GetMachine(snap, &snapMachine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get machine")); goto cleanup; } def->ndisks = 0; rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no medium attachments")); goto cleanup; } /* get the number of attachments */ for (i = 0; i < mediumAttachments.count; i++) { IMediumAttachment *imediumattach = mediumAttachments.items[i]; if (imediumattach) { IMedium *medium = NULL; rc = imediumattach->vtbl->GetMedium(imediumattach, &medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium")); goto cleanup; } if (medium) { def->ndisks++; VBOX_RELEASE(medium); } } } /* Allocate mem, if fails return error */ if (VIR_ALLOC_N(def->disks, def->ndisks) < 0) goto cleanup; for (i = 0; i < def->ndisks; i++) { if (VIR_ALLOC(def->disks[i].src) < 0) goto cleanup; } if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort)) goto cleanup; /* get the attachment details here */ for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks; i++) { IStorageController *storageController = NULL; PRUnichar *storageControllerName = NULL; PRUint32 deviceType = DeviceType_Null; PRUint32 storageBus = StorageBus_Null; IMedium *disk = NULL; PRUnichar *childLocUtf16 = NULL; char *childLocUtf8 = NULL; PRUint32 deviceInst = 0; PRInt32 devicePort = 0; PRInt32 deviceSlot = 0; vboxArray children = VBOX_ARRAY_INITIALIZER; vboxArray snapshotIids = VBOX_ARRAY_INITIALIZER; IMediumAttachment *imediumattach = mediumAttachments.items[i]; size_t j = 0; size_t k = 0; if (!imediumattach) continue; rc = imediumattach->vtbl->GetMedium(imediumattach, &disk); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium")); goto cleanup; } if (!disk) continue; rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get controller")); goto cleanup; } if (!storageControllerName) { VBOX_RELEASE(disk); continue; } rc = vboxArrayGet(&children, disk, disk->vtbl->GetChildren); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get children disk")); goto cleanup; } rc = vboxArrayGetWithPtrArg(&snapshotIids, disk, disk->vtbl->GetSnapshotIds, domiid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get snapshot ids")); goto cleanup; } for (j = 0; j < children.count; ++j) { IMedium *child = children.items[j]; for (k = 0; k < snapshotIids.count; ++k) { PRUnichar *diskSnapId = snapshotIids.items[k]; char *diskSnapIdStr = NULL; VBOX_UTF16_TO_UTF8(diskSnapId, &diskSnapIdStr); if (STREQ(diskSnapIdStr, snapshotUuidStr)) { rc = machine->vtbl->GetStorageControllerByName(machine, storageControllerName, &storageController); VBOX_UTF16_FREE(storageControllerName); if (!storageController) { VBOX_RELEASE(child); break; } rc = child->vtbl->GetLocation(child, &childLocUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get disk location")); goto cleanup; } VBOX_UTF16_TO_UTF8(childLocUtf16, &childLocUtf8); VBOX_UTF16_FREE(childLocUtf16); if (VIR_STRDUP(def->disks[diskCount].src->path, childLocUtf8) < 0) { VBOX_RELEASE(child); VBOX_RELEASE(storageController); goto cleanup; } VBOX_UTF8_FREE(childLocUtf8); rc = storageController->vtbl->GetBus(storageController, &storageBus); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get storage controller bus")); goto cleanup; } rc = imediumattach->vtbl->GetType(imediumattach, &deviceType); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium attachment type")); goto cleanup; } rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium attachment type")); goto cleanup; } rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium attachment device")); goto cleanup; } def->disks[diskCount].src->type = VIR_STORAGE_TYPE_FILE; def->disks[diskCount].name = vboxGenerateMediumName(storageBus, deviceInst, devicePort, deviceSlot, maxPortPerInst, maxSlotPerPort); } VBOX_UTF8_FREE(diskSnapIdStr); } } VBOX_RELEASE(storageController); VBOX_RELEASE(disk); diskCount++; } vboxArrayRelease(&mediumAttachments); ret = 0; cleanup: if (ret < 0) { for (i = 0; i < def->ndisks; i++) { VIR_FREE(def->disks[i].src); } VIR_FREE(def->disks); def->ndisks = 0; } VBOX_RELEASE(snap); return ret; } static int vboxSnapshotGetReadOnlyDisks(virDomainSnapshotPtr snapshot, virDomainSnapshotDefPtr def) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID domiid = VBOX_IID_INITIALIZER; ISnapshot *snap = NULL; IMachine *machine = NULL; IMachine *snapMachine = NULL; IStorageController *storageController = NULL; IMedium *disk = NULL; nsresult rc; vboxIIDFromUUID(&domiid, dom->uuid); vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; size_t i = 0; PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; int diskCount = 0; rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) goto cleanup; rc = snap->vtbl->GetMachine(snap, &snapMachine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get machine")); goto cleanup; } /* * Get READ ONLY disks * In the snapshot metadata, these are the disks written inside the node */ rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium attachments")); goto cleanup; } /* get the number of attachments */ for (i = 0; i < mediumAttachments.count; i++) { IMediumAttachment *imediumattach = mediumAttachments.items[i]; if (imediumattach) { IMedium *medium = NULL; rc = imediumattach->vtbl->GetMedium(imediumattach, &medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium")); goto cleanup; } if (medium) { def->dom->ndisks++; VBOX_RELEASE(medium); } } } /* Allocate mem, if fails return error */ if (VIR_ALLOC_N(def->dom->disks, def->dom->ndisks) >= 0) { for (i = 0; i < def->dom->ndisks; i++) { virDomainDiskDefPtr diskDef = virDomainDiskDefNew(); if (!diskDef) goto cleanup; def->dom->disks[i] = diskDef; } } else { goto cleanup; } if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort)) goto cleanup; /* get the attachment details here */ for (i = 0; i < mediumAttachments.count && diskCount < def->dom->ndisks; i++) { PRUnichar *storageControllerName = NULL; PRUint32 deviceType = DeviceType_Null; PRUint32 storageBus = StorageBus_Null; PRBool readOnly = PR_FALSE; PRUnichar *mediumLocUtf16 = NULL; char *mediumLocUtf8 = NULL; PRUint32 deviceInst = 0; PRInt32 devicePort = 0; PRInt32 deviceSlot = 0; IMediumAttachment *imediumattach = mediumAttachments.items[i]; if (!imediumattach) continue; rc = imediumattach->vtbl->GetMedium(imediumattach, &disk); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium")); goto cleanup; } if (!disk) continue; rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get storage controller name")); goto cleanup; } if (!storageControllerName) continue; rc = machine->vtbl->GetStorageControllerByName(machine, storageControllerName, &storageController); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get storage controller")); goto cleanup; } VBOX_UTF16_FREE(storageControllerName); if (!storageController) continue; rc = disk->vtbl->GetLocation(disk, &mediumLocUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get disk location")); goto cleanup; } VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8); VBOX_UTF16_FREE(mediumLocUtf16); if (VIR_STRDUP(def->dom->disks[diskCount]->src->path, mediumLocUtf8) < 0) goto cleanup; VBOX_UTF8_FREE(mediumLocUtf8); rc = storageController->vtbl->GetBus(storageController, &storageBus); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get storage controller bus")); goto cleanup; } if (storageBus == StorageBus_IDE) { def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE; } else if (storageBus == StorageBus_SATA) { def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA; } else if (storageBus == StorageBus_SCSI) { def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI; } else if (storageBus == StorageBus_Floppy) { def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC; } rc = imediumattach->vtbl->GetType(imediumattach, &deviceType); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium attachment type")); goto cleanup; } if (deviceType == DeviceType_HardDisk) def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK; else if (deviceType == DeviceType_Floppy) def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; else if (deviceType == DeviceType_DVD) def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM; rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get medium attachment port")); goto cleanup; } rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get device")); goto cleanup; } rc = disk->vtbl->GetReadOnly(disk, &readOnly); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get read only attribute")); goto cleanup; } if (readOnly == PR_TRUE) def->dom->disks[diskCount]->src->readonly = true; def->dom->disks[diskCount]->src->type = VIR_STORAGE_TYPE_FILE; def->dom->disks[diskCount]->dst = vboxGenerateMediumName(storageBus, deviceInst, devicePort, deviceSlot, maxPortPerInst, maxSlotPerPort); if (!def->dom->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); ret = -1; goto cleanup; } diskCount ++; } /* cleanup on error */ ret = 0; cleanup: if (ret < 0) { for (i = 0; i < def->dom->ndisks; i++) virDomainDiskDefFree(def->dom->disks[i]); VIR_FREE(def->dom->disks); def->dom->ndisks = 0; } VBOX_RELEASE(disk); VBOX_RELEASE(storageController); vboxArrayRelease(&mediumAttachments); VBOX_RELEASE(snap); return ret; } #endif static char * vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, char *, NULL); vboxIID domiid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snap = NULL; ISnapshot *parent = NULL; nsresult rc; virDomainSnapshotDefPtr def = NULL; PRUnichar *str16; char *str8; PRInt64 timestamp; PRBool online = PR_FALSE; char uuidstr[VIR_UUID_STRING_BUFLEN]; #if VBOX_API_VERSION >=4002000 PRUint32 memorySize = 0; PRUint32 CPUCount = 0; #endif virCheckFlags(0, NULL); vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) goto cleanup; if (VIR_ALLOC(def) < 0 || VIR_ALLOC(def->dom) < 0) goto cleanup; if (VIR_STRDUP(def->name, snapshot->name) < 0) goto cleanup; #if VBOX_API_VERSION >=4002000 /* Register def->dom properties for them to be saved inside the snapshot XMl * Otherwise, there is a problem while parsing the xml */ def->dom->virtType = VIR_DOMAIN_VIRT_VBOX; def->dom->id = dom->id; memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); if (VIR_STRDUP(def->dom->name, dom->name) < 0) goto cleanup; machine->vtbl->GetMemorySize(machine, &memorySize); def->dom->mem.cur_balloon = memorySize * 1024; /* Currently setting memory and maxMemory as same, cause * the notation here seems to be inconsistent while * reading and while dumping xml */ def->dom->mem.max_balloon = memorySize * 1024; if (VIR_STRDUP(def->dom->os.type, "hvm") < 0) goto cleanup; def->dom->os.arch = virArchFromHost(); machine->vtbl->GetCPUCount(machine, &CPUCount); def->dom->maxvcpus = def->dom->vcpus = CPUCount; if (vboxSnapshotGetReadWriteDisks(def, snapshot) < 0) { VIR_DEBUG("Could not get read write disks for snapshot"); } if (vboxSnapshotGetReadOnlyDisks(snapshot, def) < 0) { VIR_DEBUG("Could not get Readonly disks for snapshot"); } #endif /* VBOX_API_VERSION >= 4002000 */ rc = snap->vtbl->GetDescription(snap, &str16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get description of snapshot %s"), snapshot->name); goto cleanup; } if (str16) { VBOX_UTF16_TO_UTF8(str16, &str8); VBOX_UTF16_FREE(str16); if (VIR_STRDUP(def->description, str8) < 0) { VBOX_UTF8_FREE(str8); goto cleanup; } VBOX_UTF8_FREE(str8); } rc = snap->vtbl->GetTimeStamp(snap, ×tamp); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get creation time of snapshot %s"), snapshot->name); goto cleanup; } /* timestamp is in milliseconds while creationTime in seconds */ def->creationTime = timestamp / 1000; rc = snap->vtbl->GetParent(snap, &parent); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get parent of snapshot %s"), snapshot->name); goto cleanup; } if (parent) { rc = parent->vtbl->GetName(parent, &str16); if (NS_FAILED(rc) || !str16) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get name of parent of snapshot %s"), snapshot->name); goto cleanup; } VBOX_UTF16_TO_UTF8(str16, &str8); VBOX_UTF16_FREE(str16); if (VIR_STRDUP(def->parent, str8) < 0) { VBOX_UTF8_FREE(str8); goto cleanup; } VBOX_UTF8_FREE(str8); } rc = snap->vtbl->GetOnline(snap, &online); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get online state of snapshot %s"), snapshot->name); goto cleanup; } if (online) def->state = VIR_DOMAIN_RUNNING; else def->state = VIR_DOMAIN_SHUTOFF; virUUIDFormat(dom->uuid, uuidstr); memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0); cleanup: virDomainSnapshotDefFree(def); VBOX_RELEASE(parent); VBOX_RELEASE(snap); VBOX_RELEASE(machine); vboxIIDUnalloc(&domiid); return ret; } static int vboxDomainSnapshotNum(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; nsresult rc; PRUint32 snapshotCount; virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS | VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } /* VBox snapshots do not require libvirt to maintain any metadata. */ if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) { ret = 0; goto cleanup; } rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get snapshot count for domain %s"), dom->name); goto cleanup; } /* VBox has at most one root snapshot. */ if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) ret = 1; else ret = snapshotCount; cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainSnapshotListNames(virDomainPtr dom, char **names, int nameslen, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; nsresult rc; ISnapshot **snapshots = NULL; int count = 0; size_t i; virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS | VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) { ret = 0; goto cleanup; } if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) { vboxIID empty = VBOX_IID_INITIALIZER; if (VIR_ALLOC_N(snapshots, 1) < 0) goto cleanup; #if VBOX_API_VERSION < 4000000 rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots); #else /* VBOX_API_VERSION >= 4000000 */ rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_FAILED(rc) || !snapshots[0]) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get root snapshot for domain %s"), dom->name); goto cleanup; } count = 1; } else { if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0) goto cleanup; } for (i = 0; i < nameslen; i++) { PRUnichar *nameUtf16; char *name; if (i >= count) break; rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16); if (NS_FAILED(rc) || !nameUtf16) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get snapshot name")); goto cleanup; } VBOX_UTF16_TO_UTF8(nameUtf16, &name); VBOX_UTF16_FREE(nameUtf16); if (VIR_STRDUP(names[i], name) < 0) { VBOX_UTF8_FREE(name); goto cleanup; } VBOX_UTF8_FREE(name); } if (count <= nameslen) ret = count; else ret = nameslen; cleanup: if (count > 0) { for (i = 0; i < count; i++) VBOX_RELEASE(snapshots[i]); } VIR_FREE(snapshots); VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static virDomainSnapshotPtr vboxDomainSnapshotLookupByName(virDomainPtr dom, const char *name, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snapshot = NULL; nsresult rc; virCheckFlags(0, NULL); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } if (!(snapshot = vboxDomainSnapshotGet(data, dom, machine, name))) goto cleanup; ret = virGetDomainSnapshot(dom, name); cleanup: VBOX_RELEASE(snapshot); VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainHasCurrentSnapshot(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snapshot = NULL; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get current snapshot")); goto cleanup; } if (snapshot) ret = 1; else ret = 0; cleanup: VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static virDomainSnapshotPtr vboxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snap = NULL; ISnapshot *parent = NULL; PRUnichar *nameUtf16 = NULL; char *name = NULL; nsresult rc; virCheckFlags(0, NULL); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) goto cleanup; rc = snap->vtbl->GetParent(snap, &parent); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get parent of snapshot %s"), snapshot->name); goto cleanup; } if (!parent) { virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, _("snapshot '%s' does not have a parent"), snapshot->name); goto cleanup; } rc = parent->vtbl->GetName(parent, &nameUtf16); if (NS_FAILED(rc) || !nameUtf16) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get name of parent of snapshot %s"), snapshot->name); goto cleanup; } VBOX_UTF16_TO_UTF8(nameUtf16, &name); if (!name) { virReportOOMError(); goto cleanup; } ret = virGetDomainSnapshot(dom, name); cleanup: VBOX_UTF8_FREE(name); VBOX_UTF16_FREE(nameUtf16); VBOX_RELEASE(snap); VBOX_RELEASE(parent); VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static virDomainSnapshotPtr vboxDomainSnapshotCurrent(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snapshot = NULL; PRUnichar *nameUtf16 = NULL; char *name = NULL; nsresult rc; virCheckFlags(0, NULL); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get current snapshot")); goto cleanup; } if (!snapshot) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("domain has no snapshots")); goto cleanup; } rc = snapshot->vtbl->GetName(snapshot, &nameUtf16); if (NS_FAILED(rc) || !nameUtf16) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get current snapshot name")); goto cleanup; } VBOX_UTF16_TO_UTF8(nameUtf16, &name); if (!name) { virReportOOMError(); goto cleanup; } ret = virGetDomainSnapshot(dom, name); cleanup: VBOX_UTF8_FREE(name); VBOX_UTF16_FREE(nameUtf16); VBOX_RELEASE(snapshot); VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snap = NULL; ISnapshot *current = NULL; PRUnichar *nameUtf16 = NULL; char *name = NULL; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) goto cleanup; rc = machine->vtbl->GetCurrentSnapshot(machine, ¤t); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get current snapshot")); goto cleanup; } if (!current) { ret = 0; goto cleanup; } rc = current->vtbl->GetName(current, &nameUtf16); if (NS_FAILED(rc) || !nameUtf16) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get current snapshot name")); goto cleanup; } VBOX_UTF16_TO_UTF8(nameUtf16, &name); if (!name) { virReportOOMError(); goto cleanup; } ret = STREQ(snapshot->name, name); cleanup: VBOX_UTF8_FREE(name); VBOX_UTF16_FREE(nameUtf16); VBOX_RELEASE(snap); VBOX_RELEASE(current); VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snap = NULL; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } /* Check that snapshot exists. If so, there is no metadata. */ if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) goto cleanup; ret = 0; cleanup: VBOX_RELEASE(snap); VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } #if VBOX_API_VERSION < 3001000 static int vboxDomainSnapshotRestore(virDomainPtr dom, IMachine *machine, ISnapshot *snapshot) { VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID iid = VBOX_IID_INITIALIZER; nsresult rc; rc = snapshot->vtbl->GetId(snapshot, &iid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get snapshot UUID")); goto cleanup; } rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not restore snapshot for domain %s"), dom->name); goto cleanup; } ret = 0; cleanup: vboxIIDUnalloc(&iid); return ret; } #else static int vboxDomainSnapshotRestore(virDomainPtr dom, IMachine *machine, ISnapshot *snapshot) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IConsole *console = NULL; IProgress *progress = NULL; PRUint32 state; nsresult rc; PRInt32 result; vboxIID domiid = VBOX_IID_INITIALIZER; rc = machine->vtbl->GetId(machine, &domiid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get domain UUID")); goto cleanup; } rc = machine->vtbl->GetState(machine, &state); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get domain state")); goto cleanup; } if (state >= MachineState_FirstOnline && state <= MachineState_LastOnline) { virReportError(VIR_ERR_OPERATION_INVALID, _("domain %s is already running"), dom->name); goto cleanup; } rc = VBOX_SESSION_OPEN(domiid.value, machine); if (NS_SUCCEEDED(rc)) rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not open VirtualBox session with domain %s"), dom->name); goto cleanup; } rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress); if (NS_FAILED(rc) || !progress) { if (rc == VBOX_E_INVALID_VM_STATE) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot restore domain snapshot for running domain")); } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not restore snapshot for domain %s"), dom->name); } goto cleanup; } progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &result); if (NS_FAILED(result)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not restore snapshot for domain %s"), dom->name); goto cleanup; } ret = 0; cleanup: VBOX_RELEASE(progress); VBOX_RELEASE(console); VBOX_SESSION_CLOSE(); vboxIIDUnalloc(&domiid); return ret; } #endif static int vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID domiid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *newSnapshot = NULL; ISnapshot *prevSnapshot = NULL; PRBool online = PR_FALSE; PRUint32 state; nsresult rc; virCheckFlags(0, -1); vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } newSnapshot = vboxDomainSnapshotGet(data, dom, machine, snapshot->name); if (!newSnapshot) goto cleanup; rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get online state of snapshot %s"), snapshot->name); goto cleanup; } rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get current snapshot of domain %s"), dom->name); goto cleanup; } rc = machine->vtbl->GetState(machine, &state); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get domain state")); goto cleanup; } if (state >= MachineState_FirstOnline && state <= MachineState_LastOnline) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot revert snapshot of running domain")); goto cleanup; } if (vboxDomainSnapshotRestore(dom, machine, newSnapshot)) goto cleanup; if (online) { ret = vboxDomainCreate(dom); if (!ret) vboxDomainSnapshotRestore(dom, machine, prevSnapshot); } else ret = 0; cleanup: VBOX_RELEASE(prevSnapshot); VBOX_RELEASE(newSnapshot); vboxIIDUnalloc(&domiid); return ret; } static int vboxDomainSnapshotDeleteSingle(vboxGlobalData *data, IConsole *console, ISnapshot *snapshot) { IProgress *progress = NULL; vboxIID iid = VBOX_IID_INITIALIZER; int ret = -1; nsresult rc; #if VBOX_API_VERSION == 2002000 nsresult result; #else PRInt32 result; #endif rc = snapshot->vtbl->GetId(snapshot, &iid.value); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get snapshot UUID")); goto cleanup; } #if VBOX_API_VERSION < 3001000 rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress); #else rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress); #endif if (NS_FAILED(rc) || !progress) { if (rc == VBOX_E_INVALID_VM_STATE) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot delete domain snapshot for running domain")); } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not delete snapshot")); } goto cleanup; } progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &result); if (NS_FAILED(result)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not delete snapshot")); goto cleanup; } ret = 0; cleanup: VBOX_RELEASE(progress); vboxIIDUnalloc(&iid); return ret; } static int vboxDomainSnapshotDeleteTree(vboxGlobalData *data, IConsole *console, ISnapshot *snapshot) { vboxArray children = VBOX_ARRAY_INITIALIZER; int ret = -1; nsresult rc; size_t i; rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get children snapshots")); goto cleanup; } for (i = 0; i < children.count; i++) { if (vboxDomainSnapshotDeleteTree(data, console, children.items[i])) goto cleanup; } ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot); cleanup: vboxArrayRelease(&children); return ret; } #if VBOX_API_VERSION >= 4002000 static int vboxDomainSnapshotDeleteMetadataOnly(virDomainSnapshotPtr snapshot) { /* * This function will remove the node in the vbox xml corresponding to the snapshot. * It is usually called by vboxDomainSnapshotDelete() with the flag * VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY. * If you want to use it anywhere else, be careful, if the snapshot you want to delete * has children, the result is not granted, they will probably will be deleted in the * xml, but you may have a problem with hard drives. * * If the snapshot which is being deleted is the current one, we will set the current * snapshot of the machine to the parent of this snapshot. Before writing the modified * xml file, we undefine the machine from vbox. After writing the file, we redefine * the machine with the new file. */ virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, int, -1); virDomainSnapshotDefPtr def = NULL; char *defXml = NULL; vboxIID domiid = VBOX_IID_INITIALIZER; nsresult rc; IMachine *machine = NULL; PRUnichar *settingsFilePathUtf16 = NULL; char *settingsFilepath = NULL; virVBoxSnapshotConfMachinePtr snapshotMachineDesc = NULL; int isCurrent = -1; int it = 0; PRUnichar *machineNameUtf16 = NULL; char *machineName = NULL; char *nameTmpUse = NULL; char *machineLocationPath = NULL; PRUint32 aMediaSize = 0; IMedium **aMedia = NULL; defXml = vboxDomainSnapshotGetXMLDesc(snapshot, 0); if (!defXml) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get XML Desc of snapshot")); goto cleanup; } def = virDomainSnapshotDefParseString(defXml, data->caps, data->xmlopt, -1, VIR_DOMAIN_SNAPSHOT_PARSE_DISKS | VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE); if (!def) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get a virDomainSnapshotDefPtr")); goto cleanup; } vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } rc = machine->vtbl->GetSettingsFilePath(machine, &settingsFilePathUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get settings file path")); goto cleanup; } VBOX_UTF16_TO_UTF8(settingsFilePathUtf16, &settingsFilepath); /*Getting the machine name to retrieve the machine location path.*/ rc = machine->vtbl->GetName(machine, &machineNameUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get machine name")); goto cleanup; } VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); if (virAsprintf(&nameTmpUse, "%s.vbox", machineName) < 0) goto cleanup; machineLocationPath = virStringReplace(settingsFilepath, nameTmpUse, ""); if (machineLocationPath == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get the machine location path")); goto cleanup; } snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilepath, machineLocationPath); if (!snapshotMachineDesc) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot create a vboxSnapshotXmlPtr")); goto cleanup; } isCurrent = virVBoxSnapshotConfIsCurrentSnapshot(snapshotMachineDesc, def->name); if (isCurrent < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to know if the snapshot is the current snapshot")); goto cleanup; } if (isCurrent) { /* * If the snapshot is the current snapshot, it means that the machine has read-write * disks. The first thing to do is to manipulate VirtualBox API to create * differential read-write disks if the parent snapshot is not null. */ if (def->parent != NULL) { for (it = 0; it < def->dom->ndisks; it++) { virVBoxSnapshotConfHardDiskPtr readOnly = NULL; IMedium *medium = NULL; PRUnichar *locationUtf16 = NULL; PRUnichar *parentUuidUtf16 = NULL; char *parentUuid = NULL; IMedium *newMedium = NULL; PRUnichar *formatUtf16 = NULL; PRUnichar *newLocation = NULL; char *newLocationUtf8 = NULL; IProgress *progress = NULL; PRInt32 resultCode = -1; virVBoxSnapshotConfHardDiskPtr disk = NULL; PRUnichar *uuidUtf16 = NULL; char *uuid = NULL; char *format = NULL; char **searchResultTab = NULL; ssize_t resultSize = 0; char *tmp = NULL; readOnly = virVBoxSnapshotConfHardDiskPtrByLocation(snapshotMachineDesc, def->dom->disks[it]->src->path); if (!readOnly) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot get hard disk by location")); goto cleanup; } if (readOnly->parent == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("The read only disk has no parent")); goto cleanup; } VBOX_UTF8_TO_UTF16(readOnly->parent->location, &locationUtf16); rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, locationUtf16, DeviceType_HardDisk, AccessMode_ReadWrite, false, &medium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } rc = medium->vtbl->GetId(medium, &parentUuidUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to get hardDisk Id, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid); VBOX_UTF16_FREE(parentUuidUtf16); VBOX_UTF16_FREE(locationUtf16); VBOX_UTF8_TO_UTF16("VDI", &formatUtf16); if (virAsprintf(&newLocationUtf8, "%sfakedisk-%s-%d.vdi", machineLocationPath, def->parent, it) < 0) goto cleanup; VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation); rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, formatUtf16, newLocation, &newMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to create HardDisk, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_UTF16_FREE(formatUtf16); VBOX_UTF16_FREE(newLocation); # if VBOX_API_VERSION < 4003000 medium->vtbl->CreateDiffStorage(medium, newMedium, MediumVariant_Diff, &progress); # else PRUint32 tab[1]; tab[0] = MediumVariant_Diff; medium->vtbl->CreateDiffStorage(medium, newMedium, 1, tab, &progress); # endif progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &resultCode); if (NS_FAILED(resultCode)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Error while creating diff storage, rc=%08x"), (unsigned)resultCode); goto cleanup; } VBOX_RELEASE(progress); /* * The differential disk is created, we add it to the media registry and * the machine storage controller. */ if (VIR_ALLOC(disk) < 0) goto cleanup; rc = newMedium->vtbl->GetId(newMedium, &uuidUtf16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to get medium uuid, rc=%08x"), (unsigned)rc); VIR_FREE(disk); goto cleanup; } VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid); disk->uuid = uuid; VBOX_UTF16_FREE(uuidUtf16); if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) { VIR_FREE(disk); goto cleanup; } rc = newMedium->vtbl->GetFormat(newMedium, &formatUtf16); VBOX_UTF16_TO_UTF8(formatUtf16, &format); disk->format = format; VBOX_UTF16_FREE(formatUtf16); if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk, snapshotMachineDesc->mediaRegistry, parentUuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to add hard disk to the media registry")); goto cleanup; } /*Adding fake disks to the machine storage controllers*/ resultSize = virStringSearch(snapshotMachineDesc->storageController, VBOX_UUID_REGEX, it + 1, &searchResultTab); if (resultSize != it + 1) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find UUID %s"), searchResultTab[it]); goto cleanup; } tmp = virStringReplace(snapshotMachineDesc->storageController, searchResultTab[it], disk->uuid); virStringFreeList(searchResultTab); VIR_FREE(snapshotMachineDesc->storageController); if (!tmp) goto cleanup; if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) goto cleanup; VIR_FREE(tmp); /*Closing the "fake" disk*/ rc = newMedium->vtbl->Close(newMedium); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to close the new medium, rc=%08x"), (unsigned)rc); goto cleanup; } } } else { for (it = 0; it < def->dom->ndisks; it++) { const char *uuidRO = NULL; char **searchResultTab = NULL; ssize_t resultSize = 0; char *tmp = NULL; uuidRO = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, def->dom->disks[it]->src->path); if (!uuidRO) { virReportError(VIR_ERR_INTERNAL_ERROR, _("No such disk in media registry %s"), def->dom->disks[it]->src->path); goto cleanup; } resultSize = virStringSearch(snapshotMachineDesc->storageController, VBOX_UUID_REGEX, it + 1, &searchResultTab); if (resultSize != it + 1) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find UUID %s"), searchResultTab[it]); goto cleanup; } tmp = virStringReplace(snapshotMachineDesc->storageController, searchResultTab[it], uuidRO); virStringFreeList(searchResultTab); VIR_FREE(snapshotMachineDesc->storageController); if (!tmp) goto cleanup; if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) goto cleanup; VIR_FREE(tmp); } } } /*We remove the read write disks from the media registry*/ for (it = 0; it < def->ndisks; it++) { const char *uuidRW = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, def->disks[it].src->path); if (!uuidRW) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find UUID for location %s"), def->disks[it].src->path); goto cleanup; } if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRW) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to remove disk from media registry. uuid = %s"), uuidRW); goto cleanup; } } /*If the parent snapshot is not NULL, we remove the-read only disks from the media registry*/ if (def->parent != NULL) { for (it = 0; it < def->dom->ndisks; it++) { const char *uuidRO = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, def->dom->disks[it]->src->path); if (!uuidRO) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find UUID for location %s"), def->dom->disks[it]->src->path); goto cleanup; } if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRO) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to remove disk from media registry. uuid = %s"), uuidRO); goto cleanup; } } } rc = machine->vtbl->Unregister(machine, CleanupMode_DetachAllReturnHardDisksOnly, &aMediaSize, &aMedia); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to unregister machine, rc=%08x"), (unsigned)rc); goto cleanup; } VBOX_RELEASE(machine); for (it = 0; it < aMediaSize; it++) { IMedium *medium = aMedia[it]; if (medium) { PRUnichar *locationUtf16 = NULL; char *locationUtf8 = NULL; rc = medium->vtbl->GetLocation(medium, &locationUtf16); VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8); if (isCurrent && strstr(locationUtf8, "fake") != NULL) { /*we delete the fake disk because we don't need it anymore*/ IProgress *progress = NULL; PRInt32 resultCode = -1; rc = medium->vtbl->DeleteStorage(medium, &progress); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to delete medium, rc=%08x"), (unsigned)rc); goto cleanup; } progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &resultCode); if (NS_FAILED(resultCode)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Error while closing medium, rc=%08x"), (unsigned)resultCode); goto cleanup; } VBOX_RELEASE(progress); } else { /* This a comment from vboxmanage code in the handleUnregisterVM * function in VBoxManageMisc.cpp : * Note that the IMachine::Unregister method will return the medium * reference in a sane order, which means that closing will normally * succeed, unless there is still another machine which uses the * medium. No harm done if we ignore the error. */ rc = medium->vtbl->Close(medium); } VBOX_UTF16_FREE(locationUtf16); VBOX_UTF8_FREE(locationUtf8); } } /*removing the snapshot*/ if (virVBoxSnapshotConfRemoveSnapshot(snapshotMachineDesc, def->name) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to remove snapshot %s"), def->name); goto cleanup; } if (isCurrent) { VIR_FREE(snapshotMachineDesc->currentSnapshot); if (def->parent != NULL) { virVBoxSnapshotConfSnapshotPtr snap = virVBoxSnapshotConfSnapshotByName(snapshotMachineDesc->snapshot, def->parent); if (!snap) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to get the snapshot to remove")); goto cleanup; } if (VIR_STRDUP(snapshotMachineDesc->currentSnapshot, snap->uuid) < 0) goto cleanup; } } /*Registering the machine*/ if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilepath) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to serialize the machine description")); goto cleanup; } rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj, settingsFilePathUtf16, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to open Machine, rc=%08x"), (unsigned)rc); goto cleanup; } rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to register Machine, rc=%08x"), (unsigned)rc); goto cleanup; } ret = 0; cleanup: VIR_FREE(def); VIR_FREE(defXml); VBOX_RELEASE(machine); VBOX_UTF16_FREE(settingsFilePathUtf16); VBOX_UTF8_FREE(settingsFilepath); VIR_FREE(snapshotMachineDesc); VBOX_UTF16_FREE(machineNameUtf16); VBOX_UTF8_FREE(machineName); VIR_FREE(machineLocationPath); VIR_FREE(nameTmpUse); return ret; } #endif static int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainPtr dom = snapshot->domain; VBOX_OBJECT_CHECK(dom->conn, int, -1); vboxIID domiid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; ISnapshot *snap = NULL; IConsole *console = NULL; PRUint32 state; nsresult rc; vboxArray snapChildren = VBOX_ARRAY_INITIALIZER; virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1); vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching UUID")); goto cleanup; } snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name); if (!snap) goto cleanup; rc = machine->vtbl->GetState(machine, &state); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get domain state")); goto cleanup; } /* In case we just want to delete the metadata, we will edit the vbox file in order *to remove the node concerning the snapshot */ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) { rc = vboxArrayGet(&snapChildren, snap, snap->vtbl->GetChildren); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get snapshot children")); goto cleanup; } if (snapChildren.count != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot delete metadata of a snapshot with children")); goto cleanup; } else { #if VBOX_API_VERSION >= 4002000 ret = vboxDomainSnapshotDeleteMetadataOnly(snapshot); #endif } goto cleanup; } if (state >= MachineState_FirstOnline && state <= MachineState_LastOnline) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot delete snapshots of running domain")); goto cleanup; } rc = VBOX_SESSION_OPEN(domiid.value, machine); if (NS_SUCCEEDED(rc)) rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not open VirtualBox session with domain %s"), dom->name); goto cleanup; } if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) ret = vboxDomainSnapshotDeleteTree(data, console, snap); else ret = vboxDomainSnapshotDeleteSingle(data, console, snap); cleanup: VBOX_RELEASE(console); VBOX_RELEASE(snap); vboxIIDUnalloc(&domiid); VBOX_SESSION_CLOSE(); return ret; } #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 /* No Callback support for VirtualBox 2.2.* series */ /* No Callback support for VirtualBox 4.* series */ #else /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */ /* Functions needed for Callbacks */ static nsresult PR_COM_METHOD vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUint32 state) { virDomainPtr dom = NULL; int event = 0; int detail = 0; vboxDriverLock(g_pVBoxGlobalData); VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state); DEBUGPRUnichar("machineId", machineId); if (machineId) { char *machineIdUtf8 = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8); ignore_value(virUUIDParse(machineIdUtf8, uuid)); dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid); if (dom) { virObjectEventPtr ev; if (state == MachineState_Starting) { event = VIR_DOMAIN_EVENT_STARTED; detail = VIR_DOMAIN_EVENT_STARTED_BOOTED; } else if (state == MachineState_Restoring) { event = VIR_DOMAIN_EVENT_STARTED; detail = VIR_DOMAIN_EVENT_STARTED_RESTORED; } else if (state == MachineState_Paused) { event = VIR_DOMAIN_EVENT_SUSPENDED; detail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED; } else if (state == MachineState_Running) { event = VIR_DOMAIN_EVENT_RESUMED; detail = VIR_DOMAIN_EVENT_RESUMED_UNPAUSED; } else if (state == MachineState_PoweredOff) { event = VIR_DOMAIN_EVENT_STOPPED; detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN; } else if (state == MachineState_Stopping) { event = VIR_DOMAIN_EVENT_STOPPED; detail = VIR_DOMAIN_EVENT_STOPPED_DESTROYED; } else if (state == MachineState_Aborted) { event = VIR_DOMAIN_EVENT_STOPPED; detail = VIR_DOMAIN_EVENT_STOPPED_CRASHED; } else if (state == MachineState_Saving) { event = VIR_DOMAIN_EVENT_STOPPED; detail = VIR_DOMAIN_EVENT_STOPPED_SAVED; } else { event = VIR_DOMAIN_EVENT_STOPPED; detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN; } ev = virDomainEventLifecycleNewFromDom(dom, event, detail); if (ev) virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev); } } vboxDriverUnlock(g_pVBoxGlobalData); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId) { VIR_DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUnichar *key, PRUnichar *value, PRUnichar **error ATTRIBUTE_UNUSED, PRBool *allowChange ATTRIBUTE_UNUSED) { VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false"); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("key", key); DEBUGPRUnichar("value", value); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUnichar *key, PRUnichar *value) { VIR_DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("key", key); DEBUGPRUnichar("value", value); return NS_OK; } # if VBOX_API_VERSION < 3001000 static nsresult PR_COM_METHOD vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *mediaId, PRUint32 mediaType ATTRIBUTE_UNUSED, PRBool registered ATTRIBUTE_UNUSED) { VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false"); VIR_DEBUG("mediaType: %d", mediaType); DEBUGPRUnichar("mediaId", mediaId); return NS_OK; } # else /* VBOX_API_VERSION >= 3001000 */ # endif /* VBOX_API_VERSION >= 3001000 */ static nsresult PR_COM_METHOD vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRBool registered) { virDomainPtr dom = NULL; int event = 0; int detail = 0; vboxDriverLock(g_pVBoxGlobalData); VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false"); DEBUGPRUnichar("machineId", machineId); if (machineId) { char *machineIdUtf8 = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8); ignore_value(virUUIDParse(machineIdUtf8, uuid)); dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid); if (dom) { virObjectEventPtr ev; /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED * event because the when the machine is de-registered the call * to vboxDomainLookupByUUID fails and thus we don't get any * dom pointer which is necessary (null dom pointer doesn't work) * to show the VIR_DOMAIN_EVENT_UNDEFINED event */ if (registered) { event = VIR_DOMAIN_EVENT_DEFINED; detail = VIR_DOMAIN_EVENT_DEFINED_ADDED; } else { event = VIR_DOMAIN_EVENT_UNDEFINED; detail = VIR_DOMAIN_EVENT_UNDEFINED_REMOVED; } ev = virDomainEventLifecycleNewFromDom(dom, event, detail); if (ev) virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev); } } vboxDriverUnlock(g_pVBoxGlobalData); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUint32 state ATTRIBUTE_UNUSED) { VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state); DEBUGPRUnichar("machineId", machineId); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUnichar *snapshotId) { VIR_DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("snapshotId", snapshotId); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUnichar *snapshotId) { VIR_DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("snapshotId", snapshotId); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUnichar *snapshotId) { VIR_DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("snapshotId", snapshotId); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED, PRUnichar *machineId, PRUnichar *name, PRUnichar *value, PRUnichar *flags) { VIR_DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("name", name); DEBUGPRUnichar("value", value); DEBUGPRUnichar("flags", flags); return NS_OK; } static nsresult PR_COM_METHOD vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED) { nsresult c; c = ++g_pVBoxGlobalData->vboxCallBackRefCount; VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c); return c; } static nsresult PR_COM_METHOD vboxCallbackRelease(nsISupports *pThis) { nsresult c; c = --g_pVBoxGlobalData->vboxCallBackRefCount; if (c == 0) { /* delete object */ VIR_FREE(pThis->vtbl); VIR_FREE(pThis); } VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c); return c; } static nsresult PR_COM_METHOD vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp) { IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis; static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID; static const nsID isupportIID = NS_ISUPPORTS_IID; /* Match UUID for IVirtualBoxCallback class */ if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 || memcmp(iid, &isupportIID, sizeof(nsID)) == 0) { g_pVBoxGlobalData->vboxCallBackRefCount++; *resultp = that; VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount); return NS_OK; } VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis); DEBUGUUID("The UUID Callback Interface expects", iid); DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID); return NS_NOINTERFACE; } static IVirtualBoxCallback *vboxAllocCallbackObj(void) { IVirtualBoxCallback *vboxCallback = NULL; /* Allocate, Initialize and return a valid * IVirtualBoxCallback object here */ if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) { VIR_FREE(vboxCallback); return NULL; } { vboxCallback->vtbl->nsisupports.AddRef = &vboxCallbackAddRef; vboxCallback->vtbl->nsisupports.Release = &vboxCallbackRelease; vboxCallback->vtbl->nsisupports.QueryInterface = &vboxCallbackQueryInterface; vboxCallback->vtbl->OnMachineStateChange = &vboxCallbackOnMachineStateChange; vboxCallback->vtbl->OnMachineDataChange = &vboxCallbackOnMachineDataChange; vboxCallback->vtbl->OnExtraDataCanChange = &vboxCallbackOnExtraDataCanChange; vboxCallback->vtbl->OnExtraDataChange = &vboxCallbackOnExtraDataChange; # if VBOX_API_VERSION < 3001000 vboxCallback->vtbl->OnMediaRegistered = &vboxCallbackOnMediaRegistered; # else /* VBOX_API_VERSION >= 3001000 */ # endif /* VBOX_API_VERSION >= 3001000 */ vboxCallback->vtbl->OnMachineRegistered = &vboxCallbackOnMachineRegistered; vboxCallback->vtbl->OnSessionStateChange = &vboxCallbackOnSessionStateChange; vboxCallback->vtbl->OnSnapshotTaken = &vboxCallbackOnSnapshotTaken; # if VBOX_API_VERSION < 3002000 vboxCallback->vtbl->OnSnapshotDiscarded = &vboxCallbackOnSnapshotDiscarded; # else /* VBOX_API_VERSION >= 3002000 */ vboxCallback->vtbl->OnSnapshotDeleted = &vboxCallbackOnSnapshotDiscarded; # endif /* VBOX_API_VERSION >= 3002000 */ vboxCallback->vtbl->OnSnapshotChange = &vboxCallbackOnSnapshotChange; vboxCallback->vtbl->OnGuestPropertyChange = &vboxCallbackOnGuestPropertyChange; g_pVBoxGlobalData->vboxCallBackRefCount = 1; } return vboxCallback; } static void vboxReadCallback(int watch ATTRIBUTE_UNUSED, int fd, int events ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) { if (fd >= 0) { g_pVBoxGlobalData->vboxQueue->vtbl->ProcessPendingEvents(g_pVBoxGlobalData->vboxQueue); } else { nsresult rc; PLEvent *pEvent = NULL; rc = g_pVBoxGlobalData->vboxQueue->vtbl->WaitForEvent(g_pVBoxGlobalData->vboxQueue, &pEvent); if (NS_SUCCEEDED(rc)) g_pVBoxGlobalData->vboxQueue->vtbl->HandleEvent(g_pVBoxGlobalData->vboxQueue, pEvent); } } static int vboxConnectDomainEventRegister(virConnectPtr conn, virConnectDomainEventCallback callback, void *opaque, virFreeCallback freecb) { VBOX_OBJECT_CHECK(conn, int, -1); int vboxRet = -1; nsresult rc; /* Locking has to be there as callbacks are not * really fully thread safe */ vboxDriverLock(data); if (data->vboxCallback == NULL) { data->vboxCallback = vboxAllocCallbackObj(); if (data->vboxCallback != NULL) { rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback); if (NS_SUCCEEDED(rc)) { vboxRet = 0; } } } else { vboxRet = 0; } /* Get the vbox file handle and add a event handle to it * so that the events can be passed down to the user */ if (vboxRet == 0) { if (data->fdWatch < 0) { PRInt32 vboxFileHandle; vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue); data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL); } if (data->fdWatch >= 0) { /* Once a callback is registered with virtualbox, use a list * to store the callbacks registered with libvirt so that * later you can iterate over them */ ret = virDomainEventStateRegister(conn, data->domainEvents, callback, opaque, freecb); VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, " "callback: %p, opaque: %p, " "freecb: %p)", ret, conn, callback, opaque, freecb); } } vboxDriverUnlock(data); if (ret >= 0) { return 0; } else { if (data->vboxObj && data->vboxCallback) { data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback); } return -1; } } static int vboxConnectDomainEventDeregister(virConnectPtr conn, virConnectDomainEventCallback callback) { VBOX_OBJECT_CHECK(conn, int, -1); int cnt; /* Locking has to be there as callbacks are not * really fully thread safe */ vboxDriverLock(data); cnt = virDomainEventStateDeregister(conn, data->domainEvents, callback); if (data->vboxCallback && cnt == 0) { data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback); VBOX_RELEASE(data->vboxCallback); /* Remove the Event file handle on which we are listening as well */ virEventRemoveHandle(data->fdWatch); data->fdWatch = -1; } vboxDriverUnlock(data); if (cnt >= 0) ret = 0; return ret; } static int vboxConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback callback, void *opaque, virFreeCallback freecb) { VBOX_OBJECT_CHECK(conn, int, -1); int vboxRet = -1; nsresult rc; /* Locking has to be there as callbacks are not * really fully thread safe */ vboxDriverLock(data); if (data->vboxCallback == NULL) { data->vboxCallback = vboxAllocCallbackObj(); if (data->vboxCallback != NULL) { rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback); if (NS_SUCCEEDED(rc)) { vboxRet = 0; } } } else { vboxRet = 0; } /* Get the vbox file handle and add a event handle to it * so that the events can be passed down to the user */ if (vboxRet == 0) { if (data->fdWatch < 0) { PRInt32 vboxFileHandle; vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue); data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL); } if (data->fdWatch >= 0) { /* Once a callback is registered with virtualbox, use a list * to store the callbacks registered with libvirt so that * later you can iterate over them */ if (virDomainEventStateRegisterID(conn, data->domainEvents, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, " "callback: %p, opaque: %p, " "freecb: %p)", ret, conn, callback, opaque, freecb); } } vboxDriverUnlock(data); if (ret >= 0) { return ret; } else { if (data->vboxObj && data->vboxCallback) { data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback); } return -1; } } static int vboxConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID) { VBOX_OBJECT_CHECK(conn, int, -1); int cnt; /* Locking has to be there as callbacks are not * really fully thread safe */ vboxDriverLock(data); cnt = virObjectEventStateDeregisterID(conn, data->domainEvents, callbackID); if (data->vboxCallback && cnt == 0) { data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback); VBOX_RELEASE(data->vboxCallback); /* Remove the Event file handle on which we are listening as well */ virEventRemoveHandle(data->fdWatch); data->fdWatch = -1; } vboxDriverUnlock(data); if (cnt >= 0) ret = 0; return ret; } #endif /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */ /** * The Network Functions here on */ static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { vboxGlobalData *data = conn->privateData; virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "VBOX")) goto cleanup; if ((data->pFuncs == NULL) || (data->vboxObj == NULL) || (data->vboxSession == NULL)) goto cleanup; VIR_DEBUG("network initialized"); /* conn->networkPrivateData = some network specific data */ return VIR_DRV_OPEN_SUCCESS; cleanup: return VIR_DRV_OPEN_DECLINED; } static int vboxNetworkClose(virConnectPtr conn) { VIR_DEBUG("network uninitialized"); conn->networkPrivateData = NULL; return 0; } static int vboxConnectNumOfNetworks(virConnectPtr conn) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; size_t i = 0; vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); for (i = 0; i < networkInterfaces.count; i++) { IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Up) ret++; } } } vboxArrayRelease(&networkInterfaces); VBOX_RELEASE(host); VIR_DEBUG("numActive: %d", ret); return ret; } static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; size_t i = 0; vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) { IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Up) { char *nameUtf8 = NULL; PRUnichar *nameUtf16 = NULL; networkInterface->vtbl->GetName(networkInterface, &nameUtf16); VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8); if (VIR_STRDUP(names[ret], nameUtf8) >= 0) ret++; VBOX_UTF8_FREE(nameUtf8); VBOX_UTF16_FREE(nameUtf16); } } } } vboxArrayRelease(&networkInterfaces); VBOX_RELEASE(host); return ret; } static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; size_t i = 0; vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); for (i = 0; i < networkInterfaces.count; i++) { IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Down) ret++; } } } vboxArrayRelease(&networkInterfaces); VBOX_RELEASE(host); VIR_DEBUG("numActive: %d", ret); return ret; } static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; size_t i = 0; vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) { IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Down) { char *nameUtf8 = NULL; PRUnichar *nameUtf16 = NULL; networkInterface->vtbl->GetName(networkInterface, &nameUtf16); VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8); if (VIR_STRDUP(names[ret], nameUtf8) >= 0) ret++; VBOX_UTF8_FREE(nameUtf8); VBOX_UTF16_FREE(nameUtf16); } } } } vboxArrayRelease(&networkInterfaces); VBOX_RELEASE(host); return ret; } static virNetworkPtr vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL); vboxIID iid = VBOX_IID_INITIALIZER; vboxIIDFromUUID(&iid, uuid); /* TODO: "internal" networks are just strings and * thus can't do much with them */ IHostNetworkInterface *networkInterface = NULL; host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface); if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { char *nameUtf8 = NULL; PRUnichar *nameUtf16 = NULL; networkInterface->vtbl->GetName(networkInterface, &nameUtf16); VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); ret = virGetNetwork(conn, nameUtf8, uuid); VIR_DEBUG("Network Name: %s", nameUtf8); DEBUGIID("Network UUID", iid.value); VBOX_UTF8_FREE(nameUtf8); VBOX_UTF16_FREE(nameUtf16); } VBOX_RELEASE(networkInterface); } VBOX_RELEASE(host); vboxIIDUnalloc(&iid); return ret; } static virNetworkPtr vboxNetworkLookupByName(virConnectPtr conn, const char *name) { VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL); PRUnichar *nameUtf16 = NULL; IHostNetworkInterface *networkInterface = NULL; VBOX_UTF8_TO_UTF16(name, &nameUtf16); host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface); if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { unsigned char uuid[VIR_UUID_BUFLEN]; vboxIID iid = VBOX_IID_INITIALIZER; networkInterface->vtbl->GetId(networkInterface, &iid.value); vboxIIDToUUID(&iid, uuid); ret = virGetNetwork(conn, name, uuid); VIR_DEBUG("Network Name: %s", name); DEBUGIID("Network UUID", iid.value); vboxIIDUnalloc(&iid); } VBOX_RELEASE(networkInterface); } VBOX_UTF16_FREE(nameUtf16); VBOX_RELEASE(host); return ret; } static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start) { VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL); PRUnichar *networkInterfaceNameUtf16 = NULL; char *networkInterfaceNameUtf8 = NULL; IHostNetworkInterface *networkInterface = NULL; nsresult rc; virNetworkDefPtr def = virNetworkDefParseString(xml); virNetworkIpDefPtr ipdef; virSocketAddr netmask; if ((!def) || (def->forward.type != VIR_NETWORK_FORWARD_NONE) || (def->nips == 0 || !def->ips)) goto cleanup; /* Look for the first IPv4 IP address definition and use that. * If there weren't any IPv4 addresses, ignore the network (since it's * required below to have an IPv4 address) */ ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0); if (!ipdef) goto cleanup; if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) goto cleanup; /* the current limitation of hostonly network is that you can't * assign a name to it and it defaults to vboxnet*, for e.g: * vboxnet0, vboxnet1, etc. Also the UUID is assigned to it * automatically depending on the mac address and thus both * these paramters are ignored here for now. */ #if VBOX_API_VERSION == 2002000 if (STREQ(def->name, "vboxnet0")) { PRUint32 interfaceType = 0; VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16); host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface); networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType != HostNetworkInterfaceType_HostOnly) { VBOX_RELEASE(networkInterface); networkInterface = NULL; } } #else /* VBOX_API_VERSION != 2002000 */ { IProgress *progress = NULL; host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface, &progress); if (progress) { progress->vtbl->WaitForCompletion(progress, -1); VBOX_RELEASE(progress); } } #endif /* VBOX_API_VERSION != 2002000 */ if (networkInterface) { unsigned char uuid[VIR_UUID_BUFLEN]; char *networkNameUtf8 = NULL; PRUnichar *networkNameUtf16 = NULL; vboxIID vboxnetiid = VBOX_IID_INITIALIZER; networkInterface->vtbl->GetName(networkInterface, &networkInterfaceNameUtf16); if (networkInterfaceNameUtf16) { VBOX_UTF16_TO_UTF8(networkInterfaceNameUtf16, &networkInterfaceNameUtf8); if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", networkInterfaceNameUtf8) < 0) { VBOX_RELEASE(host); VBOX_RELEASE(networkInterface); goto cleanup; } } VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16); /* Currently support only one dhcp server per network * with contigious address space from start to end */ if ((ipdef->nranges >= 1) && VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) && VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) { IDHCPServer *dhcpServer = NULL; data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj, networkNameUtf16, &dhcpServer); if (!dhcpServer) { /* create a dhcp server */ data->vboxObj->vtbl->CreateDHCPServer(data->vboxObj, networkNameUtf16, &dhcpServer); VIR_DEBUG("couldn't find dhcp server so creating one"); } if (dhcpServer) { PRUnichar *ipAddressUtf16 = NULL; PRUnichar *networkMaskUtf16 = NULL; PRUnichar *fromIPAddressUtf16 = NULL; PRUnichar *toIPAddressUtf16 = NULL; PRUnichar *trunkTypeUtf16 = NULL; ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address); networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask); fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start); toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end); if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL || fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) { VBOX_UTF16_FREE(ipAddressUtf16); VBOX_UTF16_FREE(networkMaskUtf16); VBOX_UTF16_FREE(fromIPAddressUtf16); VBOX_UTF16_FREE(toIPAddressUtf16); VBOX_RELEASE(dhcpServer); goto cleanup; } VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16); dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE); dhcpServer->vtbl->SetConfiguration(dhcpServer, ipAddressUtf16, networkMaskUtf16, fromIPAddressUtf16, toIPAddressUtf16); if (start) dhcpServer->vtbl->Start(dhcpServer, networkNameUtf16, networkInterfaceNameUtf16, trunkTypeUtf16); VBOX_UTF16_FREE(ipAddressUtf16); VBOX_UTF16_FREE(networkMaskUtf16); VBOX_UTF16_FREE(fromIPAddressUtf16); VBOX_UTF16_FREE(toIPAddressUtf16); VBOX_UTF16_FREE(trunkTypeUtf16); VBOX_RELEASE(dhcpServer); } } if ((ipdef->nhosts >= 1) && VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) { PRUnichar *ipAddressUtf16 = NULL; PRUnichar *networkMaskUtf16 = NULL; ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip); networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask); if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) { VBOX_UTF16_FREE(ipAddressUtf16); VBOX_UTF16_FREE(networkMaskUtf16); goto cleanup; } /* Current drawback is that since EnableStaticIpConfig() sets * IP and enables the interface so even if the dhcpserver is not * started the interface is still up and running */ #if VBOX_API_VERSION < 4002000 networkInterface->vtbl->EnableStaticIpConfig(networkInterface, ipAddressUtf16, networkMaskUtf16); #else networkInterface->vtbl->EnableStaticIPConfig(networkInterface, ipAddressUtf16, networkMaskUtf16); #endif VBOX_UTF16_FREE(ipAddressUtf16); VBOX_UTF16_FREE(networkMaskUtf16); } else { #if VBOX_API_VERSION < 4002000 networkInterface->vtbl->EnableDynamicIpConfig(networkInterface); networkInterface->vtbl->DhcpRediscover(networkInterface); #else networkInterface->vtbl->EnableDynamicIPConfig(networkInterface); networkInterface->vtbl->DHCPRediscover(networkInterface); #endif } rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value); if (NS_SUCCEEDED(rc)) { vboxIIDToUUID(&vboxnetiid, uuid); DEBUGIID("Real Network UUID", vboxnetiid.value); vboxIIDUnalloc(&vboxnetiid); ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid); } VIR_FREE(networkNameUtf8); VBOX_UTF16_FREE(networkNameUtf16); VBOX_RELEASE(networkInterface); } VBOX_UTF8_FREE(networkInterfaceNameUtf8); VBOX_UTF16_FREE(networkInterfaceNameUtf16); VBOX_RELEASE(host); cleanup: virNetworkDefFree(def); return ret; } static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml) { return vboxNetworkDefineCreateXML(conn, xml, true); } static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml) { return vboxNetworkDefineCreateXML(conn, xml, false); } static int vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface) { VBOX_OBJECT_HOST_CHECK(network->conn, int, -1); char *networkNameUtf8 = NULL; PRUnichar *networkInterfaceNameUtf16 = NULL; IHostNetworkInterface *networkInterface = NULL; /* Current limitation of the function for VirtualBox 2.2.* is * that you can't delete the default hostonly adaptor namely: * vboxnet0 and thus all this functions does is remove the * dhcp server configuration, but the network can still be used * by giving the machine static IP and also it will still * show up in the net-list in virsh */ if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) goto cleanup; VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16); host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface); if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUnichar *networkNameUtf16 = NULL; IDHCPServer *dhcpServer = NULL; #if VBOX_API_VERSION != 2002000 if (removeinterface) { PRUnichar *iidUtf16 = NULL; IProgress *progress = NULL; networkInterface->vtbl->GetId(networkInterface, &iidUtf16); if (iidUtf16) { # if VBOX_API_VERSION == 3000000 IHostNetworkInterface *netInt = NULL; host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress); VBOX_RELEASE(netInt); # else /* VBOX_API_VERSION > 3000000 */ host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress); # endif /* VBOX_API_VERSION > 3000000 */ VBOX_UTF16_FREE(iidUtf16); } if (progress) { progress->vtbl->WaitForCompletion(progress, -1); VBOX_RELEASE(progress); } } #endif /* VBOX_API_VERSION != 2002000 */ VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16); data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj, networkNameUtf16, &dhcpServer); if (dhcpServer) { dhcpServer->vtbl->SetEnabled(dhcpServer, PR_FALSE); dhcpServer->vtbl->Stop(dhcpServer); if (removeinterface) data->vboxObj->vtbl->RemoveDHCPServer(data->vboxObj, dhcpServer); VBOX_RELEASE(dhcpServer); } VBOX_UTF16_FREE(networkNameUtf16); } VBOX_RELEASE(networkInterface); } VBOX_UTF16_FREE(networkInterfaceNameUtf16); VBOX_RELEASE(host); ret = 0; cleanup: VIR_FREE(networkNameUtf8); return ret; } static int vboxNetworkUndefine(virNetworkPtr network) { return vboxNetworkUndefineDestroy(network, true); } static int vboxNetworkCreate(virNetworkPtr network) { VBOX_OBJECT_HOST_CHECK(network->conn, int, -1); char *networkNameUtf8 = NULL; PRUnichar *networkInterfaceNameUtf16 = NULL; IHostNetworkInterface *networkInterface = NULL; /* Current limitation of the function for VirtualBox 2.2.* is * that the default hostonly network "vboxnet0" is always active * and thus all this functions does is start the dhcp server, * but the network can still be used without starting the dhcp * server by giving the machine static IP */ if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) goto cleanup; VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16); host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface); if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUnichar *networkNameUtf16 = NULL; IDHCPServer *dhcpServer = NULL; VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16); data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj, networkNameUtf16, &dhcpServer); if (dhcpServer) { PRUnichar *trunkTypeUtf16 = NULL; dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE); VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16); dhcpServer->vtbl->Start(dhcpServer, networkNameUtf16, networkInterfaceNameUtf16, trunkTypeUtf16); VBOX_UTF16_FREE(trunkTypeUtf16); VBOX_RELEASE(dhcpServer); } VBOX_UTF16_FREE(networkNameUtf16); } VBOX_RELEASE(networkInterface); } VBOX_UTF16_FREE(networkInterfaceNameUtf16); VBOX_RELEASE(host); ret = 0; cleanup: VIR_FREE(networkNameUtf8); return ret; } static int vboxNetworkDestroy(virNetworkPtr network) { return vboxNetworkUndefineDestroy(network, false); } static char *vboxNetworkGetXMLDesc(virNetworkPtr network, unsigned int flags) { VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL); virNetworkDefPtr def = NULL; virNetworkIpDefPtr ipdef = NULL; char *networkNameUtf8 = NULL; PRUnichar *networkInterfaceNameUtf16 = NULL; IHostNetworkInterface *networkInterface = NULL; virCheckFlags(0, NULL); if (VIR_ALLOC(def) < 0) goto cleanup; if (VIR_ALLOC(ipdef) < 0) goto cleanup; def->ips = ipdef; def->nips = 1; if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) goto cleanup; VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16); host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface); if (networkInterface) { PRUint32 interfaceType = 0; networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { if (VIR_STRDUP(def->name, network->name) >= 0) { PRUnichar *networkNameUtf16 = NULL; IDHCPServer *dhcpServer = NULL; vboxIID vboxnet0IID = VBOX_IID_INITIALIZER; networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value); vboxIIDToUUID(&vboxnet0IID, def->uuid); VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16); def->forward.type = VIR_NETWORK_FORWARD_NONE; data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj, networkNameUtf16, &dhcpServer); if (dhcpServer) { ipdef->nranges = 1; if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >= 0) { PRUnichar *ipAddressUtf16 = NULL; PRUnichar *networkMaskUtf16 = NULL; PRUnichar *fromIPAddressUtf16 = NULL; PRUnichar *toIPAddressUtf16 = NULL; bool errorOccurred = false; dhcpServer->vtbl->GetIPAddress(dhcpServer, &ipAddressUtf16); dhcpServer->vtbl->GetNetworkMask(dhcpServer, &networkMaskUtf16); dhcpServer->vtbl->GetLowerIP(dhcpServer, &fromIPAddressUtf16); dhcpServer->vtbl->GetUpperIP(dhcpServer, &toIPAddressUtf16); /* Currently virtualbox supports only one dhcp server per network * with contigious address space from start to end */ if (vboxSocketParseAddrUtf16(data, ipAddressUtf16, &ipdef->address) < 0 || vboxSocketParseAddrUtf16(data, networkMaskUtf16, &ipdef->netmask) < 0 || vboxSocketParseAddrUtf16(data, fromIPAddressUtf16, &ipdef->ranges[0].start) < 0 || vboxSocketParseAddrUtf16(data, toIPAddressUtf16, &ipdef->ranges[0].end) < 0) { errorOccurred = true; } VBOX_UTF16_FREE(ipAddressUtf16); VBOX_UTF16_FREE(networkMaskUtf16); VBOX_UTF16_FREE(fromIPAddressUtf16); VBOX_UTF16_FREE(toIPAddressUtf16); if (errorOccurred) { goto cleanup; } } else { ipdef->nranges = 0; } ipdef->nhosts = 1; if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >= 0) { if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) { VIR_FREE(ipdef->hosts); ipdef->nhosts = 0; } else { PRUnichar *macAddressUtf16 = NULL; PRUnichar *ipAddressUtf16 = NULL; bool errorOccurred = false; networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16); networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16); VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac); if (vboxSocketParseAddrUtf16(data, ipAddressUtf16, &ipdef->hosts[0].ip) < 0) { errorOccurred = true; } VBOX_UTF16_FREE(macAddressUtf16); VBOX_UTF16_FREE(ipAddressUtf16); if (errorOccurred) { goto cleanup; } } } else { ipdef->nhosts = 0; } VBOX_RELEASE(dhcpServer); } else { PRUnichar *networkMaskUtf16 = NULL; PRUnichar *ipAddressUtf16 = NULL; bool errorOccurred = false; networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16); networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16); if (vboxSocketParseAddrUtf16(data, networkMaskUtf16, &ipdef->netmask) < 0 || vboxSocketParseAddrUtf16(data, ipAddressUtf16, &ipdef->address) < 0) { errorOccurred = true; } VBOX_UTF16_FREE(networkMaskUtf16); VBOX_UTF16_FREE(ipAddressUtf16); if (errorOccurred) { goto cleanup; } } DEBUGIID("Network UUID", vboxnet0IID.value); vboxIIDUnalloc(&vboxnet0IID); VBOX_UTF16_FREE(networkNameUtf16); } } VBOX_RELEASE(networkInterface); } VBOX_UTF16_FREE(networkInterfaceNameUtf16); VBOX_RELEASE(host); ret = virNetworkDefFormat(def, 0); cleanup: virNetworkDefFree(def); VIR_FREE(networkNameUtf8); return ret; } /** * The Storage Functions here on */ static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { vboxGlobalData *data = conn->privateData; virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "VBOX")) return VIR_DRV_OPEN_DECLINED; if ((data->pFuncs == NULL) || (data->vboxObj == NULL) || (data->vboxSession == NULL)) return VIR_DRV_OPEN_ERROR; VIR_DEBUG("vbox storage initialized"); /* conn->storagePrivateData = some storage specific data */ return VIR_DRV_OPEN_SUCCESS; } static int vboxStorageClose(virConnectPtr conn) { VIR_DEBUG("vbox storage uninitialized"); conn->storagePrivateData = NULL; return 0; } static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED) { /** Currently only one pool supported, the default one * given by ISystemProperties::defaultHardDiskFolder() */ return 1; } static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED, char **const names, int nnames) { int numActive = 0; if (nnames == 1 && VIR_STRDUP(names[numActive], "default-pool") > 0) numActive++; return numActive; } static virStoragePoolPtr vboxStoragePoolLookupByName(virConnectPtr conn, const char *name) { virStoragePoolPtr ret = NULL; /** Current limitation of the function: since * the default pool doesn't have UUID just assign * one till vbox can handle pools */ if (STREQ("default-pool", name)) { unsigned char uuid[VIR_UUID_BUFLEN]; const char *uuidstr = "1deff1ff-1481-464f-967f-a50fe8936cc4"; ignore_value(virUUIDParse(uuidstr, uuid)); ret = virGetStoragePool(conn, name, uuid, NULL, NULL); } return ret; } static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool) { VBOX_OBJECT_CHECK(pool->conn, int, -1); vboxArray hardDisks = VBOX_ARRAY_INITIALIZER; PRUint32 hardDiskAccessible = 0; nsresult rc; size_t i; rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks); if (NS_SUCCEEDED(rc)) { for (i = 0; i < hardDisks.count; ++i) { IHardDisk *hardDisk = hardDisks.items[i]; if (hardDisk) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) hardDiskAccessible++; } } vboxArrayRelease(&hardDisks); ret = hardDiskAccessible; } else { ret = -1; virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get number of volumes in the pool: %s, rc=%08x"), pool->name, (unsigned)rc); } return ret; } static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) { VBOX_OBJECT_CHECK(pool->conn, int, -1); vboxArray hardDisks = VBOX_ARRAY_INITIALIZER; PRUint32 numActive = 0; nsresult rc; size_t i; rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks); if (NS_SUCCEEDED(rc)) { for (i = 0; i < hardDisks.count && numActive < nnames; ++i) { IHardDisk *hardDisk = hardDisks.items[i]; if (hardDisk) { PRUint32 hddstate; char *nameUtf8 = NULL; PRUnichar *nameUtf16 = NULL; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16); VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); VBOX_UTF16_FREE(nameUtf16); if (nameUtf8) { VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8); if (VIR_STRDUP(names[numActive], nameUtf8) > 0) numActive++; VBOX_UTF8_FREE(nameUtf8); } } } } vboxArrayRelease(&hardDisks); ret = numActive; } else { ret = -1; virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get the volume list in the pool: %s, rc=%08x"), pool->name, (unsigned)rc); } return ret; } static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name) { VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL); vboxArray hardDisks = VBOX_ARRAY_INITIALIZER; nsresult rc; size_t i; if (!name) return ret; rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks); if (NS_SUCCEEDED(rc)) { for (i = 0; i < hardDisks.count; ++i) { IHardDisk *hardDisk = hardDisks.items[i]; if (hardDisk) { PRUint32 hddstate; char *nameUtf8 = NULL; PRUnichar *nameUtf16 = NULL; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16); if (nameUtf16) { VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); VBOX_UTF16_FREE(nameUtf16); } if (nameUtf8 && STREQ(nameUtf8, name)) { vboxIID hddIID = VBOX_IID_INITIALIZER; unsigned char uuid[VIR_UUID_BUFLEN]; char key[VIR_UUID_STRING_BUFLEN] = ""; rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value); if (NS_SUCCEEDED(rc)) { vboxIIDToUUID(&hddIID, uuid); virUUIDFormat(uuid, key); ret = virGetStorageVol(pool->conn, pool->name, name, key, NULL, NULL); VIR_DEBUG("virStorageVolPtr: %p", ret); VIR_DEBUG("Storage Volume Name: %s", name); VIR_DEBUG("Storage Volume key : %s", key); VIR_DEBUG("Storage Volume Pool: %s", pool->name); } vboxIIDUnalloc(&hddIID); VBOX_UTF8_FREE(nameUtf8); break; } VBOX_UTF8_FREE(nameUtf8); } } } vboxArrayRelease(&hardDisks); } return ret; } static virStorageVolPtr vboxStorageVolLookupByKey(virConnectPtr conn, const char *key) { VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL); vboxIID hddIID = VBOX_IID_INITIALIZER; unsigned char uuid[VIR_UUID_BUFLEN]; IHardDisk *hardDisk = NULL; nsresult rc; if (!key) return ret; if (virUUIDParse(key, uuid) < 0) { virReportError(VIR_ERR_INVALID_ARG, _("Could not parse UUID from '%s'"), key); return NULL; } vboxIIDFromUUID(&hddIID, uuid); #if VBOX_API_VERSION < 4000000 rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk); #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, &hardDisk); #else rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, AccessMode_ReadWrite, PR_FALSE, &hardDisk); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_SUCCEEDED(rc)) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { PRUnichar *hddNameUtf16 = NULL; char *hddNameUtf8 = NULL; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16); VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8); if (hddNameUtf8) { if (vboxConnectNumOfStoragePools(conn) == 1) { ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key, NULL, NULL); VIR_DEBUG("Storage Volume Pool: %s", "default-pool"); } else { /* TODO: currently only one default pool and thus * nothing here, change it when pools are supported */ } VIR_DEBUG("Storage Volume Name: %s", key); VIR_DEBUG("Storage Volume key : %s", hddNameUtf8); VBOX_UTF8_FREE(hddNameUtf8); VBOX_UTF16_FREE(hddNameUtf16); } } VBOX_MEDIUM_RELEASE(hardDisk); } vboxIIDUnalloc(&hddIID); return ret; } static virStorageVolPtr vboxStorageVolLookupByPath(virConnectPtr conn, const char *path) { VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL); PRUnichar *hddPathUtf16 = NULL; IHardDisk *hardDisk = NULL; nsresult rc; if (!path) return ret; VBOX_UTF8_TO_UTF16(path, &hddPathUtf16); if (!hddPathUtf16) return ret; #if VBOX_API_VERSION < 4000000 rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk); #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16, DeviceType_HardDisk, &hardDisk); #else rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16, DeviceType_HardDisk, AccessMode_ReadWrite, PR_FALSE, &hardDisk); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_SUCCEEDED(rc)) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { PRUnichar *hddNameUtf16 = NULL; char *hddNameUtf8 = NULL; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16); if (hddNameUtf16) { VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8); VBOX_UTF16_FREE(hddNameUtf16); } if (hddNameUtf8) { vboxIID hddIID = VBOX_IID_INITIALIZER; unsigned char uuid[VIR_UUID_BUFLEN]; char key[VIR_UUID_STRING_BUFLEN] = ""; rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value); if (NS_SUCCEEDED(rc)) { vboxIIDToUUID(&hddIID, uuid); virUUIDFormat(uuid, key); /* TODO: currently only one default pool and thus * the check below, change it when pools are supported */ if (vboxConnectNumOfStoragePools(conn) == 1) ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key, NULL, NULL); VIR_DEBUG("Storage Volume Pool: %s", "default-pool"); VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8); VIR_DEBUG("Storage Volume key : %s", key); } vboxIIDUnalloc(&hddIID); } VBOX_UTF8_FREE(hddNameUtf8); } VBOX_MEDIUM_RELEASE(hardDisk); } VBOX_UTF16_FREE(hddPathUtf16); return ret; } static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool, const char *xml, unsigned int flags) { VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL); virStorageVolDefPtr def = NULL; PRUnichar *hddFormatUtf16 = NULL; PRUnichar *hddNameUtf16 = NULL; virStoragePoolDef poolDef; nsresult rc; virCheckFlags(0, NULL); /* since there is currently one default pool now * and virStorageVolDefFormat() just checks it type * so just assign it for now, change the behaviour * when vbox supports pools. */ memset(&poolDef, 0, sizeof(poolDef)); poolDef.type = VIR_STORAGE_POOL_DIR; if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL) goto cleanup; if (!def->name || (def->type != VIR_STORAGE_VOL_FILE)) goto cleanup; /* For now only the vmdk, vpc and vdi type harddisk * variants can be created. For historical reason, we default to vdi */ if (def->target.format == VIR_STORAGE_FILE_VMDK) { VBOX_UTF8_TO_UTF16("VMDK", &hddFormatUtf16); } else if (def->target.format == VIR_STORAGE_FILE_VPC) { VBOX_UTF8_TO_UTF16("VHD", &hddFormatUtf16); } else { VBOX_UTF8_TO_UTF16("VDI", &hddFormatUtf16); } VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16); if (hddFormatUtf16 && hddNameUtf16) { IHardDisk *hardDisk = NULL; rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk); if (NS_SUCCEEDED(rc)) { IProgress *progress = NULL; PRUint64 logicalSize = VIR_DIV_UP(def->target.capacity, 1024 * 1024); PRUint32 variant = HardDiskVariant_Standard; if (def->target.capacity == def->target.allocation) variant = HardDiskVariant_Fixed; #if VBOX_API_VERSION < 4003000 rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress); #else rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress); #endif if (NS_SUCCEEDED(rc) && progress) { #if VBOX_API_VERSION == 2002000 nsresult resultCode; #else PRInt32 resultCode; #endif progress->vtbl->WaitForCompletion(progress, -1); progress->vtbl->GetResultCode(progress, &resultCode); if (NS_SUCCEEDED(resultCode)) { vboxIID hddIID = VBOX_IID_INITIALIZER; unsigned char uuid[VIR_UUID_BUFLEN]; char key[VIR_UUID_STRING_BUFLEN] = ""; rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value); if (NS_SUCCEEDED(rc)) { vboxIIDToUUID(&hddIID, uuid); virUUIDFormat(uuid, key); ret = virGetStorageVol(pool->conn, pool->name, def->name, key, NULL, NULL); } vboxIIDUnalloc(&hddIID); } VBOX_RELEASE(progress); } } } VBOX_UTF16_FREE(hddFormatUtf16); VBOX_UTF16_FREE(hddNameUtf16); cleanup: virStorageVolDefFree(def); return ret; } static int vboxStorageVolDelete(virStorageVolPtr vol, unsigned int flags) { VBOX_OBJECT_CHECK(vol->conn, int, -1); vboxIID hddIID = VBOX_IID_INITIALIZER; unsigned char uuid[VIR_UUID_BUFLEN]; IHardDisk *hardDisk = NULL; int deregister = 0; nsresult rc; size_t i = 0; size_t j = 0; virCheckFlags(0, -1); if (virUUIDParse(vol->key, uuid) < 0) { virReportError(VIR_ERR_INVALID_ARG, _("Could not parse UUID from '%s'"), vol->key); return -1; } vboxIIDFromUUID(&hddIID, uuid); #if VBOX_API_VERSION < 4000000 rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk); #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, &hardDisk); #else rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, AccessMode_ReadWrite, PR_FALSE, &hardDisk); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_SUCCEEDED(rc)) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { PRUint32 machineIdsSize = 0; vboxArray machineIds = VBOX_ARRAY_INITIALIZER; #if VBOX_API_VERSION < 3001000 vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds); #else /* VBOX_API_VERSION >= 3001000 */ vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds); #endif /* VBOX_API_VERSION >= 3001000 */ #if VBOX_API_VERSION == 2002000 && defined WIN32 /* VirtualBox 2.2 on Windows represents IIDs as GUIDs and the * machineIds array contains direct instances of the GUID struct * instead of pointers to the actual struct instances. But there * is no 128bit width simple item type for a SafeArray to fit a * GUID in. The largest simple type it 64bit width and VirtualBox * uses two of this 64bit items to represents one GUID. Therefore, * we divide the size of the SafeArray by two, to compensate for * this workaround in VirtualBox */ machineIds.count /= 2; #endif /* VBOX_API_VERSION >= 2002000 */ machineIdsSize = machineIds.count; for (i = 0; i < machineIds.count; i++) { IMachine *machine = NULL; vboxIID machineId = VBOX_IID_INITIALIZER; vboxIIDFromArrayItem(&machineId, &machineIds, i); #if VBOX_API_VERSION >= 4000000 rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); break; } #endif rc = VBOX_SESSION_OPEN(machineId.value, machine); if (NS_SUCCEEDED(rc)) { rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine); if (NS_SUCCEEDED(rc)) { vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER; #if VBOX_API_VERSION < 3001000 vboxArrayGet(&hddAttachments, machine, machine->vtbl->GetHardDiskAttachments); #else /* VBOX_API_VERSION >= 3001000 */ vboxArrayGet(&hddAttachments, machine, machine->vtbl->GetMediumAttachments); #endif /* VBOX_API_VERSION >= 3001000 */ for (j = 0; j < hddAttachments.count; j++) { IHardDiskAttachment *hddAttachment = hddAttachments.items[j]; if (hddAttachment) { IHardDisk *hdd = NULL; #if VBOX_API_VERSION < 3001000 rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd); #else /* VBOX_API_VERSION >= 3001000 */ rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd); #endif /* VBOX_API_VERSION >= 3001000 */ if (NS_SUCCEEDED(rc) && hdd) { vboxIID iid = VBOX_IID_INITIALIZER; rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value); if (NS_SUCCEEDED(rc)) { DEBUGIID("HardDisk (to delete) UUID", hddIID.value); DEBUGIID("HardDisk (currently processing) UUID", iid.value); if (vboxIIDIsEqual(&hddIID, &iid)) { PRUnichar *controller = NULL; PRInt32 port = 0; PRInt32 device = 0; DEBUGIID("Found HardDisk to delete, UUID", hddIID.value); hddAttachment->vtbl->GetController(hddAttachment, &controller); hddAttachment->vtbl->GetPort(hddAttachment, &port); hddAttachment->vtbl->GetDevice(hddAttachment, &device); #if VBOX_API_VERSION < 3001000 rc = machine->vtbl->DetachHardDisk(machine, controller, port, device); #else /* VBOX_API_VERSION >= 3001000 */ rc = machine->vtbl->DetachDevice(machine, controller, port, device); #endif /* VBOX_API_VERSION >= 3001000 */ if (NS_SUCCEEDED(rc)) { rc = machine->vtbl->SaveSettings(machine); VIR_DEBUG("saving machine settings"); } if (NS_SUCCEEDED(rc)) { deregister++; VIR_DEBUG("deregistering hdd:%d", deregister); } VBOX_UTF16_FREE(controller); } vboxIIDUnalloc(&iid); } VBOX_MEDIUM_RELEASE(hdd); } } } vboxArrayRelease(&hddAttachments); VBOX_RELEASE(machine); } VBOX_SESSION_CLOSE(); } vboxIIDUnalloc(&machineId); } vboxArrayUnalloc(&machineIds); if (machineIdsSize == 0 || machineIdsSize == deregister) { IProgress *progress = NULL; rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress); if (NS_SUCCEEDED(rc) && progress) { progress->vtbl->WaitForCompletion(progress, -1); VBOX_RELEASE(progress); DEBUGIID("HardDisk deleted, UUID", hddIID.value); ret = 0; } } } VBOX_MEDIUM_RELEASE(hardDisk); } vboxIIDUnalloc(&hddIID); return ret; } static int vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) { VBOX_OBJECT_CHECK(vol->conn, int, -1); IHardDisk *hardDisk = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; vboxIID hddIID = VBOX_IID_INITIALIZER; nsresult rc; if (!info) return ret; if (virUUIDParse(vol->key, uuid) < 0) { virReportError(VIR_ERR_INVALID_ARG, _("Could not parse UUID from '%s'"), vol->key); return ret; } vboxIIDFromUUID(&hddIID, uuid); #if VBOX_API_VERSION < 4000000 rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk); #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, &hardDisk); #else rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, AccessMode_ReadWrite, PR_FALSE, &hardDisk); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_SUCCEEDED(rc)) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { #if VBOX_API_VERSION < 4000000 PRUint64 hddLogicalSize; PRUint64 hddActualSize; #else /* VBOX_API_VERSION >= 4000000 */ PRInt64 hddLogicalSize; PRInt64 hddActualSize; #endif /* VBOX_API_VERSION >= 4000000 */ info->type = VIR_STORAGE_VOL_FILE; hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize); #if VBOX_API_VERSION < 4000000 info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */ #else /* VBOX_API_VERSION >= 4000000 */ info->capacity = hddLogicalSize; #endif /* VBOX_API_VERSION >= 4000000 */ VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize); info->allocation = hddActualSize; ret = 0; VIR_DEBUG("Storage Volume Name: %s", vol->name); VIR_DEBUG("Storage Volume Type: %s", info->type == VIR_STORAGE_VOL_BLOCK ? "Block" : "File"); VIR_DEBUG("Storage Volume Capacity: %llu", info->capacity); VIR_DEBUG("Storage Volume Allocation: %llu", info->allocation); } VBOX_MEDIUM_RELEASE(hardDisk); } vboxIIDUnalloc(&hddIID); return ret; } static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags) { VBOX_OBJECT_CHECK(vol->conn, char *, NULL); IHardDisk *hardDisk = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; vboxIID hddIID = VBOX_IID_INITIALIZER; virStoragePoolDef pool; virStorageVolDef def; int defOk = 0; nsresult rc; virCheckFlags(0, NULL); memset(&pool, 0, sizeof(pool)); memset(&def, 0, sizeof(def)); if (virUUIDParse(vol->key, uuid) < 0) { virReportError(VIR_ERR_INVALID_ARG, _("Could not parse UUID from '%s'"), vol->key); return ret; } vboxIIDFromUUID(&hddIID, uuid); #if VBOX_API_VERSION < 4000000 rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk); #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, &hardDisk); #else rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, AccessMode_ReadWrite, PR_FALSE, &hardDisk); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_SUCCEEDED(rc)) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) { PRUnichar *hddFormatUtf16 = NULL; #if VBOX_API_VERSION < 4000000 PRUint64 hddLogicalSize; PRUint64 hddActualSize; #else /* VBOX_API_VERSION >= 4000000 */ PRInt64 hddLogicalSize; PRInt64 hddActualSize; #endif /* VBOX_API_VERSION >= 4000000 */ /* since there is currently one default pool now * and virStorageVolDefFormat() just checks it type * so just assign it for now, change the behaviour * when vbox supports pools. */ pool.type = VIR_STORAGE_POOL_DIR; def.type = VIR_STORAGE_VOL_FILE; defOk = 1; rc = hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize); if (NS_SUCCEEDED(rc) && defOk) { #if VBOX_API_VERSION < 4000000 def.target.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */ #else /* VBOX_API_VERSION >= 4000000 */ def.target.capacity = hddLogicalSize; #endif /* VBOX_API_VERSION >= 4000000 */ } else defOk = 0; rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize); if (NS_SUCCEEDED(rc) && defOk) def.target.allocation = hddActualSize; else defOk = 0; if (VIR_STRDUP(def.name, vol->name) < 0) defOk = 0; if (VIR_STRDUP(def.key, vol->key) < 0) defOk = 0; rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16); if (NS_SUCCEEDED(rc) && defOk) { char *hddFormatUtf8 = NULL; VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8); if (hddFormatUtf8) { VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8); if (STRCASEEQ("vmdk", hddFormatUtf8)) def.target.format = VIR_STORAGE_FILE_VMDK; else if (STRCASEEQ("vhd", hddFormatUtf8)) def.target.format = VIR_STORAGE_FILE_VPC; else if (STRCASEEQ("vdi", hddFormatUtf8)) def.target.format = VIR_STORAGE_FILE_VDI; else def.target.format = VIR_STORAGE_FILE_RAW; VBOX_UTF8_FREE(hddFormatUtf8); } VBOX_UTF16_FREE(hddFormatUtf16); } else { defOk = 0; } } VBOX_MEDIUM_RELEASE(hardDisk); } vboxIIDUnalloc(&hddIID); if (defOk) ret = virStorageVolDefFormat(&pool, &def); return ret; } static char *vboxStorageVolGetPath(virStorageVolPtr vol) { VBOX_OBJECT_CHECK(vol->conn, char *, NULL); IHardDisk *hardDisk = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; vboxIID hddIID = VBOX_IID_INITIALIZER; nsresult rc; if (virUUIDParse(vol->key, uuid) < 0) { virReportError(VIR_ERR_INVALID_ARG, _("Could not parse UUID from '%s'"), vol->key); return ret; } vboxIIDFromUUID(&hddIID, uuid); #if VBOX_API_VERSION < 4000000 rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk); #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, &hardDisk); #else rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value, DeviceType_HardDisk, AccessMode_ReadWrite, PR_FALSE, &hardDisk); #endif /* VBOX_API_VERSION >= 4000000 */ if (NS_SUCCEEDED(rc)) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { PRUnichar *hddLocationUtf16 = NULL; char *hddLocationUtf8 = NULL; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16); VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8); if (hddLocationUtf8) { ignore_value(VIR_STRDUP(ret, hddLocationUtf8)); VIR_DEBUG("Storage Volume Name: %s", vol->name); VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8); VIR_DEBUG("Storage Volume Pool: %s", vol->pool); VBOX_UTF8_FREE(hddLocationUtf8); } VBOX_UTF16_FREE(hddLocationUtf16); } VBOX_MEDIUM_RELEASE(hardDisk); } vboxIIDUnalloc(&hddIID); return ret; } #if VBOX_API_VERSION >= 4000000 static char * vboxDomainScreenshot(virDomainPtr dom, virStreamPtr st, unsigned int screen, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, char *, NULL); IConsole *console = NULL; vboxIID iid = VBOX_IID_INITIALIZER; IMachine *machine = NULL; nsresult rc; char *tmp; int tmp_fd = -1; unsigned int max_screen; virCheckFlags(0, NULL); vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); return NULL; } rc = machine->vtbl->GetMonitorCount(machine, &max_screen); if (NS_FAILED(rc)) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("unable to get monitor count")); VBOX_RELEASE(machine); return NULL; } if (screen >= max_screen) { virReportError(VIR_ERR_INVALID_ARG, _("screen ID higher than monitor " "count (%d)"), max_screen); VBOX_RELEASE(machine); return NULL; } if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) { VBOX_RELEASE(machine); return NULL; } if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) { virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp); VIR_FREE(tmp); VBOX_RELEASE(machine); return NULL; } rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine); if (NS_SUCCEEDED(rc)) { rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); if (NS_SUCCEEDED(rc) && console) { IDisplay *display = NULL; console->vtbl->GetDisplay(console, &display); if (display) { PRUint32 width, height, bitsPerPixel; PRUint32 screenDataSize; PRUint8 *screenData; # if VBOX_API_VERSION >= 4003000 PRInt32 xOrigin, yOrigin; # endif rc = display->vtbl->GetScreenResolution(display, screen, &width, &height, # if VBOX_API_VERSION < 4003000 &bitsPerPixel); # else &bitsPerPixel, &xOrigin, &yOrigin); # endif if (NS_FAILED(rc) || !width || !height) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("unable to get screen resolution")); goto endjob; } rc = display->vtbl->TakeScreenShotPNGToArray(display, screen, width, height, &screenDataSize, &screenData); if (NS_FAILED(rc)) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to take screenshot")); goto endjob; } if (safewrite(tmp_fd, (char *) screenData, screenDataSize) < 0) { virReportSystemError(errno, _("unable to write data " "to '%s'"), tmp); goto endjob; } if (VIR_CLOSE(tmp_fd) < 0) { virReportSystemError(errno, _("unable to close %s"), tmp); goto endjob; } if (VIR_STRDUP(ret, "image/png") < 0) goto endjob; if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("unable to open stream")); VIR_FREE(ret); } endjob: VIR_FREE(screenData); VBOX_RELEASE(display); } VBOX_RELEASE(console); } VBOX_SESSION_CLOSE(); } VIR_FORCE_CLOSE(tmp_fd); unlink(tmp); VIR_FREE(tmp); VBOX_RELEASE(machine); vboxIIDUnalloc(&iid); return ret; } #endif /* VBOX_API_VERSION >= 4000000 */ #define MATCH(FLAG) (flags & (FLAG)) static int vboxConnectListAllDomains(virConnectPtr conn, virDomainPtr **domains, unsigned int flags) { VBOX_OBJECT_CHECK(conn, int, -1); vboxArray machines = VBOX_ARRAY_INITIALIZER; char *machineNameUtf8 = NULL; PRUnichar *machineNameUtf16 = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; vboxIID iid = VBOX_IID_INITIALIZER; PRUint32 state; nsresult rc; size_t i; virDomainPtr dom; virDomainPtr *doms = NULL; int count = 0; bool active; PRUint32 snapshotCount; virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); /* filter out flag options that will produce 0 results in vbox driver: * - managed save: vbox guests don't have managed save images * - autostart: vbox doesn't support autostarting guests * - persistance: vbox doesn't support transient guests */ if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) || (MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART)) || (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) { if (domains && VIR_ALLOC_N(*domains, 1) < 0) goto cleanup; ret = 0; goto cleanup; } rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of domains, rc=%08x"), (unsigned)rc); goto cleanup; } if (domains && VIR_ALLOC_N(doms, machines.count + 1) < 0) goto cleanup; for (i = 0; i < machines.count; i++) { IMachine *machine = machines.items[i]; if (machine) { PRBool isAccessible = PR_FALSE; machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { machine->vtbl->GetState(machine, &state); if (state >= MachineState_FirstOnline && state <= MachineState_LastOnline) active = true; else active = false; /* filter by active state */ if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) || (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active))) continue; /* filter by snapshot existence */ if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) { rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get snapshot count for listed domains")); goto cleanup; } if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && snapshotCount > 0) || (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && snapshotCount == 0))) continue; } /* filter by machine state */ if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && state == MachineState_Running) || (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) && state == MachineState_Paused) || (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) && state == MachineState_PoweredOff) || (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) && (state != MachineState_Running && state != MachineState_Paused && state != MachineState_PoweredOff)))) continue; /* just count the machines */ if (!doms) { count++; continue; } machine->vtbl->GetName(machine, &machineNameUtf16); VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8); machine->vtbl->GetId(machine, &iid.value); vboxIIDToUUID(&iid, uuid); vboxIIDUnalloc(&iid); dom = virGetDomain(conn, machineNameUtf8, uuid); VBOX_UTF8_FREE(machineNameUtf8); VBOX_UTF16_FREE(machineNameUtf16); if (!dom) goto cleanup; if (active) dom->id = i + 1; doms[count++] = dom; } } } if (doms) { /* safe to ignore, new size will be equal or less than * previous allocation*/ ignore_value(VIR_REALLOC_N(doms, count + 1)); *domains = doms; doms = NULL; } ret = count; cleanup: if (doms) { for (i = 0; i < count; i++) { if (doms[i]) virDomainFree(doms[i]); } } VIR_FREE(doms); vboxArrayRelease(&machines); return ret; } #undef MATCH static int vboxNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) { return nodeGetInfo(nodeinfo); } static int vboxNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long *freeMems, int startCell, int maxCells) { return nodeGetCellsFreeMemory(freeMems, startCell, maxCells); } static unsigned long long vboxNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED) { unsigned long long freeMem; if (nodeGetMemory(NULL, &freeMem) < 0) return 0; return freeMem; } static int vboxNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned int npages, unsigned int *pages, int startCell, unsigned int cellCount, unsigned long long *counts, unsigned int flags) { virCheckFlags(0, -1); return nodeGetFreePages(npages, pages, startCell, cellCount, counts); } static int _pfnInitialize(vboxGlobalData *data) { data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION); if (data->pFuncs == NULL) return -1; #if VBOX_XPCOMC_VERSION == 0x00010000U data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession); #else /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */ data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj, ISESSION_IID_STR, &data->vboxSession); #endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */ return 0; } static int _initializeDomainEvent(vboxGlobalData *data ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 /* No event queue functionality in 2.2.* and 4.* as of now */ vboxUnsupported(); #else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ /* Initialize the fWatch needed for Event Callbacks */ data->fdWatch = -1; data->pFuncs->pfnGetEventQueue(&data->vboxQueue); if (data->vboxQueue == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nsIEventQueue object is null")); return -1; } #endif /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ return 0; } static void _registerGlobalData(vboxGlobalData *data ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION == 2002000 vboxUnsupported(); #else /* VBOX_API_VERSION != 2002000 */ g_pVBoxGlobalData = data; #endif /* VBOX_API_VERSION != 2002000 */ } #if VBOX_API_VERSION < 4000000 # if VBOX_API_VERSION < 3001000 static void _detachDevices(vboxGlobalData *data ATTRIBUTE_UNUSED, IMachine *machine, PRUnichar *hddcnameUtf16) { /* Disconnect all the drives if present */ machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 0); machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 1); machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 1, 1); } # else /* VBOX_API_VERSION >= 3001000 */ static void _detachDevices(vboxGlobalData *data, IMachine *machine, PRUnichar *hddcnameUtf16 ATTRIBUTE_UNUSED) { /* get all the controller first, then the attachments and * remove them all so that the machine can be undefined */ vboxArray storageControllers = VBOX_ARRAY_INITIALIZER; size_t i = 0, j = 0; vboxArrayGet(&storageControllers, machine, machine->vtbl->GetStorageControllers); for (i = 0; i < storageControllers.count; i++) { IStorageController *strCtl = storageControllers.items[i]; PRUnichar *strCtlName = NULL; vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; if (!strCtl) continue; strCtl->vtbl->GetName(strCtl, &strCtlName); vboxArrayGetWithPtrArg(&mediumAttachments, machine, machine->vtbl->GetMediumAttachmentsOfController, strCtlName); for (j = 0; j < mediumAttachments.count; j++) { IMediumAttachment *medAtt = mediumAttachments.items[j]; PRInt32 port = ~0U; PRInt32 device = ~0U; if (!medAtt) continue; medAtt->vtbl->GetPort(medAtt, &port); medAtt->vtbl->GetDevice(medAtt, &device); if ((port != ~0U) && (device != ~0U)) { machine->vtbl->DetachDevice(machine, strCtlName, port, device); } } vboxArrayRelease(&storageControllers); machine->vtbl->RemoveStorageController(machine, strCtlName); VBOX_UTF16_FREE(strCtlName); } vboxArrayRelease(&storageControllers); } # endif /* VBOX_API_VERSION >= 3001000 */ static nsresult _unregisterMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine) { return data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, IID_MEMBER(value), machine); } static void _deleteConfig(IMachine *machine) { machine->vtbl->DeleteSettings(machine); } #else /* VBOX_API_VERSION >= 4000000 */ static void _detachDevices(vboxGlobalData *data ATTRIBUTE_UNUSED, IMachine *machine ATTRIBUTE_UNUSED, PRUnichar *hddcnameUtf16 ATTRIBUTE_UNUSED) { vboxUnsupported(); } static nsresult _unregisterMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine) { nsresult rc; vboxArray media = VBOX_ARRAY_INITIALIZER; rc = VBOX_OBJECT_GET_MACHINE(IID_MEMBER(value), machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); return rc; } /* We're not interested in the array returned by the Unregister method, * but in the side effect of unregistering the virtual machine. In order * to call the Unregister method correctly we need to use the vboxArray * wrapper here. */ rc = vboxArrayGetWithUintArg(&media, *machine, (*machine)->vtbl->Unregister, CleanupMode_DetachAllReturnNone); vboxArrayUnalloc(&media); return rc; } static void _deleteConfig(IMachine *machine) { IProgress *progress = NULL; /* The IMachine Delete method takes an array of IMedium items to be * deleted along with the virtual machine. We just want to pass an * empty array. But instead of adding a full vboxArraySetWithReturn to * the glue layer (in order to handle the required signature of the * Delete method) we use a local solution here. */ # ifdef WIN32 SAFEARRAY *safeArray = NULL; typedef HRESULT __stdcall (*IMachine_Delete)(IMachine *self, SAFEARRAY **media, IProgress **progress); # if VBOX_API_VERSION < 4003000 ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress); # else ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress); # endif # else /* XPCOM doesn't like NULL as an array, even when the array size is 0. * Instead pass it a dummy array to avoid passing NULL. */ IMedium *array[] = { NULL }; # if VBOX_API_VERSION < 4003000 machine->vtbl->Delete(machine, 0, array, &progress); # else machine->vtbl->DeleteConfig(machine, 0, array, &progress); # endif # endif if (progress != NULL) { progress->vtbl->WaitForCompletion(progress, -1); VBOX_RELEASE(progress); } } #endif /* VBOX_API_VERSION >= 4000000 */ static void _pfnUninitialize(vboxGlobalData *data) { if (data->pFuncs) data->pFuncs->pfnComUninitialize(); } static void _pfnComUnallocMem(PCVBOXXPCOM pFuncs, void *pv) { pFuncs->pfnComUnallocMem(pv); } static void _pfnUtf16Free(PCVBOXXPCOM pFuncs, PRUnichar *pwszString) { pFuncs->pfnUtf16Free(pwszString); } static void _pfnUtf8Free(PCVBOXXPCOM pFuncs, char *pszString) { pFuncs->pfnUtf8Free(pszString); } static int _pfnUtf16ToUtf8(PCVBOXXPCOM pFuncs, const PRUnichar *pwszString, char **ppszString) { return pFuncs->pfnUtf16ToUtf8(pwszString, ppszString); } static int _pfnUtf8ToUtf16(PCVBOXXPCOM pFuncs, const char *pszString, PRUnichar **ppwszString) { return pFuncs->pfnUtf8ToUtf16(pszString, ppwszString); } #if VBOX_API_VERSION == 2002000 static void _vboxIIDInitialize(vboxIIDUnion *iidu) { memset(iidu, 0, sizeof(vboxIIDUnion)); } static void _DEBUGIID(const char *msg, vboxIIDUnion *iidu) { # ifdef WIN32 DEBUGUUID(msg, (nsID *)&IID_MEMBER(value)); # else /* !WIN32 */ DEBUGUUID(msg, IID_MEMBER(value)); # endif /* !WIN32 */ } #else /* VBOX_API_VERSION != 2002000 */ static void _vboxIIDInitialize(vboxIIDUnion *iidu) { memset(iidu, 0, sizeof(vboxIIDUnion)); IID_MEMBER(owner) = true; } static void _DEBUGIID(const char *msg, vboxIIDUnion *iidu) { DEBUGPRUnichar(msg, IID_MEMBER(value)); } #endif /* VBOX_API_VERSION != 2002000 */ static void* _handleGetMachines(IVirtualBox *vboxObj) { return vboxObj->vtbl->GetMachines; } static nsresult _nsisupportsRelease(nsISupports *nsi) { return nsi->vtbl->Release(nsi); } static nsresult _virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16) { return vboxObj->vtbl->GetVersion(vboxObj, versionUtf16); } #if VBOX_API_VERSION < 4000000 static nsresult _virtualboxGetMachine(IVirtualBox *vboxObj, vboxIIDUnion *iidu, IMachine **machine) { return vboxObj->vtbl->GetMachine(vboxObj, IID_MEMBER(value), machine); } #else /* VBOX_API_VERSION >= 4000000 */ static nsresult _virtualboxGetMachine(IVirtualBox *vboxObj, vboxIIDUnion *iidu, IMachine **machine) { return vboxObj->vtbl->FindMachine(vboxObj, IID_MEMBER(value), machine); } #endif /* VBOX_API_VERSION >= 4000000 */ static nsresult _virtualboxGetSystemProperties(IVirtualBox *vboxObj, ISystemProperties **systemProperties) { return vboxObj->vtbl->GetSystemProperties(vboxObj, systemProperties); } static nsresult _virtualboxCreateMachine(vboxGlobalData *data, virDomainDefPtr def, IMachine **machine, char *uuidstr ATTRIBUTE_UNUSED) { vboxIID iid = VBOX_IID_INITIALIZER; PRUnichar *machineNameUtf16 = NULL; nsresult rc; VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16); vboxIIDFromUUID(&iid, def->uuid); { #if VBOX_API_VERSION < 3002000 rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj, machineNameUtf16, NULL, NULL, iid.value, machine); #elif VBOX_API_VERSION < 4000000 /* 3002000 <= VBOX_API_VERSION < 4000000 */ PRBool override = PR_FALSE; rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj, machineNameUtf16, NULL, NULL, iid.value, override, machine); #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 PRBool override = PR_FALSE; rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj, NULL, machineNameUtf16, NULL, iid.value, override, machine); #else /* VBOX_API_VERSION >= 4002000 */ const char *flagsUUIDPrefix = "UUID="; const char *flagsForceOverwrite = "forceOverwrite=0"; const char *flagsSeparator = ","; char createFlags[strlen(flagsUUIDPrefix) + VIR_UUID_STRING_BUFLEN + strlen(flagsSeparator) + strlen(flagsForceOverwrite) + 1]; PRUnichar *createFlagsUtf16 = NULL; snprintf(createFlags, sizeof(createFlags), "%s%s%s%s", flagsUUIDPrefix, uuidstr, flagsSeparator, flagsForceOverwrite ); VBOX_UTF8_TO_UTF16(createFlags, &createFlagsUtf16); rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj, NULL, machineNameUtf16, 0, nsnull, nsnull, createFlagsUtf16, machine); #endif /* VBOX_API_VERSION >= 4002000 */ } VBOX_UTF16_FREE(machineNameUtf16); vboxIIDUnalloc(&iid); return rc; } static nsresult _virtualboxRegisterMachine(IVirtualBox *vboxObj, IMachine *machine) { return vboxObj->vtbl->RegisterMachine(vboxObj, machine); } static nsresult _virtualboxFindMedium(IVirtualBox *vboxObj ATTRIBUTE_UNUSED, PRUnichar *location ATTRIBUTE_UNUSED, PRUint32 deviceType ATTRIBUTE_UNUSED, PRUint32 accessMode ATTRIBUTE_UNUSED, IMedium **medium ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000 return vboxObj->vtbl->FindMedium(vboxObj, location, deviceType, medium); #elif VBOX_API_VERSION >= 4002000 return vboxObj->vtbl->OpenMedium(vboxObj, location, deviceType, accessMode, PR_FALSE, medium); #else vboxUnsupported(); return 0; #endif } static nsresult _virtualboxOpenMedium(IVirtualBox *vboxObj ATTRIBUTE_UNUSED, PRUnichar *location ATTRIBUTE_UNUSED, PRUint32 deviceType ATTRIBUTE_UNUSED, PRUint32 accessMode ATTRIBUTE_UNUSED, IMedium **medium ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION == 4000000 return vboxObj->vtbl->OpenMedium(vboxObj, location, deviceType, accessMode, medium); #elif VBOX_API_VERSION >= 4001000 return vboxObj->vtbl->OpenMedium(vboxObj, location, deviceType, accessMode, false, medium); #else vboxUnsupported(); return 0; #endif } static nsresult _machineAddStorageController(IMachine *machine, PRUnichar *name, PRUint32 connectionType, IStorageController **controller) { return machine->vtbl->AddStorageController(machine, name, connectionType, controller); } static nsresult _machineAttachDevice(IMachine *machine ATTRIBUTE_UNUSED, PRUnichar *name ATTRIBUTE_UNUSED, PRInt32 controllerPort ATTRIBUTE_UNUSED, PRInt32 device ATTRIBUTE_UNUSED, PRUint32 type ATTRIBUTE_UNUSED, IMedium * medium ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION >= 4000000 return machine->vtbl->AttachDevice(machine, name, controllerPort, device, type, medium); #else /* VBOX_API_VERSION < 4000000 */ vboxUnsupported(); return 0; #endif /* VBOX_API_VERSION < 4000000 */ } static nsresult _machineCreateSharedFolder(IMachine *machine, PRUnichar *name, PRUnichar *hostPath, PRBool writable, PRBool automount ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION < 4000000 return machine->vtbl->CreateSharedFolder(machine, name, hostPath, writable); #else /* VBOX_API_VERSION >= 4000000 */ return machine->vtbl->CreateSharedFolder(machine, name, hostPath, writable, automount); #endif /* VBOX_API_VERSION >= 4000000 */ } static nsresult _machineLaunchVMProcess(vboxGlobalData *data, IMachine *machine ATTRIBUTE_UNUSED, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, PRUnichar *sessionType, PRUnichar *env, IProgress **progress) { #if VBOX_API_VERSION < 4000000 return data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj, data->vboxSession, IID_MEMBER(value), sessionType, env, progress); #else /* VBOX_API_VERSION >= 4000000 */ return machine->vtbl->LaunchVMProcess(machine, data->vboxSession, sessionType, env, progress); #endif /* VBOX_API_VERSION >= 4000000 */ } static nsresult _machineGetAccessible(IMachine *machine, PRBool *isAccessible) { return machine->vtbl->GetAccessible(machine, isAccessible); } static nsresult _machineGetState(IMachine *machine, PRUint32 *state) { return machine->vtbl->GetState(machine, state); } static nsresult _machineGetName(IMachine *machine, PRUnichar **name) { return machine->vtbl->GetName(machine, name); } static nsresult _machineGetId(IMachine *machine, vboxIIDUnion *iidu) { return machine->vtbl->GetId(machine, &IID_MEMBER(value)); } static nsresult _machineGetBIOSSettings(IMachine *machine, IBIOSSettings **bios) { return machine->vtbl->GetBIOSSettings(machine, bios); } static nsresult _machineGetAudioAdapter(IMachine *machine, IAudioAdapter **audioadapter) { return machine->vtbl->GetAudioAdapter(machine, audioadapter); } static nsresult _machineGetNetworkAdapter(IMachine *machine, PRUint32 slot, INetworkAdapter **adapter) { return machine->vtbl->GetNetworkAdapter(machine, slot, adapter); } static nsresult _machineGetChipsetType(IMachine *machine ATTRIBUTE_UNUSED, PRUint32 *chipsetType ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION >= 4001000 return machine->vtbl->GetChipsetType(machine, chipsetType); #else /* VBOX_API_VERSION < 4001000 */ vboxUnsupported(); return 0; #endif /* VBOX_API_VERSION < 4001000 */ } static nsresult _machineGetSerialPort(IMachine *machine, PRUint32 slot, ISerialPort **port) { return machine->vtbl->GetSerialPort(machine, slot, port); } static nsresult _machineGetParallelPort(IMachine *machine, PRUint32 slot, IParallelPort **port) { return machine->vtbl->GetParallelPort(machine, slot, port); } static nsresult _machineGetVRDxServer(IMachine *machine, IVRDxServer **VRDxServer) { #if VBOX_API_VERSION < 4000000 return machine->vtbl->GetVRDPServer(machine, VRDxServer); #else /* VBOX_API_VERSION >= 4000000 */ return machine->vtbl->GetVRDEServer(machine, VRDxServer); #endif /* VBOX_API_VERSION >= 4000000 */ } static nsresult _machineGetUSBCommon(IMachine *machine, IUSBCommon **USBCommon) { #if VBOX_API_VERSION < 4003000 return machine->vtbl->GetUSBController(machine, USBCommon); #else return machine->vtbl->GetUSBDeviceFilters(machine, USBCommon); #endif } static nsresult _machineSetCPUCount(IMachine *machine, PRUint32 CPUCount) { return machine->vtbl->SetCPUCount(machine, CPUCount); } static nsresult _machineSetMemorySize(IMachine *machine, PRUint32 memorySize) { return machine->vtbl->SetMemorySize(machine, memorySize); } static nsresult _machineSetCPUProperty(IMachine *machine, PRUint32 property ATTRIBUTE_UNUSED, PRBool value) { #if VBOX_API_VERSION < 3001000 return machine->vtbl->SetPAEEnabled(machine, value); #elif VBOX_API_VERSION == 3001000 return machine->vtbl->SetCpuProperty(machine, property, value); #elif VBOX_API_VERSION >= 3002000 return machine->vtbl->SetCPUProperty(machine, property, value); #endif } static nsresult _machineSetBootOrder(IMachine *machine, PRUint32 position, PRUint32 device) { return machine->vtbl->SetBootOrder(machine, position, device); } static nsresult _machineSetVRAMSize(IMachine *machine, PRUint32 VRAMSize) { return machine->vtbl->SetVRAMSize(machine, VRAMSize); } static nsresult _machineSetMonitorCount(IMachine *machine, PRUint32 monitorCount) { return machine->vtbl->SetMonitorCount(machine, monitorCount); } static nsresult _machineSetAccelerate3DEnabled(IMachine *machine, PRBool accelerate3DEnabled) { return machine->vtbl->SetAccelerate3DEnabled(machine, accelerate3DEnabled); } static nsresult _machineSetAccelerate2DVideoEnabled(IMachine *machine ATTRIBUTE_UNUSED, PRBool accelerate2DVideoEnabled ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION >= 3001000 return machine->vtbl->SetAccelerate2DVideoEnabled(machine, accelerate2DVideoEnabled); #else /* VBOX_API_VERSION < 3001000 */ vboxUnsupported(); return 0; #endif /* VBOX_API_VERSION < 3001000 */ } static nsresult _machineGetExtraData(IMachine *machine, PRUnichar *key, PRUnichar **value) { return machine->vtbl->GetExtraData(machine, key, value); } static nsresult _machineSetExtraData(IMachine *machine, PRUnichar *key, PRUnichar *value) { return machine->vtbl->SetExtraData(machine, key, value); } static nsresult _machineSaveSettings(IMachine *machine) { return machine->vtbl->SaveSettings(machine); } #if VBOX_API_VERSION < 4000000 static nsresult _sessionOpen(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine ATTRIBUTE_UNUSED) { return data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, IID_MEMBER(value)); } static nsresult _sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine ATTRIBUTE_UNUSED) { return data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, IID_MEMBER(value)); } static nsresult _sessionClose(ISession *session) { return session->vtbl->Close(session); } #else /* VBOX_API_VERSION >= 4000000 */ static nsresult _sessionOpen(vboxGlobalData *data, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, IMachine *machine) { return machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Write); } static nsresult _sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, IMachine *machine) { return machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared); } static nsresult _sessionClose(ISession *session) { return session->vtbl->UnlockMachine(session); } #endif /* VBOX_API_VERSION >= 4000000 */ static nsresult _sessionGetConsole(ISession *session, IConsole **console) { return session->vtbl->GetConsole(session, console); } static nsresult _sessionGetMachine(ISession *session, IMachine **machine) { return session->vtbl->GetMachine(session, machine); } static nsresult _consoleSaveState(IConsole *console, IProgress **progress) { return console->vtbl->SaveState(console, progress); } static nsresult _progressWaitForCompletion(IProgress *progress, PRInt32 timeout) { return progress->vtbl->WaitForCompletion(progress, timeout); } static nsresult _progressGetResultCode(IProgress *progress, resultCodeUnion *resultCode) { #if VBOX_API_VERSION == 2002000 return progress->vtbl->GetResultCode(progress, &resultCode->uResultCode); #else /* VBOX_API_VERSION != 2002000 */ return progress->vtbl->GetResultCode(progress, &resultCode->resultCode); #endif /* VBOX_API_VERSION != 2002000 */ } static nsresult _progressGetCompleted(IProgress *progress, PRBool *completed) { return progress->vtbl->GetCompleted(progress, completed); } static nsresult _systemPropertiesGetMaxGuestCPUCount(ISystemProperties *systemProperties, PRUint32 *maxCPUCount) { return systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, maxCPUCount); } static nsresult _systemPropertiesGetMaxBootPosition(ISystemProperties *systemProperties, PRUint32 *maxBootPosition) { return systemProperties->vtbl->GetMaxBootPosition(systemProperties, maxBootPosition); } static nsresult _systemPropertiesGetMaxNetworkAdapters(ISystemProperties *systemProperties, PRUint32 chipset ATTRIBUTE_UNUSED, PRUint32 *maxNetworkAdapters) { #if VBOX_API_VERSION < 4001000 return systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, maxNetworkAdapters); #else /* VBOX_API_VERSION >= 4000000 */ return systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipset, maxNetworkAdapters); #endif /* VBOX_API_VERSION >= 4000000 */ } static nsresult _systemPropertiesGetSerialPortCount(ISystemProperties *systemProperties, PRUint32 *SerialPortCount) { return systemProperties->vtbl->GetSerialPortCount(systemProperties, SerialPortCount); } static nsresult _systemPropertiesGetParallelPortCount(ISystemProperties *systemProperties, PRUint32 *ParallelPortCount) { return systemProperties->vtbl->GetParallelPortCount(systemProperties, ParallelPortCount); } #if VBOX_API_VERSION >= 3001000 static nsresult _systemPropertiesGetMaxPortCountForStorageBus(ISystemProperties *systemProperties, PRUint32 bus, PRUint32 *maxPortCount) { return systemProperties->vtbl->GetMaxPortCountForStorageBus(systemProperties, bus, maxPortCount); } static nsresult _systemPropertiesGetMaxDevicesPerPortForStorageBus(ISystemProperties *systemProperties, PRUint32 bus, PRUint32 *maxDevicesPerPort) { return systemProperties->vtbl->GetMaxDevicesPerPortForStorageBus(systemProperties, bus, maxDevicesPerPort); } #else /* VBOX_API_VERSION < 3001000 */ static nsresult _systemPropertiesGetMaxPortCountForStorageBus(ISystemProperties *systemProperties ATTRIBUTE_UNUSED, PRUint32 bus ATTRIBUTE_UNUSED, PRUint32 *maxPortCount ATTRIBUTE_UNUSED) { vboxUnsupported(); return 0; } static nsresult _systemPropertiesGetMaxDevicesPerPortForStorageBus(ISystemProperties *systemProperties ATTRIBUTE_UNUSED, PRUint32 bus ATTRIBUTE_UNUSED, PRUint32 *maxDevicesPerPort ATTRIBUTE_UNUSED) { vboxUnsupported(); return 0; } #endif static nsresult _biosSettingsSetACPIEnabled(IBIOSSettings *bios, PRBool ACPIEnabled) { return bios->vtbl->SetACPIEnabled(bios, ACPIEnabled); } static nsresult _biosSettingsSetIOAPICEnabled(IBIOSSettings *bios, PRBool IOAPICEnabled) { return bios->vtbl->SetIOAPICEnabled(bios, IOAPICEnabled); } static nsresult _audioAdapterSetEnabled(IAudioAdapter *audioAdapter, PRBool enabled) { return audioAdapter->vtbl->SetEnabled(audioAdapter, enabled); } static nsresult _audioAdapterSetAudioController(IAudioAdapter *audioAdapter, PRUint32 audioController) { return audioAdapter->vtbl->SetAudioController(audioAdapter, audioController); } static nsresult _networkAdapterSetEnabled(INetworkAdapter *adapter, PRBool enabled) { return adapter->vtbl->SetEnabled(adapter, enabled); } static nsresult _networkAdapterSetAdapterType(INetworkAdapter *adapter, PRUint32 adapterType) { return adapter->vtbl->SetAdapterType(adapter, adapterType); } static nsresult _networkAdapterSetInternalNetwork(INetworkAdapter *adapter, PRUnichar *internalNetwork) { return adapter->vtbl->SetInternalNetwork(adapter, internalNetwork); } static nsresult _networkAdapterSetMACAddress(INetworkAdapter *adapter, PRUnichar *MACAddress) { return adapter->vtbl->SetMACAddress(adapter, MACAddress); } #if VBOX_API_VERSION < 4001000 static nsresult _networkAdapterSetBridgedInterface(INetworkAdapter *adapter, PRUnichar *hostInterface) { return adapter->vtbl->SetHostInterface(adapter, hostInterface); } static nsresult _networkAdapterSetHostOnlyInterface(INetworkAdapter *adapter, PRUnichar *hostOnlyInterface) { return adapter->vtbl->SetHostInterface(adapter, hostOnlyInterface); } static nsresult _networkAdapterAttachToBridgedInterface(INetworkAdapter *adapter) { return adapter->vtbl->AttachToBridgedInterface(adapter); } static nsresult _networkAdapterAttachToInternalNetwork(INetworkAdapter *adapter) { return adapter->vtbl->AttachToInternalNetwork(adapter); } static nsresult _networkAdapterAttachToHostOnlyInterface(INetworkAdapter *adapter) { return adapter->vtbl->AttachToHostOnlyInterface(adapter); } static nsresult _networkAdapterAttachToNAT(INetworkAdapter *adapter) { return adapter->vtbl->AttachToNAT(adapter); } #else /* VBOX_API_VERSION >= 4001000 */ static nsresult _networkAdapterSetBridgedInterface(INetworkAdapter *adapter, PRUnichar *bridgedInterface) { return adapter->vtbl->SetBridgedInterface(adapter, bridgedInterface); } static nsresult _networkAdapterSetHostOnlyInterface(INetworkAdapter *adapter, PRUnichar *hostOnlyInterface) { return adapter->vtbl->SetHostOnlyInterface(adapter, hostOnlyInterface); } static nsresult _networkAdapterAttachToBridgedInterface(INetworkAdapter *adapter) { return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged); } static nsresult _networkAdapterAttachToInternalNetwork(INetworkAdapter *adapter) { return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal); } static nsresult _networkAdapterAttachToHostOnlyInterface(INetworkAdapter *adapter) { return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly); } static nsresult _networkAdapterAttachToNAT(INetworkAdapter *adapter) { return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT); } #endif /* VBOX_API_VERSION >= 4001000 */ static nsresult _serialPortSetEnabled(ISerialPort *port, PRBool enabled) { return port->vtbl->SetEnabled(port, enabled); } static nsresult _serialPortSetPath(ISerialPort *port, PRUnichar *path) { return port->vtbl->SetPath(port, path); } static nsresult _serialPortSetIRQ(ISerialPort *port, PRUint32 IRQ) { return port->vtbl->SetIRQ(port, IRQ); } static nsresult _serialPortSetIOBase(ISerialPort *port, PRUint32 IOBase) { return port->vtbl->SetIOBase(port, IOBase); } static nsresult _serialPortSetHostMode(ISerialPort *port, PRUint32 hostMode) { return port->vtbl->SetHostMode(port, hostMode); } static nsresult _parallelPortSetEnabled(IParallelPort *port, PRBool enabled) { return port->vtbl->SetEnabled(port, enabled); } static nsresult _parallelPortSetPath(IParallelPort *port, PRUnichar *path) { return port->vtbl->SetPath(port, path); } static nsresult _parallelPortSetIRQ(IParallelPort *port, PRUint32 IRQ) { return port->vtbl->SetIRQ(port, IRQ); } static nsresult _parallelPortSetIOBase(IParallelPort *port, PRUint32 IOBase) { return port->vtbl->SetIOBase(port, IOBase); } static nsresult _vrdxServerSetEnabled(IVRDxServer *VRDxServer, PRBool enabled) { return VRDxServer->vtbl->SetEnabled(VRDxServer, enabled); } static nsresult _vrdxServerSetPorts(vboxGlobalData *data ATTRIBUTE_UNUSED, IVRDxServer *VRDxServer, virDomainGraphicsDefPtr graphics) { nsresult rc = 0; #if VBOX_API_VERSION < 3001000 if (graphics->data.rdp.port) { rc = VRDxServer->vtbl->SetPort(VRDxServer, graphics->data.rdp.port); VIR_DEBUG("VRDP Port changed to: %d", graphics->data.rdp.port); } else if (graphics->data.rdp.autoport) { /* Setting the port to 0 will reset its value to * the default one which is 3389 currently */ rc = VRDxServer->vtbl->SetPort(VRDxServer, 0); VIR_DEBUG("VRDP Port changed to default, which is 3389 currently"); } #elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */ PRUnichar *portUtf16 = NULL; portUtf16 = PRUnicharFromInt(graphics->data.rdp.port); rc = VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16); VBOX_UTF16_FREE(portUtf16); #else /* VBOX_API_VERSION >= 4000000 */ PRUnichar *VRDEPortsKey = NULL; PRUnichar *VRDEPortsValue = NULL; VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey); VRDEPortsValue = PRUnicharFromInt(graphics->data.rdp.port); rc = VRDxServer->vtbl->SetVRDEProperty(VRDxServer, VRDEPortsKey, VRDEPortsValue); VBOX_UTF16_FREE(VRDEPortsKey); VBOX_UTF16_FREE(VRDEPortsValue); #endif /* VBOX_API_VERSION >= 4000000 */ return rc; } static nsresult _vrdxServerSetReuseSingleConnection(IVRDxServer *VRDxServer, PRBool enabled) { return VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer, enabled); } static nsresult _vrdxServerSetAllowMultiConnection(IVRDxServer *VRDxServer, PRBool enabled) { return VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer, enabled); } static nsresult _vrdxServerSetNetAddress(vboxGlobalData *data ATTRIBUTE_UNUSED, IVRDxServer *VRDxServer, PRUnichar *netAddress) { #if VBOX_API_VERSION < 4000000 return VRDxServer->vtbl->SetNetAddress(VRDxServer, netAddress); #else /* VBOX_API_VERSION >= 4000000 */ PRUnichar *netAddressKey = NULL; nsresult rc; VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey); rc = VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey, netAddress); VBOX_UTF16_FREE(netAddressKey); return rc; #endif /* VBOX_API_VERSION >= 4000000 */ } static nsresult _usbCommonEnable(IUSBCommon *USBCommon ATTRIBUTE_UNUSED) { nsresult rc = 0; #if VBOX_API_VERSION < 4003000 USBCommon->vtbl->SetEnabled(USBCommon, 1); # if VBOX_API_VERSION < 4002000 rc = USBCommon->vtbl->SetEnabledEhci(USBCommon, 1); # else /* VBOX_API_VERSION >= 4002000 */ rc = USBCommon->vtbl->SetEnabledEHCI(USBCommon, 1); # endif /* VBOX_API_VERSION >= 4002000 */ #endif /* VBOX_API_VERSION >= 4003000 */ /* We don't need to set usb enabled for vbox 4.3 and later */ return rc; } static nsresult _usbCommonCreateDeviceFilter(IUSBCommon *USBCommon, PRUnichar *name, IUSBDeviceFilter **filter) { return USBCommon->vtbl->CreateDeviceFilter(USBCommon, name, filter); } static nsresult _usbCommonInsertDeviceFilter(IUSBCommon *USBCommon, PRUint32 position, IUSBDeviceFilter *filter) { return USBCommon->vtbl->InsertDeviceFilter(USBCommon, position, filter); } static nsresult _usbDeviceFilterSetProductId(IUSBDeviceFilter *USBDeviceFilter, PRUnichar *productId) { return USBDeviceFilter->vtbl->SetProductId(USBDeviceFilter, productId); } static nsresult _usbDeviceFilterSetActive(IUSBDeviceFilter *USBDeviceFilter, PRBool active) { return USBDeviceFilter->vtbl->SetActive(USBDeviceFilter, active); } static nsresult _usbDeviceFilterSetVendorId(IUSBDeviceFilter *USBDeviceFilter, PRUnichar *vendorId) { return USBDeviceFilter->vtbl->SetVendorId(USBDeviceFilter, vendorId); } static nsresult _mediumGetId(IMedium *medium, vboxIIDUnion *iidu) { return medium->vtbl->GetId(medium, &IID_MEMBER(value)); } static nsresult _mediumRelease(IMedium *medium) { return medium->vtbl->nsisupports.Release((nsISupports *)medium); } static nsresult _mediumSetType(IMedium *medium ATTRIBUTE_UNUSED, PRUint32 type ATTRIBUTE_UNUSED) { #if VBOX_API_VERSION > 3000000 return medium->vtbl->SetType(medium, type); #else vboxUnsupported(); return 0; #endif } static bool _machineStateOnline(PRUint32 state) { return ((state >= MachineState_FirstOnline) && (state <= MachineState_LastOnline)); } static bool _machineStateNotStart(PRUint32 state) { return ((state == MachineState_PoweredOff) || (state == MachineState_Saved) || (state == MachineState_Aborted)); } static vboxUniformedPFN _UPFN = { .Initialize = _pfnInitialize, .Uninitialize = _pfnUninitialize, .ComUnallocMem = _pfnComUnallocMem, .Utf16Free = _pfnUtf16Free, .Utf8Free = _pfnUtf8Free, .Utf16ToUtf8 = _pfnUtf16ToUtf8, .Utf8ToUtf16 = _pfnUtf8ToUtf16, }; static vboxUniformedIID _UIID = { .vboxIIDInitialize = _vboxIIDInitialize, .vboxIIDUnalloc = _vboxIIDUnalloc, .vboxIIDToUUID = _vboxIIDToUUID, .vboxIIDFromUUID = _vboxIIDFromUUID, .vboxIIDIsEqual = _vboxIIDIsEqual, .vboxIIDFromArrayItem = _vboxIIDFromArrayItem, .DEBUGIID = _DEBUGIID, }; static vboxUniformedArray _UArray = { .vboxArrayGet = vboxArrayGet, .vboxArrayRelease = vboxArrayRelease, .handleGetMachines = _handleGetMachines, }; static vboxUniformednsISupports _nsUISupports = { .Release = _nsisupportsRelease, }; static vboxUniformedIVirtualBox _UIVirtualBox = { .GetVersion = _virtualboxGetVersion, .GetMachine = _virtualboxGetMachine, .GetSystemProperties = _virtualboxGetSystemProperties, .CreateMachine = _virtualboxCreateMachine, .RegisterMachine = _virtualboxRegisterMachine, .FindMedium = _virtualboxFindMedium, .OpenMedium = _virtualboxOpenMedium, }; static vboxUniformedIMachine _UIMachine = { .AddStorageController = _machineAddStorageController, .AttachDevice = _machineAttachDevice, .CreateSharedFolder = _machineCreateSharedFolder, .LaunchVMProcess = _machineLaunchVMProcess, .GetAccessible = _machineGetAccessible, .GetState = _machineGetState, .GetName = _machineGetName, .GetId = _machineGetId, .GetBIOSSettings = _machineGetBIOSSettings, .GetAudioAdapter = _machineGetAudioAdapter, .GetNetworkAdapter = _machineGetNetworkAdapter, .GetChipsetType = _machineGetChipsetType, .GetSerialPort = _machineGetSerialPort, .GetParallelPort = _machineGetParallelPort, .GetVRDxServer = _machineGetVRDxServer, .GetUSBCommon = _machineGetUSBCommon, .SetCPUCount = _machineSetCPUCount, .SetMemorySize = _machineSetMemorySize, .SetCPUProperty = _machineSetCPUProperty, .SetBootOrder = _machineSetBootOrder, .SetVRAMSize = _machineSetVRAMSize, .SetMonitorCount = _machineSetMonitorCount, .SetAccelerate3DEnabled = _machineSetAccelerate3DEnabled, .SetAccelerate2DVideoEnabled = _machineSetAccelerate2DVideoEnabled, .GetExtraData = _machineGetExtraData, .SetExtraData = _machineSetExtraData, .SaveSettings = _machineSaveSettings, }; static vboxUniformedISession _UISession = { .Open = _sessionOpen, .OpenExisting = _sessionOpenExisting, .GetConsole = _sessionGetConsole, .GetMachine = _sessionGetMachine, .Close = _sessionClose, }; static vboxUniformedIConsole _UIConsole = { .SaveState = _consoleSaveState, }; static vboxUniformedIProgress _UIProgress = { .WaitForCompletion = _progressWaitForCompletion, .GetResultCode = _progressGetResultCode, .GetCompleted = _progressGetCompleted, }; static vboxUniformedISystemProperties _UISystemProperties = { .GetMaxGuestCPUCount = _systemPropertiesGetMaxGuestCPUCount, .GetMaxBootPosition = _systemPropertiesGetMaxBootPosition, .GetMaxNetworkAdapters = _systemPropertiesGetMaxNetworkAdapters, .GetSerialPortCount = _systemPropertiesGetSerialPortCount, .GetParallelPortCount = _systemPropertiesGetParallelPortCount, .GetMaxPortCountForStorageBus = _systemPropertiesGetMaxPortCountForStorageBus, .GetMaxDevicesPerPortForStorageBus = _systemPropertiesGetMaxDevicesPerPortForStorageBus, }; static vboxUniformedIBIOSSettings _UIBIOSSettings = { .SetACPIEnabled = _biosSettingsSetACPIEnabled, .SetIOAPICEnabled = _biosSettingsSetIOAPICEnabled, }; static vboxUniformedIAudioAdapter _UIAudioAdapter = { .SetEnabled = _audioAdapterSetEnabled, .SetAudioController = _audioAdapterSetAudioController, }; static vboxUniformedINetworkAdapter _UINetworkAdapter = { .SetEnabled = _networkAdapterSetEnabled, .SetAdapterType = _networkAdapterSetAdapterType, .SetBridgedInterface = _networkAdapterSetBridgedInterface, .SetInternalNetwork = _networkAdapterSetInternalNetwork, .SetHostOnlyInterface = _networkAdapterSetHostOnlyInterface, .SetMACAddress = _networkAdapterSetMACAddress, .AttachToBridgedInterface = _networkAdapterAttachToBridgedInterface, .AttachToInternalNetwork = _networkAdapterAttachToInternalNetwork, .AttachToHostOnlyInterface = _networkAdapterAttachToHostOnlyInterface, .AttachToNAT = _networkAdapterAttachToNAT, }; static vboxUniformedISerialPort _UISerialPort = { .SetEnabled = _serialPortSetEnabled, .SetPath = _serialPortSetPath, .SetIRQ = _serialPortSetIRQ, .SetIOBase = _serialPortSetIOBase, .SetHostMode = _serialPortSetHostMode, }; static vboxUniformedIParallelPort _UIParallelPort = { .SetEnabled = _parallelPortSetEnabled, .SetPath = _parallelPortSetPath, .SetIRQ = _parallelPortSetIRQ, .SetIOBase = _parallelPortSetIOBase, }; static vboxUniformedIVRDxServer _UIVRDxServer = { .SetEnabled = _vrdxServerSetEnabled, .SetPorts = _vrdxServerSetPorts, .SetReuseSingleConnection = _vrdxServerSetReuseSingleConnection, .SetAllowMultiConnection = _vrdxServerSetAllowMultiConnection, .SetNetAddress = _vrdxServerSetNetAddress, }; static vboxUniformedIUSBCommon _UIUSBCommon = { .Enable = _usbCommonEnable, .CreateDeviceFilter = _usbCommonCreateDeviceFilter, .InsertDeviceFilter = _usbCommonInsertDeviceFilter, }; static vboxUniformedIUSBDeviceFilter _UIUSBDeviceFilter = { .SetProductId = _usbDeviceFilterSetProductId, .SetActive = _usbDeviceFilterSetActive, .SetVendorId = _usbDeviceFilterSetVendorId, }; static vboxUniformedIMedium _UIMedium = { .GetId = _mediumGetId, .Release = _mediumRelease, .SetType = _mediumSetType, }; static uniformedMachineStateChecker _machineStateChecker = { .Online = _machineStateOnline, .NotStart = _machineStateNotStart, }; void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI) { pVBoxAPI->APIVersion = VBOX_API_VERSION; pVBoxAPI->XPCOMCVersion = VBOX_XPCOMC_VERSION; pVBoxAPI->initializeDomainEvent = _initializeDomainEvent; pVBoxAPI->registerGlobalData = _registerGlobalData; pVBoxAPI->detachDevices = _detachDevices; pVBoxAPI->unregisterMachine = _unregisterMachine; pVBoxAPI->deleteConfig = _deleteConfig; pVBoxAPI->vboxAttachDrivesOld = _vboxAttachDrivesOld; pVBoxAPI->UPFN = _UPFN; pVBoxAPI->UIID = _UIID; pVBoxAPI->UArray = _UArray; pVBoxAPI->nsUISupports = _nsUISupports; pVBoxAPI->UIVirtualBox = _UIVirtualBox; pVBoxAPI->UIMachine = _UIMachine; pVBoxAPI->UISession = _UISession; pVBoxAPI->UIConsole = _UIConsole; pVBoxAPI->UIProgress = _UIProgress; pVBoxAPI->UISystemProperties = _UISystemProperties; pVBoxAPI->UIBIOSSettings = _UIBIOSSettings; pVBoxAPI->UIAudioAdapter = _UIAudioAdapter; pVBoxAPI->UINetworkAdapter = _UINetworkAdapter; pVBoxAPI->UISerialPort = _UISerialPort; pVBoxAPI->UIParallelPort = _UIParallelPort; pVBoxAPI->UIVRDxServer = _UIVRDxServer; pVBoxAPI->UIUSBCommon = _UIUSBCommon; pVBoxAPI->UIUSBDeviceFilter = _UIUSBDeviceFilter; pVBoxAPI->UIMedium = _UIMedium; pVBoxAPI->machineStateChecker = _machineStateChecker; #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 pVBoxAPI->domainEventCallbacks = 0; #else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ pVBoxAPI->domainEventCallbacks = 1; #endif /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ #if VBOX_API_VERSION == 2002000 pVBoxAPI->hasStaticGlobalData = 0; #else /* VBOX_API_VERSION > 2002000 */ pVBoxAPI->hasStaticGlobalData = 1; #endif /* VBOX_API_VERSION > 2002000 */ #if VBOX_API_VERSION >= 4000000 /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */ pVBoxAPI->getMachineForSession = 1; pVBoxAPI->detachDevicesExplicitly = 0; pVBoxAPI->vboxAttachDrivesUseOld = 0; #else /* VBOX_API_VERSION < 4000000 */ pVBoxAPI->getMachineForSession = 0; pVBoxAPI->detachDevicesExplicitly = 1; pVBoxAPI->vboxAttachDrivesUseOld = 1; #endif /* VBOX_API_VERSION < 4000000 */ #if VBOX_API_VERSION >= 4001000 pVBoxAPI->chipsetType = 1; #else /* VBOX_API_VERSION < 4001000 */ pVBoxAPI->chipsetType = 0; #endif /* VBOX_API_VERSION < 4001000 */ #if VBOX_API_VERSION >= 3001000 pVBoxAPI->accelerate2DVideo = 1; #else /* VBOX_API_VERSION < 3001000 */ pVBoxAPI->accelerate2DVideo = 0; #endif /* VBOX_API_VERSION < 3001000 */ } /** * Function Tables */ virDriver NAME(Driver) = { .no = VIR_DRV_VBOX, .name = "VBOX", .connectOpen = vboxConnectOpen, /* 0.6.3 */ .connectClose = vboxConnectClose, /* 0.6.3 */ .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */ .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */ .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */ .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */ .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */ .connectListDomains = vboxConnectListDomains, /* 0.6.3 */ .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */ .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */ .domainCreateXML = vboxDomainCreateXML, /* 0.6.3 */ .domainLookupByID = vboxDomainLookupByID, /* 0.6.3 */ .domainLookupByUUID = vboxDomainLookupByUUID, /* 0.6.3 */ .domainLookupByName = vboxDomainLookupByName, /* 0.6.3 */ .domainSuspend = vboxDomainSuspend, /* 0.6.3 */ .domainResume = vboxDomainResume, /* 0.6.3 */ .domainShutdown = vboxDomainShutdown, /* 0.6.3 */ .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */ .domainReboot = vboxDomainReboot, /* 0.6.3 */ .domainDestroy = vboxDomainDestroy, /* 0.6.3 */ .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */ .domainGetOSType = vboxDomainGetOSType, /* 0.6.3 */ .domainSetMemory = vboxDomainSetMemory, /* 0.6.3 */ .domainGetInfo = vboxDomainGetInfo, /* 0.6.3 */ .domainGetState = vboxDomainGetState, /* 0.9.2 */ .domainSave = vboxDomainSave, /* 0.6.3 */ .domainSetVcpus = vboxDomainSetVcpus, /* 0.7.1 */ .domainSetVcpusFlags = vboxDomainSetVcpusFlags, /* 0.8.5 */ .domainGetVcpusFlags = vboxDomainGetVcpusFlags, /* 0.8.5 */ .domainGetMaxVcpus = vboxDomainGetMaxVcpus, /* 0.7.1 */ .domainGetXMLDesc = vboxDomainGetXMLDesc, /* 0.6.3 */ .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */ .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */ .domainCreate = vboxDomainCreate, /* 0.6.3 */ .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */ .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */ .domainUndefine = vboxDomainUndefine, /* 0.6.3 */ .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */ .domainAttachDevice = vboxDomainAttachDevice, /* 0.6.3 */ .domainAttachDeviceFlags = vboxDomainAttachDeviceFlags, /* 0.7.7 */ .domainDetachDevice = vboxDomainDetachDevice, /* 0.6.3 */ .domainDetachDeviceFlags = vboxDomainDetachDeviceFlags, /* 0.7.7 */ .domainUpdateDeviceFlags = vboxDomainUpdateDeviceFlags, /* 0.8.0 */ .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */ .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */ #if VBOX_API_VERSION >= 4000000 .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */ #endif #if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000 .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */ .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */ #endif .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */ .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */ .domainIsActive = vboxDomainIsActive, /* 0.7.3 */ .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */ .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */ #if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000 .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */ .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */ #endif .domainSnapshotCreateXML = vboxDomainSnapshotCreateXML, /* 0.8.0 */ .domainSnapshotGetXMLDesc = vboxDomainSnapshotGetXMLDesc, /* 0.8.0 */ .domainSnapshotNum = vboxDomainSnapshotNum, /* 0.8.0 */ .domainSnapshotListNames = vboxDomainSnapshotListNames, /* 0.8.0 */ .domainSnapshotLookupByName = vboxDomainSnapshotLookupByName, /* 0.8.0 */ .domainHasCurrentSnapshot = vboxDomainHasCurrentSnapshot, /* 0.8.0 */ .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */ .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */ .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */ .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */ .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */ .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */ .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */ .nodeGetFreePages = vboxNodeGetFreePages, /* 1.2.6 */ }; virNetworkDriver NAME(NetworkDriver) = { "VBOX", .networkOpen = vboxNetworkOpen, /* 0.6.4 */ .networkClose = vboxNetworkClose, /* 0.6.4 */ .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */ .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */ .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */ .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */ .networkLookupByUUID = vboxNetworkLookupByUUID, /* 0.6.4 */ .networkLookupByName = vboxNetworkLookupByName, /* 0.6.4 */ .networkCreateXML = vboxNetworkCreateXML, /* 0.6.4 */ .networkDefineXML = vboxNetworkDefineXML, /* 0.6.4 */ .networkUndefine = vboxNetworkUndefine, /* 0.6.4 */ .networkCreate = vboxNetworkCreate, /* 0.6.4 */ .networkDestroy = vboxNetworkDestroy, /* 0.6.4 */ .networkGetXMLDesc = vboxNetworkGetXMLDesc, /* 0.6.4 */ }; virStorageDriver NAME(StorageDriver) = { .name = "VBOX", .storageOpen = vboxStorageOpen, /* 0.7.1 */ .storageClose = vboxStorageClose, /* 0.7.1 */ .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */ .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */ .storagePoolLookupByName = vboxStoragePoolLookupByName, /* 0.7.1 */ .storagePoolNumOfVolumes = vboxStoragePoolNumOfVolumes, /* 0.7.1 */ .storagePoolListVolumes = vboxStoragePoolListVolumes, /* 0.7.1 */ .storageVolLookupByName = vboxStorageVolLookupByName, /* 0.7.1 */ .storageVolLookupByKey = vboxStorageVolLookupByKey, /* 0.7.1 */ .storageVolLookupByPath = vboxStorageVolLookupByPath, /* 0.7.1 */ .storageVolCreateXML = vboxStorageVolCreateXML, /* 0.7.1 */ .storageVolDelete = vboxStorageVolDelete, /* 0.7.1 */ .storageVolGetInfo = vboxStorageVolGetInfo, /* 0.7.1 */ .storageVolGetXMLDesc = vboxStorageVolGetXMLDesc, /* 0.7.1 */ .storageVolGetPath = vboxStorageVolGetPath /* 0.7.1 */ };