libvirt/src/vbox/vbox_tmpl.c

3669 lines
157 KiB
C
Raw Normal View History

/** @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) 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" 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 <config.h>
#include <dlfcn.h>
#include <sys/utsname.h>
#include "internal.h"
#include "datatypes.h"
#include "domain_conf.h"
#include "virterror_internal.h"
#include "uuid.h"
#include "memory.h"
#include "nodeinfo.h"
#include "logging.h"
#include "vbox_driver.h"
#include "vbox_XPCOMCGlue.h"
/* This one changes from version to version. */
#if VBOX_API_VERSION == 2002
# include "vbox_CAPI_v2_2.h"
/* Commented for now, v2.5 is far far away */
/*
#elif VBOX_API_VERSION == 2005
# include "VBoxCAPI_v2_5.h"
*/
#endif
#define VIR_FROM_THIS VIR_FROM_VBOX
#define vboxError(conn, code, fmt...) \
virReportErrorHelper(conn, VIR_FROM_VBOX, code, __FILE__, \
__FUNCTION__, __LINE__, fmt)
typedef struct {
virMutex lock;
int version;
virDomainObjList domains;
virCapsPtr caps;
IVirtualBox *vboxObj;
ISession *vboxSession;
} vboxGlobalData;
extern int errorval;
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
static int vboxDomainCreate(virDomainPtr dom);
static int vboxDomainUndefine(virDomainPtr dom);
static void nsIDtoChar(unsigned char *uuid, nsID *iid) {
char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
char uuidstrdst[VIR_UUID_STRING_BUFLEN];
unsigned char uuidinterim[VIR_UUID_BUFLEN];
int 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';
virUUIDParse(uuidstrdst, uuid);
}
static void vboxDriverLock(vboxGlobalData *data) {
virMutexLock(&data->lock);
}
static void vboxDriverUnlock(vboxGlobalData *data) {
virMutexUnlock(&data->lock);
}
static void nsIDFromChar(nsID *iid, unsigned char *uuid) {
char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
char uuidstrdst[VIR_UUID_STRING_BUFLEN];
unsigned char uuidinterim[VIR_UUID_BUFLEN];
int 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';
virUUIDParse(uuidstrdst, uuidinterim);
memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
}
static virCapsPtr vboxCapsInit(void) {
struct utsname utsname;
virCapsPtr caps;
virCapsGuestPtr guest;
uname(&utsname);
if ((caps = virCapabilitiesNew(utsname.machine,
0, 0)) == NULL)
goto no_memory;
if (virCapsInitNUMA(caps) < 0)
goto no_memory;
virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x08, 0x00, 0x27 });
if ((guest = virCapabilitiesAddGuest(caps,
"hvm",
utsname.machine,
sizeof(void *) * CHAR_BIT,
NULL,
NULL,
0,
NULL)) == NULL)
goto no_memory;
if (virCapabilitiesAddGuestDomain(guest,
"vbox",
NULL,
NULL,
0,
NULL) == NULL)
goto no_memory;
return caps;
no_memory:
virCapabilitiesFree(caps);
return NULL;
}
static int vboxInitialize(virConnectPtr conn, vboxGlobalData *data) {
if (VBoxCGlueInit() != 0) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR, "Can't Initialize VirtualBox, VBoxCGlueInit failed.");
goto cleanup;
}
g_pVBoxFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
if (data->vboxObj == NULL)
goto cleanup;
if (data->vboxSession == NULL)
goto cleanup;
return 0;
cleanup:
return -1;
}
static int vboxExtractVersion(virConnectPtr conn, vboxGlobalData *data) {
unsigned int major = 0;
unsigned int minor = 0;
unsigned int micro = 0;
int ret = -1;
PRUnichar *versionUtf16 = NULL;
nsresult rc;
if (data->version > 0)
return 0;
rc = data->vboxObj->vtbl->GetVersion(data->vboxObj, &versionUtf16);
if (NS_SUCCEEDED(rc)) {
char *vboxVersion = NULL;
g_pVBoxFuncs->pfnUtf16ToUtf8(versionUtf16, &vboxVersion);
if (sscanf(vboxVersion, "%u.%u.%u", &major, &minor, &micro) == 3)
ret = 0;
g_pVBoxFuncs->pfnUtf8Free(vboxVersion);
g_pVBoxFuncs->pfnComUnallocMem(versionUtf16);
} else {
ret = -1;
}
data->version = (major * 1000 * 1000) + (minor * 1000) + micro;
if (ret != 0)
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s",
"Cound not extract VirtualBox version");
return ret;
}
static void vboxUninitialize(vboxGlobalData *data) {
g_pVBoxFuncs->pfnComUninitialize();
VBoxCGlueTerm();
if (!data)
return;
virDomainObjListFree(&data->domains);
virCapabilitiesFree(data->caps);
VIR_FREE(data);
}
static virDrvOpenStatus vboxOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED) {
vboxGlobalData *data;
uid_t uid = getuid();
if (errorval == -1)
return VIR_DRV_OPEN_DECLINED;
if (conn->uri == NULL) {
conn->uri = xmlParseURI(uid ? "vbox:///session" : "vbox:///system");
if (conn->uri == NULL) {
return VIR_DRV_OPEN_ERROR;
}
} else if (conn->uri->scheme == NULL ||
conn->uri->path == NULL ) {
return VIR_DRV_OPEN_DECLINED;
}
if (STRNEQ (conn->uri->scheme, "vbox"))
return VIR_DRV_OPEN_DECLINED;
if (uid != 0) {
if (STRNEQ (conn->uri->path, "/session"))
return VIR_DRV_OPEN_DECLINED;
} else { /* root */
if (STRNEQ (conn->uri->path, "/system") &&
STRNEQ (conn->uri->path, "/session"))
return VIR_DRV_OPEN_DECLINED;
}
if (VIR_ALLOC(data) < 0) {
virReportOOMError(conn);
goto cleanup;
}
if (!(data->caps = vboxCapsInit()))
goto cleanup;
if (vboxInitialize(conn, data) < 0)
goto cleanup;
if (vboxExtractVersion(conn, data) < 0)
goto cleanup;
conn->privateData = data;
DEBUG0("in vboxOpen");
return VIR_DRV_OPEN_SUCCESS;
cleanup:
vboxUninitialize(data);
return VIR_DRV_OPEN_ERROR;
}
static int vboxClose(virConnectPtr conn) {
vboxGlobalData *data = conn->privateData;
DEBUG("%s: in vboxClose",conn->driver->name);
vboxUninitialize(data);
conn->privateData = NULL;
return 0;
}
static int vboxGetVersion(virConnectPtr conn, unsigned long *version) {
vboxGlobalData *data = conn->privateData;
DEBUG("%s: in vboxGetVersion",conn->driver->name);
vboxDriverLock(data);
*version = data->version;
vboxDriverUnlock(data);
return 0;
}
static char *vboxGetHostname(virConnectPtr conn) {
char *hostname;
/* the return string should be freed by caller */
hostname = virGetHostname();
if (hostname == NULL) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s",
"failed to determine host name");
return NULL;
}
return hostname;
}
static int vboxGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED) {
vboxGlobalData *data = conn->privateData;
PRUint32 maxCPUCount = 0;
int ret = -1;
/* VirtualBox Supports only hvm and thus the type passed to it
* has no meaning, setting it to ATTRIBUTE_UNUSED
*/
if(data->vboxObj) {
ISystemProperties *systemProperties = NULL;
data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
if (systemProperties) {
systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
}
}
if (maxCPUCount > 0)
ret = maxCPUCount;
return ret;
}
static int vboxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo) {
return virNodeInfoPopulate(conn, nodeinfo);
}
static char *vboxGetCapabilities(virConnectPtr conn) {
vboxGlobalData *data = conn->privateData;
char *ret;
vboxDriverLock(data);
ret = virCapabilitiesFormatXML(data->caps);
vboxDriverUnlock(data);
return ret;
}
static int vboxListDomains(virConnectPtr conn, int *ids, int nids) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
PRUint32 state;
int ret = -1;
int i, j;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get list of Domains",(unsigned)rc);
goto cleanup;
}
if (machineCnt == 0) {
ret = 0;
goto cleanup;
}
for (i = 0,j = 0; (i < machineCnt) && (j < nids); ++i) {
IMachine *machine = machines[i];
if (machine) {
PRBool isAccessible = PR_FALSE;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
machine->vtbl->GetState(machine, &state);
if ((state == MachineState_Running) ||
(state == MachineState_Paused) ) {
ret++;
ids[j++] = i;
}
}
}
}
ret++;
}
cleanup:
for (i = 0; i < machineCnt; ++i)
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
return ret;
}
static int vboxNumOfDomains(virConnectPtr conn) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
PRUint32 state;
int ret = -1;
int i;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get number of Domains",(unsigned)rc);
goto cleanup;
}
if (machineCnt == 0) {
ret = 0;
goto cleanup;
}
/* Do the cleanup as required by GetMachines() */
for (i = 0; i < machineCnt; ++i) {
IMachine *machine = machines[i];
if (machine) {
PRBool isAccessible = PR_FALSE;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
machine->vtbl->GetState(machine, &state);
if ((state == MachineState_Running) ||
(state == MachineState_Paused) ) {
ret++;
}
}
}
}
ret++;
}
cleanup:
for (i = 0; i < machineCnt; ++i)
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
return ret;
}
static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
unsigned int flags ATTRIBUTE_UNUSED) {
virDomainPtr dom = NULL;
/* VirtualBox currently doesn't have support for running
* virtual machines without actually defining them and thus
* for time being just define new machine and start it.
*
* TODO: After the appropriate API's are added in VirtualBox
* change this behaviour to the expected one.
*/
dom = vboxDomainDefineXML(conn, xml);
if (dom) {
if (vboxDomainCreate(dom) < 0)
goto cleanup;
} else {
goto cleanup;
}
return dom;
cleanup:
vboxDomainUndefine(dom);
return NULL;
}
static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
virDomainPtr dom = NULL;
nsID *iid = NULL;
unsigned char iidl[VIR_UUID_BUFLEN];
PRUint32 state;
int i;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get list of machines",(unsigned)rc);
return NULL;
}
if (id < machineCnt) {
if (machines[id]) {
PRBool isAccessible = PR_FALSE;
machines[id]->vtbl->GetAccessible(machines[id], &isAccessible);
if (isAccessible) {
machines[id]->vtbl->GetState(machines[id], &state);
if ((state == MachineState_Running) ||
(state == MachineState_Paused) ) {
PRUnichar *machineNameUtf16 = NULL;
char *machineName;
machines[id]->vtbl->GetName(machines[id], &machineNameUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineName);
machines[id]->vtbl->GetId(machines[id], &iid);
nsIDtoChar(iidl, iid);
/* get a new domain pointer from virGetDomain, if it fails
* then no need to assign the id, else assign the id, cause
* it is -1 by default. rest is taken care by virGetDomain
* itself, so need not worry.
*/
dom = virGetDomain(conn, machineName, iidl);
if (dom)
dom->id = id;
/* Cleanup all the XPCOM allocated stuff here */
g_pVBoxFuncs->pfnComUnallocMem(iid);
g_pVBoxFuncs->pfnUtf8Free(machineName);
g_pVBoxFuncs->pfnComUnallocMem(machineNameUtf16);
}
}
}
}
/* Do the cleanup as required by GetMachines() */
for (i = 0; i < machineCnt; ++i) {
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
}
}
return dom;
}
static virDomainPtr vboxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
virDomainPtr dom = NULL;
nsID *iid = NULL;
char *machineName = NULL;
PRUnichar *machineNameUtf16 = NULL;
unsigned char iidl[VIR_UUID_BUFLEN];
int i, matched = 0;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get list of machines",(unsigned)rc);
return NULL;
}
for (i = 0; i < machineCnt; ++i) {
IMachine *machine = machines[i];
PRBool isAccessible = PR_FALSE;
if (!machine)
continue;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
machine->vtbl->GetId(machine, &iid);
if (!iid)
continue;
nsIDtoChar(iidl, iid);
if (memcmp(uuid, iidl, VIR_UUID_BUFLEN) == 0) {
PRUint32 state;
matched = 1;
machine->vtbl->GetName(machine, &machineNameUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineName);
machine->vtbl->GetState(machine, &state);
/* get a new domain pointer from virGetDomain, if it fails
* then no need to assign the id, else assign the id, cause
* it is -1 by default. rest is taken care by virGetDomain
* itself, so need not worry.
*/
dom = virGetDomain(conn, machineName, iidl);
if (dom)
if ((state == MachineState_Running) ||
(state == MachineState_Paused) )
dom->id = i;
}
if (iid) {
g_pVBoxFuncs->pfnComUnallocMem(iid);
iid = NULL;
}
if (matched == 1)
break;
}
}
/* Do the cleanup and take care you dont leak any memory */
if (machineName)
g_pVBoxFuncs->pfnUtf8Free(machineName);
if (machineNameUtf16)
g_pVBoxFuncs->pfnComUnallocMem(machineNameUtf16);
for (i = 0; i < machineCnt; ++i) {
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
}
}
return dom;
}
static virDomainPtr vboxDomainLookupByName(virConnectPtr conn, const char *name) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
virDomainPtr dom = NULL;
nsID *iid = NULL;
char *machineName = NULL;
PRUnichar *machineNameUtf16 = NULL;
unsigned char iidl[VIR_UUID_BUFLEN];
int i, matched = 0;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get list of machines",(unsigned)rc);
return NULL;
}
for (i = 0; i < machineCnt; ++i) {
IMachine *machine = machines[i];
PRBool isAccessible = PR_FALSE;
if (!machine)
continue;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
machine->vtbl->GetName(machine, &machineNameUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineName);
if (machineName && (STREQ(name, machineName))) {
PRUint32 state;
matched = 1;
machine->vtbl->GetId(machine, &iid);
nsIDtoChar(iidl, iid);
machine->vtbl->GetState(machine, &state);
/* get a new domain pointer from virGetDomain, if it fails
* then no need to assign the id, else assign the id, cause
* it is -1 by default. rest is taken care by virGetDomain
* itself, so need not worry.
*/
dom = virGetDomain(conn, machineName, iidl);
if (dom)
if ((state == MachineState_Running) ||
(state == MachineState_Paused) )
dom->id = i;
}
if (machineName) {
g_pVBoxFuncs->pfnUtf8Free(machineName);
machineName = NULL;
}
if (machineNameUtf16) {
g_pVBoxFuncs->pfnComUnallocMem(machineNameUtf16);
machineNameUtf16 = NULL;
}
if (matched == 1)
break;
}
}
/* Do the cleanup and take care you dont leak any memory */
if (iid)
g_pVBoxFuncs->pfnComUnallocMem(iid);
for (i = 0; i < machineCnt; ++i) {
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
}
}
return dom;
}
static int vboxDomainSuspend(virDomainPtr dom) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
IConsole *console = NULL;
PRUint32 state;
int ret = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if (data->vboxObj) {
PRBool isAccessible = PR_FALSE;
nsIDFromChar(iid, dom->uuid);
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_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 */
data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
if (console) {
console->vtbl->Pause(console);
console->vtbl->nsisupports.Release((nsISupports *)console);
ret = 0;
} else {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "error while suspend the domain");
goto cleanup;
}
data->vboxSession->vtbl->Close(data->vboxSession);
} else {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "machine not in running state to suspend it");
goto cleanup;
}
}
}
cleanup:
if (machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
return ret;
}
static int vboxDomainResume(virDomainPtr dom) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
IConsole *console = NULL;
PRUint32 state = MachineState_Null;
int ret = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if (data->vboxObj) {
PRBool isAccessible = PR_FALSE;
nsIDFromChar(iid, dom->uuid);
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_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 */
data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
if (console) {
console->vtbl->Resume(console);
console->vtbl->nsisupports.Release((nsISupports *)console);
ret = 0;
} else {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "error while resuming the domain");
goto cleanup;
}
data->vboxSession->vtbl->Close(data->vboxSession);
} else {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "machine not paused, so can't resume it");
goto cleanup;
}
}
}
cleanup:
if (machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
return ret;
}
static int vboxDomainShutdown(virDomainPtr dom) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
IConsole *console = NULL;
PRUint32 state = MachineState_Null;
int ret = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if(data->vboxObj) {
PRBool isAccessible = PR_FALSE;
nsIDFromChar(iid, dom->uuid);
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_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) {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "machine paused, so can't power it down");
goto cleanup;
} else if (state == MachineState_PoweredOff) {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "machine already powered down");
goto cleanup;
}
data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
if (console) {
console->vtbl->PowerButton(console);
console->vtbl->nsisupports.Release((nsISupports *)console);
ret = 0;
}
data->vboxSession->vtbl->Close(data->vboxSession);
}
}
cleanup:
if (machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
return ret;
}
static int vboxDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
IConsole *console = NULL;
PRUint32 state = MachineState_Null;
int ret = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if(data->vboxObj) {
PRBool isAccessible = PR_FALSE;
nsIDFromChar(iid, dom->uuid);
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_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) {
data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
if (console) {
console->vtbl->Reset(console);
console->vtbl->nsisupports.Release((nsISupports *)console);
ret = 0;
}
data->vboxSession->vtbl->Close(data->vboxSession);
} else {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "machine not running, so can't reboot it");
goto cleanup;
}
}
}
cleanup:
if (machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
return ret;
}
static int vboxDomainDestroy(virDomainPtr dom) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
IConsole *console = NULL;
PRUint32 state = MachineState_Null;
int ret = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if(data->vboxObj) {
PRBool isAccessible = PR_FALSE;
nsIDFromChar(iid, dom->uuid);
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_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) {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "machine already powered down");
goto cleanup;
}
data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
if (console) {
console->vtbl->PowerDown(console);
console->vtbl->nsisupports.Release((nsISupports *)console);
ret = 0;
}
data->vboxSession->vtbl->Close(data->vboxSession);
}
}
cleanup:
if (machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
return ret;
}
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 ;)
*/
return strdup("hvm");
}
static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
PRUint32 state = MachineState_Null;
int ret = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if(data->vboxObj) {
PRBool isAccessible = PR_FALSE;
nsIDFromChar(iid, dom->uuid);
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_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) {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "memory size can't be changed unless domain is powered down");
goto cleanup;
}
rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
if (NS_SUCCEEDED(rc)) {
rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
if (NS_SUCCEEDED(rc) && machine) {
rc = machine->vtbl->SetMemorySize(machine, memory / 1024);
if (NS_SUCCEEDED(rc)) {
machine->vtbl->SaveSettings(machine);
ret = 0;
} else {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%lu Kb, rc=%08x",
"could not set the memory size of the domain to",
memory, (unsigned)rc);
}
}
data->vboxSession->vtbl->Close(data->vboxSession);
}
}
}
cleanup:
if (machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
return ret;
}
static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
char *machineName = NULL;
PRUnichar *machineNameUtf16 = NULL;
int i, ret = -1;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(NULL, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get list of machines",(unsigned)rc);
goto cleanup;
}
info->nrVirtCpu = 0;
for (i = 0; i < machineCnt; ++i) {
IMachine *machine = machines[i];
PRBool isAccessible = PR_FALSE;
if (!machine)
continue;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
machine->vtbl->GetName(machine, &machineNameUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(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 maxmem and memory 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 (This is 1 for current
* VirtualBox builds).
*/
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);
systemProperties->vtbl->nsisupports.Release((nsISupports *)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;
switch(state) {
case MachineState_Running:
info->state = VIR_DOMAIN_RUNNING;
break;
case MachineState_Stuck:
info->state = VIR_DOMAIN_BLOCKED;
break;
case MachineState_Paused:
info->state = VIR_DOMAIN_PAUSED;
break;
case MachineState_Stopping:
info->state = VIR_DOMAIN_SHUTDOWN;
break;
case MachineState_PoweredOff:
info->state = VIR_DOMAIN_SHUTOFF;
break;
case MachineState_Aborted:
info->state = VIR_DOMAIN_CRASHED;
break;
case MachineState_Null:
default:
info->state = VIR_DOMAIN_NOSTATE;
break;
}
}
if (machineName)
g_pVBoxFuncs->pfnUtf8Free(machineName);
if (machineNameUtf16)
g_pVBoxFuncs->pfnComUnallocMem(machineNameUtf16);
if (info->nrVirtCpu)
break;
}
}
/* Do the cleanup and take care you dont leak any memory */
for (i = 0; i < machineCnt; ++i) {
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
}
}
ret = 0;
cleanup:
return ret;
}
static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IConsole *console = NULL;
nsID *iid = NULL;
int ret = -1;
/* VirtualBox currently doesn't support saving to a file
* at a location other then the machine folder and thus
* setting path to ATTRIBUTE_UNUSED for now, will change
* this behaviour once get the VirtualBox API in right
* shape to do this
*/
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if(data->vboxObj) {
nsIDFromChar(iid, dom->uuid);
/* Open a Session for the machine */
rc = data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
if (NS_SUCCEEDED(rc)) {
rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
if (NS_SUCCEEDED(rc) && console) {
IProgress *progress = NULL;
console->vtbl->SaveState(console, &progress);
if (progress) {
nsresult resultCode;
progress->vtbl->WaitForCompletion(progress, -1);
progress->vtbl->GetResultCode(progress, &resultCode);
if (NS_SUCCEEDED(rc)) {
ret = 0;
}
progress->vtbl->nsisupports.Release((nsISupports *)progress);
}
console->vtbl->nsisupports.Release((nsISupports *)console);
}
data->vboxSession->vtbl->Close(data->vboxSession);
}
DEBUG("UUID of machine being saved:"
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(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]);
}
cleanup:
VIR_FREE(iid);
return ret;
}
static char *vboxDomainDumpXML(virDomainPtr dom, int flags) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
virDomainDefPtr def = NULL;
IMachine *machine = NULL;
nsID *iid = NULL;
char *ret = NULL;
int gotAllABoutDef = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if (VIR_ALLOC(def) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if(data->vboxObj) {
nsIDFromChar(iid, dom->uuid);
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_SUCCEEDED(rc) && machine) {
PRBool accessible = PR_FALSE;
machine->vtbl->GetAccessible(machine, &accessible);
if (accessible) {
int i = 0;
struct utsname utsname;
PRBool PAEEnabled = PR_FALSE;
PRBool ACPIEnabled = PR_FALSE;
PRBool IOAPICEnabled = PR_FALSE;
#if 0
PRBool VRDPEnabled = PR_FALSE;
#endif
PRInt32 hddNum = 0;
PRUint32 CPUCount = 0;
PRUint32 memorySize = 0;
PRUint32 netAdpCnt = 0;
PRUint32 netAdpIncCnt = 0;
PRUint32 maxMemorySize = 4 * 1024;
PRUint32 USBFilterCount = 0;
PRUint32 maxBootPosition = 0;
PRUint32 serialPortCount = 0;
PRUint32 serialPortIncCount = 0;
PRUint32 parallelPortCount = 0;
PRUint32 parallelPortIncCount = 0;
IBIOSSettings *bios = NULL;
IDVDDrive *dvdDrive = NULL;
IHardDisk *hardDiskPM = NULL;
IHardDisk *hardDiskPS = NULL;
IHardDisk *hardDiskSS = NULL;
PRUnichar *hddBusUtf16 = NULL;
#if 0
IVRDPServer *VRDPServer = NULL;
#endif
IFloppyDrive *floppyDrive = NULL;
IAudioAdapter *audioAdapter = NULL;
IUSBController *USBController = NULL;
ISystemProperties *systemProperties = NULL;
char *hddBus = strdup("IDE");
def->virtType = VIR_DOMAIN_VIRT_VBOX;
def->id = dom->id;
memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
def->name = strdup(dom->name);
machine->vtbl->GetMemorySize(machine, &memorySize);
def->memory = memorySize * 1024;
data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
if (systemProperties) {
systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount);
systemProperties->vtbl->GetParallelPortCount(systemProperties, &parallelPortCount);
systemProperties->vtbl->nsisupports.Release((nsISupports *)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->maxmem = maxMemorySize * 1024; */
def->maxmem = memorySize * 1024;
machine->vtbl->GetCPUCount(machine, &CPUCount);
def->vcpus = CPUCount;
/* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */
def->os.type = strdup("hvm");
uname(&utsname);
def->os.arch = strdup(utsname.machine);
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 */
}
}
def->features = 0;
machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
if (PAEEnabled) {
def->features = def->features | (1 << VIR_DOMAIN_FEATURE_PAE);
}
machine->vtbl->GetBIOSSettings(machine, &bios);
if (bios) {
bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
if (ACPIEnabled) {
def->features = def->features | (1 << VIR_DOMAIN_FEATURE_ACPI);
}
bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
if (IOAPICEnabled) {
def->features = def->features | (1 << VIR_DOMAIN_FEATURE_APIC);
}
bios->vtbl->nsisupports.Release((nsISupports *)bios);
}
/* Currently VirtualBox always uses locatime
* so locatime is always true here */
def->localtime = 1;
#if 0
machine->vtbl->GetVRDPServer(machine, &VRDPServer);
if (VRDPServer) {
VRDPServer->vtbl->GetEnabled(VRDPServer, &VRDPEnabled);
if (VRDPEnabled) {
if (VIR_ALLOC(def->graphics) >= 0) {
PRUint32 VRDPport = 0;
PRUnichar *netAddressUtf16 = NULL;
PRUnichar *sessionTypeUtf16 = NULL;
char *sessionTypeUtf8 = NULL;
char *netAddressUtf8 = NULL;
PRUint32 authType = VRDPAuthType_Null;
PRBool allowMultiConnection = PR_FALSE;
PRBool reuseSingleConnection = PR_FALSE;
def->graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
VRDPServer->vtbl->GetPort(VRDPServer, &VRDPport);
if (VRDPport) {
def->graphics->data.rdp.port = VRDPport;
} else {
def->graphics->data.rdp.autoport = 1;
}
VRDPServer->vtbl->GetNetAddress(VRDPServer, &netAddressUtf16);
if (netAddressUtf16) {
g_pVBoxFuncs->pfnUtf16ToUtf8(netAddressUtf16, &netAddressUtf8);
if (STRNEQ(netAddressUtf8, ""))
def->graphics->data.rdp.listenAddr = strdup(netAddressUtf8);
g_pVBoxFuncs->pfnUtf16Free(netAddressUtf16);
g_pVBoxFuncs->pfnUtf8Free(netAddressUtf8);
}
VRDPServer->vtbl->GetAuthType(VRDPServer, &authType);
if (authType == VRDPAuthType_External) {
PRUint32 authTimeout = 0;
VRDPServer->vtbl->GetAuthTimeout(VRDPServer, &authTimeout);
def->graphics->data.rdp.auth = strdup("external");
def->graphics->data.rdp.authtimeout = authTimeout;
} else if (authType == VRDPAuthType_Guest) {
PRUint32 authTimeout = 0;
VRDPServer->vtbl->GetAuthTimeout(VRDPServer, &authTimeout);
def->graphics->data.rdp.auth = strdup("guest");
def->graphics->data.rdp.authtimeout = authTimeout;
}
VRDPServer->vtbl->GetAllowMultiConnection(VRDPServer, &allowMultiConnection);
if (allowMultiConnection) {
def->graphics->data.rdp.multiconnections = 1;
}
VRDPServer->vtbl->GetReuseSingleConnection(VRDPServer, &reuseSingleConnection);
if (reuseSingleConnection) {
def->graphics->data.rdp.reuseconnection = 1;
}
machine->vtbl->GetSessionType(machine, &sessionTypeUtf16);
DEBUG0("Session Type:");
if (sessionTypeUtf16) {
g_pVBoxFuncs->pfnUtf16ToUtf8(sessionTypeUtf16, &sessionTypeUtf8);
DEBUG("Session Type: %s", sessionTypeUtf8);
if (STREQ(sessionTypeUtf8, "vrdp")) {
def->graphics->data.rdp.headless = 1;
}
g_pVBoxFuncs->pfnUtf16Free(sessionTypeUtf16);
g_pVBoxFuncs->pfnUtf8Free(sessionTypeUtf8);
}
}
}
VRDPServer->vtbl->nsisupports.Release((nsISupports *)VRDPServer);
}
#endif
/* dump IDE hdds if present */
g_pVBoxFuncs->pfnUtf8ToUtf16(hddBus, &hddBusUtf16);
VIR_FREE(hddBus);
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++;
g_pVBoxFuncs->pfnUtf16Free(hddBusUtf16);
if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
for (i = 0; i < def->ndisks; i++) {
if (VIR_ALLOC(def->disks[i]) >= 0) {
def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
def->disks[i]->type = VIR_DOMAIN_DISK_TYPE_FILE;
}
}
}
if (hardDiskPM) {
PRUnichar *hddlocationUtf16 = NULL;
char *hddlocation = NULL;
PRUint32 hddType = HardDiskType_Normal;
hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(hddlocationUtf16, &hddlocation);
hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
if (hddType == HardDiskType_Immutable)
def->disks[hddNum]->readonly = 1;
def->disks[hddNum]->src = strdup(hddlocation);
def->disks[hddNum]->dst = strdup("hda");
hddNum++;
g_pVBoxFuncs->pfnUtf8Free(hddlocation);
g_pVBoxFuncs->pfnUtf16Free(hddlocationUtf16);
hardDiskPM->vtbl->imedium.nsisupports.Release((nsISupports *)hardDiskPM);
}
if (hardDiskPS) {
PRUnichar *hddlocationUtf16 = NULL;
char *hddlocation = NULL;
PRUint32 hddType = HardDiskType_Normal;
hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(hddlocationUtf16, &hddlocation);
hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
if (hddType == HardDiskType_Immutable)
def->disks[hddNum]->readonly = 1;
def->disks[hddNum]->src = strdup(hddlocation);
def->disks[hddNum]->dst = strdup("hdb");
hddNum++;
g_pVBoxFuncs->pfnUtf8Free(hddlocation);
g_pVBoxFuncs->pfnUtf16Free(hddlocationUtf16);
hardDiskPS->vtbl->imedium.nsisupports.Release((nsISupports *)hardDiskPS);
}
if (hardDiskSS) {
PRUnichar *hddlocationUtf16 = NULL;
char *hddlocation = NULL;
PRUint32 hddType = HardDiskType_Normal;
hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(hddlocationUtf16, &hddlocation);
hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
if (hddType == HardDiskType_Immutable)
def->disks[hddNum]->readonly = 1;
def->disks[hddNum]->src = strdup(hddlocation);
def->disks[hddNum]->dst = strdup("hdd");
hddNum++;
g_pVBoxFuncs->pfnUtf8Free(hddlocation);
g_pVBoxFuncs->pfnUtf16Free(hddlocationUtf16);
hardDiskSS->vtbl->imedium.nsisupports.Release((nsISupports *)hardDiskSS);
}
/* 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++;
}
adapter->vtbl->nsisupports.Release((nsISupports *)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++) {
if (VIR_ALLOC(def->nets[i]) >= 0) {
}
}
}
/* 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;
adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(hostIntUtf16, &hostInt);
def->nets[netAdpIncCnt]->data.bridge.brname = strdup(hostInt);
g_pVBoxFuncs->pfnUtf8Free(hostInt);
g_pVBoxFuncs->pfnUtf16Free(hostIntUtf16);
#if 0
} 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);
g_pVBoxFuncs->pfnUtf16ToUtf8(intNetUtf16, &intNet);
def->nets[netAdpIncCnt]->data.internal.name = strdup(intNet);
g_pVBoxFuncs->pfnUtf8Free(intNet);
g_pVBoxFuncs->pfnUtf16Free(intNetUtf16);
} else if (attachmentType == NetworkAttachmentType_HostOnly) {
PRUnichar *hostIntUtf16 = NULL;
char *hostInt = NULL;
def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_HOSTONLY;
adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(hostIntUtf16, &hostInt);
def->nets[netAdpIncCnt]->data.hostonly.name = strdup(hostInt);
g_pVBoxFuncs->pfnUtf8Free(hostInt);
g_pVBoxFuncs->pfnUtf16Free(hostIntUtf16);
#endif
} 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) {
def->nets[netAdpIncCnt]->model = strdup("Am79C970A");
} else if (adapterType == NetworkAdapterType_Am79C973) {
def->nets[netAdpIncCnt]->model = strdup("Am79C973");
} else if (adapterType == NetworkAdapterType_I82540EM) {
def->nets[netAdpIncCnt]->model = strdup("82540EM");
} else if (adapterType == NetworkAdapterType_I82545EM) {
def->nets[netAdpIncCnt]->model = strdup("82545EM");
} else if (adapterType == NetworkAdapterType_I82543GC) {
def->nets[netAdpIncCnt]->model = strdup("82543GC");
}
adapter->vtbl->GetMACAddress(adapter, &MACAddressUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(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]);
virParseMacAddr(macaddr, def->nets[netAdpIncCnt]->mac);
netAdpIncCnt++;
g_pVBoxFuncs->pfnUtf16Free(MACAddressUtf16);
g_pVBoxFuncs->pfnUtf8Free(MACAddress);
}
adapter->vtbl->nsisupports.Release((nsISupports *)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_ES97;
}
} else {
VIR_FREE(def->sounds);
def->nsounds = 0;
}
} else {
def->nsounds = 0;
}
}
audioAdapter->vtbl->nsisupports.Release((nsISupports *)audioAdapter);
}
/* 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);
g_pVBoxFuncs->pfnUtf16ToUtf8(locationUtf16, &location);
def->ndisks++;
if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
def->disks[def->ndisks - 1]->readonly = 1;
def->disks[def->ndisks - 1]->src = strdup(location);
def->disks[def->ndisks - 1]->dst = strdup("hdc");
} else {
def->ndisks--;
}
} else {
def->ndisks--;
}
g_pVBoxFuncs->pfnUtf8Free(location);
g_pVBoxFuncs->pfnUtf16Free(locationUtf16);
dvdImage->vtbl->imedium.nsisupports.Release((nsISupports *)dvdImage);
}
}
dvdDrive->vtbl->nsisupports.Release((nsISupports *)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);
g_pVBoxFuncs->pfnUtf16ToUtf8(locationUtf16, &location);
def->ndisks++;
if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
def->disks[def->ndisks - 1]->readonly = 0;
def->disks[def->ndisks - 1]->src = strdup(location);
def->disks[def->ndisks - 1]->dst = strdup("fda");
} else {
def->ndisks--;
}
} else {
def->ndisks--;
}
g_pVBoxFuncs->pfnUtf8Free(location);
g_pVBoxFuncs->pfnUtf16Free(locationUtf16);
floppyImage->vtbl->imedium.nsisupports.Release((nsISupports *)floppyImage);
}
}
}
floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
}
/* 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++;
}
serialPort->vtbl->nsisupports.Release((nsISupports *)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++) {
if (VIR_ALLOC(def->serials[i]) >= 0) {
}
}
}
/* 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]->type = VIR_DOMAIN_CHR_TYPE_PIPE;
} else if (hostMode == PortMode_HostDevice) {
def->serials[serialPortIncCount]->type = VIR_DOMAIN_CHR_TYPE_DEV;
} else {
def->serials[serialPortIncCount]->type = VIR_DOMAIN_CHR_TYPE_NULL;
}
serialPort->vtbl->GetIRQ(serialPort, &IRQ);
serialPort->vtbl->GetIOBase(serialPort, &IOBase);
if ((IRQ == 4) && (IOBase == 1016)) {
def->serials[serialPortIncCount]->dstPort = 0;
} else if ((IRQ == 3) && (IOBase == 760)) {
def->serials[serialPortIncCount]->dstPort = 1;
}
serialPort->vtbl->GetPath(serialPort, &pathUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(pathUtf16, &path);
def->serials[serialPortIncCount]->data.file.path = strdup(path);
serialPortIncCount++;
g_pVBoxFuncs->pfnUtf16Free(pathUtf16);
g_pVBoxFuncs->pfnUtf8Free(path);
}
serialPort->vtbl->nsisupports.Release((nsISupports *)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, &parallelPort);
if (parallelPort) {
PRBool enabled = PR_FALSE;
parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
if (enabled) {
def->nparallels++;
}
parallelPort->vtbl->nsisupports.Release((nsISupports *)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++) {
if (VIR_ALLOC(def->parallels[i]) >= 0) {
}
}
}
/* 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, &parallelPort);
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]->dstPort = 0;
} else if ((IRQ == 5) && (IOBase == 632)) {
def->parallels[parallelPortIncCount]->dstPort = 1;
}
def->parallels[parallelPortIncCount]->type = VIR_DOMAIN_CHR_TYPE_FILE;
parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(pathUtf16, &path);
def->parallels[parallelPortIncCount]->data.file.path = strdup(path);
parallelPortIncCount++;
g_pVBoxFuncs->pfnUtf16Free(pathUtf16);
g_pVBoxFuncs->pfnUtf8Free(path);
}
parallelPort->vtbl->nsisupports.Release((nsISupports *)parallelPort);
}
}
/* dump USB devices/filters if active */
def->nhostdevs = 0;
machine->vtbl->GetUSBController(machine, &USBController);
if (USBController) {
PRBool enabled = PR_FALSE;
USBController->vtbl->GetEnabled(USBController, &enabled);
if (enabled) {
PRUint32 deviceFiltersNum = 0;
IUSBDeviceFilter **deviceFilters = NULL;
USBController->vtbl->GetDeviceFilters(USBController,
&deviceFiltersNum,
&deviceFilters);
if (deviceFiltersNum > 0) {
/* check if the filters are active and then only
* alloc mem and set def->nhostdevs
*/
for(i = 0; i < deviceFiltersNum; i++) {
PRBool active = PR_FALSE;
deviceFilters[i]->vtbl->GetActive(deviceFilters[i], &active);
if (active) {
def->nhostdevs++;
}
}
if (def->nhostdevs > 0) {
/* Alloc mem needed for the filters now */
if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) >= 0) {
for(i = 0; (USBFilterCount < def->nhostdevs) || (i < deviceFiltersNum); i++) {
PRBool active = PR_FALSE;
deviceFilters[i]->vtbl->GetActive(deviceFilters[i], &active);
if (active) {
if (VIR_ALLOC(def->hostdevs[USBFilterCount]) >= 0) {
PRUnichar *vendorIdUtf16 = NULL;
char *vendorIdUtf8 = NULL;
unsigned vendorId = 0;
PRUnichar *productIdUtf16 = NULL;
char *productIdUtf8 = NULL;
unsigned productId = 0;
char *endptr = NULL;
def->hostdevs[USBFilterCount]->mode =
VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
def->hostdevs[USBFilterCount]->source.subsys.type =
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
deviceFilters[i]->vtbl->GetVendorId(deviceFilters[i], &vendorIdUtf16);
deviceFilters[i]->vtbl->GetProductId(deviceFilters[i], &productIdUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(vendorIdUtf16, &vendorIdUtf8);
g_pVBoxFuncs->pfnUtf16ToUtf8(productIdUtf16, &productIdUtf8);
vendorId = strtol(vendorIdUtf8, &endptr, 16);
productId = strtol(productIdUtf8, &endptr, 16);
def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor = vendorId;
def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId;
g_pVBoxFuncs->pfnUtf16Free(vendorIdUtf16);
g_pVBoxFuncs->pfnUtf8Free(vendorIdUtf8);
g_pVBoxFuncs->pfnUtf16Free(productIdUtf16);
g_pVBoxFuncs->pfnUtf8Free(productIdUtf8);
USBFilterCount++;
}
}
}
}
}
}
/* Cleanup */
for(i = 0; i < deviceFiltersNum; i++) {
if (deviceFilters[i])
deviceFilters[i]->vtbl->nsisupports.Release((nsISupports *)deviceFilters[i]);
}
}
USBController->vtbl->nsisupports.Release((nsISupports *)USBController);
}
/* all done so set gotAllABoutDef and pass def to virDomainDefFormat
* to generate XML for it
*/
gotAllABoutDef = 0;
}
machine->vtbl->nsisupports.Release((nsISupports *)machine);
machine = NULL;
}
}
if (gotAllABoutDef == 0)
ret = virDomainDefFormat(dom->conn, def, flags);
cleanup:
VIR_FREE(iid);
virDomainDefFree(def);
return ret;
}
static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
char *machineName = NULL;
PRUnichar *machineNameUtf16 = NULL;
PRUint32 state;
int ret = -1;
int i, j;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get list of Defined Domains",(unsigned)rc);
goto cleanup;
}
if (machineCnt == 0) {
ret = 0;
goto cleanup;
}
for (i = 0,j = 0; (i < machineCnt) && (j < maxnames); i++) {
IMachine *machine = machines[i];
if (machine) {
PRBool isAccessible = PR_FALSE;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
machine->vtbl->GetState(machine, &state);
if ((state != MachineState_Running) &&
(state != MachineState_Paused) ) {
machine->vtbl->GetName(machine, &machineNameUtf16);
g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineName);
if (!(names[j++] = strdup(machineName))) {
virReportOOMError(conn);
for ( ; j >= 0 ; j--)
VIR_FREE(names[j]);
ret = -1;
goto cleanup;
}
ret++;
}
}
}
}
ret++;
}
cleanup:
g_pVBoxFuncs->pfnUtf8Free(machineName);
g_pVBoxFuncs->pfnUtf16Free(machineNameUtf16);
for (i = 0; i < machineCnt; ++i)
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
return ret;
}
static int vboxNumOfDefinedDomains(virConnectPtr conn) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine **machines = NULL;
PRUint32 machineCnt = 0;
PRUint32 state = MachineState_Null;
int ret = -1;
int i;
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get number of Defined Domains",(unsigned)rc);
goto cleanup;
}
if (machineCnt == 0) {
ret = 0;
goto cleanup;
}
/* Do the cleanup as required by GetMachines() */
for (i = 0; i < machineCnt; ++i) {
IMachine *machine = machines[i];
if (machine) {
PRBool isAccessible = PR_FALSE;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
machine->vtbl->GetState(machine, &state);
if ((state != MachineState_Running) &&
(state != MachineState_Paused) ) {
ret++;
}
}
}
}
ret++;
}
cleanup:
for (i = 0; i < machineCnt; ++i)
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
return ret;
}
static int vboxDomainCreate(virDomainPtr dom) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine **machines = NULL;
IProgress *progress = NULL;
PRUint32 machineCnt = 0;
PRUnichar *env = NULL;
const char *display = getenv("DISPLAY");
PRUnichar *sessionType = NULL;
char displayutf8[32] = {0};
unsigned char iidl[VIR_UUID_BUFLEN] = {0};
int i, ret = -1;
if (display) {
sprintf(displayutf8, "DISPLAY=%s", display);
g_pVBoxFuncs->pfnUtf8ToUtf16(displayutf8, &env);
}
g_pVBoxFuncs->pfnUtf8ToUtf16("gui", &sessionType);
if (!dom->name) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s",
"Error while reading the domain name");
goto cleanup;
}
if(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"Could not get list of machines",(unsigned)rc);
goto cleanup;
}
for (i = 0; i < machineCnt; ++i) {
IMachine *machine = machines[i];
PRBool isAccessible = PR_FALSE;
if (!machine)
continue;
machine->vtbl->GetAccessible(machine, &isAccessible);
if (isAccessible) {
nsID *iid = NULL;
machine->vtbl->GetId(machine, &iid);
if (!iid)
continue;
nsIDtoChar(iidl, iid);
if (memcmp(dom->uuid, iidl, VIR_UUID_BUFLEN) == 0) {
PRUint32 state = MachineState_Null;
machine->vtbl->GetState(machine, &state);
if ( (state == MachineState_PoweredOff) ||
(state == MachineState_Saved) ||
(state == MachineState_Aborted) ) {
data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
data->vboxSession,
iid,
sessionType,
env,
&progress );
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "openremotesession failed, domain can't be started");
ret = -1;
} else {
PRBool completed = 0;
nsresult resultCode;
progress->vtbl->WaitForCompletion(progress, -1);
rc = progress->vtbl->GetCompleted(progress, &completed);
if (NS_FAILED(rc)) {
/* error */
ret = -1;
}
progress->vtbl->GetResultCode(progress, &resultCode);
if (NS_FAILED(resultCode)) {
/* error */
ret = -1;
} else {
/* all ok set the domid */
dom->id = i;
ret = 0;
}
}
if (progress)
progress->vtbl->nsisupports.Release((nsISupports *)progress);
data->vboxSession->vtbl->Close(data->vboxSession);
} else {
vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
"%s", "machine is not in poweroff|saved|"
"aborted state, so couldn't start it");
ret = -1;
}
}
if (iid)
g_pVBoxFuncs->pfnComUnallocMem(iid);
if (ret != -1)
break;
}
}
/* Do the cleanup and take care you dont leak any memory */
for (i = 0; i < machineCnt; ++i) {
if (machines[i])
machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
}
}
g_pVBoxFuncs->pfnUtf16Free(env);
g_pVBoxFuncs->pfnUtf16Free(sessionType);
cleanup:
return ret;
}
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) {
nsresult rc;
vboxGlobalData *data = conn->privateData;
IMachine *machine = NULL;
IBIOSSettings *bios = NULL;
virDomainPtr dom = NULL;
nsID *iid = NULL;
nsID *mchiid = NULL;
virDomainDefPtr def = NULL;
PRUnichar *machineNameUtf16 = NULL;
if (!(def = virDomainDefParseString(conn, data->caps, xml,
VIR_DOMAIN_XML_INACTIVE))) {
goto cleanup;
}
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(conn);
goto cleanup;
}
if (data->vboxObj) {
g_pVBoxFuncs->pfnUtf8ToUtf16(def->name, &machineNameUtf16);
nsIDFromChar(iid, def->uuid);
rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
machineNameUtf16,
NULL,
NULL,
iid,
&machine);
g_pVBoxFuncs->pfnUtf16Free(machineNameUtf16);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"could not define a domain",(unsigned)rc);
goto cleanup;
}
rc = machine->vtbl->SetMemorySize(machine, def->memory / 1024);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%lu Kb, rc=%08x",
"could not set the memory size of the domain to",
def->memory, (unsigned)rc);
}
rc = machine->vtbl->SetCPUCount(machine, def->vcpus);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%lu, rc=%08x",
"could not set the number of virtual CPUs to",
def->vcpus, (unsigned)rc);
}
rc = machine->vtbl->SetPAEEnabled(machine, (def->features) &
(1 << VIR_DOMAIN_FEATURE_PAE));
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not change PAE status to",
((def->features) & (1 << VIR_DOMAIN_FEATURE_PAE))
? "Enabled" : "Disabled", (unsigned)rc);
}
machine->vtbl->GetBIOSSettings(machine, &bios);
if (bios) {
rc = bios->vtbl->SetACPIEnabled(bios, (def->features) &
(1 << VIR_DOMAIN_FEATURE_ACPI));
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not change ACPI status to",
((def->features) & (1 << VIR_DOMAIN_FEATURE_ACPI))
? "Enabled" : "Disabled", (unsigned)rc);
}
rc = bios->vtbl->SetIOAPICEnabled(bios, (def->features) &
(1 << VIR_DOMAIN_FEATURE_APIC));
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not change APIC status to",
((def->features) & (1 << VIR_DOMAIN_FEATURE_APIC))
? "Enabled" : "Disabled", (unsigned)rc);
}
bios->vtbl->nsisupports.Release((nsISupports *)bios);
}
/* Register the machine before attaching other devices to it */
rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"could not define a domain",(unsigned)rc);
goto cleanup;
}
/* Get the uuid of the machine, currently it is immutable
* object so open a session to it and get it back, so that
* you can make changes to the machine setting
*/
machine->vtbl->GetId(machine, &mchiid);
data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, mchiid);
data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
{ /* Started:Block to set the boot device order */
ISystemProperties *systemProperties = NULL;
PRUint32 maxBootPosition = 0;
int i = 0;
DEBUG("def->os.type %s", def->os.type);
DEBUG("def->os.arch %s", def->os.arch);
DEBUG("def->os.machine %s", def->os.machine);
DEBUG("def->os.nBootDevs %d", def->os.nBootDevs);
DEBUG("def->os.bootDevs[0] %d", def->os.bootDevs[0]);
DEBUG("def->os.bootDevs[1] %d", def->os.bootDevs[1]);
DEBUG("def->os.bootDevs[2] %d", def->os.bootDevs[2]);
DEBUG("def->os.bootDevs[3] %d", def->os.bootDevs[3]);
DEBUG("def->os.init %s", def->os.init);
DEBUG("def->os.kernel %s", def->os.kernel);
DEBUG("def->os.initrd %s", def->os.initrd);
DEBUG("def->os.cmdline %s", def->os.cmdline);
DEBUG("def->os.root %s", def->os.root);
DEBUG("def->os.loader %s", def->os.loader);
DEBUG("def->os.bootloader %s", def->os.bootloader);
DEBUG("def->os.bootloaderArgs %s", def->os.bootloaderArgs);
data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
if (systemProperties) {
systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
systemProperties = NULL;
}
/* Clear the defaults first */
for (i = 0; i < maxBootPosition; i++) {
machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
}
for (i = 0; (i < def->os.nBootDevs) && (i < maxBootPosition); i++) {
PRUint32 device = DeviceType_Null;
if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) {
device = DeviceType_Floppy;
} else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) {
device = DeviceType_DVD;
} else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_DISK) {
device = DeviceType_HardDisk;
} else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
device = DeviceType_Network;
}
machine->vtbl->SetBootOrder(machine, i+1, device);
}
} /* Finished:Block to set the boot device order */
{ /* Started:Block to attach the CDROM/DVD Drive and HardDisks to the VM */
if (def->ndisks > 0) {
int i;
for (i = 0; i < def->ndisks; i++) {
DEBUG("disk(%d) type: %d", i, def->disks[i]->type);
DEBUG("disk(%d) device: %d", i, def->disks[i]->device);
DEBUG("disk(%d) bus: %d", i, def->disks[i]->bus);
DEBUG("disk(%d) src: %s", i, def->disks[i]->src);
DEBUG("disk(%d) dst: %s", i, def->disks[i]->dst);
DEBUG("disk(%d) driverName: %s", i, def->disks[i]->driverName);
DEBUG("disk(%d) driverType: %s", i, def->disks[i]->driverType);
DEBUG("disk(%d) cachemode: %d", i, def->disks[i]->cachemode);
DEBUG("disk(%d) readonly: %s", i, def->disks[i]->readonly ? "True" : "False");
DEBUG("disk(%d) shared: %s", i, def->disks[i]->shared ? "True" : "False");
DEBUG("disk(%d) slotnum: %d", i, def->disks[i]->slotnum);
if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
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;
nsID *dvduuid = NULL;
nsID dvdemptyuuid;
memset(&dvdemptyuuid, 0, sizeof(dvdemptyuuid));
g_pVBoxFuncs->pfnUtf8ToUtf16(def->disks[i]->src, &dvdfileUtf16);
data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
if (!dvdImage) {
data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, &dvdemptyuuid, &dvdImage);
}
if (dvdImage) {
rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"can't get the uuid of the file to be attached to cdrom",
def->disks[i]->src, (unsigned)rc);
} else {
rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not attach the file to cdrom",
def->disks[i]->src, (unsigned)rc);
} else {
DEBUG("CD/DVDImage UUID:{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(unsigned)dvduuid->m0, (unsigned)dvduuid->m1, (unsigned)dvduuid->m2,
(unsigned)dvduuid->m3[0], (unsigned)dvduuid->m3[1],
(unsigned)dvduuid->m3[2], (unsigned)dvduuid->m3[3],
(unsigned)dvduuid->m3[4], (unsigned)dvduuid->m3[5],
(unsigned)dvduuid->m3[6], (unsigned)dvduuid->m3[7]);
}
g_pVBoxFuncs->pfnComUnallocMem(dvduuid);
}
dvdImage->vtbl->imedium.nsisupports.Release((nsISupports *)dvdImage);
}
g_pVBoxFuncs->pfnUtf16Free(dvdfileUtf16);
dvdDrive->vtbl->nsisupports.Release((nsISupports *)dvdDrive);
}
} else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
}
} else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
IHardDisk *hardDisk = NULL;
PRUnichar *hddfileUtf16 = NULL;
nsID *hdduuid = NULL;
/* Current Limitation: Harddisk can't be connected to
* Secondary Master as Secondary Master is always used
* for CD/DVD Drive, so not connect the harddisk if it
* is requested to be connected to Secondary master
*/
g_pVBoxFuncs->pfnUtf8ToUtf16(def->disks[i]->src, &hddfileUtf16);
data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16, &hardDisk);
if (!hardDisk) {
data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
hddfileUtf16,
AccessMode_ReadWrite,
&hardDisk);
}
if (hardDisk) {
rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk, &hdduuid);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"can't get the uuid of the file to be attached as harddisk",
def->disks[i]->src, (unsigned)rc);
} else {
if (def->disks[i]->readonly) {
hardDisk->vtbl->SetType(hardDisk, HardDiskType_Immutable);
DEBUG0("setting harddisk to readonly");
} else if (!def->disks[i]->readonly) {
hardDisk->vtbl->SetType(hardDisk, HardDiskType_Normal);
DEBUG0("setting harddisk type to normal");
}
if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
if (STREQ(def->disks[i]->dst, "hdc")) {
DEBUG0("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 = strdup("IDE");
g_pVBoxFuncs->pfnUtf8ToUtf16(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,
hddcnameUtf16,
channel, device);
g_pVBoxFuncs->pfnUtf16Free(hddcnameUtf16);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not attach the file as harddisk",
def->disks[i]->src, (unsigned)rc);
} else {
DEBUG("Attached HDD with UUID:"
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(unsigned)hdduuid->m0, (unsigned)hdduuid->m1,
(unsigned)hdduuid->m2,
(unsigned)hdduuid->m3[0], (unsigned)hdduuid->m3[1],
(unsigned)hdduuid->m3[2], (unsigned)hdduuid->m3[3],
(unsigned)hdduuid->m3[4], (unsigned)hdduuid->m3[5],
(unsigned)hdduuid->m3[6], (unsigned)hdduuid->m3[7]);
}
}
}
g_pVBoxFuncs->pfnComUnallocMem(hdduuid);
}
hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk);
}
g_pVBoxFuncs->pfnUtf16Free(hddfileUtf16);
} else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
}
} else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
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;
nsID *fduuid = NULL;
nsID fdemptyuuid;
memset(&fdemptyuuid, 0, sizeof(fdemptyuuid));
g_pVBoxFuncs->pfnUtf8ToUtf16(def->disks[i]->src, &fdfileUtf16);
rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj, fdfileUtf16,
&floppyImage);
if (!floppyImage) {
data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj, fdfileUtf16,
&fdemptyuuid, &floppyImage);
}
if (floppyImage) {
rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"can't get the uuid of the file to be attached to floppy drive",
def->disks[i]->src, (unsigned)rc);
} else {
rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid);
if (NS_FAILED(rc)) {
vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not attach the file to floppy drive",
def->disks[i]->src, (unsigned)rc);
} else {
DEBUG("floppyImage UUID:"
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(unsigned)fduuid->m0, (unsigned)fduuid->m1,
(unsigned)fduuid->m2,
(unsigned)fduuid->m3[0], (unsigned)fduuid->m3[1],
(unsigned)fduuid->m3[2], (unsigned)fduuid->m3[3],
(unsigned)fduuid->m3[4], (unsigned)fduuid->m3[5],
(unsigned)fduuid->m3[6], (unsigned)fduuid->m3[7]);
}
g_pVBoxFuncs->pfnComUnallocMem(fduuid);
}
floppyImage->vtbl->imedium.nsisupports.Release((nsISupports *)floppyImage);
}
g_pVBoxFuncs->pfnUtf16Free(fdfileUtf16);
}
floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
}
} else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
}
}
}
}
} /* Finished:Block to attach the CDROM/DVD Drive and HardDisks to the VM */
{ /* Started:Block to attach the Sound Controller to the VM */
/* Check if def->nsounds is one as VirtualBox currently supports
* only one sound card
*/
if (def->nsounds == 1) {
IAudioAdapter *audioAdapter = NULL;
machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
if (audioAdapter) {
rc = audioAdapter->vtbl->SetEnabled(audioAdapter, 1);
if (NS_SUCCEEDED(rc)) {
if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_SB16) {
audioAdapter->vtbl->SetAudioController(audioAdapter, AudioControllerType_SB16);
} else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_ES97) {
audioAdapter->vtbl->SetAudioController(audioAdapter, AudioControllerType_AC97);
}
}
audioAdapter->vtbl->nsisupports.Release((nsISupports *)audioAdapter);
}
}
} /* Finished:Block to attach the Sound Controller to the VM */
{ /* Started:Block to attach the Network Card to the VM */
ISystemProperties *systemProperties = NULL;
PRUint32 networkAdapterCount = 0;
int i = 0;
data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
if (systemProperties) {
systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &networkAdapterCount);
systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
systemProperties = NULL;
}
DEBUG("Number of Network Cards to be connected: %d", def->nnets);
DEBUG("Number of Network Cards available: %d", networkAdapterCount);
for (i = 0; (i < def->nnets) && (i < networkAdapterCount); i++) {
INetworkAdapter *adapter = NULL;
PRUint32 adapterType = NetworkAdapterType_Null;
char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
char macaddrvbox[VIR_MAC_STRING_BUFLEN - 5] = {0};
virFormatMacAddr(def->nets[i]->mac, macaddr);
snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
"%02X%02X%02X%02X%02X%02X",
def->nets[i]->mac[0],
def->nets[i]->mac[1],
def->nets[i]->mac[2],
def->nets[i]->mac[3],
def->nets[i]->mac[4],
def->nets[i]->mac[5]);
macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';
DEBUG("NIC(%d): Type: %d", i, def->nets[i]->type);
DEBUG("NIC(%d): Model: %s", i, def->nets[i]->model);
DEBUG("NIC(%d): Mac: %s", i, macaddr);
DEBUG("NIC(%d): ifname: %s", i, def->nets[i]->ifname);
#if 0
if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTONLY) {
DEBUG("NIC(%d): name: %s", i, def->nets[i]->data.hostonly.name);
} else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
DEBUG("NIC(%d): name: %s", i, def->nets[i]->data.internal.name);
} else
#endif
if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
DEBUG("NIC(%d): NAT.", i);
} else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
DEBUG("NIC(%d): brname: %s", i, def->nets[i]->data.bridge.brname);
DEBUG("NIC(%d): script: %s", i, def->nets[i]->data.bridge.script);
DEBUG("NIC(%d): ipaddr: %s", i, def->nets[i]->data.bridge.ipaddr);
}
machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
if (adapter) {
PRUnichar *MACAddress = NULL;
adapter->vtbl->SetEnabled(adapter, 1);
if (STRCASEEQ(def->nets[i]->model , "Am79C970A")) {
adapterType = NetworkAdapterType_Am79C970A;
} else if (STRCASEEQ(def->nets[i]->model , "Am79C973")) {
adapterType = NetworkAdapterType_Am79C973;
} else if (STRCASEEQ(def->nets[i]->model , "82540EM")) {
adapterType = NetworkAdapterType_I82540EM;
} else if (STRCASEEQ(def->nets[i]->model , "82545EM")) {
adapterType = NetworkAdapterType_I82545EM;
} else if (STRCASEEQ(def->nets[i]->model , "82543GC")) {
adapterType = NetworkAdapterType_I82543GC;
}
adapter->vtbl->SetAdapterType(adapter, adapterType);
if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
PRUnichar *hostInterface = NULL;
/* Bridged Network */
adapter->vtbl->AttachToBridgedInterface(adapter);
if (def->nets[i]->data.bridge.brname) {
g_pVBoxFuncs->pfnUtf8ToUtf16(def->nets[i]->data.bridge.brname, &hostInterface);
adapter->vtbl->SetHostInterface(adapter, hostInterface);
g_pVBoxFuncs->pfnUtf16Free(hostInterface);
}
#if 0
} else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
PRUnichar *internalNetwork = NULL;
/* Internal Network */
adapter->vtbl->AttachToInternalNetwork(adapter);
if (def->nets[i]->data.network.name) {
g_pVBoxFuncs->pfnUtf8ToUtf16(def->nets[i]->data.internal.name, &internalNetwork);
adapter->vtbl->SetInternalNetwork(adapter, internalNetwork);
g_pVBoxFuncs->pfnUtf16Free(internalNetwork);
}
} else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTONLY) {
PRUnichar *hostInterface = NULL;
/* Host Only Networking (currently only vboxnet0 available
* on *nix and mac, on windows you can create and configure
* as many as you want)
*/
adapter->vtbl->AttachToHostOnlyInterface(adapter);
if (def->nets[i]->data.ethernet.dev) {
g_pVBoxFuncs->pfnUtf8ToUtf16(def->nets[i]->data.hostonly.name, &hostInterface);
adapter->vtbl->SetHostInterface(adapter, hostInterface);
g_pVBoxFuncs->pfnUtf16Free(hostInterface);
}
#endif
} else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
/* NAT */
adapter->vtbl->AttachToNAT(adapter);
} else {
/* else always default to NAT if we don't understand
* what option is been passed to us
*/
adapter->vtbl->AttachToNAT(adapter);
}
g_pVBoxFuncs->pfnUtf8ToUtf16(macaddrvbox, &MACAddress);
if (def->nets[i]->mac) {
adapter->vtbl->SetMACAddress(adapter, MACAddress);
}
g_pVBoxFuncs->pfnUtf16Free(MACAddress);
}
}
} /* Finished:Block to attach the Network Card to the VM */
{ /* Started:Block to attach the Serial Port to the VM */
ISystemProperties *systemProperties = NULL;
PRUint32 serialPortCount = 0;
int i = 0;
data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
if (systemProperties) {
systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount);
systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
systemProperties = NULL;
}
DEBUG("Number of Serial Ports to be connected: %d", def->nserials);
DEBUG("Number of Serial Ports available: %d", serialPortCount);
for (i = 0; (i < def->nserials) && (i < serialPortCount); i++) {
ISerialPort *serialPort = NULL;
DEBUG("SerialPort(%d): Type: %d", i, def->serials[i]->type);
DEBUG("SerialPort(%d): dstPort: %d", i, def->serials[i]->dstPort);
machine->vtbl->GetSerialPort(machine, i, &serialPort);
if (serialPort) {
PRUnichar *pathUtf16 = NULL;
serialPort->vtbl->SetEnabled(serialPort, 1);
g_pVBoxFuncs->pfnUtf8ToUtf16(def->serials[i]->data.file.path, &pathUtf16);
/* For now hard code the serial ports to COM1 and COM2,
* COM1 (Base Addr: 0x3F8 (decimal: 1016), IRQ: 4)
* COM2 (Base Addr: 0x2F8 (decimal: 760), IRQ: 3)
* TODO: make this more flexible
*/
/* TODO: to improve the libvirt XMl handling so
* that def->serials[i]->dstPort shows real port
* and not always start at 0
*/
if (def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_DEV) {
serialPort->vtbl->SetPath(serialPort, pathUtf16);
if (def->serials[i]->dstPort == 0) {
serialPort->vtbl->SetIRQ(serialPort, 4);
serialPort->vtbl->SetIOBase(serialPort, 1016);
DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
i, 4, 1016, def->serials[i]->data.file.path);
} else if (def->serials[i]->dstPort == 1) {
serialPort->vtbl->SetIRQ(serialPort, 3);
serialPort->vtbl->SetIOBase(serialPort, 760);
DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
i, 3, 760, def->serials[i]->data.file.path);
}
serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
} else if (def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PIPE) {
serialPort->vtbl->SetPath(serialPort, pathUtf16);
if (def->serials[i]->dstPort == 0) {
serialPort->vtbl->SetIRQ(serialPort, 4);
serialPort->vtbl->SetIOBase(serialPort, 1016);
DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
i, 4, 1016, def->serials[i]->data.file.path);
} else if (def->serials[i]->dstPort == 1) {
serialPort->vtbl->SetIRQ(serialPort, 3);
serialPort->vtbl->SetIOBase(serialPort, 760);
DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
i, 3, 760, def->serials[i]->data.file.path);
}
if (!virFileExists(def->serials[i]->data.file.path)) {
serialPort->vtbl->SetServer(serialPort, 1);
}
serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
} else if (def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_NULL) {
serialPort->vtbl->SetHostMode(serialPort, PortMode_Disconnected);
}
serialPort->vtbl->nsisupports.Release((nsISupports *)serialPort);
if (pathUtf16) {
g_pVBoxFuncs->pfnUtf16Free(pathUtf16);
pathUtf16 = NULL;
}
}
}
} /* Finished:Block to attach the Serial Port to the VM */
{ /* Started:Block to attach the Parallel Port to the VM */
ISystemProperties *systemProperties = NULL;
PRUint32 parallelPortCount = 0;
int i = 0;
data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
if (systemProperties) {
systemProperties->vtbl->GetParallelPortCount(systemProperties, &parallelPortCount);
systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
systemProperties = NULL;
}
DEBUG("Number of Parallel Ports to be connected: %d", def->nparallels);
DEBUG("Number of Parallel Ports available: %d", parallelPortCount);
for (i = 0; (i < def->nparallels) && (i < parallelPortCount); i++) {
IParallelPort *parallelPort = NULL;
DEBUG("ParallelPort(%d): Type: %d", i, def->parallels[i]->type);
DEBUG("ParallelPort(%d): dstPort: %d", i, def->parallels[i]->dstPort);
machine->vtbl->GetParallelPort(machine, i, &parallelPort);
if (parallelPort) {
PRUnichar *pathUtf16 = NULL;
g_pVBoxFuncs->pfnUtf8ToUtf16(def->parallels[i]->data.file.path, &pathUtf16);
/* For now hard code the parallel ports to
* LPT1 (Base Addr: 0x378 (decimal: 888), IRQ: 7)
* LPT2 (Base Addr: 0x278 (decimal: 632), IRQ: 5)
* TODO: make this more flexible
*/
if ((def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_DEV) ||
(def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_PTY) ||
(def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_FILE) ||
(def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_PIPE)) {
parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
if (i == 0) {
parallelPort->vtbl->SetIRQ(parallelPort, 7);
parallelPort->vtbl->SetIOBase(parallelPort, 888);
DEBUG(" parallePort-%d irq: %d, iobase 0x%x, path: %s",
i, 7, 888, def->parallels[i]->data.file.path);
} else if (i == 1) {
parallelPort->vtbl->SetIRQ(parallelPort, 5);
parallelPort->vtbl->SetIOBase(parallelPort, 632);
DEBUG(" parallePort-%d irq: %d, iobase 0x%x, path: %s",
i, 5, 632, def->parallels[i]->data.file.path);
}
}
/* like serial port, parallel port can't be enabled unless
* correct IRQ and IOBase values are specified.
*/
parallelPort->vtbl->SetEnabled(parallelPort, 1);
parallelPort->vtbl->nsisupports.Release((nsISupports *)parallelPort);
if (pathUtf16) {
g_pVBoxFuncs->pfnUtf16Free(pathUtf16);
pathUtf16 = NULL;
}
}
}
} /* Finished:Block to attach the Parallel Port to the VM */
#if 0
{ /* Started:Block to attach the Remote Display to VM */
if (def->graphics) {
IVRDPServer *VRDPServer = NULL;
/* TODO: include the support for headless stuff
*/
if (def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) {
machine->vtbl->GetVRDPServer(machine, &VRDPServer);
if (VRDPServer) {
VRDPServer->vtbl->SetEnabled(VRDPServer, PR_TRUE);
DEBUG0("VRDP Support turned ON on port: 3389");
if (def->graphics->data.rdp.port) {
VRDPServer->vtbl->SetPort(VRDPServer, def->graphics->data.rdp.port);
DEBUG("VRDP Port changed to: %d", def->graphics->data.rdp.port);
} else if (def->graphics->data.rdp.autoport) {
/* Setting the port to 0 will reset its value to
* the default one which is 3389 currently
*/
VRDPServer->vtbl->SetPort(VRDPServer, 0);
DEBUG0("VRDP Port changed to default, which is 3389 currently");
}
if (def->graphics->data.rdp.reuseconnection) {
VRDPServer->vtbl->SetReuseSingleConnection(VRDPServer, PR_TRUE);
DEBUG0("VRDP set to reuse single connection");
}
if (def->graphics->data.rdp.multiconnections) {
VRDPServer->vtbl->SetAllowMultiConnection(VRDPServer, PR_TRUE);
DEBUG0("VRDP set to allow multiple connection");
}
if (def->graphics->data.rdp.auth) {
if (STREQ(def->graphics->data.rdp.auth, "guest")) {
VRDPServer->vtbl->SetAuthType(VRDPServer, VRDPAuthType_Guest);
DEBUG0("VRDP authentication method set to Guest");
} else if (STREQ(def->graphics->data.rdp.auth, "external")) {
VRDPServer->vtbl->SetAuthType(VRDPServer, VRDPAuthType_External);
DEBUG0("VRDP authentication method set to External");
}
if (def->graphics->data.rdp.authtimeout) {
VRDPServer->vtbl->SetAuthTimeout(VRDPServer, def->graphics->data.rdp.authtimeout);
DEBUG("VRDP authentication timeout is set to %llu", def->graphics->data.rdp.authtimeout);
}
}
if (def->graphics->data.rdp.listenAddr) {
PRUnichar *netAddressUtf16 = NULL;
g_pVBoxFuncs->pfnUtf8ToUtf16(def->graphics->data.rdp.listenAddr, &netAddressUtf16);
VRDPServer->vtbl->SetNetAddress(VRDPServer, netAddressUtf16);
DEBUG("VRDP listen address is set to: %s", def->graphics->data.rdp.listenAddr);
g_pVBoxFuncs->pfnUtf16Free(netAddressUtf16);
}
VRDPServer->vtbl->nsisupports.Release((nsISupports *)VRDPServer);
}
}
}
} /* Finished:Block to attach the Remote Display to VM */
#endif
{ /* Started:Block to attach USB Devices to VM */
if (def->nhostdevs > 0) {
IUSBController *USBController = NULL;
int i = 0, isUSB = 0;
/* Loop through the devices first and see if you
* have a USB Device, only if you have one then
* start the USB controller else just proceed as
* usual
*/
for (i = 0; i < def->nhostdevs; i++) {
if (def->hostdevs[i]->mode ==
VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
if (def->hostdevs[i]->source.subsys.type ==
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
if (def->hostdevs[i]->source.subsys.u.usb.vendor ||
def->hostdevs[i]->source.subsys.u.usb.product) {
DEBUG("USB Device detected, VendorId:0x%x, ProductId:0x%x",
def->hostdevs[i]->source.subsys.u.usb.vendor,
def->hostdevs[i]->source.subsys.u.usb.product);
isUSB++;
}
}
}
}
if (isUSB > 0) {
/* First Start the USB Controller and then loop
* to attach USB Devices to it
*/
machine->vtbl->GetUSBController(machine, &USBController);
if (USBController) {
USBController->vtbl->SetEnabled(USBController, 1);
USBController->vtbl->SetEnabledEhci(USBController, 1);
for (i = 0; i < def->nhostdevs; i++) {
if (def->hostdevs[i]->mode ==
VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
if (def->hostdevs[i]->source.subsys.type ==
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
char filtername[11] = {0};
PRUnichar *filternameUtf16 = NULL;
IUSBDeviceFilter *filter = NULL;
/* Assuming can't have more then 9999 devices so
* restricting to %04d
*/
sprintf(filtername, "filter%04d", i);
g_pVBoxFuncs->pfnUtf8ToUtf16(filtername, &filternameUtf16);
USBController->vtbl->CreateDeviceFilter(USBController,
filternameUtf16,
&filter);
g_pVBoxFuncs->pfnUtf16Free(filternameUtf16);
if (filter &&
(def->hostdevs[i]->source.subsys.u.usb.vendor ||
def->hostdevs[i]->source.subsys.u.usb.product)) {
PRUnichar *vendorIdUtf16 = NULL;
char vendorId[40] = {0};
PRUnichar *productIdUtf16 = NULL;
char productId[40] = {0};
if (def->hostdevs[i]->source.subsys.u.usb.vendor) {
sprintf(vendorId, "%x", def->hostdevs[i]->source.subsys.u.usb.vendor);
g_pVBoxFuncs->pfnUtf8ToUtf16(vendorId, &vendorIdUtf16);
filter->vtbl->SetVendorId(filter, vendorIdUtf16);
g_pVBoxFuncs->pfnUtf16Free(vendorIdUtf16);
}
if (def->hostdevs[i]->source.subsys.u.usb.product) {
sprintf(productId, "%x", def->hostdevs[i]->source.subsys.u.usb.product);
g_pVBoxFuncs->pfnUtf8ToUtf16(productId, &productIdUtf16);
filter->vtbl->SetProductId(filter, productIdUtf16);
g_pVBoxFuncs->pfnUtf16Free(productIdUtf16);
}
filter->vtbl->SetActive(filter, 1);
USBController->vtbl->InsertDeviceFilter(USBController,
i,
filter);
filter->vtbl->nsisupports.Release((nsISupports *)filter);
}
}
}
}
USBController->vtbl->nsisupports.Release((nsISupports *)USBController);
}
}
}
} /* Finished:Block to attach USB Devices to VM */
/* Save the machine settings made till now and close the
* session. also free up the mchiid variable used.
*/
rc = machine->vtbl->SaveSettings(machine);
data->vboxSession->vtbl->Close(data->vboxSession);
g_pVBoxFuncs->pfnComUnallocMem(mchiid);
dom = virGetDomain(conn, def->name, def->uuid);
if(machine) {
machine->vtbl->nsisupports.Release((nsISupports *)machine);
machine = NULL;
}
}
VIR_FREE(iid);
virDomainDefFree(def);
return dom;
cleanup:
if(machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
virDomainDefFree(def);
return NULL;
}
static int vboxDomainUndefine(virDomainPtr dom) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
int ret = -1;
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
if(data->vboxObj) {
nsIDFromChar(iid, dom->uuid);
/* Block for checking if HDD's are attched to VM.
* considering just IDE bus for now. Also skipped
* chanel=1 and device=0 (Secondary Master) as currenlty
* it is allocated to CD/DVD Drive bt default
*/
{
PRUnichar *hddcnameUtf16 = NULL;
char *hddcname = strdup("IDE");
g_pVBoxFuncs->pfnUtf8ToUtf16(hddcname, &hddcnameUtf16);
VIR_FREE(hddcname);
/* Open a Session for the machine */
rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
if (NS_SUCCEEDED(rc)) {
rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
if (NS_SUCCEEDED(rc) && machine) {
/* 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);
machine->vtbl->SaveSettings(machine);
}
data->vboxSession->vtbl->Close(data->vboxSession);
}
g_pVBoxFuncs->pfnUtf16Free(hddcnameUtf16);
}
rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid, &machine);
DEBUG("UUID of machine being undefined:{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(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 (NS_SUCCEEDED(rc) && machine){
machine->vtbl->DeleteSettings(machine);
ret = 0;
}
}
cleanup:
if (machine)
machine->vtbl->nsisupports.Release((nsISupports *)machine);
VIR_FREE(iid);
return ret;
}
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
PRUint32 state = MachineState_Null;
virDomainDefPtr def = NULL;
virDomainDeviceDefPtr dev = NULL;
int ret = -1;
if (VIR_ALLOC(def) < 0) {
virReportOOMError(dom->conn);
return ret;
}
def->os.type = strdup("hvm");
dev = virDomainDeviceDefParse(dom->conn, data->caps, def, xml,
VIR_DOMAIN_XML_INACTIVE);
if (dev == NULL) {
virReportOOMError(dom->conn);
goto cleanup;
}
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
nsIDFromChar(iid, dom->uuid);
DEBUG("machine uuid:{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(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(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
"no domain with matching uuid:"
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(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]);
goto cleanup;
}
if (machine) {
machine->vtbl->GetState(machine, &state);
if ((state == MachineState_Running) ||
(state == MachineState_Paused)) {
rc = data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
} else {
rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
}
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 (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
if (dev->data.disk->type == VIR_DOMAIN_DISK_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) {
IDVDImage *dvdImage = NULL;
PRUnichar *dvdfileUtf16 = NULL;
nsID *dvduuid = NULL;
nsID dvdemptyuuid;
memset(&dvdemptyuuid, 0, sizeof(dvdemptyuuid));
g_pVBoxFuncs->pfnUtf8ToUtf16(dev->data.disk->src, &dvdfileUtf16);
data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
if (!dvdImage) {
data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, &dvdemptyuuid, &dvdImage);
}
if (dvdImage) {
rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"can't get the uuid of the file to be attached to cdrom",
dev->data.disk->src, (unsigned)rc);
} else {
/* unmount the previous mounted image */
dvdDrive->vtbl->Unmount(dvdDrive);
rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not attach the file to cdrom",
dev->data.disk->src, (unsigned)rc);
} else {
ret = 0;
DEBUG("CD/DVD Image UUID:"
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(unsigned)dvduuid->m0, (unsigned)dvduuid->m1,
(unsigned)dvduuid->m2, (unsigned)dvduuid->m3[0],
(unsigned)dvduuid->m3[1], (unsigned)dvduuid->m3[2],
(unsigned)dvduuid->m3[3], (unsigned)dvduuid->m3[4],
(unsigned)dvduuid->m3[5], (unsigned)dvduuid->m3[6],
(unsigned)dvduuid->m3[7]);
}
g_pVBoxFuncs->pfnComUnallocMem(dvduuid);
}
dvdImage->vtbl->imedium.nsisupports.Release((nsISupports *)dvdImage);
}
g_pVBoxFuncs->pfnUtf16Free(dvdfileUtf16);
dvdDrive->vtbl->nsisupports.Release((nsISupports *)dvdDrive);
}
} else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
}
} else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
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;
nsID *fduuid = NULL;
nsID fdemptyuuid;
memset(&fdemptyuuid, 0, sizeof(fdemptyuuid));
g_pVBoxFuncs->pfnUtf8ToUtf16(dev->data.disk->src, &fdfileUtf16);
rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj, fdfileUtf16,
&floppyImage);
if (!floppyImage) {
data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj, fdfileUtf16,
&fdemptyuuid, &floppyImage);
}
if (floppyImage) {
rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"can't get the uuid of the file to be attached to floppy drive",
dev->data.disk->src, (unsigned)rc);
} else {
rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
"could not attach the file to floppy drive",
dev->data.disk->src, (unsigned)rc);
} else {
ret = 0;
DEBUG("attached floppy, UUID:"
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(unsigned)fduuid->m0, (unsigned)fduuid->m1,
(unsigned)fduuid->m2,
(unsigned)fduuid->m3[0], (unsigned)fduuid->m3[1],
(unsigned)fduuid->m3[2], (unsigned)fduuid->m3[3],
(unsigned)fduuid->m3[4], (unsigned)fduuid->m3[5],
(unsigned)fduuid->m3[6], (unsigned)fduuid->m3[7]);
}
g_pVBoxFuncs->pfnComUnallocMem(fduuid);
}
floppyImage->vtbl->imedium.nsisupports.Release((nsISupports *)floppyImage);
}
g_pVBoxFuncs->pfnUtf16Free(fdfileUtf16);
}
floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
}
} else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
}
}
} 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) {
}
}
}
machine->vtbl->SaveSettings(machine);
machine->vtbl->nsisupports.Release((nsISupports *)machine);
}
data->vboxSession->vtbl->Close(data->vboxSession);
}
}
}
cleanup:
VIR_FREE(iid);
virDomainDefFree(def);
virDomainDeviceDefFree(dev);
return ret;
}
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml) {
nsresult rc;
vboxGlobalData *data = dom->conn->privateData;
IMachine *machine = NULL;
nsID *iid = NULL;
PRUint32 state = MachineState_Null;
virDomainDefPtr def = NULL;
virDomainDeviceDefPtr dev = NULL;
int ret = -1;
if (VIR_ALLOC(def) < 0) {
virReportOOMError(dom->conn);
return ret;
}
def->os.type = strdup("hvm");
dev = virDomainDeviceDefParse(dom->conn, data->caps, def, xml,
VIR_DOMAIN_XML_INACTIVE);
if (dev == NULL) {
virReportOOMError(dom->conn);
goto cleanup;
}
if (VIR_ALLOC(iid) < 0) {
virReportOOMError(dom->conn);
goto cleanup;
}
nsIDFromChar(iid, dom->uuid);
DEBUG("machine uuid:{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(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(data->vboxObj) {
rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
if (NS_FAILED(rc)) {
vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
"no domain with matching uuid:"
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(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]);
goto cleanup;
}
if (machine) {
machine->vtbl->GetState(machine, &state);
if ((state == MachineState_Running) ||
(state == MachineState_Paused)) {
rc = data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
} else {
rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
}
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 (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
if (dev->data.disk->type == VIR_DOMAIN_DISK_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)) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"could not de-attach the mounted ISO",
(unsigned)rc);
} else {
ret = 0;
}
dvdDrive->vtbl->nsisupports.Release((nsISupports *)dvdDrive);
}
} else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
}
} else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
if (dev->data.disk->type == VIR_DOMAIN_DISK_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)) {
vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
"could not attach the file to floppy drive",
(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;
}
floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
}
} else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
}
}
} 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) {
}
}
}
machine->vtbl->SaveSettings(machine);
machine->vtbl->nsisupports.Release((nsISupports *)machine);
}
data->vboxSession->vtbl->Close(data->vboxSession);
}
}
}
cleanup:
VIR_FREE(iid);
virDomainDefFree(def);
virDomainDeviceDefFree(dev);
return ret;
}
virDriver NAME(Driver) = {
VIR_DRV_VBOX,
"VBOX",
.open = vboxOpen,
.close = vboxClose,
.supports_feature = NULL,
.type = NULL,
.version = vboxGetVersion,
.getHostname = vboxGetHostname,
.getMaxVcpus = vboxGetMaxVcpus,
.nodeGetInfo = vboxNodeGetInfo,
.getCapabilities = vboxGetCapabilities,
.listDomains = vboxListDomains,
.numOfDomains = vboxNumOfDomains,
.domainCreateXML = vboxDomainCreateXML,
.domainLookupByID = vboxDomainLookupByID,
.domainLookupByUUID = vboxDomainLookupByUUID,
.domainLookupByName = vboxDomainLookupByName,
.domainSuspend = vboxDomainSuspend,
.domainResume = vboxDomainResume,
.domainShutdown = vboxDomainShutdown,
.domainReboot = vboxDomainReboot,
.domainDestroy = vboxDomainDestroy,
.domainGetOSType = vboxDomainGetOSType,
.domainGetMaxMemory = NULL,
.domainSetMaxMemory = NULL,
.domainSetMemory = vboxDomainSetMemory,
.domainGetInfo = vboxDomainGetInfo,
.domainSave = vboxDomainSave,
.domainRestore = NULL,
.domainCoreDump = NULL,
.domainSetVcpus = NULL,
.domainPinVcpu = NULL,
.domainGetVcpus = NULL,
.domainGetMaxVcpus = NULL,
.domainDumpXML = vboxDomainDumpXML,
.listDefinedDomains = vboxListDefinedDomains,
.numOfDefinedDomains = vboxNumOfDefinedDomains,
.domainCreate = vboxDomainCreate,
.domainDefineXML = vboxDomainDefineXML,
.domainUndefine = vboxDomainUndefine,
.domainAttachDevice = vboxDomainAttachDevice,
.domainDetachDevice = vboxDomainDetachDevice,
.domainGetAutostart = NULL,
.domainSetAutostart = NULL,
.domainGetSchedulerType = NULL,
.domainGetSchedulerParameters = NULL,
.domainSetSchedulerParameters = NULL,
.domainMigratePrepare = NULL,
.domainMigratePerform = NULL,
.domainMigrateFinish = NULL,
.domainBlockStats = NULL,
.domainInterfaceStats = NULL,
.domainBlockPeek = NULL,
.domainMemoryPeek = NULL,
.nodeGetCellsFreeMemory = NULL,
.getFreeMemory = NULL,
.domainEventRegister = NULL,
.domainEventDeregister = NULL,
.domainMigratePrepare2 = NULL,
.domainMigrateFinish2 = NULL,
};