mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 15:27:47 +00:00
vbox: Begin to rewrite, vboxConnectOpen
Introduce vbox_uniformed_api to deal with version conflicts. Use vbox_install_api to register the currect vboxUniformedAPI with vbox version. vboxConnectOpen has been rewritten.
This commit is contained in:
parent
7809615056
commit
7f0f415b87
@ -217,6 +217,7 @@ src/util/virxml.c
|
||||
src/vbox/vbox_MSCOMGlue.c
|
||||
src/vbox/vbox_XPCOMCGlue.c
|
||||
src/vbox/vbox_driver.c
|
||||
src/vbox/vbox_common.c
|
||||
src/vbox/vbox_snapshot_conf.c
|
||||
src/vbox/vbox_tmpl.c
|
||||
src/vmware/vmware_conf.c
|
||||
|
@ -675,7 +675,10 @@ VBOX_DRIVER_SOURCES = \
|
||||
vbox/vbox_V4_2.c vbox/vbox_CAPI_v4_2.h \
|
||||
vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h \
|
||||
vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h \
|
||||
vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h
|
||||
vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h \
|
||||
vbox/vbox_common.c vbox/vbox_common.h \
|
||||
vbox/vbox_uniformed_api.h \
|
||||
vbox/vbox_install_api.h
|
||||
|
||||
VBOX_DRIVER_EXTRA_DIST = \
|
||||
vbox/vbox_tmpl.c vbox/README \
|
||||
|
291
src/vbox/vbox_common.c
Normal file
291
src/vbox/vbox_common.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 2014, Taowei Luo (uaedante@gmail.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "datatypes.h"
|
||||
#include "domain_conf.h"
|
||||
#include "domain_event.h"
|
||||
#include "virlog.h"
|
||||
#include "viralloc.h"
|
||||
#include "nodeinfo.h"
|
||||
|
||||
#include "vbox_common.h"
|
||||
#include "vbox_uniformed_api.h"
|
||||
#include "vbox_install_api.h"
|
||||
|
||||
/* Common codes for vbox driver. With the definitions in vbox_common.h,
|
||||
* it treats vbox structs as a void*. Though vboxUniformedAPI
|
||||
* it call vbox functions. This file is a high level implement about
|
||||
* the vbox driver.
|
||||
*/
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_VBOX
|
||||
|
||||
VIR_LOG_INIT("vbox.vbox_common");
|
||||
|
||||
#define VBOX_UTF16_FREE(arg) \
|
||||
do { \
|
||||
if (arg) { \
|
||||
gVBoxAPI.UPFN.Utf16Free(data->pFuncs, arg); \
|
||||
(arg) = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VBOX_UTF8_FREE(arg) \
|
||||
do { \
|
||||
if (arg) { \
|
||||
gVBoxAPI.UPFN.Utf8Free(data->pFuncs, arg); \
|
||||
(arg) = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VBOX_COM_UNALLOC_MEM(arg) \
|
||||
do { \
|
||||
if (arg) { \
|
||||
gVBoxAPI.UPFN.ComUnallocMem(data->pFuncs, arg); \
|
||||
(arg) = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VBOX_UTF16_TO_UTF8(arg1, arg2) gVBoxAPI.UPFN.Utf16ToUtf8(data->pFuncs, arg1, arg2)
|
||||
#define VBOX_UTF8_TO_UTF16(arg1, arg2) gVBoxAPI.UPFN.Utf8ToUtf16(data->pFuncs, arg1, arg2)
|
||||
|
||||
/* global vbox API, used for all common codes. */
|
||||
static vboxUniformedAPI gVBoxAPI;
|
||||
|
||||
int vboxRegisterUniformedAPI(uint32_t uVersion)
|
||||
{
|
||||
/* Install gVBoxAPI according to the vbox API version.
|
||||
* Return -1 for unsupported version.
|
||||
*/
|
||||
if (uVersion >= 2001052 && uVersion < 2002051) {
|
||||
vbox22InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 2002051 && uVersion < 3000051) {
|
||||
vbox30InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 3000051 && uVersion < 3001051) {
|
||||
vbox31InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 3001051 && uVersion < 3002051) {
|
||||
vbox32InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 3002051 && uVersion < 4000051) {
|
||||
vbox40InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 4000051 && uVersion < 4001051) {
|
||||
vbox41InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 4001051 && uVersion < 4002020) {
|
||||
vbox42InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 4002020 && uVersion < 4002051) {
|
||||
vbox42_20InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 4002051 && uVersion < 4003004) {
|
||||
vbox43InstallUniformedAPI(&gVBoxAPI);
|
||||
} else if (uVersion >= 4003004 && uVersion < 4003051) {
|
||||
vbox43_4InstallUniformedAPI(&gVBoxAPI);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static virDomainDefParserConfig vboxDomainDefParserConfig = {
|
||||
.macPrefix = { 0x08, 0x00, 0x27 },
|
||||
};
|
||||
|
||||
static virDomainXMLOptionPtr
|
||||
vboxXMLConfInit(void)
|
||||
{
|
||||
return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static int vboxInitialize(vboxGlobalData *data)
|
||||
{
|
||||
if (gVBoxAPI.UPFN.Initialize(data) != 0)
|
||||
goto cleanup;
|
||||
|
||||
if (gVBoxAPI.domainEventCallbacks && gVBoxAPI.initializeDomainEvent(data) != 0)
|
||||
goto cleanup;
|
||||
|
||||
if (data->vboxObj == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("IVirtualBox object is null"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (data->vboxSession == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("ISession object is null"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static virCapsPtr vboxCapsInit(void)
|
||||
{
|
||||
virCapsPtr caps;
|
||||
virCapsGuestPtr guest;
|
||||
|
||||
if ((caps = virCapabilitiesNew(virArchFromHost(),
|
||||
false, false)) == NULL)
|
||||
goto no_memory;
|
||||
|
||||
if (nodeCapsInitNUMA(caps) < 0)
|
||||
goto no_memory;
|
||||
|
||||
if ((guest = virCapabilitiesAddGuest(caps,
|
||||
"hvm",
|
||||
caps->host.arch,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL)) == NULL)
|
||||
goto no_memory;
|
||||
|
||||
if (virCapabilitiesAddGuestDomain(guest,
|
||||
"vbox",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL) == NULL)
|
||||
goto no_memory;
|
||||
|
||||
return caps;
|
||||
|
||||
no_memory:
|
||||
virObjectUnref(caps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int vboxExtractVersion(vboxGlobalData *data)
|
||||
{
|
||||
int ret = -1;
|
||||
PRUnichar *versionUtf16 = NULL;
|
||||
char *vboxVersion = NULL;
|
||||
nsresult rc;
|
||||
|
||||
if (data->version > 0)
|
||||
return 0;
|
||||
|
||||
rc = gVBoxAPI.UIVirtualBox.GetVersion(data->vboxObj, &versionUtf16);
|
||||
if (NS_FAILED(rc))
|
||||
goto failed;
|
||||
|
||||
VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
|
||||
|
||||
if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
|
||||
ret = 0;
|
||||
|
||||
VBOX_UTF8_FREE(vboxVersion);
|
||||
VBOX_COM_UNALLOC_MEM(versionUtf16);
|
||||
failed:
|
||||
if (ret != 0)
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Could not extract VirtualBox version"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vboxUninitialize(vboxGlobalData *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
gVBoxAPI.UPFN.Uninitialize(data);
|
||||
|
||||
virObjectUnref(data->caps);
|
||||
virObjectUnref(data->xmlopt);
|
||||
if (gVBoxAPI.domainEventCallbacks)
|
||||
virObjectEventStateFree(data->domainEvents);
|
||||
VIR_FREE(data);
|
||||
}
|
||||
|
||||
virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
|
||||
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
{
|
||||
vboxGlobalData *data = NULL;
|
||||
uid_t uid = geteuid();
|
||||
|
||||
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
|
||||
|
||||
if (conn->uri == NULL &&
|
||||
!(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
|
||||
if (conn->uri->scheme == NULL ||
|
||||
STRNEQ(conn->uri->scheme, "vbox"))
|
||||
return VIR_DRV_OPEN_DECLINED;
|
||||
|
||||
/* Leave for remote driver */
|
||||
if (conn->uri->server != NULL)
|
||||
return VIR_DRV_OPEN_DECLINED;
|
||||
|
||||
if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("no VirtualBox driver path specified (try vbox:///session)"));
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
|
||||
if (uid != 0) {
|
||||
if (STRNEQ(conn->uri->path, "/session")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
} else { /* root */
|
||||
if (STRNEQ(conn->uri->path, "/system") &&
|
||||
STRNEQ(conn->uri->path, "/session")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (VIR_ALLOC(data) < 0)
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
|
||||
if (!(data->caps = vboxCapsInit()) ||
|
||||
vboxInitialize(data) < 0 ||
|
||||
vboxExtractVersion(data) < 0 ||
|
||||
!(data->xmlopt = vboxXMLConfInit())) {
|
||||
vboxUninitialize(data);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
|
||||
if (gVBoxAPI.domainEventCallbacks) {
|
||||
if (!(data->domainEvents = virObjectEventStateNew())) {
|
||||
vboxUninitialize(data);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
|
||||
data->conn = conn;
|
||||
}
|
||||
|
||||
if (gVBoxAPI.hasStaticGlobalData)
|
||||
gVBoxAPI.registerGlobalData(data);
|
||||
|
||||
conn->privateData = data;
|
||||
VIR_DEBUG("in vboxOpen");
|
||||
|
||||
return VIR_DRV_OPEN_SUCCESS;
|
||||
}
|
130
src/vbox/vbox_common.h
Normal file
130
src/vbox/vbox_common.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2014, Taowei Luo (uaedante@gmail.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VBOX_COMMON_H
|
||||
# define VBOX_COMMON_H
|
||||
|
||||
# ifdef ___VirtualBox_CXPCOM_h
|
||||
# error this file should not be included after vbox_CAPI_v*.h
|
||||
# endif
|
||||
|
||||
# include "internal.h"
|
||||
# include <stddef.h>
|
||||
# include "wchar.h"
|
||||
|
||||
/* This file extracts some symbols defined in
|
||||
* vbox_CAPI_v*.h. It tells the vbox_common.c
|
||||
* how to treat with this symbols. This file
|
||||
* can't be included with files such as
|
||||
* vbox_CAPI_v*.h, or it would casue multiple
|
||||
* definitions.
|
||||
*
|
||||
* You can see the more informations in vbox_api.h
|
||||
*/
|
||||
|
||||
/* Copied definitions from vbox_CAPI_*.h.
|
||||
* We must MAKE SURE these codes are compatible. */
|
||||
|
||||
typedef unsigned char PRUint8;
|
||||
# if (defined(HPUX) && defined(__cplusplus) \
|
||||
&& !defined(__GNUC__) && __cplusplus < 199707L) \
|
||||
|| (defined(SCO) && defined(__cplusplus) \
|
||||
&& !defined(__GNUC__) && __cplusplus == 1L)
|
||||
typedef char PRInt8;
|
||||
# else
|
||||
typedef signed char PRInt8;
|
||||
# endif
|
||||
|
||||
# define PR_INT8_MAX 127
|
||||
# define PR_INT8_MIN (-128)
|
||||
# define PR_UINT8_MAX 255U
|
||||
|
||||
typedef unsigned short PRUint16;
|
||||
typedef short PRInt16;
|
||||
|
||||
# define PR_INT16_MAX 32767
|
||||
# define PR_INT16_MIN (-32768)
|
||||
# define PR_UINT16_MAX 65535U
|
||||
|
||||
typedef unsigned int PRUint32;
|
||||
typedef int PRInt32;
|
||||
# define PR_INT32(x) x
|
||||
# define PR_UINT32(x) x ## U
|
||||
|
||||
# define PR_INT32_MAX PR_INT32(2147483647)
|
||||
# define PR_INT32_MIN (-PR_INT32_MAX - 1)
|
||||
# define PR_UINT32_MAX PR_UINT32(4294967295)
|
||||
|
||||
typedef long PRInt64;
|
||||
typedef unsigned long PRUint64;
|
||||
typedef int PRIntn;
|
||||
typedef unsigned int PRUintn;
|
||||
|
||||
typedef double PRFloat64;
|
||||
typedef size_t PRSize;
|
||||
|
||||
typedef ptrdiff_t PRPtrdiff;
|
||||
|
||||
typedef unsigned long PRUptrdiff;
|
||||
|
||||
typedef PRIntn PRBool;
|
||||
|
||||
# define PR_TRUE 1
|
||||
# define PR_FALSE 0
|
||||
|
||||
typedef PRUint8 PRPackedBool;
|
||||
|
||||
/*
|
||||
** Status code used by some routines that have a single point of failure or
|
||||
** special status return.
|
||||
*/
|
||||
typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
|
||||
|
||||
# ifndef __PRUNICHAR__
|
||||
# define __PRUNICHAR__
|
||||
# if defined(WIN32) || defined(XP_MAC)
|
||||
typedef wchar_t PRUnichar;
|
||||
# else
|
||||
typedef PRUint16 PRUnichar;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
typedef long PRWord;
|
||||
typedef unsigned long PRUword;
|
||||
|
||||
# define nsnull 0
|
||||
typedef PRUint32 nsresult;
|
||||
|
||||
# if defined(__GNUC__) && (__GNUC__ > 2)
|
||||
# define NS_LIKELY(x) (__builtin_expect((x), 1))
|
||||
# define NS_UNLIKELY(x) (__builtin_expect((x), 0))
|
||||
# else
|
||||
# define NS_LIKELY(x) (x)
|
||||
# define NS_UNLIKELY(x) (x)
|
||||
# endif
|
||||
|
||||
# define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000))
|
||||
# define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000)))
|
||||
|
||||
/* Simplied definitions in vbox_CAPI_*.h */
|
||||
|
||||
typedef void const *PCVBOXXPCOM;
|
||||
typedef void IVirtualBox;
|
||||
typedef void ISession;
|
||||
|
||||
#endif /* VBOX_COMMON_H */
|
@ -39,6 +39,10 @@
|
||||
#include "vbox_glue.h"
|
||||
#include "virerror.h"
|
||||
#include "virutil.h"
|
||||
#include "domain_event.h"
|
||||
#include "domain_conf.h"
|
||||
|
||||
#include "vbox_install_api.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_VBOX
|
||||
|
||||
@ -161,6 +165,8 @@ int vboxRegister(void)
|
||||
} else {
|
||||
VIR_DEBUG("Unsupported VirtualBox API version: %u", uVersion);
|
||||
}
|
||||
/* Register vboxUniformedAPI. */
|
||||
vboxRegisterUniformedAPI(uVersion);
|
||||
} else {
|
||||
VIR_DEBUG("VBoxCGlueInit failed, using dummy driver");
|
||||
}
|
||||
@ -175,9 +181,9 @@ int vboxRegister(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
|
||||
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
static virDrvOpenStatus dummyConnectOpen(virConnectPtr conn,
|
||||
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
{
|
||||
uid_t uid = geteuid();
|
||||
|
||||
@ -218,5 +224,5 @@ static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
|
||||
static virDriver vboxDriverDummy = {
|
||||
VIR_DRV_VBOX,
|
||||
"VBOX",
|
||||
.connectOpen = vboxConnectOpen,
|
||||
.connectOpen = dummyConnectOpen,
|
||||
};
|
||||
|
26
src/vbox/vbox_install_api.h
Normal file
26
src/vbox/vbox_install_api.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2014, Taowei Luo (uaedante@gmail.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VBOX_INSTALL_API_H
|
||||
# define VBOX_INSTALL_API_H
|
||||
|
||||
# include "internal.h"
|
||||
|
||||
int vboxRegisterUniformedAPI(uint32_t uVersion);
|
||||
|
||||
#endif /* VBOX_INSTALL_API_H */
|
@ -89,12 +89,15 @@
|
||||
|
||||
/* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
|
||||
#include "vbox_glue.h"
|
||||
|
||||
#include "vbox_uniformed_api.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_VBOX
|
||||
|
||||
VIR_LOG_INIT("vbox.vbox_tmpl");
|
||||
|
||||
#define vboxUnsupported() \
|
||||
VIR_WARN("No %s in current vbox version %d.", __FUNCTION__, VBOX_API_VERSION);
|
||||
|
||||
#define VBOX_UTF16_FREE(arg) \
|
||||
do { \
|
||||
if (arg) { \
|
||||
@ -203,41 +206,7 @@ if (strUtf16) {\
|
||||
(unsigned)(iid)->m3[7]);\
|
||||
}\
|
||||
|
||||
typedef struct {
|
||||
virMutex lock;
|
||||
unsigned long version;
|
||||
|
||||
virCapsPtr caps;
|
||||
virDomainXMLOptionPtr xmlopt;
|
||||
|
||||
IVirtualBox *vboxObj;
|
||||
ISession *vboxSession;
|
||||
|
||||
/** Our version specific API table pointer. */
|
||||
PCVBOXXPCOM pFuncs;
|
||||
|
||||
#if VBOX_API_VERSION == 2002000
|
||||
|
||||
} vboxGlobalData;
|
||||
|
||||
#else /* !(VBOX_API_VERSION == 2002000) */
|
||||
|
||||
/* Async event handling */
|
||||
virObjectEventStatePtr domainEvents;
|
||||
int fdWatch;
|
||||
|
||||
# if VBOX_API_VERSION <= 3002000
|
||||
/* IVirtualBoxCallback is used in VirtualBox 3.x only */
|
||||
IVirtualBoxCallback *vboxCallback;
|
||||
# endif /* VBOX_API_VERSION <= 3002000 */
|
||||
|
||||
nsIEventQueue *vboxQueue;
|
||||
int volatile vboxCallBackRefCount;
|
||||
|
||||
/* pointer back to the connection */
|
||||
virConnectPtr conn;
|
||||
|
||||
} vboxGlobalData;
|
||||
#if VBOX_API_VERSION > 2002000
|
||||
|
||||
/* g_pVBoxGlobalData has to be global variable,
|
||||
* there is no other way to make the callbacks
|
||||
@ -865,137 +834,6 @@ vboxSocketParseAddrUtf16(vboxGlobalData *data, const PRUnichar *utf16,
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static virDomainDefParserConfig vboxDomainDefParserConfig = {
|
||||
.macPrefix = { 0x08, 0x00, 0x27 },
|
||||
};
|
||||
|
||||
|
||||
static virDomainXMLOptionPtr
|
||||
vboxXMLConfInit(void)
|
||||
{
|
||||
return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static virCapsPtr vboxCapsInit(void)
|
||||
{
|
||||
virCapsPtr caps;
|
||||
virCapsGuestPtr guest;
|
||||
|
||||
if ((caps = virCapabilitiesNew(virArchFromHost(),
|
||||
false, false)) == NULL)
|
||||
goto no_memory;
|
||||
|
||||
if (nodeCapsInitNUMA(caps) < 0)
|
||||
goto no_memory;
|
||||
|
||||
if ((guest = virCapabilitiesAddGuest(caps,
|
||||
"hvm",
|
||||
caps->host.arch,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL)) == NULL)
|
||||
goto no_memory;
|
||||
|
||||
if (virCapabilitiesAddGuestDomain(guest,
|
||||
"vbox",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL) == NULL)
|
||||
goto no_memory;
|
||||
|
||||
return caps;
|
||||
|
||||
no_memory:
|
||||
virObjectUnref(caps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
vboxInitialize(vboxGlobalData *data)
|
||||
{
|
||||
data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);
|
||||
|
||||
if (data->pFuncs == NULL)
|
||||
goto cleanup;
|
||||
|
||||
#if VBOX_XPCOMC_VERSION == 0x00010000U
|
||||
data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
|
||||
#else /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
|
||||
data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj,
|
||||
ISESSION_IID_STR, &data->vboxSession);
|
||||
|
||||
# if VBOX_API_VERSION == 2002000
|
||||
|
||||
/* No event queue functionality in 2.2.* as of now */
|
||||
|
||||
# else /* !(VBOX_API_VERSION == 2002000) */
|
||||
|
||||
/* Initial the fWatch needed for Event Callbacks */
|
||||
data->fdWatch = -1;
|
||||
|
||||
data->pFuncs->pfnGetEventQueue(&data->vboxQueue);
|
||||
|
||||
if (data->vboxQueue == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("nsIEventQueue object is null"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
# endif /* !(VBOX_API_VERSION == 2002000) */
|
||||
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
|
||||
|
||||
if (data->vboxObj == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("IVirtualBox object is null"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (data->vboxSession == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("ISession object is null"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int vboxExtractVersion(vboxGlobalData *data)
|
||||
{
|
||||
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;
|
||||
|
||||
VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
|
||||
|
||||
if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
|
||||
ret = 0;
|
||||
|
||||
VBOX_UTF8_FREE(vboxVersion);
|
||||
VBOX_COM_UNALLOC_MEM(versionUtf16);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Could not extract VirtualBox version"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vboxUninitialize(vboxGlobalData *data)
|
||||
{
|
||||
if (!data)
|
||||
@ -1014,82 +852,6 @@ static void vboxUninitialize(vboxGlobalData *data)
|
||||
VIR_FREE(data);
|
||||
}
|
||||
|
||||
|
||||
static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
|
||||
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
{
|
||||
vboxGlobalData *data = NULL;
|
||||
uid_t uid = geteuid();
|
||||
|
||||
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
|
||||
|
||||
if (conn->uri == NULL &&
|
||||
!(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
|
||||
if (conn->uri->scheme == NULL ||
|
||||
STRNEQ(conn->uri->scheme, "vbox"))
|
||||
return VIR_DRV_OPEN_DECLINED;
|
||||
|
||||
/* Leave for remote driver */
|
||||
if (conn->uri->server != NULL)
|
||||
return VIR_DRV_OPEN_DECLINED;
|
||||
|
||||
if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("no VirtualBox driver path specified (try vbox:///session)"));
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
|
||||
if (uid != 0) {
|
||||
if (STRNEQ(conn->uri->path, "/session")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
} else { /* root */
|
||||
if (STRNEQ(conn->uri->path, "/system") &&
|
||||
STRNEQ(conn->uri->path, "/session")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (VIR_ALLOC(data) < 0)
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
|
||||
if (!(data->caps = vboxCapsInit()) ||
|
||||
vboxInitialize(data) < 0 ||
|
||||
vboxExtractVersion(data) < 0 ||
|
||||
!(data->xmlopt = vboxXMLConfInit())) {
|
||||
vboxUninitialize(data);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
|
||||
#if VBOX_API_VERSION == 2002000
|
||||
|
||||
/* No domainEventCallbacks in 2.2.* version */
|
||||
|
||||
#else /* !(VBOX_API_VERSION == 2002000) */
|
||||
|
||||
if (!(data->domainEvents = virObjectEventStateNew())) {
|
||||
vboxUninitialize(data);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
|
||||
data->conn = conn;
|
||||
g_pVBoxGlobalData = data;
|
||||
|
||||
#endif /* !(VBOX_API_VERSION == 2002000) */
|
||||
|
||||
conn->privateData = data;
|
||||
VIR_DEBUG("in vboxOpen");
|
||||
|
||||
return VIR_DRV_OPEN_SUCCESS;
|
||||
}
|
||||
|
||||
static int vboxConnectClose(virConnectPtr conn)
|
||||
{
|
||||
vboxGlobalData *data = conn->privateData;
|
||||
@ -11497,6 +11259,121 @@ vboxNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
|
||||
}
|
||||
|
||||
static int _pfnInitialize(vboxGlobalData *data)
|
||||
{
|
||||
data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);
|
||||
if (data->pFuncs == NULL)
|
||||
return -1;
|
||||
#if VBOX_XPCOMC_VERSION == 0x00010000U
|
||||
data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
|
||||
#else /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
|
||||
data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj, ISESSION_IID_STR, &data->vboxSession);
|
||||
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_initializeDomainEvent(vboxGlobalData *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
|
||||
/* No event queue functionality in 2.2.* and 4.* as of now */
|
||||
vboxUnsupported();
|
||||
#else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */
|
||||
/* Initialize the fWatch needed for Event Callbacks */
|
||||
data->fdWatch = -1;
|
||||
data->pFuncs->pfnGetEventQueue(&data->vboxQueue);
|
||||
if (data->vboxQueue == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("nsIEventQueue object is null"));
|
||||
return -1;
|
||||
}
|
||||
#endif /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void _registerGlobalData(vboxGlobalData *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
#if VBOX_API_VERSION == 2002000
|
||||
vboxUnsupported();
|
||||
#else /* VBOX_API_VERSION != 2002000 */
|
||||
g_pVBoxGlobalData = data;
|
||||
#endif /* VBOX_API_VERSION != 2002000 */
|
||||
}
|
||||
|
||||
static void _pfnUninitialize(vboxGlobalData *data)
|
||||
{
|
||||
if (data->pFuncs)
|
||||
data->pFuncs->pfnComUninitialize();
|
||||
}
|
||||
|
||||
static void _pfnComUnallocMem(PCVBOXXPCOM pFuncs, void *pv)
|
||||
{
|
||||
pFuncs->pfnComUnallocMem(pv);
|
||||
}
|
||||
|
||||
static void _pfnUtf16Free(PCVBOXXPCOM pFuncs, PRUnichar *pwszString)
|
||||
{
|
||||
pFuncs->pfnUtf16Free(pwszString);
|
||||
}
|
||||
|
||||
static void _pfnUtf8Free(PCVBOXXPCOM pFuncs, char *pszString)
|
||||
{
|
||||
pFuncs->pfnUtf8Free(pszString);
|
||||
}
|
||||
|
||||
static int _pfnUtf16ToUtf8(PCVBOXXPCOM pFuncs, const PRUnichar *pwszString, char **ppszString)
|
||||
{
|
||||
return pFuncs->pfnUtf16ToUtf8(pwszString, ppszString);
|
||||
}
|
||||
|
||||
static int _pfnUtf8ToUtf16(PCVBOXXPCOM pFuncs, const char *pszString, PRUnichar **ppwszString)
|
||||
{
|
||||
return pFuncs->pfnUtf8ToUtf16(pszString, ppwszString);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
_virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16)
|
||||
{
|
||||
return vboxObj->vtbl->GetVersion(vboxObj, versionUtf16);
|
||||
}
|
||||
|
||||
static vboxUniformedPFN _UPFN = {
|
||||
.Initialize = _pfnInitialize,
|
||||
.Uninitialize = _pfnUninitialize,
|
||||
.ComUnallocMem = _pfnComUnallocMem,
|
||||
.Utf16Free = _pfnUtf16Free,
|
||||
.Utf8Free = _pfnUtf8Free,
|
||||
.Utf16ToUtf8 = _pfnUtf16ToUtf8,
|
||||
.Utf8ToUtf16 = _pfnUtf8ToUtf16,
|
||||
};
|
||||
|
||||
static vboxUniformedIVirtualBox _UIVirtualBox = {
|
||||
.GetVersion = _virtualboxGetVersion,
|
||||
};
|
||||
|
||||
void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI)
|
||||
{
|
||||
pVBoxAPI->APIVersion = VBOX_API_VERSION;
|
||||
pVBoxAPI->XPCOMCVersion = VBOX_XPCOMC_VERSION;
|
||||
pVBoxAPI->initializeDomainEvent = _initializeDomainEvent;
|
||||
pVBoxAPI->registerGlobalData = _registerGlobalData;
|
||||
pVBoxAPI->UPFN = _UPFN;
|
||||
pVBoxAPI->UIVirtualBox = _UIVirtualBox;
|
||||
|
||||
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
|
||||
pVBoxAPI->domainEventCallbacks = 0;
|
||||
#else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */
|
||||
pVBoxAPI->domainEventCallbacks = 1;
|
||||
#endif /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */
|
||||
|
||||
#if VBOX_API_VERSION == 2002000
|
||||
pVBoxAPI->hasStaticGlobalData = 0;
|
||||
#else /* VBOX_API_VERSION > 2002000 */
|
||||
pVBoxAPI->hasStaticGlobalData = 1;
|
||||
#endif /* VBOX_API_VERSION > 2002000 */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Tables
|
||||
|
153
src/vbox/vbox_uniformed_api.h
Normal file
153
src/vbox/vbox_uniformed_api.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2014, Taowei Luo (uaedante@gmail.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VBOX_UNIFORMED_API_H
|
||||
# define VBOX_UNIFORMED_API_H
|
||||
|
||||
# include "internal.h"
|
||||
|
||||
/* This file may be used in three place. That is vbox_tmpl.c,
|
||||
* vbox_common.c and vbox_driver.c. The vboxUniformedAPI and some
|
||||
* types used for vboxUniformedAPI is defined here.
|
||||
*
|
||||
* The vbox_tmpl.c is the only place where the driver knows the inside
|
||||
* architecture of those vbox structs(vboxObj, vboxSession,
|
||||
* pFuncs, vboxCallback and vboxQueue). The file should be included
|
||||
* after the currect vbox_CAPI_v*.h, then we can use the vbox structs
|
||||
* in vboxGlobalData. The vbox_tmpl.c should implement functions
|
||||
* defined in vboxUniformedAPI.
|
||||
*
|
||||
* In vbox_driver.c, it is used to define the struct vboxUniformedAPI.
|
||||
* The vbox_driver.c collects vboxUniformedAPI for all versions.
|
||||
* Then vboxRegister calls the vboxRegisterUniformedAPI to register.
|
||||
* Note: In vbox_driver.c, the vbox structs in vboxGlobalData is
|
||||
* defined by vbox_CAPI_v2.2.h.
|
||||
*
|
||||
* The vbox_common.c, it is used to generate common codes for all vbox
|
||||
* versions. Bacause the same member varible's offset in a vbox struct
|
||||
* may change between different vbox versions. The vbox_common.c
|
||||
* shouldn't directly use struct's member varibles defined in
|
||||
* vbox_CAPI_v*.h. To make things safety, we include the
|
||||
* vbox_common.h in vbox_common.c. In this case, we treat structs
|
||||
* defined by vbox as a void*. The common codes don't concern about
|
||||
* the inside of this structs(actually, we can't, in the common level).
|
||||
* With the help of vboxUniformed API, we call VirtualBox's API and
|
||||
* implement the vbox driver in a high level.
|
||||
*
|
||||
* In conclusion:
|
||||
* * In vbox_tmpl.c, this file is included after vbox_CAPI_v*.h
|
||||
* * In vbox_driver.c, this file is included after vbox_glue.h
|
||||
* * In vbox_common.c, this file is included after vbox_common.h
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
virMutex lock;
|
||||
unsigned long version;
|
||||
|
||||
virCapsPtr caps;
|
||||
virDomainXMLOptionPtr xmlopt;
|
||||
|
||||
IVirtualBox *vboxObj;
|
||||
ISession *vboxSession;
|
||||
|
||||
/** Our version specific API table pointer. */
|
||||
PCVBOXXPCOM pFuncs;
|
||||
|
||||
/* The next is used for domainEvent */
|
||||
# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
|
||||
|
||||
/* Async event handling */
|
||||
virObjectEventStatePtr domainEvents;
|
||||
int fdWatch;
|
||||
IVirtualBoxCallback *vboxCallback;
|
||||
nsIEventQueue *vboxQueue;
|
||||
|
||||
int volatile vboxCallBackRefCount;
|
||||
|
||||
/* pointer back to the connection */
|
||||
virConnectPtr conn;
|
||||
|
||||
# else /* VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 || VBOX_API_VERSION undefined */
|
||||
|
||||
virObjectEventStatePtr domainEvents;
|
||||
int fdWatch;
|
||||
void *vboxCallback;
|
||||
void *vboxQueue;
|
||||
int volatile vboxCallBackRefCount;
|
||||
virConnectPtr conn;
|
||||
|
||||
# endif /* VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 || VBOX_API_VERSION undefined */
|
||||
|
||||
} vboxGlobalData;
|
||||
|
||||
/* vboxUniformedAPI gives vbox_common.c a uniformed layer to see
|
||||
* vbox API.
|
||||
*/
|
||||
|
||||
/* Functions for pFuncs */
|
||||
typedef struct {
|
||||
int (*Initialize)(vboxGlobalData *data);
|
||||
void (*Uninitialize)(vboxGlobalData *data);
|
||||
void (*ComUnallocMem)(PCVBOXXPCOM pFuncs, void *pv);
|
||||
void (*Utf16Free)(PCVBOXXPCOM pFuncs, PRUnichar *pwszString);
|
||||
void (*Utf8Free)(PCVBOXXPCOM pFuncs, char *pszString);
|
||||
int (*Utf16ToUtf8)(PCVBOXXPCOM pFuncs, const PRUnichar *pwszString, char **ppszString);
|
||||
int (*Utf8ToUtf16)(PCVBOXXPCOM pFuncs, const char *pszString, PRUnichar **ppwszString);
|
||||
} vboxUniformedPFN;
|
||||
|
||||
/* Functions for IVirtualBox */
|
||||
typedef struct {
|
||||
nsresult (*GetVersion)(IVirtualBox *vboxObj, PRUnichar **versionUtf16);
|
||||
} vboxUniformedIVirtualBox;
|
||||
|
||||
typedef struct {
|
||||
/* vbox API version */
|
||||
uint32_t APIVersion;
|
||||
uint32_t XPCOMCVersion;
|
||||
/* vbox APIs */
|
||||
int (*initializeDomainEvent)(vboxGlobalData *data);
|
||||
void (*registerGlobalData)(vboxGlobalData *data);
|
||||
vboxUniformedPFN UPFN;
|
||||
vboxUniformedIVirtualBox UIVirtualBox;
|
||||
/* vbox API features */
|
||||
bool domainEventCallbacks;
|
||||
bool hasStaticGlobalData;
|
||||
} vboxUniformedAPI;
|
||||
|
||||
/* libvirt API
|
||||
* These API would be removed after we generate the
|
||||
* vboxDriver in common code.
|
||||
*/
|
||||
virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
|
||||
virConnectAuthPtr auth,
|
||||
unsigned int flags);
|
||||
|
||||
/* Version specified functions for installing uniformed API */
|
||||
void vbox22InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox30InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox31InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox32InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox40InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox41InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox42InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox42_20InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox43InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
void vbox43_4InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
|
||||
|
||||
#endif /* VBOX_UNIFORMED_API_H */
|
Loading…
Reference in New Issue
Block a user