---
cfg.mk | 1 +
configure.ac | 7 +
include/libvirt/virterror.h | 1 +
po/POTFILES.in | 2 +
src/Makefile.am | 24 +-
src/driver.h | 3 +-
src/libvirt.c | 13 +
src/util/virterror.c | 3 +
src/vmware/vmware_conf.c | 498 ++++++++++++++++
src/vmware/vmware_conf.h | 83 +++
src/vmware/vmware_driver.c | 1332 +++++++++++++++++++++++++++++++++++++++++++
src/vmware/vmware_driver.h | 25 +
12 files changed, 1988 insertions(+), 4 deletions(-)
create mode 100644 src/vmware/vmware_conf.c
create mode 100644 src/vmware/vmware_conf.h
create mode 100644 src/vmware/vmware_driver.c
create mode 100644 src/vmware/vmware_driver.h
diff --git a/cfg.mk b/cfg.mk
index bda8c57..03186b3 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -388,6 +388,7 @@ msg_gen_function += virXMLError
msg_gen_function += virXenInotifyError
msg_gen_function += virXenStoreError
msg_gen_function += virXendError
+msg_gen_function += vmwareError
msg_gen_function += xenapiSessionErrorHandler
msg_gen_function += xenUnifiedError
msg_gen_function += xenXMError
diff --git a/configure.ac b/configure.ac
index 64e76dc..5ec524d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -227,6 +227,8 @@ AC_ARG_WITH([uml],
AC_HELP_STRING([--with-uml], [add UML support
@<:@default=check@:>@]),[],[with_uml=check])
AC_ARG_WITH([openvz],
AC_HELP_STRING([--with-openvz], [add OpenVZ support
@<:@default=yes@:>@]),[],[with_openvz=yes])
+AC_ARG_WITH([vmware],
+ AC_HELP_STRING([--with-vmware], [add VMware support
@<:@default=yes@:>@]),[],[with_vmware=yes])
AC_ARG_WITH([libssh2],
AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location
@<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes])
AC_ARG_WITH([phyp],
@@ -316,6 +318,10 @@ if test "$with_openvz" = "yes"; then
fi
AM_CONDITIONAL([WITH_OPENVZ], [test "$with_openvz" = "yes"])
+if test "$with_vmware" = "yes"; then
+ AC_DEFINE_UNQUOTED([WITH_VMWARE], 1, [whether VMware driver is enabled])
+fi
+AM_CONDITIONAL([WITH_VMWARE], [test "$with_vmware" = "yes"])
dnl
dnl check for XDR
@@ -2277,6 +2283,7 @@ AC_MSG_NOTICE([ Xen: $with_xen])
AC_MSG_NOTICE([ QEMU: $with_qemu])
AC_MSG_NOTICE([ UML: $with_uml])
AC_MSG_NOTICE([ OpenVZ: $with_openvz])
+AC_MSG_NOTICE([ VMware: $with_vmware])
AC_MSG_NOTICE([ VBox: $with_vbox])
AC_MSG_NOTICE([ XenAPI: $with_xenapi])
AC_MSG_NOTICE([ LXC: $with_lxc])
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index eaeb477..a1f88f4 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -52,6 +52,7 @@ typedef enum {
VIR_FROM_TEST, /* Error from test driver */
VIR_FROM_REMOTE, /* Error from remote driver */
VIR_FROM_OPENVZ, /* Error from OpenVZ driver */
+ VIR_FROM_VMWARE, /* Error from VMware driver */
VIR_FROM_XENXM, /* Error at Xen XM layer */
VIR_FROM_STATS_LINUX,/* Error in the Linux Stats code */
VIR_FROM_LXC, /* Error from Linux Container driver */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e7be0d3..5561ace 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -100,6 +100,8 @@ src/util/xml.c
src/vbox/vbox_XPCOMCGlue.c
src/vbox/vbox_driver.c
src/vbox/vbox_tmpl.c
+src/vmware/vmware_conf.c
+src/vmware/vmware_driver.c
src/xen/xen_driver.c
src/xen/xen_hypervisor.c
src/xen/xen_inotify.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 196d8af..8bab5e2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -219,8 +219,6 @@ check-local: remote_protocol-structs
TEST_DRIVER_SOURCES = \
test/test_driver.c test/test_driver.h
-
-
# Now the Hypervisor specific drivers
XEN_DRIVER_SOURCES = \
xen/sexpr.c xen/sexpr.h \
@@ -256,6 +254,10 @@ OPENVZ_DRIVER_SOURCES = \
openvz/openvz_conf.c openvz/openvz_conf.h \
openvz/openvz_driver.c openvz/openvz_driver.h
+VMWARE_DRIVER_SOURCES = \
+ vmware/vmware_driver.c vmware/vmware.h \
+ vmware/vmware_conf.c vmware/vmware_conf.h
+
VBOX_DRIVER_SOURCES = \
vbox/vbox_XPCOMCGlue.c vbox/vbox_XPCOMCGlue.h \
vbox/vbox_driver.c vbox/vbox_driver.h \
@@ -601,6 +603,21 @@ endif
libvirt_driver_openvz_la_SOURCES = $(OPENVZ_DRIVER_SOURCES)
endif
+if WITH_VMWARE
+if WITH_DRIVER_MODULES
+mod_LTLIBRARIES += libvirt_driver_vmware.la
+else
+noinst_LTLIBRARIES += libvirt_driver_vmware.la
+libvirt_la_BUILT_LIBADD += libvirt_driver_vmware.la
+endif
+libvirt_driver_vmware_la_CFLAGS = \
+ -I@top_srcdir@/src/conf
+if WITH_DRIVER_MODULES
+libvirt_driver_vmware_la_LDFLAGS = -module -avoid-version
+endif
+libvirt_driver_vmware_la_SOURCES = $(VMWARE_DRIVER_SOURCES)
+endif
+
if WITH_VBOX
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_vbox.la
@@ -953,7 +970,8 @@ EXTRA_DIST += \
$(SECURITY_DRIVER_SELINUX_SOURCES) \
$(SECURITY_DRIVER_APPARMOR_SOURCES) \
$(SECRET_DRIVER_SOURCES) \
- $(VBOX_DRIVER_EXTRA_DIST)
+ $(VBOX_DRIVER_EXTRA_DIST) \
+ $(VMWARE_DRIVER_SOURCES)
check-local: augeas-check
diff --git a/src/driver.h b/src/driver.h
index 75305fe..03a388a 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -27,7 +27,8 @@ typedef enum {
VIR_DRV_ONE = 9,
VIR_DRV_ESX = 10,
VIR_DRV_PHYP = 11,
- VIR_DRV_XENAPI = 12
+ VIR_DRV_XENAPI = 12,
+ VIR_DRV_VMWARE = 13
} virDrvNo;
diff --git a/src/libvirt.c b/src/libvirt.c
index 4188b45..a77970c 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -54,6 +54,9 @@
# ifdef WITH_OPENVZ
# include "openvz/openvz_driver.h"
# endif
+# ifdef WITH_VMWARE
+# include "vmware/vmware_driver.h"
+# endif
# ifdef WITH_PHYP
# include "phyp/phyp_driver.h"
# endif
@@ -365,6 +368,9 @@ virInitialize(void)
# ifdef WITH_OPENVZ
virDriverLoadModule("openvz");
# endif
+# ifdef WITH_VMWARE
+ virDriverLoadModule("vmware");
+# endif
# ifdef WITH_VBOX
virDriverLoadModule("vbox");
# endif
@@ -387,6 +393,9 @@ virInitialize(void)
# ifdef WITH_OPENVZ
if (openvzRegister() == -1) return -1;
# endif
+# ifdef WITH_VMWARE
+ if (vmwareRegister() == -1) return -1;
+# endif
# ifdef WITH_PHYP
if (phypRegister() == -1) return -1;
# endif
@@ -1120,6 +1129,10 @@ virGetVersion(unsigned long *libVer, const char *type,
if (STRCASEEQ(type, "OpenVZ"))
*typeVer = LIBVIR_VERSION_NUMBER;
# endif
+# if WITH_VMWARE
+ if (STRCASEEQ(type, "VMware"))
+ *typeVer = LIBVIR_VERSION_NUMBER;
+# endif
# if WITH_VBOX
if (STRCASEEQ(type, "VBox"))
*typeVer = LIBVIR_VERSION_NUMBER;
diff --git a/src/util/virterror.c b/src/util/virterror.c
index b912737..96a09cc 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -134,6 +134,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
case VIR_FROM_OPENVZ:
dom = "OpenVZ ";
break;
+ case VIR_FROM_VMWARE:
+ dom = "VMware ";
+ break;
case VIR_FROM_XENXM:
dom = "Xen XM ";
break;
diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c
new file mode 100644
index 0000000..a3a0689
--- /dev/null
+++ b/src/vmware/vmware_conf.c
@@ -0,0 +1,498 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright 2010, diateam (
www.diateam.net)
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/utsname.h>
+
+#include "command.h"
+#include "cpu/cpu.h"
+#include "dirname.h"
+#include "memory.h"
+#include "nodeinfo.h"
+#include "util/files.h"
+#include "uuid.h"
+#include "virterror_internal.h"
+#include "../esx/esx_vmx.h"
+
+#include "vmware_conf.h"
+
+/* Free all memory associated with a vmware_driver structure */
+void
+vmwareFreeDriver(struct vmware_driver *driver)
+{
+ if (!driver)
+ return;
+
+ virMutexDestroy(&driver->lock);
+ virDomainObjListDeinit(&driver->domains);
+ virCapabilitiesFree(driver->caps);
+ VIR_FREE(driver);
+}
+
+virCapsPtr
+vmwareCapsInit(void)
+{
+ struct utsname utsname;
+ virCapsPtr caps = NULL;
+ virCapsGuestPtr guest = NULL;
+ virCPUDefPtr cpu = NULL;
+ union cpuData *data = NULL;
+
+ uname(&utsname);
+
+ if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL)
+ goto error;
+
+ if (nodeCapsInitNUMA(caps) < 0)
+ goto error;
+
+ virCapabilitiesSetMacPrefix(caps, (unsigned char[]) {0x52, 0x54, 0x00});
+
+ /* i686 guests are always supported */
+ if ((guest = virCapabilitiesAddGuest(caps,
+ "hvm",
+ "i686",
+ 32,
+ NULL, NULL, 0, NULL)) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ "vmware",
+ NULL, NULL, 0, NULL) == NULL)
+ goto error;
+
+ if (VIR_ALLOC(cpu) < 0
+ || !(cpu->arch = strdup(utsname.machine))) {
+ virReportOOMError();
+ goto error;
+ }
+
+ cpu->type = VIR_CPU_TYPE_HOST;
+
+ if (!(data = cpuNodeData(cpu->arch))
+ || cpuDecode(cpu, data, NULL, 0, NULL) < 0) {
+ goto error;
+ }
+
+ /* x86_64 guests are supported if
+ * - Host arch is x86_64
+ * Or
+ * - Host CPU is x86_64 with virtualization extensions
+ */
+ if (STREQ(utsname.machine, "x86_64") ||
+ (cpuHasFeature(utsname.machine, data, "lm") &&
+ (cpuHasFeature(utsname.machine, data, "vmx") ||
+ cpuHasFeature(utsname.machine, data, "svm")))) {
+
+ if ((guest = virCapabilitiesAddGuest(caps,
+ "hvm",
+ "x86_64",
+ 64,
+ NULL, NULL, 0, NULL)) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ "vmware",
+ NULL, NULL, 0, NULL) == NULL)
+ goto error;
+ }
+
+cleanup:
+ virCPUDefFree(cpu);
+ cpuDataFree(utsname.machine, data);
+
+ return caps;
+
+error:
+ virCapabilitiesFree(caps);
+ goto cleanup;
+}
+
+int
+vmwareLoadDomains(struct vmware_driver *driver)
+{
+ virDomainDefPtr vmdef = NULL;
+ virDomainObjPtr vm = NULL;
+ char *vmxPath = NULL;
+ char *vmx = NULL;
+ vmwareDomainPtr pDomain;
+ char *directoryName = NULL;
+ char *fileName = NULL;
+ int ret = -1;
+ esxVMX_Context ctx;
+ char *outbuf = NULL;
+ char *str;
+ char *saveptr = NULL;
+ virCommandPtr cmd;
+
+ ctx.parseFileName = esxCopyVMXFileName;
+
+ cmd = virCommandNewArgList(VMRUN, "-T",
+ driver->type == TYPE_PLAYER ? "player" :
"ws",
+ "list", NULL);
+ virCommandSetOutputBuffer(cmd, &outbuf);
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ for(str = outbuf ; (vmxPath = strtok_r(str, "\n", &saveptr)) != NULL;
+ str = NULL) {
+
+ if (vmxPath[0] != '/')
+ continue;
+
+ if (virFileReadAll(vmxPath, 10000, &vmx) < 0)
+ goto cleanup;
+
+ if ((vmdef =
+ esxVMX_ParseConfig(&ctx, driver->caps, vmx,
+ esxVI_ProductVersion_ESX4x)) == NULL) {
+ goto cleanup;
+ }
+
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains, vmdef, false)))
+ goto cleanup;
+
+ pDomain = vm->privateData;
+
+ pDomain->vmxPath = strdup(vmxPath);
+ if (pDomain->vmxPath == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ vmwareDomainConfigDisplay(pDomain, vmdef);
+
+ if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0)
+ goto cleanup;
+ //vmrun list only reports running vms
+ vm->state = VIR_DOMAIN_RUNNING;
+ vm->persistent = 1;
+
+ virDomainObjUnlock(vm);
+
+ vmdef = NULL;
+ vm = NULL;
+ }
+
+ ret = 0;
+
+cleanup:
+ virCommandFree(cmd);
+ VIR_FREE(outbuf);
+ virDomainDefFree(vmdef);
+ VIR_FREE(directoryName);
+ VIR_FREE(fileName);
+ VIR_FREE(vmx);
+ if (vm)
+ virDomainObjUnref(vm);
+ return ret;
+}
+
+void
+vmwareSetSentinal(const char **prog, const char *key)
+{
+ const char **tmp = prog;
+
+ while (tmp && *tmp) {
+ if (*tmp == PROGRAM_SENTINAL) {
+ *tmp = key;
+ break;
+ }
+ tmp++;
+ }
+}
+
+int
+vmwareExtractVersion(struct vmware_driver *driver)
+{
+ unsigned long version = 0;
+ char *tmp;
+ int ret = -1;
+ virCommandPtr cmd;
+ char * outbuf = NULL;
+ const char * bin = (driver->type == TYPE_PLAYER) ? "vmplayer" :
"vmware";
+ const char * pattern = (driver->type == TYPE_PLAYER) ?
+ "VMware Player " : "VMware Workstation ";
+
+ cmd = virCommandNewArgList(bin, "-v", NULL);
+ virCommandSetOutputBuffer(cmd, &outbuf);
+
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ if ((tmp = STRSKIP(outbuf, pattern)) == NULL) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to parse %s version"), bin);
+ goto cleanup;
+ }
+
+ if (virParseVersionString(tmp, &version) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("version parsing error"));
+ goto cleanup;
+ }
+
+ driver->version = version;
+ ret = 0;
+
+cleanup:
+ virCommandFree(cmd);
+ VIR_FREE(outbuf);
+ return ret;
+}
+
+int
+vmwareDomainConfigDisplay(vmwareDomainPtr pDomain, virDomainDefPtr def)
+{
+ int i = 0;
+
+ if (def->ngraphics == 0) {
+ pDomain->gui = true;
+ return 0;
+ } else {
+ pDomain->gui = false;
+ for (i = 0; i < def->ngraphics; i++) {
+ if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) {
+ pDomain->gui = true;
+ return 0;
+ }
+ }
+ return 0;
+ }
+}
+
+int
+vmwareParsePath(char *path, char **directory, char **filename)
+{
+ char *separator;
+
+ separator = strrchr(path, '/');
+
+ if (separator != NULL) {
+ *separator++ = '\0';
+
+ if (*separator == '\0') {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("path '%s' doesn't reference a file"),
path);
+ return -1;
+ }
+
+ if ((*directory = strdup(path)) == NULL)
+ goto no_memory;
+ if ((*filename = strdup(separator)) == NULL)
+ goto no_memory;
+
+ } else {
+ if ((*filename = strdup(separator)) == NULL)
+ goto no_memory;
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError();
+ return -1;
+}
+
+int
+vmwareConstructVmxPath(char *directoryName, char *name, char **vmxPath)
+{
+ if (directoryName != NULL) {
+ if (virAsprintf(vmxPath, "%s/%s.vmx", directoryName, name) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ } else {
+ if (virAsprintf(vmxPath, "%s.vmx", name) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+vmwareVmxPath(virDomainDefPtr vmdef, char **vmxPath)
+{
+ virDomainDiskDefPtr disk = NULL;
+ char *directoryName = NULL;
+ char *fileName = NULL;
+ int ret = -1;
+ int i = 0;
+
+ /*
+ * Build VMX URL. Use the source of the first file-based harddisk
+ * to deduce the path for the VMX file. Don't just use the
+ * first disk, because it may be CDROM disk and ISO images are normaly not
+ * located in the virtual machine's directory. This approach
+ * isn't perfect but should work in the majority of cases.
+ */
+ if (vmdef->ndisks < 1) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Domain XML doesn't contain any disks, "
+ "cannot deduce datastore and path for VMX file"));
+ goto cleanup;
+ }
+
+ for (i = 0; i < vmdef->ndisks; ++i) {
+ if (vmdef->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+ vmdef->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
+ disk = vmdef->disks[i];
+ break;
+ }
+ }
+
+ if (disk == NULL) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Domain XML doesn't contain any file-based harddisks,
"
+ "cannot deduce datastore and path for VMX file"));
+ goto cleanup;
+ }
+
+ if (disk->src == NULL) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("First file-based harddisk has no source, cannot "
+ "deduce datastore and path for VMX file"));
+ goto cleanup;
+ }
+
+ if (vmwareParsePath(disk->src, &directoryName, &fileName) < 0) {
+ goto cleanup;
+ }
+
+ if (!virFileHasSuffix(fileName, ".vmdk")) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("Expecting source '%s' of first file-based harddisk
"
+ "to be a VMDK image"), disk->src);
+ goto cleanup;
+ }
+
+ if (vmwareConstructVmxPath(directoryName, vmdef->name, vmxPath) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(directoryName);
+ VIR_FREE(fileName);
+ return ret;
+}
+
+int
+vmwareMoveFile(char *srcFile, char *dstFile)
+{
+ const char *cmdmv[] =
+ { "mv", PROGRAM_SENTINAL, PROGRAM_SENTINAL, NULL };
+
+ if (!virFileExists(srcFile)) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, _("file %s does not exist"),
+ srcFile);
+ return -1;
+ }
+
+ if (STREQ(srcFile, dstFile))
+ return 0;
+
+ vmwareSetSentinal(cmdmv, srcFile);
+ vmwareSetSentinal(cmdmv, dstFile);
+ if (virRun(cmdmv, NULL) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to move file to %s "), dstFile);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+vmwareMakePath(char *srcDir, char *srcName, char *srcExt, char **outpath)
+{
+ if (virAsprintf(outpath, "%s/%s.%s", srcDir, srcName, srcExt) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ return 0;
+}
+
+int
+vmwareExtractPid(const char * vmxPath)
+{
+ char *vmxDir = NULL;
+ char *logFilePath = NULL;
+ FILE *logFile = NULL;
+ char line[1024];
+ char *tmp = NULL;
+ int pid = -1;
+
+ if ((vmxDir = mdir_name(vmxPath)) == NULL)
+ goto cleanup;
+
+ if (virAsprintf(&logFilePath, "%s/vmware.log",
+ vmxDir) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if ((logFile = fopen(logFilePath, "r")) == NULL)
+ goto cleanup;
+
+ if (!fgets(line, sizeof(line), logFile)) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unable to read vmware log file"));
+ goto cleanup;
+ }
+
+ if ((tmp = strstr(line, " pid=")) == NULL) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot find pid in vmware log file"));
+ goto cleanup;
+ }
+
+ tmp += strlen(" pid=");
+
+ if (virStrToLong_i(tmp, &tmp, 10, &pid) < 0 || *tmp != ' ') {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot parse pid in vmware log file"));
+ goto cleanup;
+ }
+
+cleanup:
+ VIR_FREE(vmxDir);
+ VIR_FREE(logFilePath);
+ VIR_FORCE_FCLOSE(logFile);
+ return pid;
+}
+
+char *
+esxCopyVMXFileName(const char *datastorePath, void *opaque ATTRIBUTE_UNUSED)
+{
+ char *path = strdup(datastorePath);
+
+ if (path == NULL) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ return path;
+}
diff --git a/src/vmware/vmware_conf.h b/src/vmware/vmware_conf.h
new file mode 100644
index 0000000..b1cdf8f
--- /dev/null
+++ b/src/vmware/vmware_conf.h
@@ -0,0 +1,83 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright 2010, diateam (
www.diateam.net)
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifndef VMWARE_CONF_H
+# define VMWARE_CONF_H
+
+# define VMRUN "vmrun"
+# define NOGUI "nogui"
+
+# include "internal.h"
+# include "domain_conf.h"
+# include "threads.h"
+
+# define VIR_FROM_THIS VIR_FROM_VMWARE
+# define PROGRAM_SENTINAL ((char *)0x1)
+
+# define vmwareError(code, ...) \
+ virReportErrorHelper(NULL, VIR_FROM_VMWARE, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+# define TYPE_PLAYER 0
+# define TYPE_WORKSTATION 1
+
+struct vmware_driver {
+ virMutex lock;
+ virCapsPtr caps;
+
+ virDomainObjList domains;
+ int version;
+ int type;
+};
+
+typedef struct _vmwareDomain {
+ char *vmxPath;
+ bool gui;
+
+} vmwareDomain, *vmwareDomainPtr;
+
+void vmwareFreeDriver(struct vmware_driver *driver);
+
+virCapsPtr vmwareCapsInit(void);
+
+int vmwareLoadDomains(struct vmware_driver *driver);
+
+void vmwareSetSentinal(const char **prog, const char *key);
+
+int vmwareExtractVersion(struct vmware_driver *driver);
+
+int vmwareDomainConfigDisplay(vmwareDomainPtr domain, virDomainDefPtr vmdef);
+
+int vmwareParsePath(char *path, char **directory, char **filename);
+
+int vmwareConstructVmxPath(char *directoryName, char *name,
+ char **vmxPath);
+
+int vmwareVmxPath(virDomainDefPtr vmdef, char **vmxPath);
+
+int vmwareMoveFile(char *srcFile, char *dstFile);
+
+int vmwareMakePath(char *srcDir, char *srcName, char *srcExt,
+ char **outpath);
+
+int vmwareExtractPid(const char * vmxPath);
+
+char * esxCopyVMXFileName(const char *datastorePath, void *opaque);
+
+#endif
diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c
new file mode 100644
index 0000000..5967c68
--- /dev/null
+++ b/src/vmware/vmware_driver.c
@@ -0,0 +1,1332 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright 2010, diateam (
www.diateam.net)
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#include <config.h>
+
+#include <fcntl.h>
+
+#include "files.h"
+#include "memory.h"
+#include "uuid.h"
+
+#include "../esx/esx_vmx.h"
+#include "vmware_conf.h"
+#include "vmware_driver.h"
+
+const char *vmw_types[] = { "player", "ws" };
+
+static void
+vmwareDriverLock(struct vmware_driver *driver)
+{
+ virMutexLock(&driver->lock);
+}
+
+static void
+vmwareDriverUnlock(struct vmware_driver *driver)
+{
+ virMutexUnlock(&driver->lock);
+}
+
+static void *
+vmwareDataAllocFunc(void)
+{
+ vmwareDomainPtr dom;
+
+ if (VIR_ALLOC(dom) < 0)
+ return NULL;
+
+ dom->vmxPath = NULL;
+ dom->gui = true;
+
+ return dom;
+}
+
+static void
+vmwareDataFreeFunc(void *data)
+{
+ vmwareDomainPtr dom = data;
+
+ VIR_FREE(dom->vmxPath);
+ VIR_FREE(dom);
+}
+
+static virDrvOpenStatus
+vmwareOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ struct vmware_driver *driver;
+ char * vmrun = NULL;
+
+ if (conn->uri == NULL) {
+ /* @TODO accept */
+ return VIR_DRV_OPEN_DECLINED;
+ } else {
+ if (conn->uri->scheme == NULL ||
+ (STRNEQ(conn->uri->scheme, "vmwareplayer") &&
+ STRNEQ(conn->uri->scheme, "vmwarews")))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* If server name is given, its for remote driver */
+ if (conn->uri->server != NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* If path isn't /session, then they typoed, so tell them correct path */
+ if (conn->uri->path == NULL || STRNEQ(conn->uri->path,
"/session")) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected VMware URI path '%s', try
vmwareplayer:///session or vmwarews:///session"),
+ NULLSTR(conn->uri->path));
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
+
+ /* We now know the URI is definitely for this driver, so beyond
+ * here, don't return DECLINED, always use ERROR */
+
+ vmrun = virFindFileInPath(VMRUN);
+
+ if (vmrun == NULL) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("%s utility is missing"), VMRUN);
+ return VIR_DRV_OPEN_ERROR;
+ } else {
+ VIR_FREE(vmrun);
+ }
+
+ if (VIR_ALLOC(driver) < 0) {
+ virReportOOMError();
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ if (virMutexInit(&driver->lock) < 0)
+ goto cleanup;
+
+ driver->type = STRNEQ(conn->uri->scheme, "vmwareplayer") ?
+ TYPE_WORKSTATION : TYPE_PLAYER;
+
+ if (virDomainObjListInit(&driver->domains) < 0)
+ goto cleanup;
+
+ if (!(driver->caps = vmwareCapsInit()))
+ goto cleanup;
+
+ driver->caps->privateDataAllocFunc = vmwareDataAllocFunc;
+ driver->caps->privateDataFreeFunc = vmwareDataFreeFunc;
+
+ if (vmwareLoadDomains(driver) < 0)
+ goto cleanup;
+
+ if (vmwareExtractVersion(driver) < 0)
+ goto cleanup;
+
+ conn->privateData = driver;
+
+ return VIR_DRV_OPEN_SUCCESS;
+
+ cleanup:
+ vmwareFreeDriver(driver);
+ return VIR_DRV_OPEN_ERROR;
+};
+
+static int
+vmwareClose(virConnectPtr conn)
+{
+ struct vmware_driver *driver = conn->privateData;
+
+ vmwareFreeDriver(driver);
+
+ conn->privateData = NULL;
+
+ return 0;
+}
+
+static const char *
+vmwareGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return "VMware";
+}
+
+static int
+vmwareGetVersion(virConnectPtr conn, unsigned long *version)
+{
+ struct vmware_driver *driver = conn->privateData;
+
+ vmwareDriverLock(driver);
+ *version = driver->version;
+ vmwareDriverUnlock(driver);
+ return 0;
+}
+
+static int
+vmwareStopVM(struct vmware_driver *driver, virDomainObjPtr vm)
+{
+ const char *cmd[] = {
+ VMRUN, "-T", PROGRAM_SENTINAL, "stop",
+ PROGRAM_SENTINAL, "soft", NULL
+ };
+
+ vmwareSetSentinal(cmd, vmw_types[driver->type]);
+ vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
+
+ if (virRun(cmd, NULL) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VMRUN);
+ return -1;
+ }
+
+ vm->def->id = -1;
+ vm->state = VIR_DOMAIN_SHUTOFF;
+
+ return 0;
+}
+
+static int
+vmwareStartVM(struct vmware_driver *driver, virDomainObjPtr vm)
+{
+ const char *cmd[] = {
+ VMRUN, "-T", PROGRAM_SENTINAL, "start",
+ PROGRAM_SENTINAL, PROGRAM_SENTINAL, NULL
+ };
+ const char *vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;
+
+ if (vm->state != VIR_DOMAIN_SHUTOFF) {
+ vmwareError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is not in shutoff state"));
+ return -1;
+ }
+
+ vmwareSetSentinal(cmd, vmw_types[driver->type]);
+ vmwareSetSentinal(cmd, vmxPath);
+ if (!((vmwareDomainPtr) vm->privateData)->gui)
+ vmwareSetSentinal(cmd, NOGUI);
+ else
+ vmwareSetSentinal(cmd, NULL);
+
+ if (virRun(cmd, NULL) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VMRUN);
+ return -1;
+ }
+
+ if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0) {
+ vmwareStopVM(driver, vm);
+ return -1;
+ }
+
+ vm->state = VIR_DOMAIN_RUNNING;
+
+ return 0;
+}
+
+static virDomainPtr
+vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+ struct vmware_driver *driver = conn->privateData;
+ virDomainDefPtr vmdef = NULL;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+ char *vmx = NULL;
+ char *directoryName = NULL;
+ char *fileName = NULL;
+ char *vmxPath = NULL;
+ vmwareDomainPtr pDomain = NULL;
+ esxVMX_Context ctx;
+
+ ctx.formatFileName = esxCopyVMXFileName;
+
+ vmwareDriverLock(driver);
+ if ((vmdef = virDomainDefParseString(driver->caps, xml,
+ VIR_DOMAIN_XML_INACTIVE)) == NULL)
+ goto cleanup;
+
+ if (virDomainObjIsDuplicate(&driver->domains, vmdef, 1) < 0)
+ goto cleanup;
+
+ /* generate vmx file */
+ vmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef,
+ esxVI_ProductVersion_ESX4x);
+ if (vmx == NULL)
+ goto cleanup;
+
+ if (vmwareVmxPath(vmdef, &vmxPath) < 0)
+ goto cleanup;
+
+ /* create vmx file */
+ if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to write vmx file '%s'"), vmxPath);
+ goto cleanup;
+ }
+
+ /* assign def */
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains, vmdef, false)))
+ goto cleanup;
+
+ pDomain = vm->privateData;
+ if ((pDomain->vmxPath = strdup(vmxPath)) == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ vmwareDomainConfigDisplay(pDomain, vmdef);
+
+ vmdef = NULL;
+ vm->persistent = 1;
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = -1;
+
+ cleanup:
+ virDomainDefFree(vmdef);
+ VIR_FREE(vmx);
+ VIR_FREE(directoryName);
+ VIR_FREE(fileName);
+ VIR_FREE(vmxPath);
+ if (vm)
+ virDomainObjUnlock(vm);
+ vmwareDriverUnlock(driver);
+ return dom;
+}
+
+static int
+vmwareDomainShutdown(virDomainPtr dom)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ vmwareDriverLock(driver);
+
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ if (vm->state != VIR_DOMAIN_RUNNING) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("domain is not in running state"));
+ goto cleanup;
+ }
+
+ if (vmwareStopVM(driver, vm) < 0)
+ goto cleanup;
+
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+
+ ret = 0;
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ vmwareDriverUnlock(driver);
+ return ret;
+}
+
+static int
+vmwareDomainSuspend(virDomainPtr dom)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+
+ virDomainObjPtr vm;
+ const char *cmd[] = {
+ VMRUN, "-T", PROGRAM_SENTINAL, "pause",
+ PROGRAM_SENTINAL, NULL
+ };
+ int ret = -1;
+
+ if (driver->type == TYPE_PLAYER) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("vmplayer does not support libvirt suspend/resume"
+ " (vmware pause/unpause) operation "));
+ return ret;
+ }
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ vmwareSetSentinal(cmd, vmw_types[driver->type]);
+ vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
+ if (vm->state != VIR_DOMAIN_RUNNING) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("domain is not in running state"));
+ goto cleanup;
+ }
+
+ if (virRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ vm->state = VIR_DOMAIN_PAUSED;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+vmwareDomainResume(virDomainPtr dom)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+
+ virDomainObjPtr vm;
+ const char *cmd[] = {
+ VMRUN, "-T", PROGRAM_SENTINAL, "unpause", PROGRAM_SENTINAL,
+ NULL
+ };
+ int ret = -1;
+
+ if (driver->type == TYPE_PLAYER) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("vmplayer does not support libvirt suspend/resume"
+ "(vmware pause/unpause) operation "));
+ return ret;
+ }
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ vmwareSetSentinal(cmd, vmw_types[driver->type]);
+ vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
+ if (vm->state != VIR_DOMAIN_PAUSED) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("domain is not in suspend state"));
+ goto cleanup;
+ }
+
+ if (virRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ vm->state = VIR_DOMAIN_RUNNING;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+vmwareDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ const char * vmxPath = NULL;
+
+ virDomainObjPtr vm;
+ const char *cmd[] = {
+ VMRUN, "-T", PROGRAM_SENTINAL,
+ "reset", PROGRAM_SENTINAL, "soft", NULL
+ };
+ int ret = -1;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+ vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ vmwareSetSentinal(cmd, vmw_types[driver->type]);
+ vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
+
+
+ if (vm->state != VIR_DOMAIN_RUNNING) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("domain is not in running state"));
+ goto cleanup;
+ }
+
+ if (virRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+vmwareDomainSave(virDomainPtr dom, const char *path)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ const char *cmdsuspend[] = {
+ VMRUN, "-T", PROGRAM_SENTINAL,
+ "suspend", PROGRAM_SENTINAL, NULL
+ };
+ int ret = -1;
+ char *fDirectoryName = NULL;
+ char *fFileName = NULL;
+ char *tDirectoryName = NULL;
+ char *tFileName = NULL;
+ char *copyPath = NULL;
+ char *copyvmxPath = NULL;
+ char *fvmss = NULL;
+ char *tvmss = NULL;
+ char *fvmem = NULL;
+ char *tvmem = NULL;
+ char *fvmx = NULL;
+ char *tvmx = NULL;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ /* vmware suspend */
+ vmwareSetSentinal(cmdsuspend, vmw_types[driver->type]);
+ vmwareSetSentinal(cmdsuspend,
+ ((vmwareDomainPtr) vm->privateData)->vmxPath);
+
+ if (vm->state != VIR_DOMAIN_RUNNING) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("domain is not in running state"));
+ goto cleanup;
+ }
+
+ if (virRun(cmdsuspend, NULL) < 0)
+ goto cleanup;
+
+ /* create files path */
+ copyvmxPath = strdup(((vmwareDomainPtr) vm->privateData)->vmxPath);
+ if(copyvmxPath == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if((copyPath = strdup(path)) == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (vmwareParsePath(copyvmxPath, &fDirectoryName, &fFileName) < 0)
+ goto cleanup;
+ if (vmwareParsePath(copyPath, &tDirectoryName, &tFileName) < 0)
+ goto cleanup;
+
+ /* dir */
+ if (virFileMakePath(tDirectoryName) != 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", _("make path
error"));
+ goto cleanup;
+ }
+
+ if (vmwareMakePath(fDirectoryName, vm->def->name,(char *) "vmss",
&fvmss) < 0)
+ goto cleanup;
+ if (vmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmss",
&tvmss) < 0)
+ goto cleanup;
+ if (vmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmem",
&fvmem) < 0)
+ goto cleanup;
+ if (vmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmem",
&tvmem) < 0)
+ goto cleanup;
+ if (vmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmx",
&fvmx) < 0)
+ goto cleanup;
+ if (vmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmx",
&tvmx) < 0)
+ goto cleanup;
+
+ /* create linker file */
+ if (virFileWriteStr(path, ((vmwareDomainPtr) vm->privateData)->vmxPath,
+ S_IRUSR|S_IWUSR) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to write save file '%s'"), path);
+ goto cleanup;
+ }
+
+ /* we want to let saved VM inside default directory */
+ if (STREQ(fDirectoryName, tDirectoryName))
+ goto end;
+
+ /* move {vmx,vmss,vmem} files */
+ if ((vmwareMoveFile(fvmss, tvmss) < 0)
+ || (vmwareMoveFile(fvmem, tvmem) < 0)
+ || (vmwareMoveFile(fvmx, tvmx) < 0)) {
+ goto cleanup;
+ }
+
+ end:
+ vm->def->id = -1;
+ vm->state = VIR_DOMAIN_SHUTOFF;
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(fDirectoryName);
+ VIR_FREE(fFileName);
+ VIR_FREE(tDirectoryName);
+ VIR_FREE(tFileName);
+ VIR_FREE(copyPath);
+ VIR_FREE(copyvmxPath);
+
+ VIR_FREE(fvmss);
+ VIR_FREE(tvmss);
+ VIR_FREE(fvmem);
+ VIR_FREE(tvmem);
+ VIR_FREE(fvmx);
+ VIR_FREE(tvmx);
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+vmwareDomainRestore(virConnectPtr conn, const char *path)
+{
+ struct vmware_driver *driver = conn->privateData;
+ virDomainDefPtr vmdef = NULL;
+ virDomainPtr dom = NULL;
+ virDomainObjPtr vm = NULL;
+ int ret = -1;
+ char *vmxPath = NULL;
+ char *copypath = NULL;
+ char *copyvmxPath = NULL;
+ char *tDirectoryName = NULL;
+ char *tFileName = NULL;
+ char *fDirectoryName = NULL;
+ char *fFileName = NULL;
+ char *vmx = NULL;
+ char *xml = NULL;
+ char *sep = NULL;
+ char *baseVmss;
+ char *fvmss = NULL;
+ char *tvmss = NULL;
+ char *fvmem = NULL;
+ char *tvmem = NULL;
+ char *fvmx = NULL;
+ char *tvmx = NULL;
+ FILE *pFile = NULL;
+ esxVMX_Context ctx;
+
+ ctx.parseFileName = esxCopyVMXFileName;
+
+ if (!virFileExists(path)) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("file %s does not exist"), path);
+ goto cleanup;
+ }
+ if (virFileHasSuffix(path, ".vmx")) { //we want to restore a vm saved
in its default directory
+ if((tvmx = strdup(path)) == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if((copypath = strdup(path)) == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (vmwareParsePath(copypath, &fDirectoryName, &fFileName) < 0)
+ goto cleanup;
+
+ sep = strrchr(fFileName, '.');
+ if (sep != NULL)
+ *sep = '\0';
+
+ if (vmwareMakePath(fFileName, fFileName, (char *) "vmss", &fvmss)
< 0)
+ goto cleanup;
+
+ baseVmss = basename(fvmss);
+ } else { //we want to restore a vm saved elsewhere
+ if (virFileReadAll(path, 1024, &vmxPath) < 0)
+ goto cleanup;
+
+ if (!virFileHasSuffix(vmxPath, ".vmx")) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("%s is not a .vmx file"), vmxPath);
+ goto cleanup;
+ }
+
+ /* move files */
+ if((copyvmxPath = strdup(vmxPath)) == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if((copypath = strdup(path)) == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (vmwareParsePath(copypath, &fDirectoryName, &fFileName) < 0)
+ goto cleanup;
+
+ if (vmwareParsePath(copyvmxPath, &tDirectoryName, &tFileName) < 0)
+ goto cleanup;
+
+ sep = strrchr(tFileName, '.');
+ if (sep != NULL)
+ *sep = '\0';
+
+ if (virFileMakePath(tDirectoryName) != 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("make path error"));
+ goto cleanup;
+ }
+
+ if (vmwareMakePath(fDirectoryName, tFileName,(char *) "vmss",
&fvmss) < 0)
+ goto cleanup;
+ if (vmwareMakePath(tDirectoryName, tFileName, (char *) "vmss",
&tvmss) < 0)
+ goto cleanup;
+ if (vmwareMakePath(fDirectoryName, tFileName, (char *) "vmem",
&fvmem) < 0)
+ goto cleanup;
+ if (vmwareMakePath(tDirectoryName, tFileName, (char *) "vmem",
&tvmem) < 0)
+ goto cleanup;
+ if (vmwareMakePath(fDirectoryName, tFileName, (char *) "vmx",
&fvmx) < 0)
+ goto cleanup;
+ if (vmwareMakePath(tDirectoryName, tFileName, (char *) "vmx",
&tvmx) < 0)
+ goto cleanup;
+
+ if ((vmwareMoveFile(fvmss, tvmss) < 0)
+ || (vmwareMoveFile(fvmem, tvmem) < 0)
+ || (vmwareMoveFile(fvmx, tvmx) < 0)) {
+ goto cleanup;
+ }
+
+ baseVmss = basename(tvmss);
+ }
+
+ if (virFileReadAll(tvmx, 10000, &vmx) < 0)
+ goto cleanup;
+
+ vmwareDriverLock(driver);
+ if ((vmdef =
+ esxVMX_ParseConfig(&ctx, driver->caps, vmx,
+ esxVI_ProductVersion_ESX4x)) == NULL) {
+ goto cleanup;
+ }
+ vmwareDriverUnlock(driver);
+
+ xml = virDomainDefFormat(vmdef, VIR_DOMAIN_XML_SECURE);
+
+ if ((dom = vmwareDomainDefineXML(conn, xml)) == NULL)
+ goto cleanup;
+
+ /* esxVMX_ParseConfig doesn't care about vmx checkpoint property for
+ * now, so we add it here
+ * TODO
+ */
+
+ if ((pFile = fopen(tvmx, "a+")) == NULL) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to reopen vmx file"));
+ goto cleanup;
+ }
+
+ fputs("checkpoint.vmState = \"", pFile);
+ fputs(baseVmss, pFile);
+ fputs("\"", pFile);
+ if (VIR_FCLOSE(pFile) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to save vmx file %s"), tvmx);
+ goto cleanup;
+ }
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching id"));
+ goto cleanup;
+ }
+
+ /* start */
+ if (vmwareStartVM(driver, vm) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(vmxPath);
+ VIR_FREE(copypath);
+ VIR_FREE(copyvmxPath);
+ VIR_FREE(tDirectoryName);
+ VIR_FREE(tFileName);
+ VIR_FREE(fDirectoryName);
+ VIR_FREE(fFileName);
+ VIR_FREE(vmx);
+ VIR_FREE(xml);
+
+ VIR_FREE(fvmss);
+ VIR_FREE(tvmss);
+ VIR_FREE(fvmem);
+ VIR_FREE(tvmem);
+ VIR_FREE(fvmx);
+ VIR_FREE(tvmx);
+
+ if (dom)
+ virUnrefDomain(dom);
+ if (vm)
+ virDomainObjUnlock(vm);
+ vmwareDriverUnlock(driver);
+ return ret;
+}
+
+static virDomainPtr
+vmwareDomainCreateXML(virConnectPtr conn, const char *xml,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ struct vmware_driver *driver = conn->privateData;
+ virDomainDefPtr vmdef = NULL;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+ char *vmx = NULL;
+ char *vmxPath = NULL;
+ vmwareDomainPtr pDomain = NULL;
+ esxVMX_Context ctx;
+
+ ctx.formatFileName = esxCopyVMXFileName;
+
+ vmwareDriverLock(driver);
+
+ if ((vmdef = virDomainDefParseString(driver->caps, xml,
+ VIR_DOMAIN_XML_INACTIVE)) == NULL)
+ goto cleanup;
+
+ if (virDomainObjIsDuplicate(&driver->domains, vmdef, 1) < 0)
+ goto cleanup;
+
+ /* generate vmx file */
+ vmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef,
+ esxVI_ProductVersion_ESX4x);
+ if (vmx == NULL)
+ goto cleanup;
+
+ if (vmwareVmxPath(vmdef, &vmxPath) < 0)
+ goto cleanup;
+
+ /* create vmx file */
+ if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to write vmx file '%s'"), vmxPath);
+ goto cleanup;
+ }
+
+ /* assign def */
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains, vmdef, false)))
+ goto cleanup;
+
+ pDomain = vm->privateData;
+ pDomain->vmxPath = strdup(vmxPath);
+
+ vmwareDomainConfigDisplay(pDomain, vmdef);
+ vmdef = NULL;
+
+ if (vmwareStartVM(driver, vm) < 0) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+cleanup:
+ virDomainDefFree(vmdef);
+ VIR_FREE(vmx);
+ VIR_FREE(vmxPath);
+ if(vm)
+ virDomainObjUnlock(vm);
+ vmwareDriverUnlock(driver);
+ return dom;
+}
+
+static int
+vmwareDomainCreateWithFlags(virDomainPtr dom,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ vmwareError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ vmwareError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is already running"));
+ goto cleanup;
+ }
+
+ ret = vmwareStartVM(driver, vm);
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ vmwareDriverUnlock(driver);
+ return ret;
+}
+
+static int
+vmwareDomainCreate(virDomainPtr dom)
+{
+ return vmwareDomainCreateWithFlags(dom, 0);
+}
+
+static int
+vmwareDomainUndefine(virDomainPtr dom)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(dom->uuid, uuidstr);
+ vmwareError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ vmwareError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot undefine active domain"));
+ goto cleanup;
+ }
+
+ if (!vm->persistent) {
+ vmwareError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot undefine transient domain"));
+ goto cleanup;
+ }
+
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ vmwareDriverUnlock(driver);
+ return ret;
+}
+
+static virDomainPtr
+vmwareDomainLookupByID(virConnectPtr conn, int id)
+{
+ struct vmware_driver *driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByID(&driver->domains, id);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static char *
+vmwareGetOSType(virDomainPtr dom)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ char *ret = NULL;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ if (!(ret = strdup(vm->def->os.type)))
+ virReportOOMError();
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+
+static virDomainPtr
+vmwareDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ struct vmware_driver *driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, uuid);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static virDomainPtr
+vmwareDomainLookupByName(virConnectPtr conn, const char *name)
+{
+ struct vmware_driver *driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByName(&driver->domains, name);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static int
+vmwareDomainIsActive(virDomainPtr dom)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr obj;
+ int ret = -1;
+
+ vmwareDriverLock(driver);
+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+ if (!obj) {
+ vmwareError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+ ret = virDomainObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virDomainObjUnlock(obj);
+ return ret;
+}
+
+
+static int
+vmwareDomainIsPersistent(virDomainPtr dom)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr obj;
+ int ret = -1;
+
+ vmwareDriverLock(driver);
+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+ if (!obj) {
+ vmwareError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+ ret = obj->persistent;
+
+ cleanup:
+ if (obj)
+ virDomainObjUnlock(obj);
+ return ret;
+}
+
+
+static char *
+vmwareDomainDumpXML(virDomainPtr dom, int flags)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ char *ret = NULL;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ ret = virDomainDefFormat(vm->def, flags);
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+vmwareNumDefinedDomains(virConnectPtr conn)
+{
+ struct vmware_driver *driver = conn->privateData;
+ int n;
+
+ vmwareDriverLock(driver);
+ n = virDomainObjListNumOfDomains(&driver->domains, 0);
+ vmwareDriverUnlock(driver);
+
+ return n;
+}
+
+static int
+vmwareNumDomains(virConnectPtr conn)
+{
+ struct vmware_driver *driver = conn->privateData;
+ int n;
+
+ vmwareDriverLock(driver);
+ n = virDomainObjListNumOfDomains(&driver->domains, 1);
+ vmwareDriverUnlock(driver);
+
+ return n;
+}
+
+
+static int
+vmwareListDomains(virConnectPtr conn, int *ids, int nids)
+{
+ struct vmware_driver *driver = conn->privateData;
+ int n;
+
+ vmwareDriverLock(driver);
+ n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
+ vmwareDriverUnlock(driver);
+
+ return n;
+}
+
+static int
+vmwareListDefinedDomains(virConnectPtr conn,
+ char **const names, int nnames)
+{
+ struct vmware_driver *driver = conn->privateData;
+ int n;
+
+ vmwareDriverLock(driver);
+ n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
+ vmwareDriverUnlock(driver);
+ return n;
+}
+
+static int
+vmwareDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
+{
+ struct vmware_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ vmwareDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ vmwareDriverUnlock(driver);
+
+ if (!vm) {
+ vmwareError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ info->state = vm->state;
+ info->cpuTime = 0;
+ info->maxMem = vm->def->mem.max_balloon;
+ info->memory = vm->def->mem.cur_balloon;
+ info->nrVirtCpu = vm->def->vcpus;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static virDriver vmwareDriver = {
+ VIR_DRV_VMWARE,
+ "VMWARE",
+ vmwareOpen, /* open */
+ vmwareClose, /* close */
+ NULL, /* supports_feature */
+ vmwareGetType, /* type */
+ vmwareGetVersion, /* version */
+ NULL, /* libvirtVersion (impl. in libvirt.c) */
+ NULL, /* getHostname */
+ NULL, /* getMaxVcpus */
+ NULL, /* nodeGetInfo */
+ NULL, /* getCapabilities */
+ vmwareListDomains, /* listDomains */
+ vmwareNumDomains, /* numOfDomains */
+ vmwareDomainCreateXML, /* domainCreateXML */
+ vmwareDomainLookupByID, /* domainLookupByID */
+ vmwareDomainLookupByUUID, /* domainLookupByUUID */
+ vmwareDomainLookupByName, /* domainLookupByName */
+ vmwareDomainSuspend, /* domainSuspend */
+ vmwareDomainResume, /* domainResume */
+ vmwareDomainShutdown, /* domainShutdown */
+ vmwareDomainReboot, /* domainReboot */
+ vmwareDomainShutdown, /* domainDestroy */
+ vmwareGetOSType, /* domainGetOSType */
+ NULL, /* domainGetMaxMemory */
+ NULL, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ vmwareDomainGetInfo, /* domainGetInfo */
+ vmwareDomainSave, /* domainSave */
+ vmwareDomainRestore, /* domainRestore */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainSetVcpusFlags */
+ NULL, /* domainGetVcpusFlags */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ NULL, /* domainGetSecurityLabel */
+ NULL, /* nodeGetSecurityModel */
+ vmwareDomainDumpXML, /* domainDumpXML */
+ NULL, /* domainXmlFromNative */
+ NULL, /* domainXmlToNative */
+ vmwareListDefinedDomains, /* listDefinedDomains */
+ vmwareNumDefinedDomains, /* numOfDefinedDomains */
+ vmwareDomainCreate, /* domainCreate */
+ vmwareDomainCreateWithFlags,/* domainCreateWithFlags */
+ vmwareDomainDefineXML, /* domainDefineXML */
+ vmwareDomainUndefine, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainAttachDeviceFlags */
+ NULL, /* domainDetachDevice */
+ NULL, /* domainDetachDeviceFlags */
+ NULL, /* domainUpdateDeviceFlags */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ NULL, /* domainGetSchedulerType */
+ NULL, /* domainGetSchedulerParameters */
+ NULL, /* domainSetSchedulerParameters */
+ NULL, /* domainMigratePrepare */
+ NULL, /* domainMigratePerform */
+ NULL, /* domainMigrateFinish */
+ NULL, /* domainBlockStats */
+ NULL, /* domainInterfaceStats */
+ NULL, /* domainMemoryStats */
+ NULL, /* domainBlockPeek */
+ NULL, /* domainMemoryPeek */
+ NULL, /* domainGetBlockInfo */
+ NULL, /* nodeGetCellsFreeMemory */
+ NULL, /* getFreeMemory */
+ NULL, /* domainEventRegister */
+ NULL, /* domainEventDeregister */
+ NULL, /* domainMigratePrepare2 */
+ NULL, /* domainMigrateFinish2 */
+ NULL, /* nodeDeviceDettach */
+ NULL, /* nodeDeviceReAttach */
+ NULL, /* nodeDeviceReset */
+ NULL, /* domainMigratePrepareTunnel */
+ NULL, /* IsEncrypted */
+ NULL, /* IsSecure */
+ vmwareDomainIsActive, /* DomainIsActive */
+ vmwareDomainIsPersistent, /* DomainIsPersistent */
+ NULL, /* domainIsUpdated */
+ NULL, /* cpuCompare */
+ NULL, /* cpuBaseline */
+ NULL, /* domainGetJobInfo */
+ NULL, /* domainAbortJob */
+ NULL, /* domainMigrateSetMaxDowntime */
+ NULL, /* domainEventRegisterAny */
+ NULL, /* domainEventDeregisterAny */
+ NULL, /* domainManagedSave */
+ NULL, /* domainHasManagedSaveImage */
+ NULL, /* domainManagedSaveRemove */
+ NULL, /* domainSnapshotCreateXML */
+ NULL, /* domainSnapshotDumpXML */
+ NULL, /* domainSnapshotNum */
+ NULL, /* domainSnapshotListNames */
+ NULL, /* domainSnapshotLookupByName */
+ NULL, /* domainHasCurrentSnapshot */
+ NULL, /* domainSnapshotCurrent */
+ NULL, /* domainRevertToSnapshot */
+ NULL, /* domainSnapshotDelete */
+ NULL, /* qemuDomainMonitorCommand */
+ NULL, /* domainSetMemoryParameters */
+ NULL, /* domainGetMemoryParameters */
+ NULL, /* domainOpenConsole */
+};
+
+int
+vmwareRegister(void)
+{
+ if (virRegisterDriver(&vmwareDriver) < 0)
+ return -1;
+ return 0;
+}
diff --git a/src/vmware/vmware_driver.h b/src/vmware/vmware_driver.h
new file mode 100644
index 0000000..71186de
--- /dev/null
+++ b/src/vmware/vmware_driver.h
@@ -0,0 +1,25 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright 2010, diateam (
www.diateam.net)
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifndef VMWARE_DRIVER_H
+# define VMWARE_DRIVER_H
+
+int vmwareRegister(void);
+
+#endif
--
1.7.0.4