]> xenbits.xensource.com Git - libvirt.git/commitdiff
esx: Move VMX handling code out of the driver directory
authorMatthias Bolte <matthias.bolte@googlemail.com>
Tue, 21 Dec 2010 21:39:55 +0000 (22:39 +0100)
committerMatthias Bolte <matthias.bolte@googlemail.com>
Tue, 21 Dec 2010 21:40:17 +0000 (22:40 +0100)
Now the VMware driver doesn't depend on the ESX driver anymore.

Add a WITH_VMX option that depends on WITH_ESX and WITH_VMWARE.
Also add a libvirt_vmx.syms file.

Move some escaping functions from esx_util.c to vmx.c.

Adapt the test suite, ESX and VMware driver to the new code layout.

20 files changed:
configure.ac
po/POTFILES.in
src/Makefile.am
src/esx/esx_driver.c
src/esx/esx_util.c
src/esx/esx_util.h
src/esx/esx_vi.c
src/esx/esx_vi.h
src/esx/esx_vmx.c [deleted file]
src/esx/esx_vmx.h [deleted file]
src/libvirt_vmx.syms [new file with mode: 0644]
src/vmware/vmware_conf.c
src/vmware/vmware_conf.h
src/vmware/vmware_driver.c
src/vmx/vmx.c [new file with mode: 0644]
src/vmx/vmx.h [new file with mode: 0644]
tests/Makefile.am
tests/esxutilstest.c
tests/vmx2xmltest.c
tests/xml2vmxtest.c

index 73c117652bb7c28bae74e53919739a6642789579..51da1b0ede811a3d8bcffb0ec6381549c2535b40 100644 (file)
@@ -1776,6 +1776,15 @@ if test "$with_esx" = "yes" ; then
 fi
 AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"])
 
+with_vmx=yes
+if test "$with_esx" != "yes" && test "$with_vmware" != "yes"; then
+  with_vmx=no
+fi
+if test "$with_vmx" = "yes" ; then
+  AC_DEFINE_UNQUOTED([WITH_VMX], 1, [whether VMware VMX config handling is enabled])
+fi
+AM_CONDITIONAL([WITH_VMX], [test "$with_vmx" = "yes"])
+
 if test "$with_xenapi" = "yes" ; then
     AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled])
 fi
index 3b851f1e91ae971dbb3a6063b479c19a1cad5a12..3d7bc8be99e3a4529b009f6e57d188bbd16cd8ab 100644 (file)
@@ -25,7 +25,6 @@ src/esx/esx_util.c
 src/esx/esx_vi.c
 src/esx/esx_vi_methods.c
 src/esx/esx_vi_types.c
-src/esx/esx_vmx.c
 src/fdstream.c
 src/interface/netcf_driver.c
 src/internal.h
@@ -109,6 +108,7 @@ src/vbox/vbox_driver.c
 src/vbox/vbox_tmpl.c
 src/vmware/vmware_conf.c
 src/vmware/vmware_driver.c
+src/vmx/vmx.c
 src/xen/xen_driver.c
 src/xen/xen_hypervisor.c
 src/xen/xen_inotify.c
index 10c3c7e25cb11351cceb600980e84e96e95b9b81..607e39175ef834f17cd89b9e94abde078edf219a 100644 (file)
@@ -322,8 +322,7 @@ ESX_DRIVER_SOURCES =                                                \
                esx/esx_util.c esx/esx_util.h                   \
                esx/esx_vi.c esx/esx_vi.h                       \
                esx/esx_vi_methods.c esx/esx_vi_methods.h       \
-               esx/esx_vi_types.c esx/esx_vi_types.h           \
-               esx/esx_vmx.c esx/esx_vmx.h
+               esx/esx_vi_types.c esx/esx_vi_types.h
 
 ESX_DRIVER_GENERATED =                                                 \
                esx/esx_vi_methods.generated.c                          \
@@ -418,6 +417,9 @@ CPU_SOURCES =                                                       \
                cpu/cpu_x86.h cpu/cpu_x86.c cpu/cpu_x86_data.h  \
                cpu/cpu_map.h cpu/cpu_map.c
 
+VMX_SOURCES =                                                  \
+               vmx/vmx.c vmx/vmx.h
+
 pkgdata_DATA = cpu/cpu_map.xml
 
 EXTRA_DIST +=  $(pkgdata_DATA)
@@ -451,6 +453,14 @@ libvirt_cpu_la_CFLAGS = \
                -I@top_srcdir@/src/conf $(AM_CFLAGS)
 libvirt_cpu_la_SOURCES = $(CPU_SOURCES)
 
+if WITH_VMX
+noinst_LTLIBRARIES += libvirt_vmx.la
+libvirt_la_BUILT_LIBADD += libvirt_vmx.la
+libvirt_vmx_la_CFLAGS = \
+               -I@top_srcdir@/src/conf $(AM_CFLAGS)
+libvirt_vmx_la_SOURCES = $(VMX_SOURCES)
+endif
+
 
 noinst_LTLIBRARIES += libvirt_driver.la
 libvirt_la_BUILT_LIBADD += libvirt_driver.la
@@ -621,7 +631,7 @@ 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
+               -I@top_srcdir@/src/conf -I@top_srcdir@/src/vmx
 if WITH_DRIVER_MODULES
 libvirt_driver_vmware_la_LDFLAGS = -module -avoid-version
 endif
@@ -768,7 +778,7 @@ noinst_LTLIBRARIES += libvirt_driver_esx.la
 libvirt_la_BUILT_LIBADD += libvirt_driver_esx.la
 endif
 libvirt_driver_esx_la_CFLAGS = $(LIBCURL_CFLAGS) \
-               -I@top_srcdir@/src/conf $(AM_CFLAGS)
+               -I@top_srcdir@/src/conf -I@top_srcdir@/src/vmx $(AM_CFLAGS)
 libvirt_driver_esx_la_LDFLAGS = $(AM_LDFLAGS)
 libvirt_driver_esx_la_LIBADD = $(LIBCURL_LIBS)
 if WITH_DRIVER_MODULES
@@ -1043,6 +1053,10 @@ if WITH_NWFILTER
 USED_SYM_FILES += libvirt_nwfilter.syms
 endif
 
+if WITH_VMX
+USED_SYM_FILES += libvirt_vmx.syms
+endif
+
 EXTRA_DIST += \
   libvirt_public.syms          \
   libvirt_private.syms         \
index 03a7be30df88cd268aa6bacf99f864a1740a99a3..55847bcd6b7113987c2cd432e31e7325e346f87f 100644 (file)
@@ -31,6 +31,7 @@
 #include "memory.h"
 #include "logging.h"
 #include "uuid.h"
+#include "vmx.h"
 #include "esx_driver.h"
 #include "esx_interface_driver.h"
 #include "esx_network_driver.h"
@@ -42,7 +43,6 @@
 #include "esx_vi.h"
 #include "esx_vi_methods.h"
 #include "esx_util.h"
-#include "esx_vmx.h"
 
 #define VIR_FROM_THIS VIR_FROM_ESX
 
@@ -88,7 +88,7 @@ struct _esxVMX_Data {
  * Firstly this functions checks if the given file name contains a separator.
  * If it doesn't then the referenced file is in the same directory as the .vmx
  * file. The datastore name and directory of the .vmx file are passed to this
- * function via the opaque paramater by the caller of esxVMX_ParseConfig.
+ * function via the opaque parameter by the caller of virVMXParseConfig.
  *
  * Otherwise query for all known datastores and their mount directories. Then
  * try to find a datastore with a mount directory that is a prefix to the given
@@ -584,10 +584,6 @@ esxCapsInit(esxPrivate *priv)
         goto failure;
     }
 
-    /*
-     * FIXME: Maybe distinguish betwen ESX and GSX here, see
-     * esxVMX_ParseConfig() and VIR_DOMAIN_VIRT_VMWARE
-     */
     if (virCapabilitiesAddGuestDomain(guest, "vmware", NULL, NULL, 0,
                                       NULL) == NULL) {
         goto failure;
@@ -602,10 +598,6 @@ esxCapsInit(esxPrivate *priv)
             goto failure;
         }
 
-        /*
-         * FIXME: Maybe distinguish betwen ESX and GSX here, see
-         * esxVMX_ParseConfig() and VIR_DOMAIN_VIRT_VMWARE
-         */
         if (virCapabilitiesAddGuestDomain(guest, "vmware", NULL, NULL, 0,
                                           NULL) == NULL) {
             goto failure;
@@ -2570,7 +2562,7 @@ esxDomainDumpXML(virDomainPtr domain, int flags)
     virBuffer buffer = VIR_BUFFER_INITIALIZER;
     char *url = NULL;
     char *vmx = NULL;
-    esxVMX_Context ctx;
+    virVMXContext ctx;
     esxVMX_Data data;
     virDomainDefPtr def = NULL;
     char *xml = NULL;
@@ -2637,8 +2629,7 @@ esxDomainDumpXML(virDomainPtr domain, int flags)
     ctx.formatFileName = NULL;
     ctx.autodetectSCSIControllerModel = NULL;
 
-    def = esxVMX_ParseConfig(&ctx, priv->caps, vmx,
-                             priv->primary->productVersion);
+    def = virVMXParseConfig(&ctx, priv->caps, vmx);
 
     if (def != NULL) {
         if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
@@ -2674,7 +2665,7 @@ esxDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                        unsigned int flags ATTRIBUTE_UNUSED)
 {
     esxPrivate *priv = conn->privateData;
-    esxVMX_Context ctx;
+    virVMXContext ctx;
     esxVMX_Data data;
     virDomainDefPtr def = NULL;
     char *xml = NULL;
@@ -2693,8 +2684,7 @@ esxDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
     ctx.formatFileName = NULL;
     ctx.autodetectSCSIControllerModel = NULL;
 
-    def = esxVMX_ParseConfig(&ctx, priv->caps, nativeConfig,
-                             priv->primary->productVersion);
+    def = virVMXParseConfig(&ctx, priv->caps, nativeConfig);
 
     if (def != NULL) {
         xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
@@ -2713,7 +2703,8 @@ esxDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
                      unsigned int flags ATTRIBUTE_UNUSED)
 {
     esxPrivate *priv = conn->privateData;
-    esxVMX_Context ctx;
+    int virtualHW_version;
+    virVMXContext ctx;
     esxVMX_Data data;
     virDomainDefPtr def = NULL;
     char *vmx = NULL;
@@ -2724,6 +2715,13 @@ esxDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
         return NULL;
     }
 
+    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
+                          (priv->primary->productVersion);
+
+    if (virtualHW_version < 0) {
+        return NULL;
+    }
+
     def = virDomainDefParseString(priv->caps, domainXml, 0);
 
     if (def == NULL) {
@@ -2738,8 +2736,7 @@ esxDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
     ctx.formatFileName = esxFormatVMXFileName;
     ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
 
-    vmx = esxVMX_FormatConfig(&ctx, priv->caps, def,
-                              priv->primary->productVersion);
+    vmx = virVMXFormatConfig(&ctx, priv->caps, def, virtualHW_version);
 
     virDomainDefFree(def);
 
@@ -2922,7 +2919,8 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
     int i;
     virDomainDiskDefPtr disk = NULL;
     esxVI_ObjectContent *virtualMachine = NULL;
-    esxVMX_Context ctx;
+    int virtualHW_version;
+    virVMXContext ctx;
     esxVMX_Data data;
     char *datastoreName = NULL;
     char *directoryName = NULL;
@@ -2973,6 +2971,13 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
     }
 
     /* Build VMX from domain XML */
+    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
+                          (priv->primary->productVersion);
+
+    if (virtualHW_version < 0) {
+        goto cleanup;
+    }
+
     data.ctx = priv->primary;
     data.datastorePathWithoutFileName = NULL;
 
@@ -2981,8 +2986,7 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
     ctx.formatFileName = esxFormatVMXFileName;
     ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
 
-    vmx = esxVMX_FormatConfig(&ctx, priv->caps, def,
-                              priv->primary->productVersion);
+    vmx = virVMXFormatConfig(&ctx, priv->caps, def, virtualHW_version);
 
     if (vmx == NULL) {
         goto cleanup;
index 9ab0f700fc984d0341b92b0b40ba7f83d5374ccd..2603957dd7cf723236b2d1232c8d10483bbb6d65 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <config.h>
 
-#include <c-ctype.h>
 #include <netdb.h>
 
 #include "internal.h"
@@ -34,6 +33,7 @@
 #include "memory.h"
 #include "logging.h"
 #include "uuid.h"
+#include "vmx.h"
 #include "esx_private.h"
 #include "esx_util.h"
 
@@ -414,198 +414,6 @@ esxUtil_ResolveHostname(const char *hostname,
 
 
 
-int
-esxUtil_GetConfigString(virConfPtr conf, const char *name, char **string,
-                        bool optional)
-{
-    virConfValuePtr value;
-
-    *string = NULL;
-    value = virConfGetValue(conf, name);
-
-    if (value == NULL) {
-        if (optional) {
-            return 0;
-        }
-
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Missing essential config entry '%s'"), name);
-        return -1;
-    }
-
-    if (value->type != VIR_CONF_STRING) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Config entry '%s' must be a string"), name);
-        return -1;
-    }
-
-    if (value->str == NULL) {
-        if (optional) {
-            return 0;
-        }
-
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Missing essential config entry '%s'"), name);
-        return -1;
-    }
-
-    *string = strdup(value->str);
-
-    if (*string == NULL) {
-        virReportOOMError();
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
-int
-esxUtil_GetConfigUUID(virConfPtr conf, const char *name, unsigned char *uuid,
-                      bool optional)
-{
-    virConfValuePtr value;
-
-    value = virConfGetValue(conf, name);
-
-    if (value == NULL) {
-        if (optional) {
-            return 0;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Missing essential config entry '%s'"), name);
-            return -1;
-        }
-    }
-
-    if (value->type != VIR_CONF_STRING) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Config entry '%s' must be a string"), name);
-        return -1;
-    }
-
-    if (value->str == NULL) {
-        if (optional) {
-            return 0;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Missing essential config entry '%s'"), name);
-            return -1;
-        }
-    }
-
-    if (virUUIDParse(value->str, uuid) < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Could not parse UUID from string '%s'"), value->str);
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
-int
-esxUtil_GetConfigLong(virConfPtr conf, const char *name, long long *number,
-                      long long default_, bool optional)
-{
-    virConfValuePtr value;
-
-    *number = default_;
-    value = virConfGetValue(conf, name);
-
-    if (value == NULL) {
-        if (optional) {
-            return 0;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Missing essential config entry '%s'"), name);
-            return -1;
-        }
-    }
-
-    if (value->type == VIR_CONF_STRING) {
-        if (value->str == NULL) {
-            if (optional) {
-                return 0;
-            } else {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Missing essential config entry '%s'"), name);
-                return -1;
-            }
-        }
-
-        if (STREQ(value->str, "unlimited")) {
-            *number = -1;
-        } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Config entry '%s' must represent an integer value"),
-                      name);
-            return -1;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Config entry '%s' must be a string"), name);
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
-int
-esxUtil_GetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_,
-                         bool default_, bool optional)
-{
-    virConfValuePtr value;
-
-    *boolean_ = default_;
-    value = virConfGetValue(conf, name);
-
-    if (value == NULL) {
-        if (optional) {
-            return 0;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Missing essential config entry '%s'"), name);
-            return -1;
-        }
-    }
-
-    if (value->type == VIR_CONF_STRING) {
-        if (value->str == NULL) {
-            if (optional) {
-                return 0;
-            } else {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Missing essential config entry '%s'"), name);
-                return -1;
-            }
-        }
-
-        if (STRCASEEQ(value->str, "true")) {
-            *boolean_ = 1;
-        } else if (STRCASEEQ(value->str, "false")) {
-            *boolean_ = 0;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Config entry '%s' must represent a boolean value "
-                        "(true|false)"), name);
-            return -1;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Config entry '%s' must be a string"), name);
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
 int
 esxUtil_ReformatUuid(const char *input, char *output)
 {
@@ -625,81 +433,6 @@ esxUtil_ReformatUuid(const char *input, char *output)
 
 
 
-char *
-esxUtil_EscapeHex(const char *string, char escape, const char *special)
-{
-    char *escaped = NULL;
-    size_t length = 1; /* 1 byte for termination */
-    const char *tmp1 = string;
-    char *tmp2;
-
-    /* Calculate length of escaped string */
-    while (*tmp1 != '\0') {
-        if (*tmp1 == escape || strspn(tmp1, special) > 0) {
-            length += 2;
-        }
-
-        ++tmp1;
-        ++length;
-    }
-
-    if (VIR_ALLOC_N(escaped, length) < 0) {
-        virReportOOMError();
-        return NULL;
-    }
-
-    tmp1 = string; /* reading from this one */
-    tmp2 = escaped; /* writing to this one */
-
-    /* Escape to 'cXX' where c is the escape char and X is a hex digit */
-    while (*tmp1 != '\0') {
-        if (*tmp1 == escape || strspn(tmp1, special) > 0) {
-            *tmp2++ = escape;
-
-            snprintf(tmp2, 3, "%02x", (unsigned int)*tmp1);
-
-            tmp2 += 2;
-        } else {
-            *tmp2++ = *tmp1;
-        }
-
-        ++tmp1;
-    }
-
-    *tmp2 = '\0';
-
-    return escaped;
-}
-
-
-
-int
-esxUtil_UnescapeHex(char *string, char escape)
-{
-    char *tmp1 = string; /* reading from this one */
-    char *tmp2 = string; /* writing to this one */
-
-    /* Unescape from 'cXX' where c is the escape char and X is a hex digit */
-    while (*tmp1 != '\0') {
-        if (*tmp1 == escape) {
-            if (!c_isxdigit(tmp1[1]) || !c_isxdigit(tmp1[2])) {
-                return -1;
-            }
-
-            *tmp2++ = virHexToBin(tmp1[1]) * 16 + virHexToBin(tmp1[2]);
-            tmp1 += 3;
-        } else {
-            *tmp2++ = *tmp1++;
-        }
-    }
-
-    *tmp2 = '\0';
-
-    return 0;
-}
-
-
-
 char *
 esxUtil_EscapeBase64(const char *string)
 {
@@ -805,7 +538,7 @@ esxUtil_EscapeDatastoreItem(const char *string)
 
     esxUtil_ReplaceSpecialWindowsPathChars(replaced);
 
-    escaped1 = esxUtil_EscapeHexPercent(replaced);
+    escaped1 = virVMXEscapeHexPercent(replaced);
 
     if (escaped1 == NULL) {
         goto cleanup;
@@ -819,41 +552,3 @@ esxUtil_EscapeDatastoreItem(const char *string)
 
     return escaped2;
 }
-
-
-
-char *
-esxUtil_ConvertToUTF8(const char *encoding, const char *string)
-{
-    char *result = NULL;
-    xmlCharEncodingHandlerPtr handler;
-    xmlBufferPtr input;
-    xmlBufferPtr utf8;
-
-    handler = xmlFindCharEncodingHandler(encoding);
-
-    if (handler == NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("libxml2 doesn't handle %s encoding"), encoding);
-        return NULL;
-    }
-
-    input = xmlBufferCreateStatic((char *)string, strlen(string));
-    utf8 = xmlBufferCreate();
-
-    if (xmlCharEncInFunc(handler, utf8, input) < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Could not convert from %s to UTF-8 encoding"), encoding);
-        goto cleanup;
-    }
-
-    result = (char *)utf8->content;
-    utf8->content = NULL;
-
-  cleanup:
-    xmlCharEncCloseFunc(handler);
-    xmlBufferFree(input);
-    xmlBufferFree(utf8);
-
-    return result;
-}
index 694e935d6dcf900588e9d310cdec45609fd6d940..4cbf9b73b41cad9fd656aa40cf4dcbc08310fe84 100644 (file)
@@ -27,7 +27,6 @@
 # include <libxml/uri.h>
 
 # include "internal.h"
-# include "conf.h"
 
 typedef struct _esxUtil_ParsedUri esxUtil_ParsedUri;
 
@@ -57,38 +56,12 @@ int esxUtil_ParseDatastorePath(const char *datastorePath, char **datastoreName,
 int esxUtil_ResolveHostname(const char *hostname,
                             char *ipAddress, size_t ipAddress_length);
 
-int esxUtil_GetConfigString(virConfPtr conf, const char *name, char **string,
-                            bool optional);
-
-int esxUtil_GetConfigUUID(virConfPtr conf, const char *name,
-                          unsigned char *uuid, bool optional);
-
-int esxUtil_GetConfigLong(virConfPtr conf, const char *name, long long *number,
-                          long long default_, bool optional);
-
-int esxUtil_GetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_,
-                             bool default_, bool optional);
-
 int esxUtil_ReformatUuid(const char *input, char *output);
 
-char *esxUtil_EscapeHex(const char *string, char escape, const char *special);
-
-# define esxUtil_EscapeHexPipe(_string) esxUtil_EscapeHex(_string, '|', "\"")
-
-# define esxUtil_EscapeHexPercent(_string) esxUtil_EscapeHex(_string, '%', "/\\")
-
-int esxUtil_UnescapeHex(char *string, char escape);
-
-# define esxUtil_UnescapeHexPipe(_string) esxUtil_UnescapeHex(_string, '|')
-
-# define esxUtil_UnescapeHexPercent(_string) esxUtil_UnescapeHex(_string, '%')
-
 char *esxUtil_EscapeBase64(const char *string);
 
 void esxUtil_ReplaceSpecialWindowsPathChars(char *string);
 
 char *esxUtil_EscapeDatastoreItem(const char *string);
 
-char *esxUtil_ConvertToUTF8(const char *encoding, const char *string);
-
 #endif /* __ESX_UTIL_H__ */
index 482a11808393594ba9d41cdd260d094eed60da49..76be5a40cb8563c4adbe6dba79b32bf0fdaf5541 100644 (file)
@@ -31,6 +31,7 @@
 #include "logging.h"
 #include "util.h"
 #include "uuid.h"
+#include "vmx.h"
 #include "xml.h"
 #include "esx_vi.h"
 #include "esx_vi_methods.h"
@@ -2048,7 +2049,7 @@ esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent *virtualMachine,
                     goto failure;
                 }
 
-                if (esxUtil_UnescapeHexPercent(*name) < 0) {
+                if (virVMXUnescapeHexPercent(*name) < 0) {
                     ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                                  _("Domain name contains invalid escape sequence"));
                     goto failure;
@@ -3723,3 +3724,40 @@ esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
 
     return 0;
 }
+
+
+
+int
+esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion)
+{
+    /*
+     * virtualHW.version compatibility matrix:
+     *
+     *              4 7    API
+     *   ESX 3.5    +      2.5
+     *   ESX 4.0    + +    4.0
+     *   ESX 4.1    + +    4.1
+     *   GSX 2.0    + +    2.5
+     */
+    switch (productVersion) {
+      case esxVI_ProductVersion_ESX35:
+      case esxVI_ProductVersion_VPX25:
+        return 4;
+
+      case esxVI_ProductVersion_GSX20:
+      case esxVI_ProductVersion_ESX40:
+      case esxVI_ProductVersion_ESX41:
+      case esxVI_ProductVersion_VPX40:
+      case esxVI_ProductVersion_VPX41:
+        return 7;
+
+      case esxVI_ProductVersion_ESX4x:
+      case esxVI_ProductVersion_VPX4x:
+        return 7;
+
+      default:
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Unexpected product version"));
+        return -1;
+    }
+}
index 20e6fb50f6d6243412de7e9969640de243689611..d512add7f7b82c015684906dde185e1efe4bd561 100644 (file)
@@ -435,4 +435,6 @@ int esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
 int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
                              esxVI_HostCpuIdInfo *hostCpuIdInfo);
 
+int esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion);
+
 #endif /* __ESX_VI_H__ */
diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c
deleted file mode 100644 (file)
index 5cbb835..0000000
+++ /dev/null
@@ -1,3400 +0,0 @@
-
-/*
- * esx_vmx.c: VMX related functions for the VMware ESX driver
- *
- * Copyright (C) 2010 Red Hat, Inc.
- * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
- *
- */
-
-#include <config.h>
-
-#include <c-ctype.h>
-
-#include "internal.h"
-#include "virterror_internal.h"
-#include "memory.h"
-#include "logging.h"
-#include "esx_private.h"
-#include "esx_vmx.h"
-
-/*
-
-mapping:
-
-domain-xml                        <=>   vmx
-
-
-                                        config.version = "8"                    # essential
-                                        virtualHW.version = "4"                 # essential for ESX 3.5
-                                        virtualHW.version = "7"                 # essential for ESX 4.0
-
-
-???                               <=>   guestOS = "<value>"                     # essential, FIXME: not representable
-def->id = <value>                 <=>   ???                                     # not representable
-def->uuid = <value>               <=>   uuid.bios = "<value>"
-def->name = <value>               <=>   displayName = "<value>"
-def->mem.max_balloon = <value kilobyte>    <=>   memsize = "<value megabyte>"            # must be a multiple of 4, defaults to 32
-def->mem.cur_balloon = <value kilobyte>    <=>   sched.mem.max = "<value megabyte>"      # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
-def->mem.min_guarantee = <value kilobyte>  <=>   sched.mem.minsize = "<value megabyte>"  # defaults to 0
-def->maxvcpus = <value>           <=>   numvcpus = "<value>"                    # must be 1 or a multiple of 2, defaults to 1
-def->cpumask = <uint list>        <=>   sched.cpu.affinity = "<uint list>"
-
-
-
-################################################################################
-## os ##########################################################################
-
-def->os
-
-->type = "hvm"
-->arch = <arch>                   <=>   guestOS = "<value>"                     # if <value> ends with -64 than <arch> is x86_64, otherwise <arch> is i686
-->machine
-->nBootDevs
-->bootDevs
-->init
-->kernel
-->initrd
-->cmdline
-->root
-->loader
-->bootloader
-->bootloaderArgs
-->smbios_mode                     <=>   smbios.reflecthost = "<value>"          # <value> == true means SMBIOS_HOST, otherwise it's SMBIOS_EMULATE, defaults to "false"
-
-
-
-################################################################################
-## disks #######################################################################
-
-                                        scsi[0..3]:[0..6,8..15] -> <controller>:<unit> with 1 bus per controller
-                                        ide[0..1]:[0..1]        -> <bus>:<unit> with 1 controller
-                                        floppy[0..1]            -> <unit> with 1 controller and 1 bus per controller
-
-def->disks[0]...
-
-## disks: scsi hard drive from .vmdk image #####################################
-
-                                        scsi0.present = "true"                  # defaults to "false"
-                                        scsi0:0.present = "true"                # defaults to "false"
-                                        scsi0:0.startConnected = "true"         # defaults to "true"
-
-???                               <=>   scsi0:0.mode = "persistent"             # defaults to "persistent"
-                                        scsi0:0.mode = "undoable"
-                                        scsi0:0.mode = "independent-persistent"
-                                        scsi0:0.mode = "independent-nonpersistent"
-
-...
-->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
-->device = _DISK_DEVICE_DISK      <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
-->bus = _DISK_BUS_SCSI
-->src = <value>.vmdk              <=>   scsi0:0.fileName = "<value>.vmdk"
-->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
-->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
-->driverType
-->cachemode                       <=>   scsi0:0.writeThrough = "<value>"        # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
-->readonly
-->shared
-->slotnum
-
-
-## disks: ide hard drive from .vmdk image ######################################
-
-                                        ide0:0.present = "true"                 # defaults to "false"
-                                        ide0:0.startConnected = "true"          # defaults to "true"
-
-???                               <=>   ide0:0.mode = "persistent"              # defaults to "persistent"
-                                        ide0:0.mode = "undoable"
-                                        ide0:0.mode = "independent-persistent"
-                                        ide0:0.mode = "independent-nonpersistent"
-
-...
-->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
-->device = _DISK_DEVICE_DISK      <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
-->bus = _DISK_BUS_IDE
-->src = <value>.vmdk              <=>   ide0:0.fileName = "<value>.vmdk"
-->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
-->driverName
-->driverType
-->cachemode                       <=>   ide0:0.writeThrough = "<value>"         # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
-->readonly
-->shared
-->slotnum
-
-
-## disks: scsi cdrom from .iso image ###########################################
-
-                                        scsi0.present = "true"                  # defaults to "false"
-                                        scsi0:0.present = "true"                # defaults to "false"
-                                        scsi0:0.startConnected = "true"         # defaults to "true"
-
-...
-->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
-->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
-->bus = _DISK_BUS_SCSI
-->src = <value>.iso               <=>   scsi0:0.fileName = "<value>.iso"
-->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
-->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
-->driverType
-->cachemode
-->readonly
-->shared
-->slotnum
-
-
-## disks: ide cdrom from .iso image ############################################
-
-                                        ide0:0.present = "true"                 # defaults to "false"
-                                        ide0:0.startConnected = "true"          # defaults to "true"
-
-...
-->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
-->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
-->bus = _DISK_BUS_IDE
-->src = <value>.iso               <=>   ide0:0.fileName = "<value>.iso"
-->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
-->driverName
-->driverType
-->cachemode
-->readonly
-->shared
-->slotnum
-
-
-## disks: scsi cdrom from host device ##########################################
-
-                                        scsi0.present = "true"                  # defaults to "false"
-                                        scsi0:0.present = "true"                # defaults to "false"
-                                        scsi0:0.startConnected = "true"         # defaults to "true"
-
-...
-->type = _DISK_TYPE_BLOCK         <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
-->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
-->bus = _DISK_BUS_SCSI
-->src = <value>                   <=>   scsi0:0.fileName = "<value>"            # e.g. "/dev/scd0" ?
-->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
-->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
-->driverType
-->cachemode
-->readonly
-->shared
-->slotnum
-
-
-## disks: ide cdrom from host device ###########################################
-
-                                        ide0:0.present = "true"                 # defaults to "false"
-                                        ide0:0.startConnected = "true"          # defaults to "true"
-                                        ide0:0.clientDevice = "false"           # defaults to "false"
-
-...
-->type = _DISK_TYPE_BLOCK         <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
-->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
-->bus = _DISK_BUS_IDE
-->src = <value>                   <=>   ide0:0.fileName = "<value>"             # e.g. "/dev/scd0"
-->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
-->driverName
-->driverType
-->cachemode
-->readonly
-->shared
-->slotnum
-
-
-## disks: floppy from .flp image ###############################################
-
-                                        floppy0.present = "true"                # defaults to "true"
-                                        floppy0.startConnected = "true"         # defaults to "true"
-                                        floppy0.clientDevice = "false"          # defaults to "false"
-
-...
-->type = _DISK_TYPE_FILE          <=>   floppy0.fileType = "file"               # defaults to ?
-->device = _DISK_DEVICE_FLOPPY
-->bus = _DISK_BUS_FDC
-->src = <value>.flp               <=>   floppy0.fileName = "<value>.flp"
-->dst = fd[<unit> mapped to [a-z]+]
-->driverName
-->driverType
-->cachemode
-->readonly
-->shared
-->slotnum
-
-
-## disks: floppy from host device ##############################################
-
-                                        floppy0.present = "true"                # defaults to "true"
-                                        floppy0.startConnected = "true"         # defaults to "true"
-                                        floppy0.clientDevice = "false"          # defaults to "false"
-
-...
-->type = _DISK_TYPE_BLOCK         <=>   floppy0.fileType = "device"             # defaults to ?
-->device = _DISK_DEVICE_FLOPPY
-->bus = _DISK_BUS_FDC
-->src = <value>                   <=>   floppy0.fileName = "<value>"            # e.g. "/dev/fd0"
-->dst = fd[<unit> mapped to [a-z]+]
-->driverName
-->driverType
-->cachemode
-->readonly
-->shared
-->slotnum
-
-
-
-################################################################################
-## nets ########################################################################
-
-                                        ethernet[0..3] -> <controller>
-
-                                        ethernet0.present = "true"              # defaults to "false"
-                                        ethernet0.startConnected = "true"       # defaults to "true"
-
-                                        ethernet0.networkName = "VM Network"    # FIXME
-
-def->nets[0]...
-->model = <model>                 <=>   ethernet0.virtualDev = "<model>"        # default depends on guestOS value
-                                        ethernet0.features = "15"               # if present and virtualDev is "vmxnet" => vmxnet2 (enhanced)
-
-
-                                        ethernet0.addressType = "generated"     # default to "generated"
-->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
-                                        ethernet0.generatedAddressOffset = "0"  # ?
-
-
-                                        ethernet0.addressType = "static"        # default to "generated"
-->mac = <value>                   <=>   ethernet0.address = "<value>"
-
-
-                                        ethernet0.addressType = "vpx"           # default to "generated"
-->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
-
-
-                                        ethernet0.addressType = "static"        # default to "generated"
-->mac = <value>                   <=>   ethernet0.address = "<value>"
-                                        ethernet0.checkMACAddress = "false"     # mac address outside the VMware prefixes
-
-                                                                                # 00:0c:29 prefix for autogenerated mac's -> ethernet0.addressType = "generated"
-                                                                                # 00:50:56 prefix for manual configured mac's
-                                                                                #          00:50:56:00:00:00 - 00:50:56:3f:ff:ff -> ethernet0.addressType = "static"
-                                                                                #          00:50:56:80:00:00 - 00:50:56:bf:ff:ff -> ethernet0.addressType = "vpx"
-                                                                                # 00:05:69 old prefix from esx 1.5
-
-
-## nets: bridged ###############################################################
-
-...
-->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "bridged"    # defaults to "bridged"
-->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
-
-
-## nets: hostonly ##############################################################
-
-...                                                                             # FIXME: Investigate if ESX supports this
-->type = _NET_TYPE_NETWORK        <=>   ethernet0.connectionType = "hostonly"   # defaults to "bridged"
-
-
-## nets: nat ###################################################################
-
-...                                                                             # FIXME: Investigate if ESX supports this
-->type = _NET_TYPE_USER           <=>   ethernet0.connectionType = "nat"        # defaults to "bridged"
-
-
-## nets: custom ################################################################
-
-...
-->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "custom"     # defaults to "bridged"
-->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
-->ifname = <value>                <=>   ethernet0.vnet = "<value>"
-
-
-
-################################################################################
-## serials #####################################################################
-
-                                        serial[0..3] -> <port>
-
-                                        serial0.present = "true"                # defaults to "false"
-                                        serial0.startConnected = "true"         # defaults to "true"
-
-def->serials[0]...
-->target.port = <port>
-
-
-## serials: device #############################################################
-
-->type = _CHR_TYPE_DEV            <=>   serial0.fileType = "device"
-->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "/dev/ttyS0"
-???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-
-## serials: file ###############################################################
-
-->type = _CHR_TYPE_FILE           <=>   serial0.fileType = "file"
-->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.file"
-???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-
-## serials: pipe, far end -> app ###############################################
-
-->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
-->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
-???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
-???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
-->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
-???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
-???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-
-## serials: pipe, far end -> vm ################################################
-
-->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
-->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
-???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
-???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
-->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
-???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
-???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-
-## serials: network, server (since vSphere 4.1) ################################
-
-->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"
-
-->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
-->data.tcp.service = <service>                                                  # e.g. "telnet://0.0.0.0:42001"
-->data.tcp.protocol = <protocol>
-
-->data.tcp.listen = 1             <=>   serial0.network.endPoint = "server"     # defaults to "server"
-
-???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
-???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-
-## serials: network, client (since vSphere 4.1) ################################
-
-->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"
-
-->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
-->data.tcp.service = <service>                                                  # e.g. "telnet://192.168.0.17:42001"
-->data.tcp.protocol = <protocol>
-
-->data.tcp.listen = 0             <=>   serial0.network.endPoint = "client"     # defaults to "server"
-
-???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
-???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
-???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
-
-
-
-################################################################################
-## parallels ###################################################################
-
-                                        parallel[0..2] -> <port>
-
-                                        parallel0.present = "true"              # defaults to "false"
-                                        parallel0.startConnected = "true"       # defaults to "true"
-
-def->parallels[0]...
-->target.port = <port>
-
-
-## parallels: device #############################################################
-
-->type = _CHR_TYPE_DEV            <=>   parallel0.fileType = "device"
-->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "/dev/parport0"
-???                               <=>   parallel0.bidirectional = "<value>"     # defaults to ?, FIXME: not representable
-
-
-## parallels: file #############################################################
-
-->type = _CHR_TYPE_FILE           <=>   parallel0.fileType = "file"
-->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "parallel0.file"
-???                               <=>   parallel0.bidirectional = "<value>"     # must be "false" for fileType = "file", FIXME: not representable
-
-
-
-################################################################################
-## sound #######################################################################
-
-                                        sound.present = "true"                  # defaults to "false"
-                                        sound.startConnected = "true"           # defaults to "true"
-                                        sound.autodetect = "true"
-                                        sound.fileName = "-1"
-
-                                        FIXME: Investigate if ESX supports this,
-                                               at least the VI Client GUI has no
-                                               options to add a sound device, but
-                                               the VI API contains a VirtualSoundCard
-
-*/
-
-#define VIR_FROM_THIS VIR_FROM_ESX
-
-#define ESX_BUILD_VMX_NAME_EXTRA(_suffix, _extra)                             \
-    snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."_extra, prefix);
-
-#define ESX_BUILD_VMX_NAME(_suffix)                                           \
-    ESX_BUILD_VMX_NAME_EXTRA(_suffix, #_suffix)
-
-/* directly map the virDomainControllerModel to esxVMX_SCSIControllerModel,
- * this is good enough for now because all virDomainControllerModel values
- * are actually SCSI controller models in the ESX case */
-VIR_ENUM_DECL(esxVMX_SCSIControllerModel)
-VIR_ENUM_IMPL(esxVMX_SCSIControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST,
-              "auto", /* just to match virDomainControllerModel, will never be used */
-              "buslogic",
-              "lsilogic",
-              "lsisas1068",
-              "pvscsi");
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Helpers
- */
-
-int
-esxVMX_SCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
-{
-    int idx;
-
-    if (! STRPREFIX(name, "sd")) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("Expecting domain XML attribute 'dev' of entry "
-                    "'devices/disk/target' to start with 'sd'"));
-        return -1;
-    }
-
-    idx = virDiskNameToIndex(name);
-
-    if (idx < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Could not parse valid disk index from '%s'"), name);
-        return -1;
-    }
-
-    /* Each of the 4 SCSI controllers has 1 bus with 15 units each for devices */
-    if (idx >= (4 * 15)) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("SCSI disk index (parsed from '%s') is too large"), name);
-        return -1;
-    }
-
-    *controller = idx / 15;
-    *unit = idx % 15;
-
-    /* Skip the controller ifself at unit 7 */
-    if (*unit >= 7) {
-        ++(*unit);
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_IDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
-{
-    int idx;
-
-    if (! STRPREFIX(name, "hd")) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("Expecting domain XML attribute 'dev' of entry "
-                    "'devices/disk/target' to start with 'hd'"));
-        return -1;
-    }
-
-    idx = virDiskNameToIndex(name);
-
-    if (idx < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Could not parse valid disk index from '%s'"), name);
-        return -1;
-    }
-
-    /* The IDE controller has 2 buses with 2 units each for devices */
-    if (idx >= (2 * 2)) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("IDE disk index (parsed from '%s') is too large"), name);
-        return -1;
-    }
-
-    *bus = idx / 2;
-    *unit = idx % 2;
-
-    return 0;
-}
-
-
-
-int
-esxVMX_FloppyDiskNameToUnit(const char *name, int *unit)
-{
-    int idx;
-
-    if (! STRPREFIX(name, "fd")) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("Expecting domain XML attribute 'dev' of entry "
-                    "'devices/disk/target' to start with 'fd'"));
-        return -1;
-    }
-
-    idx = virDiskNameToIndex(name);
-
-    if (idx < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Could not parse valid disk index from '%s'"), name);
-        return -1;
-    }
-
-    /* The FDC controller has 1 bus with 2 units for devices */
-    if (idx >= 2) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Floppy disk index (parsed from '%s') is too large"), name);
-        return -1;
-    }
-
-    *unit = idx;
-
-    return 0;
-}
-
-
-
-int
-esxVMX_VerifyDiskAddress(virCapsPtr caps, virDomainDiskDefPtr disk)
-{
-    virDomainDiskDef def;
-    virDomainDeviceDriveAddressPtr drive;
-
-    memset(&def, 0, sizeof(def));
-
-    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unsupported disk address type '%s'"),
-                  virDomainDeviceAddressTypeToString(disk->info.type));
-        return -1;
-    }
-
-    drive = &disk->info.addr.drive;
-
-    def.dst = disk->dst;
-    def.bus = disk->bus;
-
-    if (virDomainDiskDefAssignAddress(caps, &def) < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("Could not verify disk address"));
-        return -1;
-    }
-
-    if (def.info.addr.drive.controller != drive->controller ||
-        def.info.addr.drive.bus != drive->bus ||
-        def.info.addr.drive.unit != drive->unit) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Disk address %d:%d:%d doesn't match target device '%s'"),
-                  drive->controller, drive->bus, drive->unit, disk->dst);
-        return -1;
-    }
-
-    /* drive->{controller|bus|unit} is unsigned, no >= 0 checks are necessary */
-    if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
-        if (drive->controller > 3) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("SCSI controller index %d out of [0..3] range"),
-                      drive->controller);
-            return -1;
-        }
-
-        if (drive->bus != 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("SCSI bus index %d out of [0] range"),
-                      drive->bus);
-            return -1;
-        }
-
-        if (drive->unit > 15 || drive->unit == 7) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("SCSI unit index %d out of [0..6,8..15] range"),
-                      drive->unit);
-            return -1;
-        }
-    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
-        if (drive->controller != 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("IDE controller index %d out of [0] range"),
-                      drive->controller);
-            return -1;
-        }
-
-        if (drive->bus > 1) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("IDE bus index %d out of [0..1] range"),
-                      drive->bus);
-            return -1;
-        }
-
-        if (drive->unit > 1) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("IDE unit index %d out of [0..1] range"),
-                      drive->unit);
-            return -1;
-        }
-    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
-        if (drive->controller != 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("FDC controller index %d out of [0] range"),
-                      drive->controller);
-            return -1;
-        }
-
-        if (drive->bus != 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("FDC bus index %d out of [0] range"),
-                      drive->bus);
-            return -1;
-        }
-
-        if (drive->unit > 1) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("FDC unit index %d out of [0..1] range"),
-                      drive->unit);
-            return -1;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unsupported bus type '%s'"),
-                  virDomainDiskBusTypeToString(disk->bus));
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_HandleLegacySCSIDiskDriverName(virDomainDefPtr def,
-                                      virDomainDiskDefPtr disk)
-{
-    char *tmp;
-    int model, i;
-    virDomainControllerDefPtr controller = NULL;
-
-    if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI || disk->driverName == NULL) {
-        return 0;
-    }
-
-    tmp = disk->driverName;
-
-    for (; *tmp != '\0'; ++tmp) {
-        *tmp = c_tolower(*tmp);
-    }
-
-    model = virDomainControllerModelTypeFromString(disk->driverName);
-
-    if (model < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unknown driver name '%s'"), disk->driverName);
-        return -1;
-    }
-
-    for (i = 0; i < def->ncontrollers; ++i) {
-        if (def->controllers[i]->idx == disk->info.addr.drive.controller) {
-            controller = def->controllers[i];
-            break;
-        }
-    }
-
-    if (controller == NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Missing SCSI controller for index %d"),
-                  disk->info.addr.drive.controller);
-        return -1;
-    }
-
-    if (controller->model == -1) {
-        controller->model = model;
-    } else if (controller->model != model) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Inconsistent SCSI controller model ('%s' is not '%s') "
-                    "for SCSI controller index %d"), disk->driverName,
-                  virDomainControllerModelTypeToString(controller->model),
-                  controller->idx);
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_GatherSCSIControllers(esxVMX_Context *ctx, virDomainDefPtr def,
-                             int virtualDev[4], bool present[4])
-{
-    int result = -1;
-    int i, k;
-    virDomainDiskDefPtr disk;
-    virDomainControllerDefPtr controller;
-    bool controllerHasDisksAttached;
-    int count = 0;
-    int *autodetectedModels;
-
-    if (VIR_ALLOC_N(autodetectedModels, def->ndisks) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    for (i = 0; i < def->ncontrollers; ++i) {
-        controller = def->controllers[i];
-
-        if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
-            // skip non-SCSI controllers
-            continue;
-        }
-
-        controllerHasDisksAttached = false;
-
-        for (k = 0; k < def->ndisks; ++k) {
-            disk = def->disks[k];
-
-            if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
-                disk->info.addr.drive.controller == controller->idx) {
-                controllerHasDisksAttached = true;
-                break;
-            }
-        }
-
-        if (! controllerHasDisksAttached) {
-            // skip SCSI controllers without attached disks
-            continue;
-        }
-
-        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_AUTO &&
-            ctx->autodetectSCSIControllerModel != NULL) {
-            count = 0;
-
-            // try to autodetect the SCSI controller model by collecting
-            // SCSI controller model of all disks attached to this controller
-            for (k = 0; k < def->ndisks; ++k) {
-                disk = def->disks[k];
-
-                if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
-                    disk->info.addr.drive.controller == controller->idx) {
-                    if (ctx->autodetectSCSIControllerModel
-                               (disk, &autodetectedModels[count],
-                                ctx->opaque) < 0) {
-                        goto cleanup;
-                    }
-
-                    ++count;
-                }
-            }
-
-            // autodetection fails when the disks attached to one controller
-            // have inconsistent SCSI controller models
-            for (k = 0; k < count; ++k) {
-                if (autodetectedModels[k] != autodetectedModels[0]) {
-                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                              _("Disks on SCSI controller %d have inconsistent "
-                                "controller models, cannot autodetect model"),
-                              controller->idx);
-                    goto cleanup;
-                }
-            }
-
-            controller->model = autodetectedModels[0];
-        }
-
-        if (controller->model != -1 &&
-            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC &&
-            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC &&
-            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 &&
-            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting domain XML attribute 'model' of entry "
-                        "'controller' to be 'buslogic' or 'lsilogic' or "
-                        "'lsisas1068' or 'vmpvscsi' but found '%s'"),
-                      virDomainControllerModelTypeToString(controller->model));
-            goto cleanup;
-        }
-
-        present[controller->idx] = true;
-        virtualDev[controller->idx] = controller->model;
-    }
-
-    result = 0;
-
-  cleanup:
-    VIR_FREE(autodetectedModels);
-
-    return result;
-}
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * VMX -> Domain XML
- */
-
-virDomainDefPtr
-esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx,
-                   esxVI_ProductVersion productVersion)
-{
-    bool success = false;
-    virConfPtr conf = NULL;
-    char *encoding = NULL;
-    char *utf8;
-    virDomainDefPtr def = NULL;
-    long long config_version = 0;
-    long long virtualHW_version = 0;
-    long long memsize = 0;
-    long long sched_mem_max = 0;
-    long long sched_mem_minsize = 0;
-    long long numvcpus = 0;
-    char *sched_cpu_affinity = NULL;
-    char *guestOS = NULL;
-    bool smbios_reflecthost = false;
-    int controller;
-    int bus;
-    int port;
-    bool present;
-    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
-    int unit;
-
-    if (ctx->parseFileName == NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("esxVMX_Context has no parseFileName function set"));
-        return NULL;
-    }
-
-    conf = virConfReadMem(vmx, strlen(vmx), VIR_CONF_FLAG_VMX_FORMAT);
-
-    if (conf == NULL) {
-        return NULL;
-    }
-
-    /* vmx:.encoding */
-    if (esxUtil_GetConfigString(conf, ".encoding", &encoding, true) < 0) {
-        goto cleanup;
-    }
-
-    if (encoding == NULL || STRCASEEQ(encoding, "UTF-8")) {
-        /* nothing */
-    } else {
-        virConfFree(conf);
-        conf = NULL;
-
-        utf8 = esxUtil_ConvertToUTF8(encoding, vmx);
-
-        if (utf8 == NULL) {
-            goto cleanup;
-        }
-
-        conf = virConfReadMem(utf8, strlen(utf8), VIR_CONF_FLAG_VMX_FORMAT);
-
-        VIR_FREE(utf8);
-
-        if (conf == NULL) {
-            goto cleanup;
-        }
-    }
-
-    /* Allocate domain def */
-    if (VIR_ALLOC(def) < 0) {
-        virReportOOMError();
-        return NULL;
-    }
-
-    def->virtType = VIR_DOMAIN_VIRT_VMWARE; /* FIXME: maybe add VIR_DOMAIN_VIRT_ESX ? */
-    def->id = -1;
-
-    /* vmx:config.version */
-    if (esxUtil_GetConfigLong(conf, "config.version", &config_version, 0,
-                              false) < 0) {
-        goto cleanup;
-    }
-
-    if (config_version != 8) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting VMX entry 'config.version' to be 8 but found "
-                    "%lld"), config_version);
-        goto cleanup;
-    }
-
-    /* vmx:virtualHW.version */
-    if (esxUtil_GetConfigLong(conf, "virtualHW.version", &virtualHW_version, 0,
-                              false) < 0) {
-        goto cleanup;
-    }
-
-    /*
-     * virtualHW.version compatibility matrix:
-     *
-     *              4 7    API
-     *   ESX 3.5    +      2.5
-     *   ESX 4.0    + +    4.0
-     *   ESX 4.1    + +    4.1
-     *   GSX 2.0    + +    2.5
-     */
-    switch (productVersion) {
-      case esxVI_ProductVersion_ESX35:
-      case esxVI_ProductVersion_VPX25:
-        if (virtualHW_version != 4) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting VMX entry 'virtualHW.version' to be 4 "
-                        "but found %lld"),
-                      virtualHW_version);
-            goto cleanup;
-        }
-
-        break;
-
-      case esxVI_ProductVersion_GSX20:
-      case esxVI_ProductVersion_ESX40:
-      case esxVI_ProductVersion_ESX41:
-      case esxVI_ProductVersion_VPX40:
-      case esxVI_ProductVersion_VPX41:
-        if (virtualHW_version != 4 && virtualHW_version != 7) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting VMX entry 'virtualHW.version' to be 4 or 7 "
-                        "but found %lld"),
-                      virtualHW_version);
-            goto cleanup;
-        }
-
-        break;
-
-      case esxVI_ProductVersion_ESX4x:
-      case esxVI_ProductVersion_VPX4x:
-        break;
-
-      default:
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("Unexpected product version"));
-        goto cleanup;
-    }
-
-    /* vmx:uuid.bios -> def:uuid */
-    /* FIXME: Need to handle 'uuid.action = "create"' */
-    if (esxUtil_GetConfigUUID(conf, "uuid.bios", def->uuid, true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:displayName -> def:name */
-    if (esxUtil_GetConfigString(conf, "displayName", &def->name, true) < 0) {
-        goto cleanup;
-    }
-
-    if (def->name != NULL) {
-        if (esxUtil_UnescapeHexPercent(def->name) < 0 ||
-            esxUtil_UnescapeHexPipe(def->name) < 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                      _("VMX entry 'name' contains invalid escape sequence"));
-            goto cleanup;
-        }
-    }
-
-    /* vmx:annotation -> def:description */
-    if (esxUtil_GetConfigString(conf, "annotation", &def->description,
-                                true) < 0) {
-        goto cleanup;
-    }
-
-    if (def->description != NULL) {
-        if (esxUtil_UnescapeHexPipe(def->description) < 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                      _("VMX entry 'annotation' contains invalid escape "
-                        "sequence"));
-            goto cleanup;
-        }
-    }
-
-    /* vmx:memsize -> def:mem.max_balloon */
-    if (esxUtil_GetConfigLong(conf, "memsize", &memsize, 32, true) < 0) {
-        goto cleanup;
-    }
-
-    if (memsize <= 0 || memsize % 4 != 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting VMX entry 'memsize' to be an unsigned "
-                    "integer (multiple of 4) but found %lld"), memsize);
-        goto cleanup;
-    }
-
-    def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */
-
-    /* vmx:sched.mem.max -> def:mem.cur_balloon */
-    if (esxUtil_GetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize,
-                              true) < 0) {
-        goto cleanup;
-    }
-
-    if (sched_mem_max < 0) {
-        sched_mem_max = memsize;
-    }
-
-    def->mem.cur_balloon = sched_mem_max * 1024; /* Scale from megabytes to kilobytes */
-
-    if (def->mem.cur_balloon > def->mem.max_balloon) {
-        def->mem.cur_balloon = def->mem.max_balloon;
-    }
-
-    /* vmx:sched.mem.minsize -> def:mem.min_guarantee */
-    if (esxUtil_GetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0,
-                              true) < 0) {
-        goto cleanup;
-    }
-
-    if (sched_mem_minsize < 0) {
-        sched_mem_minsize = 0;
-    }
-
-    def->mem.min_guarantee = sched_mem_minsize * 1024; /* Scale from megabytes to kilobytes */
-
-    if (def->mem.min_guarantee > def->mem.max_balloon) {
-        def->mem.min_guarantee = def->mem.max_balloon;
-    }
-
-    /* vmx:numvcpus -> def:vcpus */
-    if (esxUtil_GetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0) {
-        goto cleanup;
-    }
-
-    if (numvcpus <= 0 || (numvcpus % 2 != 0 && numvcpus != 1)) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting VMX entry 'numvcpus' to be an unsigned "
-                    "integer (1 or a multiple of 2) but found %lld"), numvcpus);
-        goto cleanup;
-    }
-
-    def->maxvcpus = def->vcpus = numvcpus;
-
-    /* vmx:sched.cpu.affinity -> def:cpumask */
-    // VirtualMachine:config.cpuAffinity.affinitySet
-    if (esxUtil_GetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
-                                true) < 0) {
-        goto cleanup;
-    }
-
-    if (sched_cpu_affinity != NULL && STRNEQ(sched_cpu_affinity, "all")) {
-        const char *current = sched_cpu_affinity;
-        int number, count = 0;
-
-        def->cpumasklen = 0;
-
-        if (VIR_ALLOC_N(def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        while (*current != '\0') {
-            virSkipSpaces(&current);
-
-            number = virParseNumber(&current);
-
-            if (number < 0) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Expecting VMX entry 'sched.cpu.affinity' to be "
-                            "a comma separated list of unsigned integers but "
-                            "found '%s'"), sched_cpu_affinity);
-                goto cleanup;
-            }
-
-            if (number >= VIR_DOMAIN_CPUMASK_LEN) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("VMX entry 'sched.cpu.affinity' contains a %d, "
-                            "this value is too large"), number);
-                goto cleanup;
-            }
-
-            if (number + 1 > def->cpumasklen) {
-                def->cpumasklen = number + 1;
-            }
-
-            def->cpumask[number] = 1;
-            ++count;
-
-            virSkipSpaces(&current);
-
-            if (*current == ',') {
-                ++current;
-            } else if (*current == '\0') {
-                break;
-            } else {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Expecting VMX entry 'sched.cpu.affinity' to be "
-                            "a comma separated list of unsigned integers but "
-                            "found '%s'"), sched_cpu_affinity);
-                goto cleanup;
-            }
-
-            virSkipSpaces(&current);
-        }
-
-        if (count < numvcpus) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting VMX entry 'sched.cpu.affinity' to contain "
-                        "at least as many values as 'numvcpus' (%lld) but "
-                        "found only %d value(s)"), numvcpus, count);
-            goto cleanup;
-        }
-    }
-
-    /* def:lifecycle */
-    def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
-    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
-    def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
-
-    /* def:os */
-    def->os.type = strdup("hvm");
-
-    if (def->os.type == NULL) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    /* vmx:guestOS -> def:os.arch */
-    if (esxUtil_GetConfigString(conf, "guestOS", &guestOS, true) < 0) {
-        goto cleanup;
-    }
-
-    if (guestOS != NULL && virFileHasSuffix(guestOS, "-64")) {
-        def->os.arch = strdup("x86_64");
-    } else {
-        def->os.arch = strdup("i686");
-    }
-
-    if (def->os.arch == NULL) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    /* vmx:smbios.reflecthost -> def:os.smbios_mode */
-    if (esxUtil_GetConfigBoolean(conf, "smbios.reflecthost",
-                                 &smbios_reflecthost, false, true) < 0) {
-        goto cleanup;
-    }
-
-    if (smbios_reflecthost) {
-        def->os.smbios_mode = VIR_DOMAIN_SMBIOS_HOST;
-    }
-
-    /* def:features */
-    /* FIXME */
-
-    /* def:clock */
-    /* FIXME */
-
-    /* def:graphics */
-    if (VIR_ALLOC_N(def->graphics, 1) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->ngraphics = 0;
-
-    if (esxVMX_ParseVNC(conf, &def->graphics[def->ngraphics]) < 0) {
-        goto cleanup;
-    }
-
-    if (def->graphics[def->ngraphics] != NULL) {
-        ++def->ngraphics;
-    }
-
-    /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */
-    if (VIR_ALLOC_N(def->disks, 66) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->ndisks = 0;
-
-    /* def:disks (scsi) */
-    for (controller = 0; controller < 4; ++controller) {
-        if (esxVMX_ParseSCSIController(conf, controller, &present,
-                                       &scsi_virtualDev[controller]) < 0) {
-            goto cleanup;
-        }
-
-        if (! present) {
-            continue;
-        }
-
-        for (unit = 0; unit < 16; ++unit) {
-            if (unit == 7) {
-                /*
-                 * SCSI unit 7 is assigned to the SCSI controller and cannot be
-                 * used for disk devices.
-                 */
-                continue;
-            }
-
-            if (esxVMX_ParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
-                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
-                                 &def->disks[def->ndisks]) < 0) {
-                goto cleanup;
-            }
-
-            if (def->disks[def->ndisks] != NULL) {
-                ++def->ndisks;
-                continue;
-            }
-
-            if (esxVMX_ParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
-                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
-                                 &def->disks[def->ndisks]) < 0) {
-                goto cleanup;
-            }
-
-            if (def->disks[def->ndisks] != NULL) {
-                ++def->ndisks;
-            }
-        }
-    }
-
-    /* def:disks (ide) */
-    for (bus = 0; bus < 2; ++bus) {
-        for (unit = 0; unit < 2; ++unit) {
-            if (esxVMX_ParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
-                                 VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
-                                 &def->disks[def->ndisks]) < 0) {
-                goto cleanup;
-            }
-
-            if (def->disks[def->ndisks] != NULL) {
-                ++def->ndisks;
-                continue;
-            }
-
-            if (esxVMX_ParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
-                                 VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
-                                 &def->disks[def->ndisks]) < 0) {
-                goto cleanup;
-            }
-
-            if (def->disks[def->ndisks] != NULL) {
-                ++def->ndisks;
-            }
-        }
-    }
-
-    /* def:disks (floppy) */
-    for (unit = 0; unit < 2; ++unit) {
-        if (esxVMX_ParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
-                             VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
-                             &def->disks[def->ndisks]) < 0) {
-            goto cleanup;
-        }
-
-        if (def->disks[def->ndisks] != NULL) {
-            ++def->ndisks;
-        }
-    }
-
-    /* def:controllers */
-    if (virDomainDefAddImplicitControllers(def) < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add controllers"));
-        goto cleanup;
-    }
-
-    for (controller = 0; controller < def->ncontrollers; ++controller) {
-        if (def->controllers[controller]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
-            if (def->controllers[controller]->idx < 0 ||
-                def->controllers[controller]->idx > 3) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("SCSI controller index %d out of [0..3] range"),
-                          def->controllers[controller]->idx);
-                goto cleanup;
-            }
-
-            def->controllers[controller]->model =
-              scsi_virtualDev[def->controllers[controller]->idx];
-        }
-    }
-
-    /* def:fss */
-    /* FIXME */
-
-    /* def:nets */
-    if (VIR_ALLOC_N(def->nets, 4) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->nnets = 0;
-
-    for (controller = 0; controller < 4; ++controller) {
-        if (esxVMX_ParseEthernet(conf, controller,
-                                 &def->nets[def->nnets]) < 0) {
-            goto cleanup;
-        }
-
-        if (def->nets[def->nnets] != NULL) {
-            ++def->nnets;
-        }
-    }
-
-    /* def:inputs */
-    /* FIXME */
-
-    /* def:sounds */
-    /* FIXME */
-
-    /* def:hostdevs */
-    /* FIXME */
-
-    /* def:serials */
-    if (VIR_ALLOC_N(def->serials, 4) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->nserials = 0;
-
-    for (port = 0; port < 4; ++port) {
-        if (esxVMX_ParseSerial(ctx, conf, port,
-                               &def->serials[def->nserials]) < 0) {
-            goto cleanup;
-        }
-
-        if (def->serials[def->nserials] != NULL) {
-            ++def->nserials;
-        }
-    }
-
-    /* def:parallels */
-    if (VIR_ALLOC_N(def->parallels, 3) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->nparallels = 0;
-
-    for (port = 0; port < 3; ++port) {
-        if (esxVMX_ParseParallel(ctx, conf, port,
-                                 &def->parallels[def->nparallels]) < 0) {
-            goto cleanup;
-        }
-
-        if (def->parallels[def->nparallels] != NULL) {
-            ++def->nparallels;
-        }
-    }
-
-    success = true;
-
-  cleanup:
-    if (! success) {
-        virDomainDefFree(def);
-        def = NULL;
-    }
-
-    virConfFree(conf);
-    VIR_FREE(encoding);
-    VIR_FREE(sched_cpu_affinity);
-    VIR_FREE(guestOS);
-
-    return def;
-}
-
-
-
-int
-esxVMX_ParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def)
-{
-    bool enabled = false;
-    long long port = 0;
-
-    if (def == NULL || *def != NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (esxUtil_GetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
-                                 false, true) < 0) {
-        return -1;
-    }
-
-    if (! enabled) {
-        return 0;
-    }
-
-    if (VIR_ALLOC(*def) < 0) {
-        virReportOOMError();
-        goto failure;
-    }
-
-    (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
-
-    if (esxUtil_GetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
-                              true) < 0 ||
-        esxUtil_GetConfigString(conf, "RemoteDisplay.vnc.ip",
-                                &(*def)->data.vnc.listenAddr, true) < 0 ||
-        esxUtil_GetConfigString(conf, "RemoteDisplay.vnc.keymap",
-                                &(*def)->data.vnc.keymap, true) < 0 ||
-        esxUtil_GetConfigString(conf, "RemoteDisplay.vnc.password",
-                                &(*def)->data.vnc.auth.passwd, true) < 0) {
-        goto failure;
-    }
-
-    if (port < 0) {
-        VIR_WARN0("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
-                  "is missing, the VNC port is unknown");
-
-        (*def)->data.vnc.port = 0;
-        (*def)->data.vnc.autoport = 1;
-    } else {
-        if (port < 5900 || port > 5964) {
-            VIR_WARN("VNC port %lld it out of [5900..5964] range", port);
-        }
-
-        (*def)->data.vnc.port = port;
-        (*def)->data.vnc.autoport = 0;
-    }
-
-    return 0;
-
-  failure:
-    virDomainGraphicsDefFree(*def);
-    *def = NULL;
-
-    return -1;
-}
-
-
-
-int
-esxVMX_ParseSCSIController(virConfPtr conf, int controller, bool *present,
-                           int *virtualDev)
-{
-    char present_name[32];
-    char virtualDev_name[32];
-    char *virtualDev_string = NULL;
-    char *tmp;
-
-    if (virtualDev == NULL || *virtualDev != -1) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (controller < 0 || controller > 3) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("SCSI controller index %d out of [0..3] range"),
-                  controller);
-        return -1;
-    }
-
-    snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
-    snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
-             controller);
-
-    if (esxUtil_GetConfigBoolean(conf, present_name, present, false,
-                                 true) < 0) {
-        goto failure;
-    }
-
-    if (! *present) {
-        return 0;
-    }
-
-    if (esxUtil_GetConfigString(conf, virtualDev_name, &virtualDev_string,
-                                true) < 0) {
-        goto failure;
-    }
-
-    if (virtualDev_string != NULL) {
-        tmp = virtualDev_string;
-
-        for (; *tmp != '\0'; ++tmp) {
-            *tmp = c_tolower(*tmp);
-        }
-
-        *virtualDev = esxVMX_SCSIControllerModelTypeFromString(virtualDev_string);
-
-        if (*virtualDev == -1 ||
-            (*virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC &&
-             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC &&
-             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 &&
-             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI)) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting VMX entry '%s' to be 'buslogic' or 'lsilogic' "
-                        "or 'lsisas1068' or 'pvscsi' but found '%s'"),
-                       virtualDev_name, virtualDev_string);
-            goto failure;
-        }
-    }
-
-    return 0;
-
-  failure:
-    VIR_FREE(virtualDev_string);
-
-    return -1;
-}
-
-
-
-/*
-struct _virDomainDiskDef {
-    int type;               // partly done
-    int device;             // done
-    int bus;                // done
-    char *src;              // done
-    char *dst;              // done
-    char *driverName;       // done
-    char *driverType;
-    int cachemode;          // done
-    unsigned int readonly : 1;
-    unsigned int shared : 1;
-    int slotnum;
-};*/
-
-int
-esxVMX_ParseDisk(esxVMX_Context *ctx, virCapsPtr caps, virConfPtr conf,
-                 int device, int busType, int controllerOrBus, int unit,
-                 virDomainDiskDefPtr *def)
-{
-    /*
-     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
-     *         busType = VIR_DOMAIN_DISK_BUS_SCSI
-     * controllerOrBus = [0..3] -> controller
-     *            unit = [0..6,8..15]
-     *
-     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
-     *         busType = VIR_DOMAIN_DISK_BUS_IDE
-     * controllerOrBus = [0..1] -> bus
-     *            unit = [0..1]
-     *
-     *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
-     *         busType = VIR_DOMAIN_DISK_BUS_FDC
-     * controllerOrBus = [0]
-     *            unit = [0..1]
-     */
-
-    int result = -1;
-    char *prefix = NULL;
-
-    char present_name[32] = "";
-    bool present = false;
-
-    char startConnected_name[32] = "";
-    bool startConnected = false;
-
-    char deviceType_name[32] = "";
-    char *deviceType = NULL;
-
-    char clientDevice_name[32] = "";
-    bool clientDevice = false;
-
-    char fileType_name[32] = "";
-    char *fileType = NULL;
-
-    char fileName_name[32] = "";
-    char *fileName = NULL;
-
-    char writeThrough_name[32] = "";
-    bool writeThrough = false;
-
-    if (def == NULL || *def != NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (VIR_ALLOC(*def) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    (*def)->device = device;
-    (*def)->bus = busType;
-
-    /* def:dst, def:driverName */
-    if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
-        device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
-        if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
-            if (controllerOrBus < 0 || controllerOrBus > 3) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("SCSI controller index %d out of [0..3] range"),
-                          controllerOrBus);
-                goto cleanup;
-            }
-
-            if (unit < 0 || unit > 15 || unit == 7) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("SCSI unit index %d out of [0..6,8..15] range"),
-                          unit);
-                goto cleanup;
-            }
-
-            if (virAsprintf(&prefix, "scsi%d:%d", controllerOrBus, unit) < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-
-            (*def)->dst =
-               virIndexToDiskName
-                 (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
-
-            if ((*def)->dst == NULL) {
-                goto cleanup;
-            }
-        } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
-            if (controllerOrBus < 0 || controllerOrBus > 1) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("IDE bus index %d out of [0..1] range"),
-                          controllerOrBus);
-                goto cleanup;
-            }
-
-            if (unit < 0 || unit > 1) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("IDE unit index %d out of [0..1] range"), unit);
-                goto cleanup;
-            }
-
-            if (virAsprintf(&prefix, "ide%d:%d", controllerOrBus, unit) < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-
-            (*def)->dst = virIndexToDiskName(controllerOrBus * 2 + unit, "hd");
-
-            if ((*def)->dst == NULL) {
-                goto cleanup;
-            }
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Unsupported bus type '%s' for device type '%s'"),
-                      virDomainDiskBusTypeToString(busType),
-                      virDomainDiskDeviceTypeToString(device));
-            goto cleanup;
-        }
-    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
-        if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
-            if (controllerOrBus != 0) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("FDC controller index %d out of [0] range"),
-                          controllerOrBus);
-                goto cleanup;
-            }
-
-            if (unit < 0 || unit > 1) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("FDC unit index %d out of [0..1] range"),
-                          unit);
-                goto cleanup;
-            }
-
-            if (virAsprintf(&prefix, "floppy%d", unit) < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-
-            (*def)->dst = virIndexToDiskName(unit, "fd");
-
-            if ((*def)->dst == NULL) {
-                goto cleanup;
-            }
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Unsupported bus type '%s' for device type '%s'"),
-                      virDomainDiskBusTypeToString(busType),
-                      virDomainDiskDeviceTypeToString(device));
-            goto cleanup;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unsupported device type '%s'"),
-                  virDomainDiskDeviceTypeToString(device));
-        goto cleanup;
-    }
-
-    ESX_BUILD_VMX_NAME(present);
-    ESX_BUILD_VMX_NAME(startConnected);
-    ESX_BUILD_VMX_NAME(deviceType);
-    ESX_BUILD_VMX_NAME(clientDevice);
-    ESX_BUILD_VMX_NAME(fileType);
-    ESX_BUILD_VMX_NAME(fileName);
-    ESX_BUILD_VMX_NAME(writeThrough);
-
-    /* vmx:present */
-    if (esxUtil_GetConfigBoolean(conf, present_name, &present, false,
-                                 true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:startConnected */
-    if (esxUtil_GetConfigBoolean(conf, startConnected_name, &startConnected,
-                                 true, true) < 0) {
-        goto cleanup;
-    }
-
-    /* FIXME: Need to distiguish between active and inactive domains here */
-    if (! present/* && ! startConnected*/) {
-        goto ignore;
-    }
-
-    /* vmx:deviceType -> def:type */
-    if (esxUtil_GetConfigString(conf, deviceType_name, &deviceType, true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:clientDevice */
-    if (esxUtil_GetConfigBoolean(conf, clientDevice_name, &clientDevice, false,
-                                 true) < 0) {
-        goto cleanup;
-    }
-
-    if (clientDevice) {
-        /*
-         * Just ignore devices in client mode, because I have no clue how to
-         * handle them (e.g. assign an image) without the VI Client GUI.
-         */
-        goto ignore;
-    }
-
-    /* vmx:fileType -> def:type */
-    if (esxUtil_GetConfigString(conf, fileType_name, &fileType, true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:fileName -> def:src, def:type */
-    if (esxUtil_GetConfigString(conf, fileName_name, &fileName, false) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:writeThrough -> def:cachemode */
-    if (esxUtil_GetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
-                                 true) < 0) {
-        goto cleanup;
-    }
-
-    /* Setup virDomainDiskDef */
-    if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
-        if (virFileHasSuffix(fileName, ".vmdk")) {
-            if (deviceType != NULL) {
-                if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
-                    STRCASENEQ(deviceType, "scsi-hardDisk") &&
-                    STRCASENEQ(deviceType, "disk")) {
-                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                              _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
-                                "or 'disk' but found '%s'"), deviceType_name,
-                              deviceType);
-                    goto cleanup;
-                } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
-                           STRCASENEQ(deviceType, "ata-hardDisk") &&
-                           STRCASENEQ(deviceType, "disk")) {
-                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                              _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
-                                "or 'disk' but found '%s'"), deviceType_name,
-                              deviceType);
-                    goto cleanup;
-                }
-            }
-
-            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
-            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
-            (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
-                                             : VIR_DOMAIN_DISK_CACHE_DEFAULT;
-
-            if ((*def)->src == NULL) {
-                goto cleanup;
-            }
-        } else if (virFileHasSuffix(fileName, ".iso") ||
-                   STREQ(deviceType, "atapi-cdrom")) {
-            /*
-             * This function was called in order to parse a harddisk device,
-             * but .iso files and 'atapi-cdrom' devices are for CDROM devices
-             * only. Just ignore it, another call to this function to parse a
-             * CDROM device may handle it.
-             */
-            goto ignore;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Invalid or not yet handled value '%s' for VMX entry "
-                        "'%s'"), fileName, fileName_name);
-            goto cleanup;
-        }
-    } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
-        if (virFileHasSuffix(fileName, ".iso")) {
-            if (deviceType != NULL) {
-                if (STRCASENEQ(deviceType, "cdrom-image")) {
-                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                              _("Expecting VMX entry '%s' to be 'cdrom-image' "
-                                "but found '%s'"), deviceType_name, deviceType);
-                    goto cleanup;
-                }
-            }
-
-            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
-            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
-
-            if ((*def)->src == NULL) {
-                goto cleanup;
-            }
-        } else if (virFileHasSuffix(fileName, ".vmdk")) {
-            /*
-             * This function was called in order to parse a CDROM device, but
-             * .vmdk files are for harddisk devices only. Just ignore it,
-             * another call to this function to parse a harddisk device may
-             * handle it.
-             */
-            goto ignore;
-        } else if (STREQ(deviceType, "atapi-cdrom")) {
-            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
-            (*def)->src = fileName;
-
-            fileName = NULL;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Invalid or not yet handled value '%s' for VMX entry "
-                        "'%s'"), fileName, fileName_name);
-            goto cleanup;
-        }
-    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
-        if (virFileHasSuffix(fileName, ".flp")) {
-            if (fileType != NULL) {
-                if (STRCASENEQ(fileType, "file")) {
-                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                              _("Expecting VMX entry '%s' to be 'file' but "
-                                "found '%s'"), fileType_name, fileType);
-                    goto cleanup;
-                }
-            }
-
-            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
-            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
-
-            if ((*def)->src == NULL) {
-                goto cleanup;
-            }
-        } else if (fileType != NULL && STREQ(fileType, "device")) {
-            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
-            (*def)->src = fileName;
-
-            fileName = NULL;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Invalid or not yet handled value '%s' for VMX entry "
-                        "'%s'"), fileName, fileName_name);
-            goto cleanup;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Unsupported device type '%s'"),
-                  virDomainDiskDeviceTypeToString(device));
-        goto cleanup;
-    }
-
-    if (virDomainDiskDefAssignAddress(caps, *def) < 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Could not assign address to disk '%s'"), (*def)->src);
-        goto cleanup;
-    }
-
-    result = 0;
-
-  cleanup:
-    if (result < 0) {
-        virDomainDiskDefFree(*def);
-        *def = NULL;
-    }
-
-    VIR_FREE(prefix);
-    VIR_FREE(deviceType);
-    VIR_FREE(fileType);
-    VIR_FREE(fileName);
-
-    return result;
-
-  ignore:
-    virDomainDiskDefFree(*def);
-    *def = NULL;
-
-    result = 0;
-
-    goto cleanup;
-}
-
-
-
-int
-esxVMX_ParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
-{
-    int result = -1;
-    char prefix[48] = "";
-
-    char present_name[48] = "";
-    bool present = false;
-
-    char startConnected_name[48] = "";
-    bool startConnected = false;
-
-    char connectionType_name[48] = "";
-    char *connectionType = NULL;
-
-    char addressType_name[48] = "";
-    char *addressType = NULL;
-
-    char generatedAddress_name[48] = "";
-    char *generatedAddress = NULL;
-
-    char address_name[48] = "";
-    char *address = NULL;
-
-    char virtualDev_name[48] = "";
-    char *virtualDev = NULL;
-
-    char features_name[48] = "";
-    long long features = 0;
-
-    char vnet_name[48] = "";
-    char *vnet = NULL;
-
-    char networkName_name[48] = "";
-    char *networkName = NULL;
-
-    if (def == NULL || *def != NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (controller < 0 || controller > 3) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Ethernet controller index %d out of [0..3] range"),
-                  controller);
-        return -1;
-    }
-
-    if (VIR_ALLOC(*def) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
-
-    ESX_BUILD_VMX_NAME(present);
-    ESX_BUILD_VMX_NAME(startConnected);
-    ESX_BUILD_VMX_NAME(connectionType);
-    ESX_BUILD_VMX_NAME(addressType);
-    ESX_BUILD_VMX_NAME(generatedAddress);
-    ESX_BUILD_VMX_NAME(address);
-    ESX_BUILD_VMX_NAME(virtualDev);
-    ESX_BUILD_VMX_NAME(features);
-    ESX_BUILD_VMX_NAME(networkName);
-    ESX_BUILD_VMX_NAME(vnet);
-
-    /* vmx:present */
-    if (esxUtil_GetConfigBoolean(conf, present_name, &present, false,
-                                 true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:startConnected */
-    if (esxUtil_GetConfigBoolean(conf, startConnected_name, &startConnected,
-                                 true, true) < 0) {
-        goto cleanup;
-    }
-
-    /* FIXME: Need to distiguish between active and inactive domains here */
-    if (! present/* && ! startConnected*/) {
-        goto ignore;
-    }
-
-    /* vmx:connectionType -> def:type */
-    if (esxUtil_GetConfigString(conf, connectionType_name, &connectionType,
-                                true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
-    if (esxUtil_GetConfigString(conf, addressType_name, &addressType,
-                                true) < 0 ||
-        esxUtil_GetConfigString(conf, generatedAddress_name, &generatedAddress,
-                                true) < 0 ||
-        esxUtil_GetConfigString(conf, address_name, &address, true) < 0) {
-        goto cleanup;
-    }
-
-    if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
-        STRCASEEQ(addressType, "vpx")) {
-        if (generatedAddress != NULL) {
-            if (virParseMacAddr(generatedAddress, (*def)->mac) < 0) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Expecting VMX entry '%s' to be MAC address but "
-                            "found '%s'"), generatedAddress_name,
-                          generatedAddress);
-                goto cleanup;
-            }
-        }
-    } else if (STRCASEEQ(addressType, "static")) {
-        if (address != NULL) {
-            if (virParseMacAddr(address, (*def)->mac) < 0) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Expecting VMX entry '%s' to be MAC address but "
-                            "found '%s'"), address_name, address);
-                goto cleanup;
-            }
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting VMX entry '%s' to be 'generated' or 'static' or "
-                    "'vpx' but found '%s'"), addressType_name, addressType);
-        goto cleanup;
-    }
-
-    /* vmx:virtualDev, vmx:features -> def:model */
-    if (esxUtil_GetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
-        esxUtil_GetConfigLong(conf, features_name, &features, 0, true) < 0) {
-        goto cleanup;
-    }
-
-    if (virtualDev != NULL) {
-        if (STRCASENEQ(virtualDev, "vlance") &&
-            STRCASENEQ(virtualDev, "vmxnet") &&
-            STRCASENEQ(virtualDev, "vmxnet3") &&
-            STRCASENEQ(virtualDev, "e1000")) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or "
-                        "'vmxnet3' or 'e1000' but found '%s'"), virtualDev_name,
-                      virtualDev);
-            goto cleanup;
-        }
-
-        if (STRCASEEQ(virtualDev, "vmxnet") && features == 15) {
-            VIR_FREE(virtualDev);
-
-            virtualDev = strdup("vmxnet2");
-
-            if (virtualDev == NULL) {
-                virReportOOMError();
-                goto cleanup;
-            }
-        }
-    }
-
-    /* vmx:networkName -> def:data.bridge.brname */
-    if ((connectionType == NULL ||
-         STRCASEEQ(connectionType, "bridged") ||
-         STRCASEEQ(connectionType, "custom")) &&
-        esxUtil_GetConfigString(conf, networkName_name, &networkName,
-                                false) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:vnet -> def:data.ifname */
-    if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
-        esxUtil_GetConfigString(conf, vnet_name, &vnet, false) < 0) {
-        goto cleanup;
-    }
-
-    /* Setup virDomainNetDef */
-    if (connectionType == NULL || STRCASEEQ(connectionType, "bridged")) {
-        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
-        (*def)->model = virtualDev;
-        (*def)->data.bridge.brname = networkName;
-
-        virtualDev = NULL;
-        networkName = NULL;
-    } else if (STRCASEEQ(connectionType, "hostonly")) {
-        /* FIXME */
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("No yet handled value '%s' for VMX entry '%s'"),
-                  connectionType, connectionType_name);
-        goto cleanup;
-    } else if (STRCASEEQ(connectionType, "nat")) {
-        /* FIXME */
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("No yet handled value '%s' for VMX entry '%s'"),
-                  connectionType, connectionType_name);
-        goto cleanup;
-    } else if (STRCASEEQ(connectionType, "custom")) {
-        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
-        (*def)->model = virtualDev;
-        (*def)->data.bridge.brname = networkName;
-        (*def)->ifname = vnet;
-
-        virtualDev = NULL;
-        networkName = NULL;
-        vnet = NULL;
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Invalid value '%s' for VMX entry '%s'"), connectionType,
-                  connectionType_name);
-        goto cleanup;
-    }
-
-    result = 0;
-
-  cleanup:
-    if (result < 0) {
-        virDomainNetDefFree(*def);
-        *def = NULL;
-    }
-
-    VIR_FREE(connectionType);
-    VIR_FREE(addressType);
-    VIR_FREE(generatedAddress);
-    VIR_FREE(address);
-    VIR_FREE(virtualDev);
-    VIR_FREE(vnet);
-
-    return result;
-
-  ignore:
-    virDomainNetDefFree(*def);
-    *def = NULL;
-
-    result = 0;
-
-    goto cleanup;
-}
-
-
-
-int
-esxVMX_ParseSerial(esxVMX_Context *ctx, virConfPtr conf, int port,
-                   virDomainChrDefPtr *def)
-{
-    int result = -1;
-    char prefix[48] = "";
-
-    char present_name[48] = "";
-    bool present = false;
-
-    char startConnected_name[48] = "";
-    bool startConnected = false;
-
-    char fileType_name[48] = "";
-    char *fileType = NULL;
-
-    char fileName_name[48] = "";
-    char *fileName = NULL;
-
-    char network_endPoint_name[48] = "";
-    char *network_endPoint = NULL;
-
-    xmlURIPtr parsedUri = NULL;
-
-    if (def == NULL || *def != NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (port < 0 || port > 3) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Serial port index %d out of [0..3] range"), port);
-        return -1;
-    }
-
-    if (VIR_ALLOC(*def) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
-
-    snprintf(prefix, sizeof(prefix), "serial%d", port);
-
-    ESX_BUILD_VMX_NAME(present);
-    ESX_BUILD_VMX_NAME(startConnected);
-    ESX_BUILD_VMX_NAME(fileType);
-    ESX_BUILD_VMX_NAME(fileName);
-    ESX_BUILD_VMX_NAME_EXTRA(network_endPoint, "network.endPoint");
-
-    /* vmx:present */
-    if (esxUtil_GetConfigBoolean(conf, present_name, &present, false,
-                                 true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:startConnected */
-    if (esxUtil_GetConfigBoolean(conf, startConnected_name, &startConnected,
-                                 true, true) < 0) {
-        goto cleanup;
-    }
-
-    /* FIXME: Need to distiguish between active and inactive domains here */
-    if (! present/* && ! startConnected*/) {
-        goto ignore;
-    }
-
-    /* vmx:fileType -> def:type */
-    if (esxUtil_GetConfigString(conf, fileType_name, &fileType, false) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:fileName -> def:data.file.path */
-    if (esxUtil_GetConfigString(conf, fileName_name, &fileName, false) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:network.endPoint -> def:data.tcp.listen */
-    if (esxUtil_GetConfigString(conf, network_endPoint_name, &network_endPoint,
-                                true) < 0) {
-        goto cleanup;
-    }
-
-    /* Setup virDomainChrDef */
-    if (STRCASEEQ(fileType, "device")) {
-        (*def)->target.port = port;
-        (*def)->type = VIR_DOMAIN_CHR_TYPE_DEV;
-        (*def)->data.file.path = fileName;
-
-        fileName = NULL;
-    } else if (STRCASEEQ(fileType, "file")) {
-        (*def)->target.port = port;
-        (*def)->type = VIR_DOMAIN_CHR_TYPE_FILE;
-        (*def)->data.file.path = ctx->parseFileName(fileName, ctx->opaque);
-
-        if ((*def)->data.file.path == NULL) {
-            goto cleanup;
-        }
-    } else if (STRCASEEQ(fileType, "pipe")) {
-        /*
-         * FIXME: Differences between client/server and VM/application pipes
-         *        not representable in domain XML form
-         */
-        (*def)->target.port = port;
-        (*def)->type = VIR_DOMAIN_CHR_TYPE_PIPE;
-        (*def)->data.file.path = fileName;
-
-        fileName = NULL;
-    } else if (STRCASEEQ(fileType, "network")) {
-        (*def)->target.port = port;
-        (*def)->type = VIR_DOMAIN_CHR_TYPE_TCP;
-
-        parsedUri = xmlParseURI(fileName);
-
-        if (parsedUri == NULL) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        if (parsedUri->port == 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("VMX entry '%s' doesn't contain a port part"),
-                      fileName_name);
-            goto cleanup;
-        }
-
-        (*def)->data.tcp.host = strdup(parsedUri->server);
-
-        if ((*def)->data.tcp.host == NULL) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        if (virAsprintf(&(*def)->data.tcp.service, "%d", parsedUri->port) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        /* See vSphere API documentation about VirtualSerialPortURIBackingInfo */
-        if (parsedUri->scheme == NULL ||
-            STRCASEEQ(parsedUri->scheme, "tcp") ||
-            STRCASEEQ(parsedUri->scheme, "tcp4") ||
-            STRCASEEQ(parsedUri->scheme, "tcp6")) {
-            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
-        } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
-            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
-        } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
-            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
-        } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
-                   STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
-                   STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
-                   STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
-            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("VMX entry '%s' contains unsupported scheme '%s'"),
-                      fileName_name, parsedUri->scheme);
-            goto cleanup;
-        }
-
-        if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
-            (*def)->data.tcp.listen = 1;
-        } else if (STRCASEEQ(network_endPoint, "client")) {
-            (*def)->data.tcp.listen = 0;
-        } else {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting VMX entry '%s' to be 'server' or 'client' "
-                        "but found '%s'"), network_endPoint_name, network_endPoint);
-            goto cleanup;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' "
-                    "or 'network' but found '%s'"), fileType_name, fileType);
-        goto cleanup;
-    }
-
-    result = 0;
-
-  cleanup:
-    if (result < 0) {
-        virDomainChrDefFree(*def);
-        *def = NULL;
-    }
-
-    VIR_FREE(fileType);
-    VIR_FREE(fileName);
-    VIR_FREE(network_endPoint);
-    xmlFreeURI(parsedUri);
-
-    return result;
-
-  ignore:
-    virDomainChrDefFree(*def);
-    *def = NULL;
-
-    result = 0;
-
-    goto cleanup;
-}
-
-
-
-int
-esxVMX_ParseParallel(esxVMX_Context *ctx, virConfPtr conf, int port,
-                     virDomainChrDefPtr *def)
-{
-    int result = -1;
-    char prefix[48] = "";
-
-    char present_name[48] = "";
-    bool present = false;
-
-    char startConnected_name[48] = "";
-    bool startConnected = false;
-
-    char fileType_name[48] = "";
-    char *fileType = NULL;
-
-    char fileName_name[48] = "";
-    char *fileName = NULL;
-
-    if (def == NULL || *def != NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (port < 0 || port > 2) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Parallel port index %d out of [0..2] range"), port);
-        return -1;
-    }
-
-    if (VIR_ALLOC(*def) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
-
-    snprintf(prefix, sizeof(prefix), "parallel%d", port);
-
-    ESX_BUILD_VMX_NAME(present);
-    ESX_BUILD_VMX_NAME(startConnected);
-    ESX_BUILD_VMX_NAME(fileType);
-    ESX_BUILD_VMX_NAME(fileName);
-
-    /* vmx:present */
-    if (esxUtil_GetConfigBoolean(conf, present_name, &present, false,
-                                 true) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:startConnected */
-    if (esxUtil_GetConfigBoolean(conf, startConnected_name, &startConnected,
-                                 true, true) < 0) {
-        goto cleanup;
-    }
-
-    /* FIXME: Need to distiguish between active and inactive domains here */
-    if (! present/* && ! startConnected*/) {
-        goto ignore;
-    }
-
-    /* vmx:fileType -> def:type */
-    if (esxUtil_GetConfigString(conf, fileType_name, &fileType, false) < 0) {
-        goto cleanup;
-    }
-
-    /* vmx:fileName -> def:data.file.path */
-    if (esxUtil_GetConfigString(conf, fileName_name, &fileName, false) < 0) {
-        goto cleanup;
-    }
-
-    /* Setup virDomainChrDef */
-    if (STRCASEEQ(fileType, "device")) {
-        (*def)->target.port = port;
-        (*def)->type = VIR_DOMAIN_CHR_TYPE_DEV;
-        (*def)->data.file.path = fileName;
-
-        fileName = NULL;
-    } else if (STRCASEEQ(fileType, "file")) {
-        (*def)->target.port = port;
-        (*def)->type = VIR_DOMAIN_CHR_TYPE_FILE;
-        (*def)->data.file.path = ctx->parseFileName(fileName, ctx->opaque);
-
-        if ((*def)->data.file.path == NULL) {
-            goto cleanup;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting VMX entry '%s' to be 'device' or 'file' but "
-                    "found '%s'"), fileType_name, fileType);
-        goto cleanup;
-    }
-
-    result = 0;
-
-  cleanup:
-    if (result < 0) {
-        virDomainChrDefFree(*def);
-        *def = NULL;
-    }
-
-    VIR_FREE(fileType);
-    VIR_FREE(fileName);
-
-    return result;
-
-  ignore:
-    virDomainChrDefFree(*def);
-    *def = NULL;
-
-    result = 0;
-
-    goto cleanup;
-}
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Domain XML -> VMX
- */
-
-char *
-esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def,
-                    esxVI_ProductVersion productVersion)
-{
-    char *vmx = NULL;
-    int i;
-    int sched_cpu_affinity_length;
-    unsigned char zero[VIR_UUID_BUFLEN];
-    virBuffer buffer = VIR_BUFFER_INITIALIZER;
-    char *preliminaryDisplayName = NULL;
-    char *displayName = NULL;
-    char *annotation = NULL;
-    bool scsi_present[4] = { false, false, false, false };
-    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
-    bool floppy_present[2] = { false, false };
-
-    if (ctx->formatFileName == NULL) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("esxVMX_Context has no formatFileName function set"));
-        return NULL;
-    }
-
-    memset(zero, 0, VIR_UUID_BUFLEN);
-
-    if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) { /* FIXME: maybe add VIR_DOMAIN_VIRT_ESX ? */
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting virt type to be '%s' but found '%s'"),
-                  virDomainVirtTypeToString(VIR_DOMAIN_VIRT_VMWARE),
-                  virDomainVirtTypeToString(def->virtType));
-        return NULL;
-    }
-
-    /* vmx:.encoding */
-    virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");
-
-    /* vmx:config.version */
-    virBufferAddLit(&buffer, "config.version = \"8\"\n");
-
-    /* vmx:virtualHW.version */
-    switch (productVersion) {
-      case esxVI_ProductVersion_ESX35:
-        virBufferAddLit(&buffer, "virtualHW.version = \"4\"\n");
-        break;
-
-      case esxVI_ProductVersion_GSX20:
-      case esxVI_ProductVersion_ESX40:
-      case esxVI_ProductVersion_ESX41:
-      case esxVI_ProductVersion_ESX4x:
-      /* FIXME: Putting VPX* here is a hack until a more fine grained system is in place */
-      case esxVI_ProductVersion_VPX40:
-      case esxVI_ProductVersion_VPX41:
-      case esxVI_ProductVersion_VPX4x:
-        virBufferAddLit(&buffer, "virtualHW.version = \"7\"\n");
-        break;
-
-      default:
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
-                  _("Unexpected product version"));
-        goto cleanup;
-    }
-
-    /* def:os.arch -> vmx:guestOS */
-    if (def->os.arch == NULL || STRCASEEQ(def->os.arch, "i686")) {
-        virBufferAddLit(&buffer, "guestOS = \"other\"\n");
-    } else if (STRCASEEQ(def->os.arch, "x86_64")) {
-        virBufferAddLit(&buffer, "guestOS = \"other-64\"\n");
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting domain XML attribute 'arch' of entry 'os/type' "
-                    "to be 'i686' or 'x86_64' but found '%s'"), def->os.arch);
-        goto cleanup;
-    }
-
-    /* def:os.smbios_mode -> vmx:smbios.reflecthost */
-    if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_NONE ||
-        def->os.smbios_mode == VIR_DOMAIN_SMBIOS_EMULATE) {
-        /* nothing */
-    } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
-        virBufferAddLit(&buffer, "smbios.reflecthost = \"true\"\n");
-    } else {
-        ESX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
-                  _("Unsupported SMBIOS mode '%s'"),
-                  virDomainSmbiosModeTypeToString(def->os.smbios_mode));
-        goto cleanup;
-    }
-
-    /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */
-    if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) {
-        virBufferAddLit(&buffer, "uuid.action = \"create\"\n");
-    } else {
-        virBufferVSprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x "
-                          "%02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\"\n",
-                          def->uuid[0], def->uuid[1], def->uuid[2], def->uuid[3],
-                          def->uuid[4], def->uuid[5], def->uuid[6], def->uuid[7],
-                          def->uuid[8], def->uuid[9], def->uuid[10], def->uuid[11],
-                          def->uuid[12], def->uuid[13], def->uuid[14],
-                          def->uuid[15]);
-    }
-
-    /* def:name -> vmx:displayName */
-    preliminaryDisplayName = esxUtil_EscapeHexPipe(def->name);
-
-    if (preliminaryDisplayName == NULL) {
-        goto cleanup;
-    }
-
-    displayName = esxUtil_EscapeHexPercent(preliminaryDisplayName);
-
-    if (displayName == NULL) {
-        goto cleanup;
-    }
-
-    virBufferVSprintf(&buffer, "displayName = \"%s\"\n", displayName);
-
-    /* def:description -> vmx:annotation */
-    if (def->description != NULL) {
-        annotation = esxUtil_EscapeHexPipe(def->description);
-
-        virBufferVSprintf(&buffer, "annotation = \"%s\"\n", annotation);
-    }
-
-    /* def:mem.max_balloon -> vmx:memsize */
-    if (def->mem.max_balloon <= 0 || def->mem.max_balloon % 4096 != 0) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting domain XML entry 'memory' to be an unsigned "
-                    "integer (multiple of 4096) but found %lld"),
-                  (unsigned long long)def->mem.max_balloon);
-        goto cleanup;
-    }
-
-    /* Scale from kilobytes to megabytes */
-    virBufferVSprintf(&buffer, "memsize = \"%d\"\n",
-                      (int)(def->mem.max_balloon / 1024));
-
-    /* def:mem.cur_balloon -> vmx:sched.mem.max */
-    if (def->mem.cur_balloon < def->mem.max_balloon) {
-        if (def->mem.cur_balloon <= 0 || def->mem.cur_balloon % 1024 != 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting domain XML entry 'currentMemory' to be an "
-                        "unsigned integer (multiple of 1024) but found %llu"),
-                      (unsigned long long)def->mem.cur_balloon);
-            goto cleanup;
-        }
-
-        /* Scale from kilobytes to megabytes */
-        virBufferVSprintf(&buffer, "sched.mem.max = \"%d\"\n",
-                          (int)(def->mem.cur_balloon / 1024));
-    }
-
-    /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
-    if (def->mem.min_guarantee > 0) {
-        if (def->mem.min_guarantee % 1024 != 0) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting domain XML entry 'memtune/min_guarantee' to "
-                        "be an unsigned integer (multiple of 1024) but found %llu"),
-                      (unsigned long long)def->mem.min_guarantee);
-            goto cleanup;
-        }
-
-        /* Scale from kilobytes to megabytes */
-        virBufferVSprintf(&buffer, "sched.mem.minsize = \"%d\"\n",
-                          (int)(def->mem.min_guarantee / 1024));
-    }
-
-    /* def:maxvcpus -> vmx:numvcpus */
-    if (def->vcpus != def->maxvcpus) {
-        ESX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                  _("No support for domain XML entry 'vcpu' attribute "
-                    "'current'"));
-        goto cleanup;
-    }
-    if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Expecting domain XML entry 'vcpu' to be an unsigned "
-                    "integer (1 or a multiple of 2) but found %d"),
-                  def->maxvcpus);
-        goto cleanup;
-    }
-
-    virBufferVSprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus);
-
-    /* def:cpumask -> vmx:sched.cpu.affinity */
-    if (def->cpumasklen > 0) {
-        virBufferAddLit(&buffer, "sched.cpu.affinity = \"");
-
-        sched_cpu_affinity_length = 0;
-
-        for (i = 0; i < def->cpumasklen; ++i) {
-            if (def->cpumask[i]) {
-                ++sched_cpu_affinity_length;
-            }
-        }
-
-        if (sched_cpu_affinity_length < def->maxvcpus) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting domain XML attribute 'cpuset' of entry "
-                        "'vcpu' to contain at least %d CPU(s)"),
-                      def->maxvcpus);
-            goto cleanup;
-        }
-
-        for (i = 0; i < def->cpumasklen; ++i) {
-            if (def->cpumask[i]) {
-                virBufferVSprintf(&buffer, "%d", i);
-
-                if (sched_cpu_affinity_length > 1) {
-                    virBufferAddChar(&buffer, ',');
-                }
-
-                --sched_cpu_affinity_length;
-            }
-        }
-
-        virBufferAddLit(&buffer, "\"\n");
-    }
-
-    /* def:graphics */
-    for (i = 0; i < def->ngraphics; ++i) {
-        switch (def->graphics[i]->type) {
-          case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
-            if (esxVMX_FormatVNC(def->graphics[i], &buffer) < 0) {
-                goto cleanup;
-            }
-
-            break;
-
-          default:
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Unsupported graphics type '%s'"),
-                      virDomainGraphicsTypeToString(def->graphics[i]->type));
-            goto cleanup;
-        }
-    }
-
-    /* def:disks */
-    for (i = 0; i < def->ndisks; ++i) {
-        if (esxVMX_VerifyDiskAddress(caps, def->disks[i]) < 0 ||
-            esxVMX_HandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
-            goto cleanup;
-        }
-    }
-
-    if (esxVMX_GatherSCSIControllers(ctx, def, scsi_virtualDev,
-                                     scsi_present) < 0) {
-        goto cleanup;
-    }
-
-    for (i = 0; i < 4; ++i) {
-        if (scsi_present[i]) {
-            virBufferVSprintf(&buffer, "scsi%d.present = \"true\"\n", i);
-
-            if (scsi_virtualDev[i] != -1) {
-                virBufferVSprintf(&buffer, "scsi%d.virtualDev = \"%s\"\n", i,
-                                  esxVMX_SCSIControllerModelTypeToString
-                                    (scsi_virtualDev[i]));
-            }
-        }
-    }
-
-    for (i = 0; i < def->ndisks; ++i) {
-        switch (def->disks[i]->device) {
-          case VIR_DOMAIN_DISK_DEVICE_DISK:
-            if (esxVMX_FormatHardDisk(ctx, def->disks[i], &buffer) < 0) {
-                goto cleanup;
-            }
-
-            break;
-
-          case VIR_DOMAIN_DISK_DEVICE_CDROM:
-            if (esxVMX_FormatCDROM(ctx, def->disks[i], &buffer) < 0) {
-                goto cleanup;
-            }
-
-            break;
-
-          case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
-            if (esxVMX_FormatFloppy(ctx, def->disks[i], &buffer,
-                                    floppy_present) < 0) {
-                goto cleanup;
-            }
-
-            break;
-
-          default:
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Unsupported disk device type '%s'"),
-                      virDomainDiskDeviceTypeToString(def->disks[i]->device));
-            goto cleanup;
-        }
-    }
-
-    for (i = 0; i < 2; ++i) {
-        /* floppy[0..1].present defaults to true, disable it explicitly */
-        if (! floppy_present[i]) {
-            virBufferVSprintf(&buffer, "floppy%d.present = \"false\"\n", i);
-        }
-    }
-
-    /* def:fss */
-    /* FIXME */
-
-    /* def:nets */
-    for (i = 0; i < def->nnets; ++i) {
-        if (esxVMX_FormatEthernet(def->nets[i], i, &buffer) < 0) {
-            goto cleanup;
-        }
-    }
-
-    /* def:inputs */
-    /* FIXME */
-
-    /* def:sounds */
-    /* FIXME */
-
-    /* def:hostdevs */
-    /* FIXME */
-
-    /* def:serials */
-    for (i = 0; i < def->nserials; ++i) {
-        if (esxVMX_FormatSerial(ctx, def->serials[i], &buffer) < 0) {
-            goto cleanup;
-        }
-    }
-
-    /* def:parallels */
-    for (i = 0; i < def->nparallels; ++i) {
-        if (esxVMX_FormatParallel(ctx, def->parallels[i], &buffer) < 0) {
-            goto cleanup;
-        }
-    }
-
-    /* Get final VMX output */
-    if (virBufferError(&buffer)) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    vmx = virBufferContentAndReset(&buffer);
-
-  cleanup:
-    if (vmx == NULL) {
-        virBufferFreeAndReset(&buffer);
-    }
-
-    VIR_FREE(preliminaryDisplayName);
-    VIR_FREE(displayName);
-    VIR_FREE(annotation);
-
-    return vmx;
-}
-
-
-
-int
-esxVMX_FormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer)
-{
-    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    virBufferVSprintf(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");
-
-    if (def->data.vnc.autoport) {
-        VIR_WARN0("VNC autoport is enabled, but the automatically assigned "
-                  "VNC port cannot be read back");
-    } else {
-        if (def->data.vnc.port < 5900 || def->data.vnc.port > 5964) {
-            VIR_WARN("VNC port %d it out of [5900..5964] range",
-                     def->data.vnc.port);
-        }
-
-        virBufferVSprintf(buffer, "RemoteDisplay.vnc.port = \"%d\"\n",
-                          def->data.vnc.port);
-    }
-
-    if (def->data.vnc.listenAddr != NULL) {
-        virBufferVSprintf(buffer, "RemoteDisplay.vnc.ip = \"%s\"\n",
-                          def->data.vnc.listenAddr);
-    }
-
-    if (def->data.vnc.keymap != NULL) {
-        virBufferVSprintf(buffer, "RemoteDisplay.vnc.keymap = \"%s\"\n",
-                          def->data.vnc.keymap);
-    }
-
-    if (def->data.vnc.auth.passwd != NULL) {
-        virBufferVSprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n",
-                          def->data.vnc.auth.passwd);
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_FormatHardDisk(esxVMX_Context *ctx, virDomainDiskDefPtr def,
-                      virBufferPtr buffer)
-{
-    int controllerOrBus, unit;
-    const char *busName = NULL;
-    const char *entryPrefix = NULL;
-    const char *deviceTypePrefix = NULL;
-    char *fileName = NULL;
-
-    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
-        busName = "SCSI";
-        entryPrefix = "scsi";
-        deviceTypePrefix = "scsi";
-
-        if (esxVMX_SCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
-                                                   &unit) < 0) {
-            return -1;
-        }
-    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
-        busName = "IDE";
-        entryPrefix = "ide";
-        deviceTypePrefix = "ata";
-
-        if (esxVMX_IDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
-                                           &unit) < 0) {
-            return -1;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unsupported bus type '%s' for harddisk"),
-                  virDomainDiskBusTypeToString(def->bus));
-        return -1;
-    }
-
-    if (def->type != VIR_DOMAIN_DISK_TYPE_FILE) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("%s harddisk '%s' has unsupported type '%s', expecting '%s'"),
-                  busName, def->dst, virDomainDiskTypeToString(def->type),
-                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE));
-        return -1;
-    }
-
-    virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n",
-                      entryPrefix, controllerOrBus, unit);
-    virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"%s-hardDisk\"\n",
-                      entryPrefix, controllerOrBus, unit, deviceTypePrefix);
-
-    if (def->src != NULL) {
-        if (! virFileHasSuffix(def->src, ".vmdk")) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Image file for %s harddisk '%s' has unsupported suffix, "
-                        "expecting '.vmdk'"), busName, def->dst);
-            return -1;
-        }
-
-        fileName = ctx->formatFileName(def->src, ctx->opaque);
-
-        if (fileName == NULL) {
-            return -1;
-        }
-
-        virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
-                          entryPrefix, controllerOrBus, unit, fileName);
-
-        VIR_FREE(fileName);
-    }
-
-    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
-        if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
-            virBufferVSprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
-                              entryPrefix, controllerOrBus, unit);
-        } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("%s harddisk '%s' has unsupported cache mode '%s'"),
-                      busName, def->dst,
-                      virDomainDiskCacheTypeToString(def->cachemode));
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_FormatCDROM(esxVMX_Context *ctx, virDomainDiskDefPtr def,
-                   virBufferPtr buffer)
-{
-    int controllerOrBus, unit;
-    const char *busName = NULL;
-    const char *entryPrefix = NULL;
-    char *fileName = NULL;
-
-    if (def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
-        busName = "SCSI";
-        entryPrefix = "scsi";
-
-        if (esxVMX_SCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
-                                                   &unit) < 0) {
-            return -1;
-        }
-    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
-        busName = "IDE";
-        entryPrefix = "ide";
-
-        if (esxVMX_IDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
-                                           &unit) < 0) {
-            return -1;
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unsupported bus type '%s' for cdrom"),
-                  virDomainDiskBusTypeToString(def->bus));
-        return -1;
-    }
-
-    virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n",
-                      entryPrefix, controllerOrBus, unit);
-
-    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
-        virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"cdrom-image\"\n",
-                          entryPrefix, controllerOrBus, unit);
-
-        if (def->src != NULL) {
-            if (! virFileHasSuffix(def->src, ".iso")) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Image file for %s cdrom '%s' has unsupported "
-                            "suffix, expecting '.iso'"), busName, def->dst);
-                return -1;
-            }
-
-            fileName = ctx->formatFileName(def->src, ctx->opaque);
-
-            if (fileName == NULL) {
-                return -1;
-            }
-
-            virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
-                              entryPrefix, controllerOrBus, unit, fileName);
-
-            VIR_FREE(fileName);
-        }
-    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
-        virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"atapi-cdrom\"\n",
-                          entryPrefix, controllerOrBus, unit);
-
-        if (def->src != NULL) {
-            virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
-                              entryPrefix, controllerOrBus, unit, def->src);
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("%s cdrom '%s' has unsupported type '%s', expecting '%s' "
-                    "or '%s'"), busName, def->dst,
-                  virDomainDiskTypeToString(def->type),
-                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
-                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_FormatFloppy(esxVMX_Context *ctx, virDomainDiskDefPtr def,
-                    virBufferPtr buffer, bool floppy_present[2])
-{
-    int unit;
-    char *fileName = NULL;
-
-    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (esxVMX_FloppyDiskNameToUnit(def->dst, &unit) < 0) {
-        return -1;
-    }
-
-    floppy_present[unit] = true;
-
-    virBufferVSprintf(buffer, "floppy%d.present = \"true\"\n", unit);
-
-    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
-        virBufferVSprintf(buffer, "floppy%d.fileType = \"file\"\n", unit);
-
-        if (def->src != NULL) {
-            if (! virFileHasSuffix(def->src, ".flp")) {
-                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                          _("Image file for floppy '%s' has unsupported "
-                            "suffix, expecting '.flp'"), def->dst);
-                return -1;
-            }
-
-            fileName = ctx->formatFileName(def->src, ctx->opaque);
-
-            if (fileName == NULL) {
-                return -1;
-            }
-
-            virBufferVSprintf(buffer, "floppy%d.fileName = \"%s\"\n",
-                              unit, fileName);
-
-            VIR_FREE(fileName);
-        }
-    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
-        virBufferVSprintf(buffer, "floppy%d.fileType = \"device\"\n", unit);
-
-        if (def->src != NULL) {
-            virBufferVSprintf(buffer, "floppy%d.fileName = \"%s\"\n",
-                              unit, def->src);
-        }
-    } else {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Floppy '%s' has unsupported type '%s', expecting '%s' "
-                    "or '%s'"), def->dst,
-                  virDomainDiskTypeToString(def->type),
-                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
-                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
-        return -1;
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_FormatEthernet(virDomainNetDefPtr def, int controller,
-                      virBufferPtr buffer)
-{
-    char mac_string[VIR_MAC_STRING_BUFLEN];
-    unsigned int prefix, suffix;
-
-    if (controller < 0 || controller > 3) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Ethernet controller index %d out of [0..3] range"),
-                  controller);
-        return -1;
-    }
-
-    virBufferVSprintf(buffer, "ethernet%d.present = \"true\"\n", controller);
-
-    /* def:model -> vmx:virtualDev, vmx:features */
-    if (def->model != NULL) {
-        if (STRCASENEQ(def->model, "vlance") &&
-            STRCASENEQ(def->model, "vmxnet") &&
-            STRCASENEQ(def->model, "vmxnet2") &&
-            STRCASENEQ(def->model, "vmxnet3") &&
-            STRCASENEQ(def->model, "e1000")) {
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Expecting domain XML entry 'devices/interfase/model' "
-                        "to be 'vlance' or 'vmxnet' or 'vmxnet2' or 'vmxnet3' "
-                        "or 'e1000' but found '%s'"), def->model);
-            return -1;
-        }
-
-        if (STRCASEEQ(def->model, "vmxnet2")) {
-            virBufferVSprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
-                              controller);
-            virBufferVSprintf(buffer, "ethernet%d.features = \"15\"\n",
-                              controller);
-        } else {
-            virBufferVSprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
-                              controller, def->model);
-        }
-    }
-
-    /* def:type, def:ifname -> vmx:connectionType */
-    switch (def->type) {
-      case VIR_DOMAIN_NET_TYPE_BRIDGE:
-        virBufferVSprintf(buffer, "ethernet%d.networkName = \"%s\"\n",
-                          controller, def->data.bridge.brname);
-
-        if (def->ifname != NULL) {
-            virBufferVSprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
-                              controller);
-            virBufferVSprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
-                              controller, def->ifname);
-        } else {
-            virBufferVSprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
-                              controller);
-        }
-
-        break;
-
-      default:
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Unsupported net type '%s'"),
-                  virDomainNetTypeToString(def->type));
-        return -1;
-    }
-
-    /* def:mac -> vmx:addressType, vmx:(generated)Address, vmx:checkMACAddress */
-    virFormatMacAddr(def->mac, mac_string);
-
-    prefix = (def->mac[0] << 16) | (def->mac[1] << 8) | def->mac[2];
-    suffix = (def->mac[3] << 16) | (def->mac[4] << 8) | def->mac[5];
-
-    if (prefix == 0x000c29) {
-        virBufferVSprintf(buffer, "ethernet%d.addressType = \"generated\"\n",
-                          controller);
-        virBufferVSprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
-                          controller, mac_string);
-        virBufferVSprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
-                          controller);
-    } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
-        virBufferVSprintf(buffer, "ethernet%d.addressType = \"static\"\n",
-                          controller);
-        virBufferVSprintf(buffer, "ethernet%d.address = \"%s\"\n",
-                          controller, mac_string);
-    } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
-        virBufferVSprintf(buffer, "ethernet%d.addressType = \"vpx\"\n",
-                          controller);
-        virBufferVSprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
-                          controller, mac_string);
-    } else {
-        virBufferVSprintf(buffer, "ethernet%d.addressType = \"static\"\n",
-                          controller);
-        virBufferVSprintf(buffer, "ethernet%d.address = \"%s\"\n",
-                          controller, mac_string);
-        virBufferVSprintf(buffer, "ethernet%d.checkMACAddress = \"false\"\n",
-                          controller);
-    }
-
-    return 0;
-}
-
-
-
-int
-esxVMX_FormatSerial(esxVMX_Context *ctx, virDomainChrDefPtr def,
-                    virBufferPtr buffer)
-{
-    char *fileName = NULL;
-    const char *protocol;
-
-    if (def->target.port < 0 || def->target.port > 3) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Serial port index %d out of [0..3] range"),
-                  def->target.port);
-        return -1;
-    }
-
-    virBufferVSprintf(buffer, "serial%d.present = \"true\"\n", def->target.port);
-
-    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
-    switch (def->type) {
-      case VIR_DOMAIN_CHR_TYPE_DEV:
-        virBufferVSprintf(buffer, "serial%d.fileType = \"device\"\n",
-                          def->target.port);
-        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
-                          def->target.port, def->data.file.path);
-        break;
-
-      case VIR_DOMAIN_CHR_TYPE_FILE:
-        virBufferVSprintf(buffer, "serial%d.fileType = \"file\"\n",
-                          def->target.port);
-
-        fileName = ctx->formatFileName(def->data.file.path, ctx->opaque);
-
-        if (fileName == NULL) {
-            return -1;
-        }
-
-        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
-                          def->target.port, fileName);
-
-        VIR_FREE(fileName);
-        break;
-
-      case VIR_DOMAIN_CHR_TYPE_PIPE:
-        virBufferVSprintf(buffer, "serial%d.fileType = \"pipe\"\n",
-                          def->target.port);
-        /* FIXME: Based on VI Client GUI default */
-        virBufferVSprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
-                          def->target.port);
-        /* FIXME: Based on VI Client GUI default */
-        virBufferVSprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
-                          def->target.port);
-        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
-                          def->target.port, def->data.file.path);
-        break;
-
-      case VIR_DOMAIN_CHR_TYPE_TCP:
-        switch (def->data.tcp.protocol) {
-          case VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW:
-            protocol = "tcp";
-            break;
-
-          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET:
-            protocol = "telnet";
-            break;
-
-          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS:
-            protocol = "telnets";
-            break;
-
-          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS:
-            protocol = "ssl";
-            break;
-
-          default:
-            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                      _("Unsupported character device TCP protocol '%s'"),
-                      virDomainChrTcpProtocolTypeToString(def->data.tcp.protocol));
-            return -1;
-        }
-
-        virBufferVSprintf(buffer, "serial%d.fileType = \"network\"\n",
-                          def->target.port);
-        virBufferVSprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
-                          def->target.port, protocol, def->data.tcp.host,
-                          def->data.tcp.service);
-        virBufferVSprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
-                          def->target.port,
-                          def->data.tcp.listen ? "server" : "client");
-        break;
-
-      default:
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unsupported character device type '%s'"),
-                  virDomainChrTypeToString(def->type));
-        return -1;
-    }
-
-    /* vmx:yieldOnMsrRead */
-    /* FIXME: Based on VI Client GUI default */
-    virBufferVSprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
-                      def->target.port);
-
-    return 0;
-}
-
-
-
-int
-esxVMX_FormatParallel(esxVMX_Context *ctx, virDomainChrDefPtr def,
-                      virBufferPtr buffer)
-{
-    char *fileName = NULL;
-
-    if (def->target.port < 0 || def->target.port > 2) {
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Parallel port index %d out of [0..2] range"),
-                  def->target.port);
-        return -1;
-    }
-
-    virBufferVSprintf(buffer, "parallel%d.present = \"true\"\n",
-                      def->target.port);
-
-    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
-    switch (def->type) {
-      case VIR_DOMAIN_CHR_TYPE_DEV:
-        virBufferVSprintf(buffer, "parallel%d.fileType = \"device\"\n",
-                          def->target.port);
-        virBufferVSprintf(buffer, "parallel%d.fileName = \"%s\"\n",
-                          def->target.port, def->data.file.path);
-        break;
-
-      case VIR_DOMAIN_CHR_TYPE_FILE:
-        virBufferVSprintf(buffer, "parallel%d.fileType = \"file\"\n",
-                          def->target.port);
-
-        fileName = ctx->formatFileName(def->data.file.path, ctx->opaque);
-
-        if (fileName == NULL) {
-            return -1;
-        }
-
-        virBufferVSprintf(buffer, "parallel%d.fileName = \"%s\"\n",
-                          def->target.port, fileName);
-
-        VIR_FREE(fileName);
-        break;
-
-      default:
-        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                  _("Unsupported character device type '%s'"),
-                  virDomainChrTypeToString(def->type));
-        return -1;
-    }
-
-    return 0;
-}
diff --git a/src/esx/esx_vmx.h b/src/esx/esx_vmx.h
deleted file mode 100644 (file)
index 12fc5af..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-
-/*
- * esx_vmx.h: VMX related functions for the VMware ESX driver
- *
- * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
- *
- */
-
-#ifndef __ESX_VMX_H__
-# define __ESX_VMX_H__
-
-# include <stdbool.h>
-
-# include "internal.h"
-# include "conf.h"
-# include "domain_conf.h"
-# include "esx_vi.h"
-
-typedef struct _esxVMX_Context esxVMX_Context;
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Context
- */
-
-typedef char * (*esxVMX_ParseFileName)(const char *fileName, void *opaque);
-typedef char * (*esxVMX_FormatFileName)(const char *src, void *opaque);
-typedef int (*esxVMX_AutodetectSCSIControllerModel)(virDomainDiskDefPtr def,
-                                                    int *model, void *opaque);
-
-/*
- * esxVMX_ParseFileName is only used by esxVMX_ParseConfig.
- * esxVMX_FormatFileName is only used by esxVMX_FormatConfig.
- * esxVMX_AutodetectSCSIControllerModel is optionally used by esxVMX_FormatConfig.
- */
-struct _esxVMX_Context {
-    void *opaque;
-    esxVMX_ParseFileName parseFileName;
-    esxVMX_FormatFileName formatFileName;
-    esxVMX_AutodetectSCSIControllerModel autodetectSCSIControllerModel;
-};
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Helpers
- */
-
-int
-esxVMX_SCSIDiskNameToControllerAndUnit(const char *name, int *controller,
-                                       int *unit);
-
-int
-esxVMX_IDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit);
-
-int
-esxVMX_FloppyDiskNameToUnit(const char *name, int *unit);
-
-int
-esxVMX_VerifyDiskAddress(virCapsPtr caps, virDomainDiskDefPtr disk);
-
-int
-esxVMX_HandleLegacySCSIDiskDriverName(virDomainDefPtr def,
-                                      virDomainDiskDefPtr disk);
-
-int
-esxVMX_GatherSCSIControllers(esxVMX_Context *ctx, virDomainDefPtr def,
-                             int virtualDev[4], bool present[4]);
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * VMX -> Domain XML
- */
-
-virDomainDefPtr
-esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx,
-                   esxVI_ProductVersion productVersion);
-
-int
-esxVMX_ParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def);
-
-int
-esxVMX_ParseSCSIController(virConfPtr conf, int controller, bool *present,
-                           int *virtualDev);
-
-int
-esxVMX_ParseDisk(esxVMX_Context *ctx, virCapsPtr caps, virConfPtr conf,
-                 int device, int busType, int controllerOrBus, int unit,
-                 virDomainDiskDefPtr *def);
-int
-esxVMX_ParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def);
-
-int
-esxVMX_ParseSerial(esxVMX_Context *ctx, virConfPtr conf, int port,
-                   virDomainChrDefPtr *def);
-
-int
-esxVMX_ParseParallel(esxVMX_Context *ctx, virConfPtr conf, int port,
-                     virDomainChrDefPtr *def);
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Domain XML -> VMX
- */
-
-char *
-esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def,
-                    esxVI_ProductVersion productVersion);
-
-int
-esxVMX_FormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer);
-
-int
-esxVMX_FormatHardDisk(esxVMX_Context *ctx, virDomainDiskDefPtr def,
-                      virBufferPtr buffer);
-
-int
-esxVMX_FormatCDROM(esxVMX_Context *ctx, virDomainDiskDefPtr def,
-                   virBufferPtr buffer);
-
-int
-esxVMX_FormatFloppy(esxVMX_Context *ctx, virDomainDiskDefPtr def,
-                    virBufferPtr buffer, bool floppy_present[2]);
-
-int
-esxVMX_FormatEthernet(virDomainNetDefPtr def, int controller,
-                      virBufferPtr buffer);
-
-int
-esxVMX_FormatSerial(esxVMX_Context *ctx, virDomainChrDefPtr def,
-                    virBufferPtr buffer);
-
-int
-esxVMX_FormatParallel(esxVMX_Context *ctx, virDomainChrDefPtr def,
-                      virBufferPtr buffer);
-
-#endif /* __ESX_VMX_H__ */
diff --git a/src/libvirt_vmx.syms b/src/libvirt_vmx.syms
new file mode 100644 (file)
index 0000000..2c98f1f
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# These symbols are dependent upon --with-esx via WITH_ESX or --with-vmware via WITH_VMWARE.
+#
+
+# vmx.h
+virVMXConvertToUTF8;
+virVMXEscapeHex;
+virVMXFormatCDROM;
+virVMXFormatConfig;
+virVMXFormatEthernet;
+virVMXFormatFloppy;
+virVMXFormatHardDisk;
+virVMXFormatParallel;
+virVMXFormatSerial;
+virVMXFormatVNC;
+virVMXParseConfig;
+virVMXParseDisk;
+virVMXParseEthernet;
+virVMXParseParallel;
+virVMXParseSCSIController;
+virVMXParseSerial;
+virVMXParseVNC;
+virVMXUnescapeHex;
index 41747c900435f9463b83f4593845e60bbef232a1..c3f53ea9768a289c7234286f040054f25bda8689 100644 (file)
 #include "dirname.h"
 #include "memory.h"
 #include "nodeinfo.h"
-#include "util/files.h"
+#include "files.h"
 #include "uuid.h"
 #include "virterror_internal.h"
-#include "../esx/esx_vmx.h"
+#include "vmx.h"
 
 #include "vmware_conf.h"
 
@@ -137,13 +137,13 @@ vmwareLoadDomains(struct vmware_driver *driver)
     char *directoryName = NULL;
     char *fileName = NULL;
     int ret = -1;
-    esxVMX_Context ctx;
+    virVMXContext ctx;
     char *outbuf = NULL;
     char *str;
     char *saveptr = NULL;
     virCommandPtr cmd;
 
-    ctx.parseFileName = esxCopyVMXFileName;
+    ctx.parseFileName = vmwareCopyVMXFileName;
 
     cmd = virCommandNewArgList(VMRUN, "-T",
                                driver->type == TYPE_PLAYER ? "player" : "ws",
@@ -162,8 +162,7 @@ vmwareLoadDomains(struct vmware_driver *driver)
             goto cleanup;
 
         if ((vmdef =
-             esxVMX_ParseConfig(&ctx, driver->caps, vmx,
-                                esxVI_ProductVersion_ESX4x)) == NULL) {
+             virVMXParseConfig(&ctx, driver->caps, vmx)) == NULL) {
             goto cleanup;
         }
 
@@ -487,7 +486,7 @@ cleanup:
 }
 
 char *
-esxCopyVMXFileName(const char *datastorePath, void *opaque ATTRIBUTE_UNUSED)
+vmwareCopyVMXFileName(const char *datastorePath, void *opaque ATTRIBUTE_UNUSED)
 {
     char *path = strdup(datastorePath);
 
index b1cdf8fea402f6b6aeddcd88bfd2216f5e125b5e..e47ce62ca3dbd28bb0dd859d6a57ddc0ae2daec8 100644 (file)
@@ -78,6 +78,6 @@ int vmwareMakePath(char *srcDir, char *srcName, char *srcExt,
 
 int vmwareExtractPid(const char * vmxPath);
 
-char * esxCopyVMXFileName(const char *datastorePath, void *opaque);
+char *vmwareCopyVMXFileName(const char *datastorePath, void *opaque);
 
 #endif
index 9662f4607e6dc5627fa222a05ea15113ca987a96..47314f80835ee4e128292e0c5780a81d9c80e12a 100644 (file)
 
 #include <fcntl.h>
 
+#include "internal.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
 #include "files.h"
 #include "memory.h"
 #include "uuid.h"
-
-#include "../esx/esx_vmx.h"
+#include "vmx.h"
 #include "vmware_conf.h"
 #include "vmware_driver.h"
 
-const char *vmw_types[] = { "player", "ws" };
+static const char *vmw_types[] = { "player", "ws" };
 
 static void
 vmwareDriverLock(struct vmware_driver *driver)
@@ -244,9 +246,9 @@ vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
     char *fileName = NULL;
     char *vmxPath = NULL;
     vmwareDomainPtr pDomain = NULL;
-    esxVMX_Context ctx;
+    virVMXContext ctx;
 
-    ctx.formatFileName = esxCopyVMXFileName;
+    ctx.formatFileName = vmwareCopyVMXFileName;
 
     vmwareDriverLock(driver);
     if ((vmdef = virDomainDefParseString(driver->caps, xml,
@@ -257,8 +259,7 @@ vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
         goto cleanup;
 
     /* generate vmx file */
-    vmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef,
-                              esxVI_ProductVersion_ESX4x);
+    vmx = virVMXFormatConfig(&ctx, driver->caps, vmdef, 7);
     if (vmx == NULL)
         goto cleanup;
 
@@ -497,9 +498,9 @@ vmwareDomainCreateXML(virConnectPtr conn, const char *xml,
     char *vmx = NULL;
     char *vmxPath = NULL;
     vmwareDomainPtr pDomain = NULL;
-    esxVMX_Context ctx;
+    virVMXContext ctx;
 
-    ctx.formatFileName = esxCopyVMXFileName;
+    ctx.formatFileName = vmwareCopyVMXFileName;
 
     vmwareDriverLock(driver);
 
@@ -511,8 +512,7 @@ vmwareDomainCreateXML(virConnectPtr conn, const char *xml,
         goto cleanup;
 
     /* generate vmx file */
-    vmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef,
-                              esxVI_ProductVersion_ESX4x);
+    vmx = virVMXFormatConfig(&ctx, driver->caps, vmdef, 7);
     if (vmx == NULL)
         goto cleanup;
 
diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c
new file mode 100644 (file)
index 0000000..6e3e9af
--- /dev/null
@@ -0,0 +1,3647 @@
+
+/*
+ * vmx.c: VMware VMX parsing/formatting functions
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (C) 2009-2010 Matthias Bolte <matthias.bolte@googlemail.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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#include <config.h>
+
+#include <c-ctype.h>
+#include <libxml/uri.h>
+
+#include "internal.h"
+#include "virterror_internal.h"
+#include "conf.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "vmx.h"
+
+/*
+
+mapping:
+
+domain-xml                        <=>   vmx
+
+
+                                        config.version = "8"                    # essential
+                                        virtualHW.version = "4"                 # essential for ESX 3.5
+                                        virtualHW.version = "7"                 # essential for ESX 4.0
+
+
+???                               <=>   guestOS = "<value>"                     # essential, FIXME: not representable
+def->id = <value>                 <=>   ???                                     # not representable
+def->uuid = <value>               <=>   uuid.bios = "<value>"
+def->name = <value>               <=>   displayName = "<value>"
+def->mem.max_balloon = <value kilobyte>    <=>   memsize = "<value megabyte>"            # must be a multiple of 4, defaults to 32
+def->mem.cur_balloon = <value kilobyte>    <=>   sched.mem.max = "<value megabyte>"      # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
+def->mem.min_guarantee = <value kilobyte>  <=>   sched.mem.minsize = "<value megabyte>"  # defaults to 0
+def->maxvcpus = <value>           <=>   numvcpus = "<value>"                    # must be 1 or a multiple of 2, defaults to 1
+def->cpumask = <uint list>        <=>   sched.cpu.affinity = "<uint list>"
+
+
+
+################################################################################
+## os ##########################################################################
+
+def->os
+
+->type = "hvm"
+->arch = <arch>                   <=>   guestOS = "<value>"                     # if <value> ends with -64 than <arch> is x86_64, otherwise <arch> is i686
+->machine
+->nBootDevs
+->bootDevs
+->init
+->kernel
+->initrd
+->cmdline
+->root
+->loader
+->bootloader
+->bootloaderArgs
+->smbios_mode                     <=>   smbios.reflecthost = "<value>"          # <value> == true means SMBIOS_HOST, otherwise it's SMBIOS_EMULATE, defaults to "false"
+
+
+
+################################################################################
+## disks #######################################################################
+
+                                        scsi[0..3]:[0..6,8..15] -> <controller>:<unit> with 1 bus per controller
+                                        ide[0..1]:[0..1]        -> <bus>:<unit> with 1 controller
+                                        floppy[0..1]            -> <unit> with 1 controller and 1 bus per controller
+
+def->disks[0]...
+
+## disks: scsi hard drive from .vmdk image #####################################
+
+                                        scsi0.present = "true"                  # defaults to "false"
+                                        scsi0:0.present = "true"                # defaults to "false"
+                                        scsi0:0.startConnected = "true"         # defaults to "true"
+
+???                               <=>   scsi0:0.mode = "persistent"             # defaults to "persistent"
+                                        scsi0:0.mode = "undoable"
+                                        scsi0:0.mode = "independent-persistent"
+                                        scsi0:0.mode = "independent-nonpersistent"
+
+...
+->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
+->device = _DISK_DEVICE_DISK      <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
+->bus = _DISK_BUS_SCSI
+->src = <value>.vmdk              <=>   scsi0:0.fileName = "<value>.vmdk"
+->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
+->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
+->driverType
+->cachemode                       <=>   scsi0:0.writeThrough = "<value>"        # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
+->readonly
+->shared
+->slotnum
+
+
+## disks: ide hard drive from .vmdk image ######################################
+
+                                        ide0:0.present = "true"                 # defaults to "false"
+                                        ide0:0.startConnected = "true"          # defaults to "true"
+
+???                               <=>   ide0:0.mode = "persistent"              # defaults to "persistent"
+                                        ide0:0.mode = "undoable"
+                                        ide0:0.mode = "independent-persistent"
+                                        ide0:0.mode = "independent-nonpersistent"
+
+...
+->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
+->device = _DISK_DEVICE_DISK      <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
+->bus = _DISK_BUS_IDE
+->src = <value>.vmdk              <=>   ide0:0.fileName = "<value>.vmdk"
+->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
+->driverName
+->driverType
+->cachemode                       <=>   ide0:0.writeThrough = "<value>"         # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
+->readonly
+->shared
+->slotnum
+
+
+## disks: scsi cdrom from .iso image ###########################################
+
+                                        scsi0.present = "true"                  # defaults to "false"
+                                        scsi0:0.present = "true"                # defaults to "false"
+                                        scsi0:0.startConnected = "true"         # defaults to "true"
+
+...
+->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
+->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
+->bus = _DISK_BUS_SCSI
+->src = <value>.iso               <=>   scsi0:0.fileName = "<value>.iso"
+->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
+->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
+->driverType
+->cachemode
+->readonly
+->shared
+->slotnum
+
+
+## disks: ide cdrom from .iso image ############################################
+
+                                        ide0:0.present = "true"                 # defaults to "false"
+                                        ide0:0.startConnected = "true"          # defaults to "true"
+
+...
+->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
+->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
+->bus = _DISK_BUS_IDE
+->src = <value>.iso               <=>   ide0:0.fileName = "<value>.iso"
+->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
+->driverName
+->driverType
+->cachemode
+->readonly
+->shared
+->slotnum
+
+
+## disks: scsi cdrom from host device ##########################################
+
+                                        scsi0.present = "true"                  # defaults to "false"
+                                        scsi0:0.present = "true"                # defaults to "false"
+                                        scsi0:0.startConnected = "true"         # defaults to "true"
+
+...
+->type = _DISK_TYPE_BLOCK         <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
+->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
+->bus = _DISK_BUS_SCSI
+->src = <value>                   <=>   scsi0:0.fileName = "<value>"            # e.g. "/dev/scd0" ?
+->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
+->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
+->driverType
+->cachemode
+->readonly
+->shared
+->slotnum
+
+
+## disks: ide cdrom from host device ###########################################
+
+                                        ide0:0.present = "true"                 # defaults to "false"
+                                        ide0:0.startConnected = "true"          # defaults to "true"
+                                        ide0:0.clientDevice = "false"           # defaults to "false"
+
+...
+->type = _DISK_TYPE_BLOCK         <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
+->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
+->bus = _DISK_BUS_IDE
+->src = <value>                   <=>   ide0:0.fileName = "<value>"             # e.g. "/dev/scd0"
+->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
+->driverName
+->driverType
+->cachemode
+->readonly
+->shared
+->slotnum
+
+
+## disks: floppy from .flp image ###############################################
+
+                                        floppy0.present = "true"                # defaults to "true"
+                                        floppy0.startConnected = "true"         # defaults to "true"
+                                        floppy0.clientDevice = "false"          # defaults to "false"
+
+...
+->type = _DISK_TYPE_FILE          <=>   floppy0.fileType = "file"               # defaults to ?
+->device = _DISK_DEVICE_FLOPPY
+->bus = _DISK_BUS_FDC
+->src = <value>.flp               <=>   floppy0.fileName = "<value>.flp"
+->dst = fd[<unit> mapped to [a-z]+]
+->driverName
+->driverType
+->cachemode
+->readonly
+->shared
+->slotnum
+
+
+## disks: floppy from host device ##############################################
+
+                                        floppy0.present = "true"                # defaults to "true"
+                                        floppy0.startConnected = "true"         # defaults to "true"
+                                        floppy0.clientDevice = "false"          # defaults to "false"
+
+...
+->type = _DISK_TYPE_BLOCK         <=>   floppy0.fileType = "device"             # defaults to ?
+->device = _DISK_DEVICE_FLOPPY
+->bus = _DISK_BUS_FDC
+->src = <value>                   <=>   floppy0.fileName = "<value>"            # e.g. "/dev/fd0"
+->dst = fd[<unit> mapped to [a-z]+]
+->driverName
+->driverType
+->cachemode
+->readonly
+->shared
+->slotnum
+
+
+
+################################################################################
+## nets ########################################################################
+
+                                        ethernet[0..3] -> <controller>
+
+                                        ethernet0.present = "true"              # defaults to "false"
+                                        ethernet0.startConnected = "true"       # defaults to "true"
+
+                                        ethernet0.networkName = "VM Network"    # FIXME
+
+def->nets[0]...
+->model = <model>                 <=>   ethernet0.virtualDev = "<model>"        # default depends on guestOS value
+                                        ethernet0.features = "15"               # if present and virtualDev is "vmxnet" => vmxnet2 (enhanced)
+
+
+                                        ethernet0.addressType = "generated"     # default to "generated"
+->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
+                                        ethernet0.generatedAddressOffset = "0"  # ?
+
+
+                                        ethernet0.addressType = "static"        # default to "generated"
+->mac = <value>                   <=>   ethernet0.address = "<value>"
+
+
+                                        ethernet0.addressType = "vpx"           # default to "generated"
+->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
+
+
+                                        ethernet0.addressType = "static"        # default to "generated"
+->mac = <value>                   <=>   ethernet0.address = "<value>"
+                                        ethernet0.checkMACAddress = "false"     # mac address outside the VMware prefixes
+
+                                                                                # 00:0c:29 prefix for autogenerated mac's -> ethernet0.addressType = "generated"
+                                                                                # 00:50:56 prefix for manual configured mac's
+                                                                                #          00:50:56:00:00:00 - 00:50:56:3f:ff:ff -> ethernet0.addressType = "static"
+                                                                                #          00:50:56:80:00:00 - 00:50:56:bf:ff:ff -> ethernet0.addressType = "vpx"
+                                                                                # 00:05:69 old prefix from esx 1.5
+
+
+## nets: bridged ###############################################################
+
+...
+->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "bridged"    # defaults to "bridged"
+->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
+
+
+## nets: hostonly ##############################################################
+
+...                                                                             # FIXME: Investigate if ESX supports this
+->type = _NET_TYPE_NETWORK        <=>   ethernet0.connectionType = "hostonly"   # defaults to "bridged"
+
+
+## nets: nat ###################################################################
+
+...                                                                             # FIXME: Investigate if ESX supports this
+->type = _NET_TYPE_USER           <=>   ethernet0.connectionType = "nat"        # defaults to "bridged"
+
+
+## nets: custom ################################################################
+
+...
+->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "custom"     # defaults to "bridged"
+->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
+->ifname = <value>                <=>   ethernet0.vnet = "<value>"
+
+
+
+################################################################################
+## serials #####################################################################
+
+                                        serial[0..3] -> <port>
+
+                                        serial0.present = "true"                # defaults to "false"
+                                        serial0.startConnected = "true"         # defaults to "true"
+
+def->serials[0]...
+->target.port = <port>
+
+
+## serials: device #############################################################
+
+->type = _CHR_TYPE_DEV            <=>   serial0.fileType = "device"
+->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "/dev/ttyS0"
+???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+
+## serials: file ###############################################################
+
+->type = _CHR_TYPE_FILE           <=>   serial0.fileType = "file"
+->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.file"
+???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+
+## serials: pipe, far end -> app ###############################################
+
+->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
+->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
+???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
+???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
+->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
+???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
+???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+
+## serials: pipe, far end -> vm ################################################
+
+->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
+->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
+???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
+???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
+->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
+???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
+???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+
+## serials: network, server (since vSphere 4.1) ################################
+
+->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"
+
+->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
+->data.tcp.service = <service>                                                  # e.g. "telnet://0.0.0.0:42001"
+->data.tcp.protocol = <protocol>
+
+->data.tcp.listen = 1             <=>   serial0.network.endPoint = "server"     # defaults to "server"
+
+???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
+???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+
+## serials: network, client (since vSphere 4.1) ################################
+
+->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"
+
+->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
+->data.tcp.service = <service>                                                  # e.g. "telnet://192.168.0.17:42001"
+->data.tcp.protocol = <protocol>
+
+->data.tcp.listen = 0             <=>   serial0.network.endPoint = "client"     # defaults to "server"
+
+???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
+???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
+???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
+
+
+
+################################################################################
+## parallels ###################################################################
+
+                                        parallel[0..2] -> <port>
+
+                                        parallel0.present = "true"              # defaults to "false"
+                                        parallel0.startConnected = "true"       # defaults to "true"
+
+def->parallels[0]...
+->target.port = <port>
+
+
+## parallels: device #############################################################
+
+->type = _CHR_TYPE_DEV            <=>   parallel0.fileType = "device"
+->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "/dev/parport0"
+???                               <=>   parallel0.bidirectional = "<value>"     # defaults to ?, FIXME: not representable
+
+
+## parallels: file #############################################################
+
+->type = _CHR_TYPE_FILE           <=>   parallel0.fileType = "file"
+->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "parallel0.file"
+???                               <=>   parallel0.bidirectional = "<value>"     # must be "false" for fileType = "file", FIXME: not representable
+
+
+
+################################################################################
+## sound #######################################################################
+
+                                        sound.present = "true"                  # defaults to "false"
+                                        sound.startConnected = "true"           # defaults to "true"
+                                        sound.autodetect = "true"
+                                        sound.fileName = "-1"
+
+                                        FIXME: Investigate if ESX supports this,
+                                               at least the VI Client GUI has no
+                                               options to add a sound device, but
+                                               the VI API contains a VirtualSoundCard
+
+*/
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define VMX_ERROR(code, ...)                                                  \
+    virReportErrorHelper(NULL, VIR_FROM_NONE, code, __FILE__, __FUNCTION__,   \
+                         __LINE__, __VA_ARGS__)
+
+#define VMX_BUILD_NAME_EXTRA(_suffix, _extra)                                 \
+    snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."_extra, prefix);
+
+#define VMX_BUILD_NAME(_suffix)                                               \
+    VMX_BUILD_NAME_EXTRA(_suffix, #_suffix)
+
+/* directly map the virDomainControllerModel to virVMXSCSIControllerModel,
+ * this is good enough for now because all virDomainControllerModel values
+ * are actually SCSI controller models in the ESX case */
+VIR_ENUM_DECL(virVMXSCSIControllerModel)
+VIR_ENUM_IMPL(virVMXSCSIControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST,
+              "auto", /* just to match virDomainControllerModel, will never be used */
+              "buslogic",
+              "lsilogic",
+              "lsisas1068",
+              "pvscsi");
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Helpers
+ */
+
+char *
+virVMXEscapeHex(const char *string, char escape, const char *special)
+{
+    char *escaped = NULL;
+    size_t length = 1; /* 1 byte for termination */
+    const char *tmp1 = string;
+    char *tmp2;
+
+    /* Calculate length of escaped string */
+    while (*tmp1 != '\0') {
+        if (*tmp1 == escape || strspn(tmp1, special) > 0) {
+            length += 2;
+        }
+
+        ++tmp1;
+        ++length;
+    }
+
+    if (VIR_ALLOC_N(escaped, length) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    tmp1 = string; /* reading from this one */
+    tmp2 = escaped; /* writing to this one */
+
+    /* Escape to 'cXX' where c is the escape char and X is a hex digit */
+    while (*tmp1 != '\0') {
+        if (*tmp1 == escape || strspn(tmp1, special) > 0) {
+            *tmp2++ = escape;
+
+            snprintf(tmp2, 3, "%02x", (unsigned int)*tmp1);
+
+            tmp2 += 2;
+        } else {
+            *tmp2++ = *tmp1;
+        }
+
+        ++tmp1;
+    }
+
+    *tmp2 = '\0';
+
+    return escaped;
+}
+
+
+
+int
+virVMXUnescapeHex(char *string, char escape)
+{
+    char *tmp1 = string; /* reading from this one */
+    char *tmp2 = string; /* writing to this one */
+
+    /* Unescape from 'cXX' where c is the escape char and X is a hex digit */
+    while (*tmp1 != '\0') {
+        if (*tmp1 == escape) {
+            if (!c_isxdigit(tmp1[1]) || !c_isxdigit(tmp1[2])) {
+                return -1;
+            }
+
+            *tmp2++ = virHexToBin(tmp1[1]) * 16 + virHexToBin(tmp1[2]);
+            tmp1 += 3;
+        } else {
+            *tmp2++ = *tmp1++;
+        }
+    }
+
+    *tmp2 = '\0';
+
+    return 0;
+}
+
+
+
+char *
+virVMXConvertToUTF8(const char *encoding, const char *string)
+{
+    char *result = NULL;
+    xmlCharEncodingHandlerPtr handler;
+    xmlBufferPtr input;
+    xmlBufferPtr utf8;
+
+    handler = xmlFindCharEncodingHandler(encoding);
+
+    if (handler == NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("libxml2 doesn't handle %s encoding"), encoding);
+        return NULL;
+    }
+
+    input = xmlBufferCreateStatic((char *)string, strlen(string));
+    utf8 = xmlBufferCreate();
+
+    if (xmlCharEncInFunc(handler, utf8, input) < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Could not convert from %s to UTF-8 encoding"), encoding);
+        goto cleanup;
+    }
+
+    result = (char *)utf8->content;
+    utf8->content = NULL;
+
+  cleanup:
+    xmlCharEncCloseFunc(handler);
+    xmlBufferFree(input);
+    xmlBufferFree(utf8);
+
+    return result;
+}
+
+
+
+static int
+virVMXGetConfigString(virConfPtr conf, const char *name, char **string,
+                      bool optional)
+{
+    virConfValuePtr value;
+
+    *string = NULL;
+    value = virConfGetValue(conf, name);
+
+    if (value == NULL) {
+        if (optional) {
+            return 0;
+        }
+
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Missing essential config entry '%s'"), name);
+        return -1;
+    }
+
+    if (value->type != VIR_CONF_STRING) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Config entry '%s' must be a string"), name);
+        return -1;
+    }
+
+    if (value->str == NULL) {
+        if (optional) {
+            return 0;
+        }
+
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Missing essential config entry '%s'"), name);
+        return -1;
+    }
+
+    *string = strdup(value->str);
+
+    if (*string == NULL) {
+        virReportOOMError();
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+virVMXGetConfigUUID(virConfPtr conf, const char *name, unsigned char *uuid,
+                    bool optional)
+{
+    virConfValuePtr value;
+
+    value = virConfGetValue(conf, name);
+
+    if (value == NULL) {
+        if (optional) {
+            return 0;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Missing essential config entry '%s'"), name);
+            return -1;
+        }
+    }
+
+    if (value->type != VIR_CONF_STRING) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Config entry '%s' must be a string"), name);
+        return -1;
+    }
+
+    if (value->str == NULL) {
+        if (optional) {
+            return 0;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Missing essential config entry '%s'"), name);
+            return -1;
+        }
+    }
+
+    if (virUUIDParse(value->str, uuid) < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Could not parse UUID from string '%s'"), value->str);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+virVMXGetConfigLong(virConfPtr conf, const char *name, long long *number,
+                    long long default_, bool optional)
+{
+    virConfValuePtr value;
+
+    *number = default_;
+    value = virConfGetValue(conf, name);
+
+    if (value == NULL) {
+        if (optional) {
+            return 0;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Missing essential config entry '%s'"), name);
+            return -1;
+        }
+    }
+
+    if (value->type == VIR_CONF_STRING) {
+        if (value->str == NULL) {
+            if (optional) {
+                return 0;
+            } else {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Missing essential config entry '%s'"), name);
+                return -1;
+            }
+        }
+
+        if (STREQ(value->str, "unlimited")) {
+            *number = -1;
+        } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Config entry '%s' must represent an integer value"),
+                      name);
+            return -1;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Config entry '%s' must be a string"), name);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+virVMXGetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_,
+                       bool default_, bool optional)
+{
+    virConfValuePtr value;
+
+    *boolean_ = default_;
+    value = virConfGetValue(conf, name);
+
+    if (value == NULL) {
+        if (optional) {
+            return 0;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Missing essential config entry '%s'"), name);
+            return -1;
+        }
+    }
+
+    if (value->type == VIR_CONF_STRING) {
+        if (value->str == NULL) {
+            if (optional) {
+                return 0;
+            } else {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Missing essential config entry '%s'"), name);
+                return -1;
+            }
+        }
+
+        if (STRCASEEQ(value->str, "true")) {
+            *boolean_ = 1;
+        } else if (STRCASEEQ(value->str, "false")) {
+            *boolean_ = 0;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Config entry '%s' must represent a boolean value "
+                        "(true|false)"), name);
+            return -1;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Config entry '%s' must be a string"), name);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+virVMXSCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
+{
+    int idx;
+
+    if (! STRPREFIX(name, "sd")) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Expecting domain XML attribute 'dev' of entry "
+                    "'devices/disk/target' to start with 'sd'"));
+        return -1;
+    }
+
+    idx = virDiskNameToIndex(name);
+
+    if (idx < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Could not parse valid disk index from '%s'"), name);
+        return -1;
+    }
+
+    /* Each of the 4 SCSI controllers has 1 bus with 15 units each for devices */
+    if (idx >= (4 * 15)) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("SCSI disk index (parsed from '%s') is too large"), name);
+        return -1;
+    }
+
+    *controller = idx / 15;
+    *unit = idx % 15;
+
+    /* Skip the controller ifself at unit 7 */
+    if (*unit >= 7) {
+        ++(*unit);
+    }
+
+    return 0;
+}
+
+
+
+static int
+virVMXIDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
+{
+    int idx;
+
+    if (! STRPREFIX(name, "hd")) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Expecting domain XML attribute 'dev' of entry "
+                    "'devices/disk/target' to start with 'hd'"));
+        return -1;
+    }
+
+    idx = virDiskNameToIndex(name);
+
+    if (idx < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Could not parse valid disk index from '%s'"), name);
+        return -1;
+    }
+
+    /* The IDE controller has 2 buses with 2 units each for devices */
+    if (idx >= (2 * 2)) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("IDE disk index (parsed from '%s') is too large"), name);
+        return -1;
+    }
+
+    *bus = idx / 2;
+    *unit = idx % 2;
+
+    return 0;
+}
+
+
+
+static int
+virVMXFloppyDiskNameToUnit(const char *name, int *unit)
+{
+    int idx;
+
+    if (! STRPREFIX(name, "fd")) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Expecting domain XML attribute 'dev' of entry "
+                    "'devices/disk/target' to start with 'fd'"));
+        return -1;
+    }
+
+    idx = virDiskNameToIndex(name);
+
+    if (idx < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Could not parse valid disk index from '%s'"), name);
+        return -1;
+    }
+
+    /* The FDC controller has 1 bus with 2 units for devices */
+    if (idx >= 2) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Floppy disk index (parsed from '%s') is too large"), name);
+        return -1;
+    }
+
+    *unit = idx;
+
+    return 0;
+}
+
+
+
+static int
+virVMXVerifyDiskAddress(virCapsPtr caps, virDomainDiskDefPtr disk)
+{
+    virDomainDiskDef def;
+    virDomainDeviceDriveAddressPtr drive;
+
+    memset(&def, 0, sizeof(def));
+
+    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unsupported disk address type '%s'"),
+                  virDomainDeviceAddressTypeToString(disk->info.type));
+        return -1;
+    }
+
+    drive = &disk->info.addr.drive;
+
+    def.dst = disk->dst;
+    def.bus = disk->bus;
+
+    if (virDomainDiskDefAssignAddress(caps, &def) < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Could not verify disk address"));
+        return -1;
+    }
+
+    if (def.info.addr.drive.controller != drive->controller ||
+        def.info.addr.drive.bus != drive->bus ||
+        def.info.addr.drive.unit != drive->unit) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Disk address %d:%d:%d doesn't match target device '%s'"),
+                  drive->controller, drive->bus, drive->unit, disk->dst);
+        return -1;
+    }
+
+    /* drive->{controller|bus|unit} is unsigned, no >= 0 checks are necessary */
+    if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+        if (drive->controller > 3) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("SCSI controller index %d out of [0..3] range"),
+                      drive->controller);
+            return -1;
+        }
+
+        if (drive->bus != 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("SCSI bus index %d out of [0] range"),
+                      drive->bus);
+            return -1;
+        }
+
+        if (drive->unit > 15 || drive->unit == 7) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("SCSI unit index %d out of [0..6,8..15] range"),
+                      drive->unit);
+            return -1;
+        }
+    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+        if (drive->controller != 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("IDE controller index %d out of [0] range"),
+                      drive->controller);
+            return -1;
+        }
+
+        if (drive->bus > 1) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("IDE bus index %d out of [0..1] range"),
+                      drive->bus);
+            return -1;
+        }
+
+        if (drive->unit > 1) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("IDE unit index %d out of [0..1] range"),
+                      drive->unit);
+            return -1;
+        }
+    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
+        if (drive->controller != 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("FDC controller index %d out of [0] range"),
+                      drive->controller);
+            return -1;
+        }
+
+        if (drive->bus != 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("FDC bus index %d out of [0] range"),
+                      drive->bus);
+            return -1;
+        }
+
+        if (drive->unit > 1) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("FDC unit index %d out of [0..1] range"),
+                      drive->unit);
+            return -1;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unsupported bus type '%s'"),
+                  virDomainDiskBusTypeToString(disk->bus));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def,
+                                     virDomainDiskDefPtr disk)
+{
+    char *tmp;
+    int model, i;
+    virDomainControllerDefPtr controller = NULL;
+
+    if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI || disk->driverName == NULL) {
+        return 0;
+    }
+
+    tmp = disk->driverName;
+
+    for (; *tmp != '\0'; ++tmp) {
+        *tmp = c_tolower(*tmp);
+    }
+
+    model = virDomainControllerModelTypeFromString(disk->driverName);
+
+    if (model < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unknown driver name '%s'"), disk->driverName);
+        return -1;
+    }
+
+    for (i = 0; i < def->ncontrollers; ++i) {
+        if (def->controllers[i]->idx == disk->info.addr.drive.controller) {
+            controller = def->controllers[i];
+            break;
+        }
+    }
+
+    if (controller == NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Missing SCSI controller for index %d"),
+                  disk->info.addr.drive.controller);
+        return -1;
+    }
+
+    if (controller->model == -1) {
+        controller->model = model;
+    } else if (controller->model != model) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Inconsistent SCSI controller model ('%s' is not '%s') "
+                    "for SCSI controller index %d"), disk->driverName,
+                  virDomainControllerModelTypeToString(controller->model),
+                  controller->idx);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def,
+                            int virtualDev[4], bool present[4])
+{
+    int result = -1;
+    int i, k;
+    virDomainDiskDefPtr disk;
+    virDomainControllerDefPtr controller;
+    bool controllerHasDisksAttached;
+    int count = 0;
+    int *autodetectedModels;
+
+    if (VIR_ALLOC_N(autodetectedModels, def->ndisks) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    for (i = 0; i < def->ncontrollers; ++i) {
+        controller = def->controllers[i];
+
+        if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
+            // skip non-SCSI controllers
+            continue;
+        }
+
+        controllerHasDisksAttached = false;
+
+        for (k = 0; k < def->ndisks; ++k) {
+            disk = def->disks[k];
+
+            if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
+                disk->info.addr.drive.controller == controller->idx) {
+                controllerHasDisksAttached = true;
+                break;
+            }
+        }
+
+        if (! controllerHasDisksAttached) {
+            // skip SCSI controllers without attached disks
+            continue;
+        }
+
+        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_AUTO &&
+            ctx->autodetectSCSIControllerModel != NULL) {
+            count = 0;
+
+            // try to autodetect the SCSI controller model by collecting
+            // SCSI controller model of all disks attached to this controller
+            for (k = 0; k < def->ndisks; ++k) {
+                disk = def->disks[k];
+
+                if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
+                    disk->info.addr.drive.controller == controller->idx) {
+                    if (ctx->autodetectSCSIControllerModel
+                               (disk, &autodetectedModels[count],
+                                ctx->opaque) < 0) {
+                        goto cleanup;
+                    }
+
+                    ++count;
+                }
+            }
+
+            // autodetection fails when the disks attached to one controller
+            // have inconsistent SCSI controller models
+            for (k = 0; k < count; ++k) {
+                if (autodetectedModels[k] != autodetectedModels[0]) {
+                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                              _("Disks on SCSI controller %d have inconsistent "
+                                "controller models, cannot autodetect model"),
+                              controller->idx);
+                    goto cleanup;
+                }
+            }
+
+            controller->model = autodetectedModels[0];
+        }
+
+        if (controller->model != -1 &&
+            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC &&
+            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC &&
+            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 &&
+            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting domain XML attribute 'model' of entry "
+                        "'controller' to be 'buslogic' or 'lsilogic' or "
+                        "'lsisas1068' or 'vmpvscsi' but found '%s'"),
+                      virDomainControllerModelTypeToString(controller->model));
+            goto cleanup;
+        }
+
+        present[controller->idx] = true;
+        virtualDev[controller->idx] = controller->model;
+    }
+
+    result = 0;
+
+  cleanup:
+    VIR_FREE(autodetectedModels);
+
+    return result;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VMX -> Domain XML
+ */
+
+virDomainDefPtr
+virVMXParseConfig(virVMXContext *ctx, virCapsPtr caps, const char *vmx)
+{
+    bool success = false;
+    virConfPtr conf = NULL;
+    char *encoding = NULL;
+    char *utf8;
+    virDomainDefPtr def = NULL;
+    long long config_version = 0;
+    long long virtualHW_version = 0;
+    long long memsize = 0;
+    long long sched_mem_max = 0;
+    long long sched_mem_minsize = 0;
+    long long numvcpus = 0;
+    char *sched_cpu_affinity = NULL;
+    char *guestOS = NULL;
+    bool smbios_reflecthost = false;
+    int controller;
+    int bus;
+    int port;
+    bool present;
+    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
+    int unit;
+
+    if (ctx->parseFileName == NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("virVMXContext has no parseFileName function set"));
+        return NULL;
+    }
+
+    conf = virConfReadMem(vmx, strlen(vmx), VIR_CONF_FLAG_VMX_FORMAT);
+
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    /* vmx:.encoding */
+    if (virVMXGetConfigString(conf, ".encoding", &encoding, true) < 0) {
+        goto cleanup;
+    }
+
+    if (encoding == NULL || STRCASEEQ(encoding, "UTF-8")) {
+        /* nothing */
+    } else {
+        virConfFree(conf);
+        conf = NULL;
+
+        utf8 = virVMXConvertToUTF8(encoding, vmx);
+
+        if (utf8 == NULL) {
+            goto cleanup;
+        }
+
+        conf = virConfReadMem(utf8, strlen(utf8), VIR_CONF_FLAG_VMX_FORMAT);
+
+        VIR_FREE(utf8);
+
+        if (conf == NULL) {
+            goto cleanup;
+        }
+    }
+
+    /* Allocate domain def */
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    def->virtType = VIR_DOMAIN_VIRT_VMWARE;
+    def->id = -1;
+
+    /* vmx:config.version */
+    if (virVMXGetConfigLong(conf, "config.version", &config_version, 0,
+                            false) < 0) {
+        goto cleanup;
+    }
+
+    if (config_version != 8) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting VMX entry 'config.version' to be 8 but found "
+                    "%lld"), config_version);
+        goto cleanup;
+    }
+
+    /* vmx:virtualHW.version */
+    if (virVMXGetConfigLong(conf, "virtualHW.version", &virtualHW_version, 0,
+                            false) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualHW_version != 4 && virtualHW_version != 7) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting VMX entry 'virtualHW.version' to be 4 or 7 "
+                    "but found %lld"),
+                  virtualHW_version);
+        goto cleanup;
+    }
+
+    /* vmx:uuid.bios -> def:uuid */
+    /* FIXME: Need to handle 'uuid.action = "create"' */
+    if (virVMXGetConfigUUID(conf, "uuid.bios", def->uuid, true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:displayName -> def:name */
+    if (virVMXGetConfigString(conf, "displayName", &def->name, true) < 0) {
+        goto cleanup;
+    }
+
+    if (def->name != NULL) {
+        if (virVMXUnescapeHexPercent(def->name) < 0 ||
+            virVMXUnescapeHexPipe(def->name) < 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                      _("VMX entry 'name' contains invalid escape sequence"));
+            goto cleanup;
+        }
+    }
+
+    /* vmx:annotation -> def:description */
+    if (virVMXGetConfigString(conf, "annotation", &def->description,
+                              true) < 0) {
+        goto cleanup;
+    }
+
+    if (def->description != NULL) {
+        if (virVMXUnescapeHexPipe(def->description) < 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                      _("VMX entry 'annotation' contains invalid escape "
+                        "sequence"));
+            goto cleanup;
+        }
+    }
+
+    /* vmx:memsize -> def:mem.max_balloon */
+    if (virVMXGetConfigLong(conf, "memsize", &memsize, 32, true) < 0) {
+        goto cleanup;
+    }
+
+    if (memsize <= 0 || memsize % 4 != 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting VMX entry 'memsize' to be an unsigned "
+                    "integer (multiple of 4) but found %lld"), memsize);
+        goto cleanup;
+    }
+
+    def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */
+
+    /* vmx:sched.mem.max -> def:mem.cur_balloon */
+    if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize,
+                            true) < 0) {
+        goto cleanup;
+    }
+
+    if (sched_mem_max < 0) {
+        sched_mem_max = memsize;
+    }
+
+    def->mem.cur_balloon = sched_mem_max * 1024; /* Scale from megabytes to kilobytes */
+
+    if (def->mem.cur_balloon > def->mem.max_balloon) {
+        def->mem.cur_balloon = def->mem.max_balloon;
+    }
+
+    /* vmx:sched.mem.minsize -> def:mem.min_guarantee */
+    if (virVMXGetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0,
+                            true) < 0) {
+        goto cleanup;
+    }
+
+    if (sched_mem_minsize < 0) {
+        sched_mem_minsize = 0;
+    }
+
+    def->mem.min_guarantee = sched_mem_minsize * 1024; /* Scale from megabytes to kilobytes */
+
+    if (def->mem.min_guarantee > def->mem.max_balloon) {
+        def->mem.min_guarantee = def->mem.max_balloon;
+    }
+
+    /* vmx:numvcpus -> def:vcpus */
+    if (virVMXGetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0) {
+        goto cleanup;
+    }
+
+    if (numvcpus <= 0 || (numvcpus % 2 != 0 && numvcpus != 1)) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting VMX entry 'numvcpus' to be an unsigned "
+                    "integer (1 or a multiple of 2) but found %lld"), numvcpus);
+        goto cleanup;
+    }
+
+    def->maxvcpus = def->vcpus = numvcpus;
+
+    /* vmx:sched.cpu.affinity -> def:cpumask */
+    // VirtualMachine:config.cpuAffinity.affinitySet
+    if (virVMXGetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
+                              true) < 0) {
+        goto cleanup;
+    }
+
+    if (sched_cpu_affinity != NULL && STRNEQ(sched_cpu_affinity, "all")) {
+        const char *current = sched_cpu_affinity;
+        int number, count = 0;
+
+        def->cpumasklen = 0;
+
+        if (VIR_ALLOC_N(def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        while (*current != '\0') {
+            virSkipSpaces(&current);
+
+            number = virParseNumber(&current);
+
+            if (number < 0) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Expecting VMX entry 'sched.cpu.affinity' to be "
+                            "a comma separated list of unsigned integers but "
+                            "found '%s'"), sched_cpu_affinity);
+                goto cleanup;
+            }
+
+            if (number >= VIR_DOMAIN_CPUMASK_LEN) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("VMX entry 'sched.cpu.affinity' contains a %d, "
+                            "this value is too large"), number);
+                goto cleanup;
+            }
+
+            if (number + 1 > def->cpumasklen) {
+                def->cpumasklen = number + 1;
+            }
+
+            def->cpumask[number] = 1;
+            ++count;
+
+            virSkipSpaces(&current);
+
+            if (*current == ',') {
+                ++current;
+            } else if (*current == '\0') {
+                break;
+            } else {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Expecting VMX entry 'sched.cpu.affinity' to be "
+                            "a comma separated list of unsigned integers but "
+                            "found '%s'"), sched_cpu_affinity);
+                goto cleanup;
+            }
+
+            virSkipSpaces(&current);
+        }
+
+        if (count < numvcpus) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting VMX entry 'sched.cpu.affinity' to contain "
+                        "at least as many values as 'numvcpus' (%lld) but "
+                        "found only %d value(s)"), numvcpus, count);
+            goto cleanup;
+        }
+    }
+
+    /* def:lifecycle */
+    def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
+    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
+    def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
+
+    /* def:os */
+    def->os.type = strdup("hvm");
+
+    if (def->os.type == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* vmx:guestOS -> def:os.arch */
+    if (virVMXGetConfigString(conf, "guestOS", &guestOS, true) < 0) {
+        goto cleanup;
+    }
+
+    if (guestOS != NULL && virFileHasSuffix(guestOS, "-64")) {
+        def->os.arch = strdup("x86_64");
+    } else {
+        def->os.arch = strdup("i686");
+    }
+
+    if (def->os.arch == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* vmx:smbios.reflecthost -> def:os.smbios_mode */
+    if (virVMXGetConfigBoolean(conf, "smbios.reflecthost",
+                               &smbios_reflecthost, false, true) < 0) {
+        goto cleanup;
+    }
+
+    if (smbios_reflecthost) {
+        def->os.smbios_mode = VIR_DOMAIN_SMBIOS_HOST;
+    }
+
+    /* def:features */
+    /* FIXME */
+
+    /* def:clock */
+    /* FIXME */
+
+    /* def:graphics */
+    if (VIR_ALLOC_N(def->graphics, 1) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->ngraphics = 0;
+
+    if (virVMXParseVNC(conf, &def->graphics[def->ngraphics]) < 0) {
+        goto cleanup;
+    }
+
+    if (def->graphics[def->ngraphics] != NULL) {
+        ++def->ngraphics;
+    }
+
+    /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */
+    if (VIR_ALLOC_N(def->disks, 66) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->ndisks = 0;
+
+    /* def:disks (scsi) */
+    for (controller = 0; controller < 4; ++controller) {
+        if (virVMXParseSCSIController(conf, controller, &present,
+                                      &scsi_virtualDev[controller]) < 0) {
+            goto cleanup;
+        }
+
+        if (! present) {
+            continue;
+        }
+
+        for (unit = 0; unit < 16; ++unit) {
+            if (unit == 7) {
+                /*
+                 * SCSI unit 7 is assigned to the SCSI controller and cannot be
+                 * used for disk devices.
+                 */
+                continue;
+            }
+
+            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
+                                VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
+                                &def->disks[def->ndisks]) < 0) {
+                goto cleanup;
+            }
+
+            if (def->disks[def->ndisks] != NULL) {
+                ++def->ndisks;
+                continue;
+            }
+
+            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
+                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
+                                 &def->disks[def->ndisks]) < 0) {
+                goto cleanup;
+            }
+
+            if (def->disks[def->ndisks] != NULL) {
+                ++def->ndisks;
+            }
+        }
+    }
+
+    /* def:disks (ide) */
+    for (bus = 0; bus < 2; ++bus) {
+        for (unit = 0; unit < 2; ++unit) {
+            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
+                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
+                                &def->disks[def->ndisks]) < 0) {
+                goto cleanup;
+            }
+
+            if (def->disks[def->ndisks] != NULL) {
+                ++def->ndisks;
+                continue;
+            }
+
+            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
+                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
+                                &def->disks[def->ndisks]) < 0) {
+                goto cleanup;
+            }
+
+            if (def->disks[def->ndisks] != NULL) {
+                ++def->ndisks;
+            }
+        }
+    }
+
+    /* def:disks (floppy) */
+    for (unit = 0; unit < 2; ++unit) {
+        if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
+                            VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
+                            &def->disks[def->ndisks]) < 0) {
+            goto cleanup;
+        }
+
+        if (def->disks[def->ndisks] != NULL) {
+            ++def->ndisks;
+        }
+    }
+
+    /* def:controllers */
+    if (virDomainDefAddImplicitControllers(def) < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add controllers"));
+        goto cleanup;
+    }
+
+    for (controller = 0; controller < def->ncontrollers; ++controller) {
+        if (def->controllers[controller]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
+            if (def->controllers[controller]->idx < 0 ||
+                def->controllers[controller]->idx > 3) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("SCSI controller index %d out of [0..3] range"),
+                          def->controllers[controller]->idx);
+                goto cleanup;
+            }
+
+            def->controllers[controller]->model =
+              scsi_virtualDev[def->controllers[controller]->idx];
+        }
+    }
+
+    /* def:fss */
+    /* FIXME */
+
+    /* def:nets */
+    if (VIR_ALLOC_N(def->nets, 4) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->nnets = 0;
+
+    for (controller = 0; controller < 4; ++controller) {
+        if (virVMXParseEthernet(conf, controller,
+                                &def->nets[def->nnets]) < 0) {
+            goto cleanup;
+        }
+
+        if (def->nets[def->nnets] != NULL) {
+            ++def->nnets;
+        }
+    }
+
+    /* def:inputs */
+    /* FIXME */
+
+    /* def:sounds */
+    /* FIXME */
+
+    /* def:hostdevs */
+    /* FIXME */
+
+    /* def:serials */
+    if (VIR_ALLOC_N(def->serials, 4) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->nserials = 0;
+
+    for (port = 0; port < 4; ++port) {
+        if (virVMXParseSerial(ctx, conf, port,
+                              &def->serials[def->nserials]) < 0) {
+            goto cleanup;
+        }
+
+        if (def->serials[def->nserials] != NULL) {
+            ++def->nserials;
+        }
+    }
+
+    /* def:parallels */
+    if (VIR_ALLOC_N(def->parallels, 3) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->nparallels = 0;
+
+    for (port = 0; port < 3; ++port) {
+        if (virVMXParseParallel(ctx, conf, port,
+                                &def->parallels[def->nparallels]) < 0) {
+            goto cleanup;
+        }
+
+        if (def->parallels[def->nparallels] != NULL) {
+            ++def->nparallels;
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    if (! success) {
+        virDomainDefFree(def);
+        def = NULL;
+    }
+
+    virConfFree(conf);
+    VIR_FREE(encoding);
+    VIR_FREE(sched_cpu_affinity);
+    VIR_FREE(guestOS);
+
+    return def;
+}
+
+
+
+int
+virVMXParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def)
+{
+    bool enabled = false;
+    long long port = 0;
+
+    if (def == NULL || *def != NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (virVMXGetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
+                               false, true) < 0) {
+        return -1;
+    }
+
+    if (! enabled) {
+        return 0;
+    }
+
+    if (VIR_ALLOC(*def) < 0) {
+        virReportOOMError();
+        goto failure;
+    }
+
+    (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
+
+    if (virVMXGetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
+                            true) < 0 ||
+        virVMXGetConfigString(conf, "RemoteDisplay.vnc.ip",
+                              &(*def)->data.vnc.listenAddr, true) < 0 ||
+        virVMXGetConfigString(conf, "RemoteDisplay.vnc.keymap",
+                              &(*def)->data.vnc.keymap, true) < 0 ||
+        virVMXGetConfigString(conf, "RemoteDisplay.vnc.password",
+                              &(*def)->data.vnc.auth.passwd, true) < 0) {
+        goto failure;
+    }
+
+    if (port < 0) {
+        VIR_WARN0("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
+                  "is missing, the VNC port is unknown");
+
+        (*def)->data.vnc.port = 0;
+        (*def)->data.vnc.autoport = 1;
+    } else {
+        if (port < 5900 || port > 5964) {
+            VIR_WARN("VNC port %lld it out of [5900..5964] range", port);
+        }
+
+        (*def)->data.vnc.port = port;
+        (*def)->data.vnc.autoport = 0;
+    }
+
+    return 0;
+
+  failure:
+    virDomainGraphicsDefFree(*def);
+    *def = NULL;
+
+    return -1;
+}
+
+
+
+int
+virVMXParseSCSIController(virConfPtr conf, int controller, bool *present,
+                          int *virtualDev)
+{
+    char present_name[32];
+    char virtualDev_name[32];
+    char *virtualDev_string = NULL;
+    char *tmp;
+
+    if (virtualDev == NULL || *virtualDev != -1) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (controller < 0 || controller > 3) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("SCSI controller index %d out of [0..3] range"),
+                  controller);
+        return -1;
+    }
+
+    snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
+    snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
+             controller);
+
+    if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0) {
+        goto failure;
+    }
+
+    if (! *present) {
+        return 0;
+    }
+
+    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev_string,
+                              true) < 0) {
+        goto failure;
+    }
+
+    if (virtualDev_string != NULL) {
+        tmp = virtualDev_string;
+
+        for (; *tmp != '\0'; ++tmp) {
+            *tmp = c_tolower(*tmp);
+        }
+
+        *virtualDev = virVMXSCSIControllerModelTypeFromString(virtualDev_string);
+
+        if (*virtualDev == -1 ||
+            (*virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC &&
+             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC &&
+             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 &&
+             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI)) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting VMX entry '%s' to be 'buslogic' or 'lsilogic' "
+                        "or 'lsisas1068' or 'pvscsi' but found '%s'"),
+                       virtualDev_name, virtualDev_string);
+            goto failure;
+        }
+    }
+
+    return 0;
+
+  failure:
+    VIR_FREE(virtualDev_string);
+
+    return -1;
+}
+
+
+
+/*
+struct _virDomainDiskDef {
+    int type;               // partly done
+    int device;             // done
+    int bus;                // done
+    char *src;              // done
+    char *dst;              // done
+    char *driverName;       // done
+    char *driverType;
+    int cachemode;          // done
+    unsigned int readonly : 1;
+    unsigned int shared : 1;
+    int slotnum;
+};*/
+
+int
+virVMXParseDisk(virVMXContext *ctx, virCapsPtr caps, virConfPtr conf,
+                int device, int busType, int controllerOrBus, int unit,
+                virDomainDiskDefPtr *def)
+{
+    /*
+     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
+     *         busType = VIR_DOMAIN_DISK_BUS_SCSI
+     * controllerOrBus = [0..3] -> controller
+     *            unit = [0..6,8..15]
+     *
+     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
+     *         busType = VIR_DOMAIN_DISK_BUS_IDE
+     * controllerOrBus = [0..1] -> bus
+     *            unit = [0..1]
+     *
+     *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
+     *         busType = VIR_DOMAIN_DISK_BUS_FDC
+     * controllerOrBus = [0]
+     *            unit = [0..1]
+     */
+
+    int result = -1;
+    char *prefix = NULL;
+
+    char present_name[32] = "";
+    bool present = false;
+
+    char startConnected_name[32] = "";
+    bool startConnected = false;
+
+    char deviceType_name[32] = "";
+    char *deviceType = NULL;
+
+    char clientDevice_name[32] = "";
+    bool clientDevice = false;
+
+    char fileType_name[32] = "";
+    char *fileType = NULL;
+
+    char fileName_name[32] = "";
+    char *fileName = NULL;
+
+    char writeThrough_name[32] = "";
+    bool writeThrough = false;
+
+    if (def == NULL || *def != NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (VIR_ALLOC(*def) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    (*def)->device = device;
+    (*def)->bus = busType;
+
+    /* def:dst, def:driverName */
+    if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
+        device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+        if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
+            if (controllerOrBus < 0 || controllerOrBus > 3) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("SCSI controller index %d out of [0..3] range"),
+                          controllerOrBus);
+                goto cleanup;
+            }
+
+            if (unit < 0 || unit > 15 || unit == 7) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("SCSI unit index %d out of [0..6,8..15] range"),
+                          unit);
+                goto cleanup;
+            }
+
+            if (virAsprintf(&prefix, "scsi%d:%d", controllerOrBus, unit) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            (*def)->dst =
+               virIndexToDiskName
+                 (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
+
+            if ((*def)->dst == NULL) {
+                goto cleanup;
+            }
+        } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
+            if (controllerOrBus < 0 || controllerOrBus > 1) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("IDE bus index %d out of [0..1] range"),
+                          controllerOrBus);
+                goto cleanup;
+            }
+
+            if (unit < 0 || unit > 1) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("IDE unit index %d out of [0..1] range"), unit);
+                goto cleanup;
+            }
+
+            if (virAsprintf(&prefix, "ide%d:%d", controllerOrBus, unit) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            (*def)->dst = virIndexToDiskName(controllerOrBus * 2 + unit, "hd");
+
+            if ((*def)->dst == NULL) {
+                goto cleanup;
+            }
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Unsupported bus type '%s' for device type '%s'"),
+                      virDomainDiskBusTypeToString(busType),
+                      virDomainDiskDeviceTypeToString(device));
+            goto cleanup;
+        }
+    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+        if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
+            if (controllerOrBus != 0) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("FDC controller index %d out of [0] range"),
+                          controllerOrBus);
+                goto cleanup;
+            }
+
+            if (unit < 0 || unit > 1) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("FDC unit index %d out of [0..1] range"),
+                          unit);
+                goto cleanup;
+            }
+
+            if (virAsprintf(&prefix, "floppy%d", unit) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            (*def)->dst = virIndexToDiskName(unit, "fd");
+
+            if ((*def)->dst == NULL) {
+                goto cleanup;
+            }
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Unsupported bus type '%s' for device type '%s'"),
+                      virDomainDiskBusTypeToString(busType),
+                      virDomainDiskDeviceTypeToString(device));
+            goto cleanup;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unsupported device type '%s'"),
+                  virDomainDiskDeviceTypeToString(device));
+        goto cleanup;
+    }
+
+    VMX_BUILD_NAME(present);
+    VMX_BUILD_NAME(startConnected);
+    VMX_BUILD_NAME(deviceType);
+    VMX_BUILD_NAME(clientDevice);
+    VMX_BUILD_NAME(fileType);
+    VMX_BUILD_NAME(fileName);
+    VMX_BUILD_NAME(writeThrough);
+
+    /* vmx:present */
+    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:startConnected */
+    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
+                               true, true) < 0) {
+        goto cleanup;
+    }
+
+    /* FIXME: Need to distiguish between active and inactive domains here */
+    if (! present/* && ! startConnected*/) {
+        goto ignore;
+    }
+
+    /* vmx:deviceType -> def:type */
+    if (virVMXGetConfigString(conf, deviceType_name, &deviceType, true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:clientDevice */
+    if (virVMXGetConfigBoolean(conf, clientDevice_name, &clientDevice, false,
+                               true) < 0) {
+        goto cleanup;
+    }
+
+    if (clientDevice) {
+        /*
+         * Just ignore devices in client mode, because I have no clue how to
+         * handle them (e.g. assign an image) without the VI Client GUI.
+         */
+        goto ignore;
+    }
+
+    /* vmx:fileType -> def:type */
+    if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:fileName -> def:src, def:type */
+    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:writeThrough -> def:cachemode */
+    if (virVMXGetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
+                               true) < 0) {
+        goto cleanup;
+    }
+
+    /* Setup virDomainDiskDef */
+    if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
+        if (virFileHasSuffix(fileName, ".vmdk")) {
+            if (deviceType != NULL) {
+                if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
+                    STRCASENEQ(deviceType, "scsi-hardDisk") &&
+                    STRCASENEQ(deviceType, "disk")) {
+                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                              _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
+                                "or 'disk' but found '%s'"), deviceType_name,
+                              deviceType);
+                    goto cleanup;
+                } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
+                           STRCASENEQ(deviceType, "ata-hardDisk") &&
+                           STRCASENEQ(deviceType, "disk")) {
+                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                              _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
+                                "or 'disk' but found '%s'"), deviceType_name,
+                              deviceType);
+                    goto cleanup;
+                }
+            }
+
+            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
+            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
+            (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
+                                             : VIR_DOMAIN_DISK_CACHE_DEFAULT;
+
+            if ((*def)->src == NULL) {
+                goto cleanup;
+            }
+        } else if (virFileHasSuffix(fileName, ".iso") ||
+                   STREQ(deviceType, "atapi-cdrom")) {
+            /*
+             * This function was called in order to parse a harddisk device,
+             * but .iso files and 'atapi-cdrom' devices are for CDROM devices
+             * only. Just ignore it, another call to this function to parse a
+             * CDROM device may handle it.
+             */
+            goto ignore;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Invalid or not yet handled value '%s' for VMX entry "
+                        "'%s'"), fileName, fileName_name);
+            goto cleanup;
+        }
+    } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+        if (virFileHasSuffix(fileName, ".iso")) {
+            if (deviceType != NULL) {
+                if (STRCASENEQ(deviceType, "cdrom-image")) {
+                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                              _("Expecting VMX entry '%s' to be 'cdrom-image' "
+                                "but found '%s'"), deviceType_name, deviceType);
+                    goto cleanup;
+                }
+            }
+
+            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
+            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
+
+            if ((*def)->src == NULL) {
+                goto cleanup;
+            }
+        } else if (virFileHasSuffix(fileName, ".vmdk")) {
+            /*
+             * This function was called in order to parse a CDROM device, but
+             * .vmdk files are for harddisk devices only. Just ignore it,
+             * another call to this function to parse a harddisk device may
+             * handle it.
+             */
+            goto ignore;
+        } else if (STREQ(deviceType, "atapi-cdrom")) {
+            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
+            (*def)->src = fileName;
+
+            fileName = NULL;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Invalid or not yet handled value '%s' for VMX entry "
+                        "'%s'"), fileName, fileName_name);
+            goto cleanup;
+        }
+    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+        if (virFileHasSuffix(fileName, ".flp")) {
+            if (fileType != NULL) {
+                if (STRCASENEQ(fileType, "file")) {
+                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                              _("Expecting VMX entry '%s' to be 'file' but "
+                                "found '%s'"), fileType_name, fileType);
+                    goto cleanup;
+                }
+            }
+
+            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
+            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
+
+            if ((*def)->src == NULL) {
+                goto cleanup;
+            }
+        } else if (fileType != NULL && STREQ(fileType, "device")) {
+            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
+            (*def)->src = fileName;
+
+            fileName = NULL;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Invalid or not yet handled value '%s' for VMX entry "
+                        "'%s'"), fileName, fileName_name);
+            goto cleanup;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Unsupported device type '%s'"),
+                  virDomainDiskDeviceTypeToString(device));
+        goto cleanup;
+    }
+
+    if (virDomainDiskDefAssignAddress(caps, *def) < 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Could not assign address to disk '%s'"), (*def)->src);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        virDomainDiskDefFree(*def);
+        *def = NULL;
+    }
+
+    VIR_FREE(prefix);
+    VIR_FREE(deviceType);
+    VIR_FREE(fileType);
+    VIR_FREE(fileName);
+
+    return result;
+
+  ignore:
+    virDomainDiskDefFree(*def);
+    *def = NULL;
+
+    result = 0;
+
+    goto cleanup;
+}
+
+
+
+int
+virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
+{
+    int result = -1;
+    char prefix[48] = "";
+
+    char present_name[48] = "";
+    bool present = false;
+
+    char startConnected_name[48] = "";
+    bool startConnected = false;
+
+    char connectionType_name[48] = "";
+    char *connectionType = NULL;
+
+    char addressType_name[48] = "";
+    char *addressType = NULL;
+
+    char generatedAddress_name[48] = "";
+    char *generatedAddress = NULL;
+
+    char address_name[48] = "";
+    char *address = NULL;
+
+    char virtualDev_name[48] = "";
+    char *virtualDev = NULL;
+
+    char features_name[48] = "";
+    long long features = 0;
+
+    char vnet_name[48] = "";
+    char *vnet = NULL;
+
+    char networkName_name[48] = "";
+    char *networkName = NULL;
+
+    if (def == NULL || *def != NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (controller < 0 || controller > 3) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Ethernet controller index %d out of [0..3] range"),
+                  controller);
+        return -1;
+    }
+
+    if (VIR_ALLOC(*def) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
+
+    VMX_BUILD_NAME(present);
+    VMX_BUILD_NAME(startConnected);
+    VMX_BUILD_NAME(connectionType);
+    VMX_BUILD_NAME(addressType);
+    VMX_BUILD_NAME(generatedAddress);
+    VMX_BUILD_NAME(address);
+    VMX_BUILD_NAME(virtualDev);
+    VMX_BUILD_NAME(features);
+    VMX_BUILD_NAME(networkName);
+    VMX_BUILD_NAME(vnet);
+
+    /* vmx:present */
+    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:startConnected */
+    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
+                               true, true) < 0) {
+        goto cleanup;
+    }
+
+    /* FIXME: Need to distiguish between active and inactive domains here */
+    if (! present/* && ! startConnected*/) {
+        goto ignore;
+    }
+
+    /* vmx:connectionType -> def:type */
+    if (virVMXGetConfigString(conf, connectionType_name, &connectionType,
+                              true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
+    if (virVMXGetConfigString(conf, addressType_name, &addressType,
+                              true) < 0 ||
+        virVMXGetConfigString(conf, generatedAddress_name, &generatedAddress,
+                              true) < 0 ||
+        virVMXGetConfigString(conf, address_name, &address, true) < 0) {
+        goto cleanup;
+    }
+
+    if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
+        STRCASEEQ(addressType, "vpx")) {
+        if (generatedAddress != NULL) {
+            if (virParseMacAddr(generatedAddress, (*def)->mac) < 0) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Expecting VMX entry '%s' to be MAC address but "
+                            "found '%s'"), generatedAddress_name,
+                          generatedAddress);
+                goto cleanup;
+            }
+        }
+    } else if (STRCASEEQ(addressType, "static")) {
+        if (address != NULL) {
+            if (virParseMacAddr(address, (*def)->mac) < 0) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Expecting VMX entry '%s' to be MAC address but "
+                            "found '%s'"), address_name, address);
+                goto cleanup;
+            }
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting VMX entry '%s' to be 'generated' or 'static' or "
+                    "'vpx' but found '%s'"), addressType_name, addressType);
+        goto cleanup;
+    }
+
+    /* vmx:virtualDev, vmx:features -> def:model */
+    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
+        virVMXGetConfigLong(conf, features_name, &features, 0, true) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualDev != NULL) {
+        if (STRCASENEQ(virtualDev, "vlance") &&
+            STRCASENEQ(virtualDev, "vmxnet") &&
+            STRCASENEQ(virtualDev, "vmxnet3") &&
+            STRCASENEQ(virtualDev, "e1000")) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or "
+                        "'vmxnet3' or 'e1000' but found '%s'"), virtualDev_name,
+                      virtualDev);
+            goto cleanup;
+        }
+
+        if (STRCASEEQ(virtualDev, "vmxnet") && features == 15) {
+            VIR_FREE(virtualDev);
+
+            virtualDev = strdup("vmxnet2");
+
+            if (virtualDev == NULL) {
+                virReportOOMError();
+                goto cleanup;
+            }
+        }
+    }
+
+    /* vmx:networkName -> def:data.bridge.brname */
+    if ((connectionType == NULL ||
+         STRCASEEQ(connectionType, "bridged") ||
+         STRCASEEQ(connectionType, "custom")) &&
+        virVMXGetConfigString(conf, networkName_name, &networkName,
+                              false) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:vnet -> def:data.ifname */
+    if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
+        virVMXGetConfigString(conf, vnet_name, &vnet, false) < 0) {
+        goto cleanup;
+    }
+
+    /* Setup virDomainNetDef */
+    if (connectionType == NULL || STRCASEEQ(connectionType, "bridged")) {
+        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+        (*def)->model = virtualDev;
+        (*def)->data.bridge.brname = networkName;
+
+        virtualDev = NULL;
+        networkName = NULL;
+    } else if (STRCASEEQ(connectionType, "hostonly")) {
+        /* FIXME */
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("No yet handled value '%s' for VMX entry '%s'"),
+                  connectionType, connectionType_name);
+        goto cleanup;
+    } else if (STRCASEEQ(connectionType, "nat")) {
+        /* FIXME */
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("No yet handled value '%s' for VMX entry '%s'"),
+                  connectionType, connectionType_name);
+        goto cleanup;
+    } else if (STRCASEEQ(connectionType, "custom")) {
+        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+        (*def)->model = virtualDev;
+        (*def)->data.bridge.brname = networkName;
+        (*def)->ifname = vnet;
+
+        virtualDev = NULL;
+        networkName = NULL;
+        vnet = NULL;
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Invalid value '%s' for VMX entry '%s'"), connectionType,
+                  connectionType_name);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        virDomainNetDefFree(*def);
+        *def = NULL;
+    }
+
+    VIR_FREE(connectionType);
+    VIR_FREE(addressType);
+    VIR_FREE(generatedAddress);
+    VIR_FREE(address);
+    VIR_FREE(virtualDev);
+    VIR_FREE(vnet);
+
+    return result;
+
+  ignore:
+    virDomainNetDefFree(*def);
+    *def = NULL;
+
+    result = 0;
+
+    goto cleanup;
+}
+
+
+
+int
+virVMXParseSerial(virVMXContext *ctx, virConfPtr conf, int port,
+                  virDomainChrDefPtr *def)
+{
+    int result = -1;
+    char prefix[48] = "";
+
+    char present_name[48] = "";
+    bool present = false;
+
+    char startConnected_name[48] = "";
+    bool startConnected = false;
+
+    char fileType_name[48] = "";
+    char *fileType = NULL;
+
+    char fileName_name[48] = "";
+    char *fileName = NULL;
+
+    char network_endPoint_name[48] = "";
+    char *network_endPoint = NULL;
+
+    xmlURIPtr parsedUri = NULL;
+
+    if (def == NULL || *def != NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (port < 0 || port > 3) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Serial port index %d out of [0..3] range"), port);
+        return -1;
+    }
+
+    if (VIR_ALLOC(*def) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
+
+    snprintf(prefix, sizeof(prefix), "serial%d", port);
+
+    VMX_BUILD_NAME(present);
+    VMX_BUILD_NAME(startConnected);
+    VMX_BUILD_NAME(fileType);
+    VMX_BUILD_NAME(fileName);
+    VMX_BUILD_NAME_EXTRA(network_endPoint, "network.endPoint");
+
+    /* vmx:present */
+    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:startConnected */
+    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
+                               true, true) < 0) {
+        goto cleanup;
+    }
+
+    /* FIXME: Need to distiguish between active and inactive domains here */
+    if (! present/* && ! startConnected*/) {
+        goto ignore;
+    }
+
+    /* vmx:fileType -> def:type */
+    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:fileName -> def:data.file.path */
+    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:network.endPoint -> def:data.tcp.listen */
+    if (virVMXGetConfigString(conf, network_endPoint_name, &network_endPoint,
+                              true) < 0) {
+        goto cleanup;
+    }
+
+    /* Setup virDomainChrDef */
+    if (STRCASEEQ(fileType, "device")) {
+        (*def)->target.port = port;
+        (*def)->type = VIR_DOMAIN_CHR_TYPE_DEV;
+        (*def)->data.file.path = fileName;
+
+        fileName = NULL;
+    } else if (STRCASEEQ(fileType, "file")) {
+        (*def)->target.port = port;
+        (*def)->type = VIR_DOMAIN_CHR_TYPE_FILE;
+        (*def)->data.file.path = ctx->parseFileName(fileName, ctx->opaque);
+
+        if ((*def)->data.file.path == NULL) {
+            goto cleanup;
+        }
+    } else if (STRCASEEQ(fileType, "pipe")) {
+        /*
+         * FIXME: Differences between client/server and VM/application pipes
+         *        not representable in domain XML form
+         */
+        (*def)->target.port = port;
+        (*def)->type = VIR_DOMAIN_CHR_TYPE_PIPE;
+        (*def)->data.file.path = fileName;
+
+        fileName = NULL;
+    } else if (STRCASEEQ(fileType, "network")) {
+        (*def)->target.port = port;
+        (*def)->type = VIR_DOMAIN_CHR_TYPE_TCP;
+
+        parsedUri = xmlParseURI(fileName);
+
+        if (parsedUri == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (parsedUri->port == 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("VMX entry '%s' doesn't contain a port part"),
+                      fileName_name);
+            goto cleanup;
+        }
+
+        (*def)->data.tcp.host = strdup(parsedUri->server);
+
+        if ((*def)->data.tcp.host == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (virAsprintf(&(*def)->data.tcp.service, "%d", parsedUri->port) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        /* See vSphere API documentation about VirtualSerialPortURIBackingInfo */
+        if (parsedUri->scheme == NULL ||
+            STRCASEEQ(parsedUri->scheme, "tcp") ||
+            STRCASEEQ(parsedUri->scheme, "tcp4") ||
+            STRCASEEQ(parsedUri->scheme, "tcp6")) {
+            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
+        } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
+            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
+        } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
+            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
+        } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
+                   STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
+                   STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
+                   STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
+            (*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("VMX entry '%s' contains unsupported scheme '%s'"),
+                      fileName_name, parsedUri->scheme);
+            goto cleanup;
+        }
+
+        if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
+            (*def)->data.tcp.listen = 1;
+        } else if (STRCASEEQ(network_endPoint, "client")) {
+            (*def)->data.tcp.listen = 0;
+        } else {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting VMX entry '%s' to be 'server' or 'client' "
+                        "but found '%s'"), network_endPoint_name, network_endPoint);
+            goto cleanup;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' "
+                    "or 'network' but found '%s'"), fileType_name, fileType);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        virDomainChrDefFree(*def);
+        *def = NULL;
+    }
+
+    VIR_FREE(fileType);
+    VIR_FREE(fileName);
+    VIR_FREE(network_endPoint);
+    xmlFreeURI(parsedUri);
+
+    return result;
+
+  ignore:
+    virDomainChrDefFree(*def);
+    *def = NULL;
+
+    result = 0;
+
+    goto cleanup;
+}
+
+
+
+int
+virVMXParseParallel(virVMXContext *ctx, virConfPtr conf, int port,
+                    virDomainChrDefPtr *def)
+{
+    int result = -1;
+    char prefix[48] = "";
+
+    char present_name[48] = "";
+    bool present = false;
+
+    char startConnected_name[48] = "";
+    bool startConnected = false;
+
+    char fileType_name[48] = "";
+    char *fileType = NULL;
+
+    char fileName_name[48] = "";
+    char *fileName = NULL;
+
+    if (def == NULL || *def != NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (port < 0 || port > 2) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Parallel port index %d out of [0..2] range"), port);
+        return -1;
+    }
+
+    if (VIR_ALLOC(*def) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
+
+    snprintf(prefix, sizeof(prefix), "parallel%d", port);
+
+    VMX_BUILD_NAME(present);
+    VMX_BUILD_NAME(startConnected);
+    VMX_BUILD_NAME(fileType);
+    VMX_BUILD_NAME(fileName);
+
+    /* vmx:present */
+    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:startConnected */
+    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
+                               true, true) < 0) {
+        goto cleanup;
+    }
+
+    /* FIXME: Need to distiguish between active and inactive domains here */
+    if (! present/* && ! startConnected*/) {
+        goto ignore;
+    }
+
+    /* vmx:fileType -> def:type */
+    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0) {
+        goto cleanup;
+    }
+
+    /* vmx:fileName -> def:data.file.path */
+    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
+        goto cleanup;
+    }
+
+    /* Setup virDomainChrDef */
+    if (STRCASEEQ(fileType, "device")) {
+        (*def)->target.port = port;
+        (*def)->type = VIR_DOMAIN_CHR_TYPE_DEV;
+        (*def)->data.file.path = fileName;
+
+        fileName = NULL;
+    } else if (STRCASEEQ(fileType, "file")) {
+        (*def)->target.port = port;
+        (*def)->type = VIR_DOMAIN_CHR_TYPE_FILE;
+        (*def)->data.file.path = ctx->parseFileName(fileName, ctx->opaque);
+
+        if ((*def)->data.file.path == NULL) {
+            goto cleanup;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting VMX entry '%s' to be 'device' or 'file' but "
+                    "found '%s'"), fileType_name, fileType);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        virDomainChrDefFree(*def);
+        *def = NULL;
+    }
+
+    VIR_FREE(fileType);
+    VIR_FREE(fileName);
+
+    return result;
+
+  ignore:
+    virDomainChrDefFree(*def);
+    *def = NULL;
+
+    result = 0;
+
+    goto cleanup;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Domain XML -> VMX
+ */
+
+char *
+virVMXFormatConfig(virVMXContext *ctx, virCapsPtr caps, virDomainDefPtr def,
+                   int virtualHW_version)
+{
+    char *vmx = NULL;
+    int i;
+    int sched_cpu_affinity_length;
+    unsigned char zero[VIR_UUID_BUFLEN];
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    char *preliminaryDisplayName = NULL;
+    char *displayName = NULL;
+    char *annotation = NULL;
+    bool scsi_present[4] = { false, false, false, false };
+    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
+    bool floppy_present[2] = { false, false };
+
+    if (ctx->formatFileName == NULL) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("virVMXContext has no formatFileName function set"));
+        return NULL;
+    }
+
+    memset(zero, 0, VIR_UUID_BUFLEN);
+
+    if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting virt type to be '%s' but found '%s'"),
+                  virDomainVirtTypeToString(VIR_DOMAIN_VIRT_VMWARE),
+                  virDomainVirtTypeToString(def->virtType));
+        return NULL;
+    }
+
+    /* vmx:.encoding */
+    virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");
+
+    /* vmx:config.version */
+    virBufferAddLit(&buffer, "config.version = \"8\"\n");
+
+    /* vmx:virtualHW.version */
+    virBufferVSprintf(&buffer, "virtualHW.version = \"%d\"\n",
+                      virtualHW_version);
+
+    /* def:os.arch -> vmx:guestOS */
+    if (def->os.arch == NULL || STRCASEEQ(def->os.arch, "i686")) {
+        virBufferAddLit(&buffer, "guestOS = \"other\"\n");
+    } else if (STRCASEEQ(def->os.arch, "x86_64")) {
+        virBufferAddLit(&buffer, "guestOS = \"other-64\"\n");
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting domain XML attribute 'arch' of entry 'os/type' "
+                    "to be 'i686' or 'x86_64' but found '%s'"), def->os.arch);
+        goto cleanup;
+    }
+
+    /* def:os.smbios_mode -> vmx:smbios.reflecthost */
+    if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_NONE ||
+        def->os.smbios_mode == VIR_DOMAIN_SMBIOS_EMULATE) {
+        /* nothing */
+    } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
+        virBufferAddLit(&buffer, "smbios.reflecthost = \"true\"\n");
+    } else {
+        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
+                  _("Unsupported SMBIOS mode '%s'"),
+                  virDomainSmbiosModeTypeToString(def->os.smbios_mode));
+        goto cleanup;
+    }
+
+    /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */
+    if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) {
+        virBufferAddLit(&buffer, "uuid.action = \"create\"\n");
+    } else {
+        virBufferVSprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x "
+                          "%02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\"\n",
+                          def->uuid[0], def->uuid[1], def->uuid[2], def->uuid[3],
+                          def->uuid[4], def->uuid[5], def->uuid[6], def->uuid[7],
+                          def->uuid[8], def->uuid[9], def->uuid[10], def->uuid[11],
+                          def->uuid[12], def->uuid[13], def->uuid[14],
+                          def->uuid[15]);
+    }
+
+    /* def:name -> vmx:displayName */
+    preliminaryDisplayName = virVMXEscapeHexPipe(def->name);
+
+    if (preliminaryDisplayName == NULL) {
+        goto cleanup;
+    }
+
+    displayName = virVMXEscapeHexPercent(preliminaryDisplayName);
+
+    if (displayName == NULL) {
+        goto cleanup;
+    }
+
+    virBufferVSprintf(&buffer, "displayName = \"%s\"\n", displayName);
+
+    /* def:description -> vmx:annotation */
+    if (def->description != NULL) {
+        annotation = virVMXEscapeHexPipe(def->description);
+
+        virBufferVSprintf(&buffer, "annotation = \"%s\"\n", annotation);
+    }
+
+    /* def:mem.max_balloon -> vmx:memsize */
+    if (def->mem.max_balloon <= 0 || def->mem.max_balloon % 4096 != 0) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting domain XML entry 'memory' to be an unsigned "
+                    "integer (multiple of 4096) but found %lld"),
+                  (unsigned long long)def->mem.max_balloon);
+        goto cleanup;
+    }
+
+    /* Scale from kilobytes to megabytes */
+    virBufferVSprintf(&buffer, "memsize = \"%d\"\n",
+                      (int)(def->mem.max_balloon / 1024));
+
+    /* def:mem.cur_balloon -> vmx:sched.mem.max */
+    if (def->mem.cur_balloon < def->mem.max_balloon) {
+        if (def->mem.cur_balloon <= 0 || def->mem.cur_balloon % 1024 != 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting domain XML entry 'currentMemory' to be an "
+                        "unsigned integer (multiple of 1024) but found %llu"),
+                      (unsigned long long)def->mem.cur_balloon);
+            goto cleanup;
+        }
+
+        /* Scale from kilobytes to megabytes */
+        virBufferVSprintf(&buffer, "sched.mem.max = \"%d\"\n",
+                          (int)(def->mem.cur_balloon / 1024));
+    }
+
+    /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
+    if (def->mem.min_guarantee > 0) {
+        if (def->mem.min_guarantee % 1024 != 0) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting domain XML entry 'memtune/min_guarantee' to "
+                        "be an unsigned integer (multiple of 1024) but found %llu"),
+                      (unsigned long long)def->mem.min_guarantee);
+            goto cleanup;
+        }
+
+        /* Scale from kilobytes to megabytes */
+        virBufferVSprintf(&buffer, "sched.mem.minsize = \"%d\"\n",
+                          (int)(def->mem.min_guarantee / 1024));
+    }
+
+    /* def:maxvcpus -> vmx:numvcpus */
+    if (def->vcpus != def->maxvcpus) {
+        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                  _("No support for domain XML entry 'vcpu' attribute "
+                    "'current'"));
+        goto cleanup;
+    }
+    if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Expecting domain XML entry 'vcpu' to be an unsigned "
+                    "integer (1 or a multiple of 2) but found %d"),
+                  def->maxvcpus);
+        goto cleanup;
+    }
+
+    virBufferVSprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus);
+
+    /* def:cpumask -> vmx:sched.cpu.affinity */
+    if (def->cpumasklen > 0) {
+        virBufferAddLit(&buffer, "sched.cpu.affinity = \"");
+
+        sched_cpu_affinity_length = 0;
+
+        for (i = 0; i < def->cpumasklen; ++i) {
+            if (def->cpumask[i]) {
+                ++sched_cpu_affinity_length;
+            }
+        }
+
+        if (sched_cpu_affinity_length < def->maxvcpus) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting domain XML attribute 'cpuset' of entry "
+                        "'vcpu' to contain at least %d CPU(s)"),
+                      def->maxvcpus);
+            goto cleanup;
+        }
+
+        for (i = 0; i < def->cpumasklen; ++i) {
+            if (def->cpumask[i]) {
+                virBufferVSprintf(&buffer, "%d", i);
+
+                if (sched_cpu_affinity_length > 1) {
+                    virBufferAddChar(&buffer, ',');
+                }
+
+                --sched_cpu_affinity_length;
+            }
+        }
+
+        virBufferAddLit(&buffer, "\"\n");
+    }
+
+    /* def:graphics */
+    for (i = 0; i < def->ngraphics; ++i) {
+        switch (def->graphics[i]->type) {
+          case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+            if (virVMXFormatVNC(def->graphics[i], &buffer) < 0) {
+                goto cleanup;
+            }
+
+            break;
+
+          default:
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Unsupported graphics type '%s'"),
+                      virDomainGraphicsTypeToString(def->graphics[i]->type));
+            goto cleanup;
+        }
+    }
+
+    /* def:disks */
+    for (i = 0; i < def->ndisks; ++i) {
+        if (virVMXVerifyDiskAddress(caps, def->disks[i]) < 0 ||
+            virVMXHandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
+            goto cleanup;
+        }
+    }
+
+    if (virVMXGatherSCSIControllers(ctx, def, scsi_virtualDev,
+                                    scsi_present) < 0) {
+        goto cleanup;
+    }
+
+    for (i = 0; i < 4; ++i) {
+        if (scsi_present[i]) {
+            virBufferVSprintf(&buffer, "scsi%d.present = \"true\"\n", i);
+
+            if (scsi_virtualDev[i] != -1) {
+                virBufferVSprintf(&buffer, "scsi%d.virtualDev = \"%s\"\n", i,
+                                  virVMXSCSIControllerModelTypeToString
+                                    (scsi_virtualDev[i]));
+            }
+        }
+    }
+
+    for (i = 0; i < def->ndisks; ++i) {
+        switch (def->disks[i]->device) {
+          case VIR_DOMAIN_DISK_DEVICE_DISK:
+            if (virVMXFormatHardDisk(ctx, def->disks[i], &buffer) < 0) {
+                goto cleanup;
+            }
+
+            break;
+
+          case VIR_DOMAIN_DISK_DEVICE_CDROM:
+            if (virVMXFormatCDROM(ctx, def->disks[i], &buffer) < 0) {
+                goto cleanup;
+            }
+
+            break;
+
+          case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
+            if (virVMXFormatFloppy(ctx, def->disks[i], &buffer,
+                                   floppy_present) < 0) {
+                goto cleanup;
+            }
+
+            break;
+
+          default:
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Unsupported disk device type '%s'"),
+                      virDomainDiskDeviceTypeToString(def->disks[i]->device));
+            goto cleanup;
+        }
+    }
+
+    for (i = 0; i < 2; ++i) {
+        /* floppy[0..1].present defaults to true, disable it explicitly */
+        if (! floppy_present[i]) {
+            virBufferVSprintf(&buffer, "floppy%d.present = \"false\"\n", i);
+        }
+    }
+
+    /* def:fss */
+    /* FIXME */
+
+    /* def:nets */
+    for (i = 0; i < def->nnets; ++i) {
+        if (virVMXFormatEthernet(def->nets[i], i, &buffer) < 0) {
+            goto cleanup;
+        }
+    }
+
+    /* def:inputs */
+    /* FIXME */
+
+    /* def:sounds */
+    /* FIXME */
+
+    /* def:hostdevs */
+    /* FIXME */
+
+    /* def:serials */
+    for (i = 0; i < def->nserials; ++i) {
+        if (virVMXFormatSerial(ctx, def->serials[i], &buffer) < 0) {
+            goto cleanup;
+        }
+    }
+
+    /* def:parallels */
+    for (i = 0; i < def->nparallels; ++i) {
+        if (virVMXFormatParallel(ctx, def->parallels[i], &buffer) < 0) {
+            goto cleanup;
+        }
+    }
+
+    /* Get final VMX output */
+    if (virBufferError(&buffer)) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    vmx = virBufferContentAndReset(&buffer);
+
+  cleanup:
+    if (vmx == NULL) {
+        virBufferFreeAndReset(&buffer);
+    }
+
+    VIR_FREE(preliminaryDisplayName);
+    VIR_FREE(displayName);
+    VIR_FREE(annotation);
+
+    return vmx;
+}
+
+
+
+int
+virVMXFormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer)
+{
+    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    virBufferVSprintf(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");
+
+    if (def->data.vnc.autoport) {
+        VIR_WARN0("VNC autoport is enabled, but the automatically assigned "
+                  "VNC port cannot be read back");
+    } else {
+        if (def->data.vnc.port < 5900 || def->data.vnc.port > 5964) {
+            VIR_WARN("VNC port %d it out of [5900..5964] range",
+                     def->data.vnc.port);
+        }
+
+        virBufferVSprintf(buffer, "RemoteDisplay.vnc.port = \"%d\"\n",
+                          def->data.vnc.port);
+    }
+
+    if (def->data.vnc.listenAddr != NULL) {
+        virBufferVSprintf(buffer, "RemoteDisplay.vnc.ip = \"%s\"\n",
+                          def->data.vnc.listenAddr);
+    }
+
+    if (def->data.vnc.keymap != NULL) {
+        virBufferVSprintf(buffer, "RemoteDisplay.vnc.keymap = \"%s\"\n",
+                          def->data.vnc.keymap);
+    }
+
+    if (def->data.vnc.auth.passwd != NULL) {
+        virBufferVSprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n",
+                          def->data.vnc.auth.passwd);
+    }
+
+    return 0;
+}
+
+
+
+int
+virVMXFormatHardDisk(virVMXContext *ctx, virDomainDiskDefPtr def,
+                     virBufferPtr buffer)
+{
+    int controllerOrBus, unit;
+    const char *busName = NULL;
+    const char *entryPrefix = NULL;
+    const char *deviceTypePrefix = NULL;
+    char *fileName = NULL;
+
+    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+        busName = "SCSI";
+        entryPrefix = "scsi";
+        deviceTypePrefix = "scsi";
+
+        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
+                                                  &unit) < 0) {
+            return -1;
+        }
+    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+        busName = "IDE";
+        entryPrefix = "ide";
+        deviceTypePrefix = "ata";
+
+        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
+                                           &unit) < 0) {
+            return -1;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unsupported bus type '%s' for harddisk"),
+                  virDomainDiskBusTypeToString(def->bus));
+        return -1;
+    }
+
+    if (def->type != VIR_DOMAIN_DISK_TYPE_FILE) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("%s harddisk '%s' has unsupported type '%s', expecting '%s'"),
+                  busName, def->dst, virDomainDiskTypeToString(def->type),
+                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE));
+        return -1;
+    }
+
+    virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n",
+                      entryPrefix, controllerOrBus, unit);
+    virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"%s-hardDisk\"\n",
+                      entryPrefix, controllerOrBus, unit, deviceTypePrefix);
+
+    if (def->src != NULL) {
+        if (! virFileHasSuffix(def->src, ".vmdk")) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Image file for %s harddisk '%s' has unsupported suffix, "
+                        "expecting '.vmdk'"), busName, def->dst);
+            return -1;
+        }
+
+        fileName = ctx->formatFileName(def->src, ctx->opaque);
+
+        if (fileName == NULL) {
+            return -1;
+        }
+
+        virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
+                          entryPrefix, controllerOrBus, unit, fileName);
+
+        VIR_FREE(fileName);
+    }
+
+    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+        if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
+            virBufferVSprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
+                              entryPrefix, controllerOrBus, unit);
+        } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("%s harddisk '%s' has unsupported cache mode '%s'"),
+                      busName, def->dst,
+                      virDomainDiskCacheTypeToString(def->cachemode));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+
+int
+virVMXFormatCDROM(virVMXContext *ctx, virDomainDiskDefPtr def,
+                  virBufferPtr buffer)
+{
+    int controllerOrBus, unit;
+    const char *busName = NULL;
+    const char *entryPrefix = NULL;
+    char *fileName = NULL;
+
+    if (def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+        busName = "SCSI";
+        entryPrefix = "scsi";
+
+        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
+                                                  &unit) < 0) {
+            return -1;
+        }
+    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+        busName = "IDE";
+        entryPrefix = "ide";
+
+        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
+                                          &unit) < 0) {
+            return -1;
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unsupported bus type '%s' for cdrom"),
+                  virDomainDiskBusTypeToString(def->bus));
+        return -1;
+    }
+
+    virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n",
+                      entryPrefix, controllerOrBus, unit);
+
+    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
+        virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"cdrom-image\"\n",
+                          entryPrefix, controllerOrBus, unit);
+
+        if (def->src != NULL) {
+            if (! virFileHasSuffix(def->src, ".iso")) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Image file for %s cdrom '%s' has unsupported "
+                            "suffix, expecting '.iso'"), busName, def->dst);
+                return -1;
+            }
+
+            fileName = ctx->formatFileName(def->src, ctx->opaque);
+
+            if (fileName == NULL) {
+                return -1;
+            }
+
+            virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
+                              entryPrefix, controllerOrBus, unit, fileName);
+
+            VIR_FREE(fileName);
+        }
+    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
+        virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"atapi-cdrom\"\n",
+                          entryPrefix, controllerOrBus, unit);
+
+        if (def->src != NULL) {
+            virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
+                              entryPrefix, controllerOrBus, unit, def->src);
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("%s cdrom '%s' has unsupported type '%s', expecting '%s' "
+                    "or '%s'"), busName, def->dst,
+                  virDomainDiskTypeToString(def->type),
+                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
+                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+int
+virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDefPtr def,
+                   virBufferPtr buffer, bool floppy_present[2])
+{
+    int unit;
+    char *fileName = NULL;
+
+    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (virVMXFloppyDiskNameToUnit(def->dst, &unit) < 0) {
+        return -1;
+    }
+
+    floppy_present[unit] = true;
+
+    virBufferVSprintf(buffer, "floppy%d.present = \"true\"\n", unit);
+
+    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
+        virBufferVSprintf(buffer, "floppy%d.fileType = \"file\"\n", unit);
+
+        if (def->src != NULL) {
+            if (! virFileHasSuffix(def->src, ".flp")) {
+                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Image file for floppy '%s' has unsupported "
+                            "suffix, expecting '.flp'"), def->dst);
+                return -1;
+            }
+
+            fileName = ctx->formatFileName(def->src, ctx->opaque);
+
+            if (fileName == NULL) {
+                return -1;
+            }
+
+            virBufferVSprintf(buffer, "floppy%d.fileName = \"%s\"\n",
+                              unit, fileName);
+
+            VIR_FREE(fileName);
+        }
+    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
+        virBufferVSprintf(buffer, "floppy%d.fileType = \"device\"\n", unit);
+
+        if (def->src != NULL) {
+            virBufferVSprintf(buffer, "floppy%d.fileName = \"%s\"\n",
+                              unit, def->src);
+        }
+    } else {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Floppy '%s' has unsupported type '%s', expecting '%s' "
+                    "or '%s'"), def->dst,
+                  virDomainDiskTypeToString(def->type),
+                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
+                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+int
+virVMXFormatEthernet(virDomainNetDefPtr def, int controller,
+                     virBufferPtr buffer)
+{
+    char mac_string[VIR_MAC_STRING_BUFLEN];
+    unsigned int prefix, suffix;
+
+    if (controller < 0 || controller > 3) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Ethernet controller index %d out of [0..3] range"),
+                  controller);
+        return -1;
+    }
+
+    virBufferVSprintf(buffer, "ethernet%d.present = \"true\"\n", controller);
+
+    /* def:model -> vmx:virtualDev, vmx:features */
+    if (def->model != NULL) {
+        if (STRCASENEQ(def->model, "vlance") &&
+            STRCASENEQ(def->model, "vmxnet") &&
+            STRCASENEQ(def->model, "vmxnet2") &&
+            STRCASENEQ(def->model, "vmxnet3") &&
+            STRCASENEQ(def->model, "e1000")) {
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Expecting domain XML entry 'devices/interfase/model' "
+                        "to be 'vlance' or 'vmxnet' or 'vmxnet2' or 'vmxnet3' "
+                        "or 'e1000' but found '%s'"), def->model);
+            return -1;
+        }
+
+        if (STRCASEEQ(def->model, "vmxnet2")) {
+            virBufferVSprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
+                              controller);
+            virBufferVSprintf(buffer, "ethernet%d.features = \"15\"\n",
+                              controller);
+        } else {
+            virBufferVSprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
+                              controller, def->model);
+        }
+    }
+
+    /* def:type, def:ifname -> vmx:connectionType */
+    switch (def->type) {
+      case VIR_DOMAIN_NET_TYPE_BRIDGE:
+        virBufferVSprintf(buffer, "ethernet%d.networkName = \"%s\"\n",
+                          controller, def->data.bridge.brname);
+
+        if (def->ifname != NULL) {
+            virBufferVSprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
+                              controller);
+            virBufferVSprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
+                              controller, def->ifname);
+        } else {
+            virBufferVSprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
+                              controller);
+        }
+
+        break;
+
+      default:
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Unsupported net type '%s'"),
+                  virDomainNetTypeToString(def->type));
+        return -1;
+    }
+
+    /* def:mac -> vmx:addressType, vmx:(generated)Address, vmx:checkMACAddress */
+    virFormatMacAddr(def->mac, mac_string);
+
+    prefix = (def->mac[0] << 16) | (def->mac[1] << 8) | def->mac[2];
+    suffix = (def->mac[3] << 16) | (def->mac[4] << 8) | def->mac[5];
+
+    if (prefix == 0x000c29) {
+        virBufferVSprintf(buffer, "ethernet%d.addressType = \"generated\"\n",
+                          controller);
+        virBufferVSprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
+                          controller, mac_string);
+        virBufferVSprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
+                          controller);
+    } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
+        virBufferVSprintf(buffer, "ethernet%d.addressType = \"static\"\n",
+                          controller);
+        virBufferVSprintf(buffer, "ethernet%d.address = \"%s\"\n",
+                          controller, mac_string);
+    } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
+        virBufferVSprintf(buffer, "ethernet%d.addressType = \"vpx\"\n",
+                          controller);
+        virBufferVSprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
+                          controller, mac_string);
+    } else {
+        virBufferVSprintf(buffer, "ethernet%d.addressType = \"static\"\n",
+                          controller);
+        virBufferVSprintf(buffer, "ethernet%d.address = \"%s\"\n",
+                          controller, mac_string);
+        virBufferVSprintf(buffer, "ethernet%d.checkMACAddress = \"false\"\n",
+                          controller);
+    }
+
+    return 0;
+}
+
+
+
+int
+virVMXFormatSerial(virVMXContext *ctx, virDomainChrDefPtr def,
+                   virBufferPtr buffer)
+{
+    char *fileName = NULL;
+    const char *protocol;
+
+    if (def->target.port < 0 || def->target.port > 3) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Serial port index %d out of [0..3] range"),
+                  def->target.port);
+        return -1;
+    }
+
+    virBufferVSprintf(buffer, "serial%d.present = \"true\"\n", def->target.port);
+
+    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
+    switch (def->type) {
+      case VIR_DOMAIN_CHR_TYPE_DEV:
+        virBufferVSprintf(buffer, "serial%d.fileType = \"device\"\n",
+                          def->target.port);
+        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
+                          def->target.port, def->data.file.path);
+        break;
+
+      case VIR_DOMAIN_CHR_TYPE_FILE:
+        virBufferVSprintf(buffer, "serial%d.fileType = \"file\"\n",
+                          def->target.port);
+
+        fileName = ctx->formatFileName(def->data.file.path, ctx->opaque);
+
+        if (fileName == NULL) {
+            return -1;
+        }
+
+        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
+                          def->target.port, fileName);
+
+        VIR_FREE(fileName);
+        break;
+
+      case VIR_DOMAIN_CHR_TYPE_PIPE:
+        virBufferVSprintf(buffer, "serial%d.fileType = \"pipe\"\n",
+                          def->target.port);
+        /* FIXME: Based on VI Client GUI default */
+        virBufferVSprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
+                          def->target.port);
+        /* FIXME: Based on VI Client GUI default */
+        virBufferVSprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
+                          def->target.port);
+        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
+                          def->target.port, def->data.file.path);
+        break;
+
+      case VIR_DOMAIN_CHR_TYPE_TCP:
+        switch (def->data.tcp.protocol) {
+          case VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW:
+            protocol = "tcp";
+            break;
+
+          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET:
+            protocol = "telnet";
+            break;
+
+          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS:
+            protocol = "telnets";
+            break;
+
+          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS:
+            protocol = "ssl";
+            break;
+
+          default:
+            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                      _("Unsupported character device TCP protocol '%s'"),
+                      virDomainChrTcpProtocolTypeToString(def->data.tcp.protocol));
+            return -1;
+        }
+
+        virBufferVSprintf(buffer, "serial%d.fileType = \"network\"\n",
+                          def->target.port);
+        virBufferVSprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
+                          def->target.port, protocol, def->data.tcp.host,
+                          def->data.tcp.service);
+        virBufferVSprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
+                          def->target.port,
+                          def->data.tcp.listen ? "server" : "client");
+        break;
+
+      default:
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unsupported character device type '%s'"),
+                  virDomainChrTypeToString(def->type));
+        return -1;
+    }
+
+    /* vmx:yieldOnMsrRead */
+    /* FIXME: Based on VI Client GUI default */
+    virBufferVSprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
+                      def->target.port);
+
+    return 0;
+}
+
+
+
+int
+virVMXFormatParallel(virVMXContext *ctx, virDomainChrDefPtr def,
+                     virBufferPtr buffer)
+{
+    char *fileName = NULL;
+
+    if (def->target.port < 0 || def->target.port > 2) {
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Parallel port index %d out of [0..2] range"),
+                  def->target.port);
+        return -1;
+    }
+
+    virBufferVSprintf(buffer, "parallel%d.present = \"true\"\n",
+                      def->target.port);
+
+    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
+    switch (def->type) {
+      case VIR_DOMAIN_CHR_TYPE_DEV:
+        virBufferVSprintf(buffer, "parallel%d.fileType = \"device\"\n",
+                          def->target.port);
+        virBufferVSprintf(buffer, "parallel%d.fileName = \"%s\"\n",
+                          def->target.port, def->data.file.path);
+        break;
+
+      case VIR_DOMAIN_CHR_TYPE_FILE:
+        virBufferVSprintf(buffer, "parallel%d.fileType = \"file\"\n",
+                          def->target.port);
+
+        fileName = ctx->formatFileName(def->data.file.path, ctx->opaque);
+
+        if (fileName == NULL) {
+            return -1;
+        }
+
+        virBufferVSprintf(buffer, "parallel%d.fileName = \"%s\"\n",
+                          def->target.port, fileName);
+
+        VIR_FREE(fileName);
+        break;
+
+      default:
+        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Unsupported character device type '%s'"),
+                  virDomainChrTypeToString(def->type));
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/vmx/vmx.h b/src/vmx/vmx.h
new file mode 100644 (file)
index 0000000..1a4fd9c
--- /dev/null
@@ -0,0 +1,132 @@
+
+/*
+ * vmx.h: VMware VMX parsing/formatting functions
+ *
+ * Copyright (C) 2009-2010 Matthias Bolte <matthias.bolte@googlemail.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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#ifndef __VIR_VMX_H__
+# define __VIR_VMX_H__
+
+# include <stdbool.h>
+
+# include "internal.h"
+# include "conf.h"
+# include "domain_conf.h"
+
+typedef struct _virVMXContext virVMXContext;
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Context
+ */
+
+typedef char * (*virVMXParseFileName)(const char *fileName, void *opaque);
+typedef char * (*virVMXFormatFileName)(const char *src, void *opaque);
+typedef int (*virVMXAutodetectSCSIControllerModel)(virDomainDiskDefPtr def,
+                                                   int *model, void *opaque);
+
+/*
+ * virVMXParseFileName is only used by virVMXParseConfig.
+ * virVMXFormatFileName is only used by virVMXFormatConfig.
+ * virVMXAutodetectSCSIControllerModel is optionally used by virVMXFormatConfig.
+ */
+struct _virVMXContext {
+    void *opaque;
+    virVMXParseFileName parseFileName;
+    virVMXFormatFileName formatFileName;
+    virVMXAutodetectSCSIControllerModel autodetectSCSIControllerModel;
+};
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Helpers
+ */
+
+char *virVMXEscapeHex(const char *string, char escape, const char *special);
+
+# define virVMXEscapeHexPipe(_string) virVMXEscapeHex(_string, '|', "\"")
+
+# define virVMXEscapeHexPercent(_string) virVMXEscapeHex(_string, '%', "/\\")
+
+int virVMXUnescapeHex(char *string, char escape);
+
+# define virVMXUnescapeHexPipe(_string) virVMXUnescapeHex(_string, '|')
+
+# define virVMXUnescapeHexPercent(_string) virVMXUnescapeHex(_string, '%')
+
+char *virVMXConvertToUTF8(const char *encoding, const char *string);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VMX -> Domain XML
+ */
+
+virDomainDefPtr virVMXParseConfig(virVMXContext *ctx, virCapsPtr caps,
+                                  const char *vmx);
+
+int virVMXParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def);
+
+int virVMXParseSCSIController(virConfPtr conf, int controller, bool *present,
+                              int *virtualDev);
+
+int virVMXParseDisk(virVMXContext *ctx, virCapsPtr caps, virConfPtr conf,
+                    int device, int busType, int controllerOrBus, int unit,
+                    virDomainDiskDefPtr *def);
+
+int virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def);
+
+int virVMXParseSerial(virVMXContext *ctx, virConfPtr conf, int port,
+                      virDomainChrDefPtr *def);
+
+int virVMXParseParallel(virVMXContext *ctx, virConfPtr conf, int port,
+                        virDomainChrDefPtr *def);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Domain XML -> VMX
+ */
+
+char *virVMXFormatConfig(virVMXContext *ctx, virCapsPtr caps,
+                         virDomainDefPtr def, int virtualHW_version);
+
+int virVMXFormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer);
+
+int virVMXFormatHardDisk(virVMXContext *ctx, virDomainDiskDefPtr def,
+                         virBufferPtr buffer);
+
+int virVMXFormatCDROM(virVMXContext *ctx, virDomainDiskDefPtr def,
+                      virBufferPtr buffer);
+
+int virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDefPtr def,
+                       virBufferPtr buffer, bool floppy_present[2]);
+
+int virVMXFormatEthernet(virDomainNetDefPtr def, int controller,
+                         virBufferPtr buffer);
+
+int virVMXFormatSerial(virVMXContext *ctx, virDomainChrDefPtr def,
+                       virBufferPtr buffer);
+
+int virVMXFormatParallel(virVMXContext *ctx, virDomainChrDefPtr def,
+                         virBufferPtr buffer);
+
+#endif /* __VIR_VMX_H__ */
index 69731d30af7b5f5835c4c7027b3e6d702d2ae6e7..697b40120eb5be96e8928820c84e43350ac23606 100644 (file)
@@ -91,7 +91,11 @@ check_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuhelptest
 endif
 
 if WITH_ESX
-check_PROGRAMS += esxutilstest vmx2xmltest xml2vmxtest
+check_PROGRAMS += esxutilstest
+endif
+
+if WITH_VMX
+check_PROGRAMS += vmx2xmltest xml2vmxtest
 endif
 
 if WITH_SECDRIVER_SELINUX
@@ -180,7 +184,11 @@ TESTS += nwfilterxml2xmltest
 endif
 
 if WITH_ESX
-TESTS += esxutilstest vmx2xmltest xml2vmxtest
+TESTS += esxutilstest
+endif
+
+if WITH_VMX
+TESTS += vmx2xmltest xml2vmxtest
 endif
 
 if WITH_SECDRIVER_SELINUX
@@ -292,18 +300,22 @@ esxutilstest_SOURCES = \
        esxutilstest.c \
        testutils.c testutils.h
 esxutilstest_LDADD = ../src/libvirt_driver_esx.la $(LDADDS)
+else
+EXTRA_DIST += esxutilstest.c
+endif
 
+if WITH_VMX
 vmx2xmltest_SOURCES = \
        vmx2xmltest.c \
        testutils.c testutils.h
-vmx2xmltest_LDADD = ../src/libvirt_driver_esx.la $(LDADDS)
+vmx2xmltest_LDADD = ../src/libvirt_vmx.la $(LDADDS)
 
 xml2vmxtest_SOURCES = \
        xml2vmxtest.c \
        testutils.c testutils.h
-xml2vmxtest_LDADD = ../src/libvirt_driver_esx.la $(LDADDS)
+xml2vmxtest_LDADD = ../src/libvirt_vmx.la $(LDADDS)
 else
-EXTRA_DIST += esxutilstest.c vmx2xmltest.c xml2vmxtest.c
+EXTRA_DIST += vmx2xmltest.c xml2vmxtest.c
 endif
 
 networkxml2xmltest_SOURCES = \
index 97e154eeddb76aea2414add799c9a9ca46681e3c..b6bf87bd05c42f01192cb4ecd58d0baec21a1e46 100644 (file)
@@ -10,6 +10,7 @@
 # include "memory.h"
 # include "testutils.h"
 # include "util.h"
+# include "vmx/vmx.h"
 # include "esx/esx_util.h"
 # include "esx/esx_vi_types.h"
 
@@ -303,8 +304,8 @@ testConvertWindows1252ToUTF8(const void *data ATTRIBUTE_UNUSED)
     for (i = 0; i < ARRAY_CARDINALITY(windows1252ToUTF8); ++i) {
         VIR_FREE(utf8);
 
-        utf8 = esxUtil_ConvertToUTF8("Windows-1252",
-                                     windows1252ToUTF8[i].windows1252);
+        utf8 = virVMXConvertToUTF8("Windows-1252",
+                                   windows1252ToUTF8[i].windows1252);
 
         if (utf8 == NULL) {
             return -1;
index ba50034d2346b998c3e25952019778cb2e26713b..9378db300feea2cf994ff14000213aba1e10ab89 100644 (file)
@@ -1,6 +1,6 @@
 #include <config.h>
 
-#ifdef WITH_ESX
+#ifdef WITH_VMX
 
 # include <stdio.h>
 # include <string.h>
@@ -9,12 +9,12 @@
 # include "internal.h"
 # include "memory.h"
 # include "testutils.h"
-# include "esx/esx_vmx.h"
+# include "vmx/vmx.h"
 
 static char *progname = NULL;
 static char *abs_srcdir = NULL;
 static virCapsPtr caps = NULL;
-static esxVMX_Context ctx;
+static virVMXContext ctx;
 
 # define MAX_FILE 4096
 
@@ -68,8 +68,7 @@ testCapsInit(void)
 }
 
 static int
-testCompareFiles(const char *vmx, const char *xml,
-                 esxVI_ProductVersion productVersion)
+testCompareFiles(const char *vmx, const char *xml)
 {
     int result = -1;
     char vmxData[MAX_FILE];
@@ -88,7 +87,7 @@ testCompareFiles(const char *vmx, const char *xml,
         goto failure;
     }
 
-    def = esxVMX_ParseConfig(&ctx, caps, vmxData, productVersion);
+    def = virVMXParseConfig(&ctx, caps, vmxData);
 
     if (def == NULL) {
         err = virGetLastError();
@@ -121,7 +120,6 @@ testCompareFiles(const char *vmx, const char *xml,
 struct testInfo {
     const char *input;
     const char *output;
-    esxVI_ProductVersion version;
 };
 
 static int
@@ -136,7 +134,7 @@ testCompareHelper(const void *data)
     snprintf(xml, PATH_MAX, "%s/vmx2xmldata/vmx2xml-%s.xml", abs_srcdir,
              info->output);
 
-    return testCompareFiles(vmx, xml, info->version);
+    return testCompareFiles(vmx, xml);
 }
 
 static char *
@@ -206,9 +204,9 @@ mymain(int argc, char **argv)
         return EXIT_FAILURE;
     }
 
-# define DO_TEST(_in, _out, _version)                                         \
+# define DO_TEST(_in, _out)                                                   \
         do {                                                                  \
-            struct testInfo info = { _in, _out, _version };                   \
+            struct testInfo info = { _in, _out };                             \
             virResetLastError();                                              \
             if (virtTestRun("VMware VMX-2-XML "_in" -> "_out, 1,              \
                             testCompareHelper, &info) < 0) {                  \
@@ -227,65 +225,65 @@ mymain(int argc, char **argv)
     ctx.formatFileName = NULL;
     ctx.autodetectSCSIControllerModel = NULL;
 
-    DO_TEST("case-insensitive-1", "case-insensitive-1", esxVI_ProductVersion_ESX35);
-    DO_TEST("case-insensitive-2", "case-insensitive-2", esxVI_ProductVersion_ESX35);
+    DO_TEST("case-insensitive-1", "case-insensitive-1");
+    DO_TEST("case-insensitive-2", "case-insensitive-2");
 
-    DO_TEST("minimal", "minimal", esxVI_ProductVersion_ESX35);
-    DO_TEST("minimal-64bit", "minimal-64bit", esxVI_ProductVersion_ESX35);
+    DO_TEST("minimal", "minimal");
+    DO_TEST("minimal-64bit", "minimal-64bit");
 
-    DO_TEST("graphics-vnc", "graphics-vnc", esxVI_ProductVersion_ESX35);
+    DO_TEST("graphics-vnc", "graphics-vnc");
 
-    DO_TEST("scsi-driver", "scsi-driver", esxVI_ProductVersion_ESX35);
-    DO_TEST("scsi-writethrough", "scsi-writethrough", esxVI_ProductVersion_ESX35);
+    DO_TEST("scsi-driver", "scsi-driver");
+    DO_TEST("scsi-writethrough", "scsi-writethrough");
 
-    DO_TEST("harddisk-scsi-file", "harddisk-scsi-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("harddisk-ide-file", "harddisk-ide-file", esxVI_ProductVersion_ESX35);
+    DO_TEST("harddisk-scsi-file", "harddisk-scsi-file");
+    DO_TEST("harddisk-ide-file", "harddisk-ide-file");
 
-    DO_TEST("cdrom-scsi-file", "cdrom-scsi-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("cdrom-scsi-device", "cdrom-scsi-device", esxVI_ProductVersion_ESX35);
-    DO_TEST("cdrom-ide-file", "cdrom-ide-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("cdrom-ide-device", "cdrom-ide-device", esxVI_ProductVersion_ESX35);
+    DO_TEST("cdrom-scsi-file", "cdrom-scsi-file");
+    DO_TEST("cdrom-scsi-device", "cdrom-scsi-device");
+    DO_TEST("cdrom-ide-file", "cdrom-ide-file");
+    DO_TEST("cdrom-ide-device", "cdrom-ide-device");
 
-    DO_TEST("floppy-file", "floppy-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("floppy-device", "floppy-device", esxVI_ProductVersion_ESX35);
+    DO_TEST("floppy-file", "floppy-file");
+    DO_TEST("floppy-device", "floppy-device");
 
-    DO_TEST("ethernet-e1000", "ethernet-e1000", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-vmxnet2", "ethernet-vmxnet2", esxVI_ProductVersion_ESX35);
+    DO_TEST("ethernet-e1000", "ethernet-e1000");
+    DO_TEST("ethernet-vmxnet2", "ethernet-vmxnet2");
 
-    DO_TEST("ethernet-custom", "ethernet-custom", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-bridged", "ethernet-bridged", esxVI_ProductVersion_ESX35);
+    DO_TEST("ethernet-custom", "ethernet-custom");
+    DO_TEST("ethernet-bridged", "ethernet-bridged");
 
-    DO_TEST("ethernet-generated", "ethernet-generated", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-static", "ethernet-static", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-vpx", "ethernet-vpx", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-other", "ethernet-other", esxVI_ProductVersion_ESX35);
+    DO_TEST("ethernet-generated", "ethernet-generated");
+    DO_TEST("ethernet-static", "ethernet-static");
+    DO_TEST("ethernet-vpx", "ethernet-vpx");
+    DO_TEST("ethernet-other", "ethernet-other");
 
-    DO_TEST("serial-file", "serial-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-device", "serial-device", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-pipe-client-app", "serial-pipe", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-pipe-server-vm", "serial-pipe", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-pipe-client-app", "serial-pipe", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-pipe-server-vm", "serial-pipe", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-network-server", "serial-network-server", esxVI_ProductVersion_ESX41);
-    DO_TEST("serial-network-client", "serial-network-client", esxVI_ProductVersion_ESX41);
+    DO_TEST("serial-file", "serial-file");
+    DO_TEST("serial-device", "serial-device");
+    DO_TEST("serial-pipe-client-app", "serial-pipe");
+    DO_TEST("serial-pipe-server-vm", "serial-pipe");
+    DO_TEST("serial-pipe-client-app", "serial-pipe");
+    DO_TEST("serial-pipe-server-vm", "serial-pipe");
+    DO_TEST("serial-network-server", "serial-network-server");
+    DO_TEST("serial-network-client", "serial-network-client");
 
-    DO_TEST("parallel-file", "parallel-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("parallel-device", "parallel-device", esxVI_ProductVersion_ESX35);
+    DO_TEST("parallel-file", "parallel-file");
+    DO_TEST("parallel-device", "parallel-device");
 
-    DO_TEST("esx-in-the-wild-1", "esx-in-the-wild-1", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-2", "esx-in-the-wild-2", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-3", "esx-in-the-wild-3", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-4", "esx-in-the-wild-4", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-5", "esx-in-the-wild-5", esxVI_ProductVersion_ESX40);
+    DO_TEST("esx-in-the-wild-1", "esx-in-the-wild-1");
+    DO_TEST("esx-in-the-wild-2", "esx-in-the-wild-2");
+    DO_TEST("esx-in-the-wild-3", "esx-in-the-wild-3");
+    DO_TEST("esx-in-the-wild-4", "esx-in-the-wild-4");
+    DO_TEST("esx-in-the-wild-5", "esx-in-the-wild-5");
 
-    DO_TEST("gsx-in-the-wild-1", "gsx-in-the-wild-1", esxVI_ProductVersion_ESX35);
-    DO_TEST("gsx-in-the-wild-2", "gsx-in-the-wild-2", esxVI_ProductVersion_ESX35);
-    DO_TEST("gsx-in-the-wild-3", "gsx-in-the-wild-3", esxVI_ProductVersion_ESX35);
-    DO_TEST("gsx-in-the-wild-4", "gsx-in-the-wild-4", esxVI_ProductVersion_ESX35);
+    DO_TEST("gsx-in-the-wild-1", "gsx-in-the-wild-1");
+    DO_TEST("gsx-in-the-wild-2", "gsx-in-the-wild-2");
+    DO_TEST("gsx-in-the-wild-3", "gsx-in-the-wild-3");
+    DO_TEST("gsx-in-the-wild-4", "gsx-in-the-wild-4");
 
-    DO_TEST("annotation", "annotation", esxVI_ProductVersion_ESX35);
+    DO_TEST("annotation", "annotation");
 
-    DO_TEST("smbios", "smbios", esxVI_ProductVersion_ESX35);
+    DO_TEST("smbios", "smbios");
 
     virCapabilitiesFree(caps);
 
@@ -301,4 +299,4 @@ int main (void)
     return 77; /* means 'test skipped' for automake */
 }
 
-#endif /* WITH_ESX */
+#endif /* WITH_VMX */
index 7041877ce987b4b2c973f79a418e58cfa38f8678..6a39582d30a78fc5a18bc93f5c92d2bccdf3b0b9 100644 (file)
@@ -1,6 +1,6 @@
 #include <config.h>
 
-#ifdef WITH_ESX
+#ifdef WITH_VMX
 
 # include <stdio.h>
 # include <string.h>
@@ -9,12 +9,12 @@
 # include "internal.h"
 # include "memory.h"
 # include "testutils.h"
-# include "esx/esx_vmx.h"
+# include "vmx/vmx.h"
 
 static char *progname = NULL;
 static char *abs_srcdir = NULL;
 static virCapsPtr caps = NULL;
-static esxVMX_Context ctx;
+static virVMXContext ctx;
 
 # define MAX_FILE 4096
 
@@ -68,8 +68,7 @@ testCapsInit(void)
 }
 
 static int
-testCompareFiles(const char *xml, const char *vmx,
-                 esxVI_ProductVersion productVersion)
+testCompareFiles(const char *xml, const char *vmx, int virtualHW_version)
 {
     int result = -1;
     char xmlData[MAX_FILE];
@@ -93,7 +92,7 @@ testCompareFiles(const char *xml, const char *vmx,
         goto failure;
     }
 
-    formatted = esxVMX_FormatConfig(&ctx, caps, def, productVersion);
+    formatted = virVMXFormatConfig(&ctx, caps, def, virtualHW_version);
 
     if (formatted == NULL) {
         goto failure;
@@ -116,7 +115,7 @@ testCompareFiles(const char *xml, const char *vmx,
 struct testInfo {
     const char *input;
     const char *output;
-    esxVI_ProductVersion version;
+    int virtualHW_version;
 };
 
 static int
@@ -131,7 +130,7 @@ testCompareHelper(const void *data)
     snprintf(vmx, PATH_MAX, "%s/xml2vmxdata/xml2vmx-%s.vmx", abs_srcdir,
              info->output);
 
-    return testCompareFiles(xml, vmx, info->version);
+    return testCompareFiles(xml, vmx, info->virtualHW_version);
 }
 
 static int
@@ -147,17 +146,35 @@ static char *
 testFormatVMXFileName(const char *src, void *opaque ATTRIBUTE_UNUSED)
 {
     bool success = false;
+    char *copyOfDatastorePath = NULL;
+    char *tmp = NULL;
+    char *saveptr = NULL;
     char *datastoreName = NULL;
     char *directoryAndFileName = NULL;
     char *absolutePath = NULL;
 
     if (STRPREFIX(src, "[")) {
         /* Found potential datastore path */
-        if (esxUtil_ParseDatastorePath(src, &datastoreName, NULL,
-                                       &directoryAndFileName) < 0) {
+        copyOfDatastorePath = strdup(src);
+
+        if (copyOfDatastorePath == NULL) {
+            goto cleanup;
+        }
+
+        /* Expected format: '[<datastore>] <path>' where <path> is optional */
+        if ((tmp = STRSKIP(copyOfDatastorePath, "[")) == NULL || *tmp == ']' ||
+            (datastoreName = strtok_r(tmp, "]", &saveptr)) == NULL) {
             goto cleanup;
         }
 
+        directoryAndFileName = strtok_r(NULL, "", &saveptr);
+
+        if (directoryAndFileName == NULL) {
+            directoryAndFileName = (char *)"";
+        } else {
+            directoryAndFileName += strspn(directoryAndFileName, " ");
+        }
+
         virAsprintf(&absolutePath, "/vmfs/volumes/%s/%s", datastoreName,
                     directoryAndFileName);
     } else if (STRPREFIX(src, "/")) {
@@ -175,8 +192,7 @@ testFormatVMXFileName(const char *src, void *opaque ATTRIBUTE_UNUSED)
         VIR_FREE(absolutePath);
     }
 
-    VIR_FREE(datastoreName);
-    VIR_FREE(directoryAndFileName);
+    VIR_FREE(copyOfDatastorePath);
 
     return absolutePath;
 }
@@ -226,59 +242,59 @@ mymain(int argc, char **argv)
     ctx.formatFileName = testFormatVMXFileName;
     ctx.autodetectSCSIControllerModel = testAutodetectSCSIControllerModel;
 
-    DO_TEST("minimal", "minimal", esxVI_ProductVersion_ESX35);
-    DO_TEST("minimal-64bit", "minimal-64bit", esxVI_ProductVersion_ESX35);
+    DO_TEST("minimal", "minimal", 4);
+    DO_TEST("minimal-64bit", "minimal-64bit", 4);
 
-    DO_TEST("graphics-vnc", "graphics-vnc", esxVI_ProductVersion_ESX35);
+    DO_TEST("graphics-vnc", "graphics-vnc", 4);
 
-    DO_TEST("scsi-driver", "scsi-driver", esxVI_ProductVersion_ESX35);
-    DO_TEST("scsi-writethrough", "scsi-writethrough", esxVI_ProductVersion_ESX35);
+    DO_TEST("scsi-driver", "scsi-driver", 4);
+    DO_TEST("scsi-writethrough", "scsi-writethrough", 4);
 
-    DO_TEST("harddisk-scsi-file", "harddisk-scsi-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("harddisk-ide-file", "harddisk-ide-file", esxVI_ProductVersion_ESX35);
+    DO_TEST("harddisk-scsi-file", "harddisk-scsi-file", 4);
+    DO_TEST("harddisk-ide-file", "harddisk-ide-file", 4);
 
-    DO_TEST("cdrom-scsi-file", "cdrom-scsi-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("cdrom-scsi-device", "cdrom-scsi-device", esxVI_ProductVersion_ESX35);
-    DO_TEST("cdrom-ide-file", "cdrom-ide-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("cdrom-ide-device", "cdrom-ide-device", esxVI_ProductVersion_ESX35);
+    DO_TEST("cdrom-scsi-file", "cdrom-scsi-file", 4);
+    DO_TEST("cdrom-scsi-device", "cdrom-scsi-device", 4);
+    DO_TEST("cdrom-ide-file", "cdrom-ide-file", 4);
+    DO_TEST("cdrom-ide-device", "cdrom-ide-device", 4);
 
-    DO_TEST("floppy-file", "floppy-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("floppy-device", "floppy-device", esxVI_ProductVersion_ESX35);
+    DO_TEST("floppy-file", "floppy-file", 4);
+    DO_TEST("floppy-device", "floppy-device", 4);
 
-    DO_TEST("ethernet-e1000", "ethernet-e1000", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-vmxnet2", "ethernet-vmxnet2", esxVI_ProductVersion_ESX35);
+    DO_TEST("ethernet-e1000", "ethernet-e1000", 4);
+    DO_TEST("ethernet-vmxnet2", "ethernet-vmxnet2", 4);
 
-    DO_TEST("ethernet-custom", "ethernet-custom", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-bridged", "ethernet-bridged", esxVI_ProductVersion_ESX35);
+    DO_TEST("ethernet-custom", "ethernet-custom", 4);
+    DO_TEST("ethernet-bridged", "ethernet-bridged", 4);
 
-    DO_TEST("ethernet-generated", "ethernet-generated", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-static", "ethernet-static", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-vpx", "ethernet-vpx", esxVI_ProductVersion_ESX35);
-    DO_TEST("ethernet-other", "ethernet-other", esxVI_ProductVersion_ESX35);
+    DO_TEST("ethernet-generated", "ethernet-generated", 4);
+    DO_TEST("ethernet-static", "ethernet-static", 4);
+    DO_TEST("ethernet-vpx", "ethernet-vpx", 4);
+    DO_TEST("ethernet-other", "ethernet-other", 4);
 
-    DO_TEST("serial-file", "serial-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-device", "serial-device", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-pipe", "serial-pipe", esxVI_ProductVersion_ESX35);
-    DO_TEST("serial-network-server", "serial-network-server", esxVI_ProductVersion_ESX41);
-    DO_TEST("serial-network-client", "serial-network-client", esxVI_ProductVersion_ESX41);
+    DO_TEST("serial-file", "serial-file", 4);
+    DO_TEST("serial-device", "serial-device", 4);
+    DO_TEST("serial-pipe", "serial-pipe", 4);
+    DO_TEST("serial-network-server", "serial-network-server", 7);
+    DO_TEST("serial-network-client", "serial-network-client", 7);
 
-    DO_TEST("parallel-file", "parallel-file", esxVI_ProductVersion_ESX35);
-    DO_TEST("parallel-device", "parallel-device", esxVI_ProductVersion_ESX35);
+    DO_TEST("parallel-file", "parallel-file", 4);
+    DO_TEST("parallel-device", "parallel-device", 4);
 
-    DO_TEST("esx-in-the-wild-1", "esx-in-the-wild-1", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-2", "esx-in-the-wild-2", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-3", "esx-in-the-wild-3", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-4", "esx-in-the-wild-4", esxVI_ProductVersion_ESX35);
-    DO_TEST("esx-in-the-wild-5", "esx-in-the-wild-5", esxVI_ProductVersion_ESX35);
+    DO_TEST("esx-in-the-wild-1", "esx-in-the-wild-1", 4);
+    DO_TEST("esx-in-the-wild-2", "esx-in-the-wild-2", 4);
+    DO_TEST("esx-in-the-wild-3", "esx-in-the-wild-3", 4);
+    DO_TEST("esx-in-the-wild-4", "esx-in-the-wild-4", 4);
+    DO_TEST("esx-in-the-wild-5", "esx-in-the-wild-5", 4);
 
-    DO_TEST("gsx-in-the-wild-1", "gsx-in-the-wild-1", esxVI_ProductVersion_ESX35);
-    DO_TEST("gsx-in-the-wild-2", "gsx-in-the-wild-2", esxVI_ProductVersion_ESX35);
-    DO_TEST("gsx-in-the-wild-3", "gsx-in-the-wild-3", esxVI_ProductVersion_ESX35);
-    DO_TEST("gsx-in-the-wild-4", "gsx-in-the-wild-4", esxVI_ProductVersion_ESX35);
+    DO_TEST("gsx-in-the-wild-1", "gsx-in-the-wild-1", 4);
+    DO_TEST("gsx-in-the-wild-2", "gsx-in-the-wild-2", 4);
+    DO_TEST("gsx-in-the-wild-3", "gsx-in-the-wild-3", 4);
+    DO_TEST("gsx-in-the-wild-4", "gsx-in-the-wild-4", 4);
 
-    DO_TEST("annotation", "annotation", esxVI_ProductVersion_ESX35);
+    DO_TEST("annotation", "annotation", 4);
 
-    DO_TEST("smbios", "smbios", esxVI_ProductVersion_ESX35);
+    DO_TEST("smbios", "smbios", 4);
 
     virCapabilitiesFree(caps);
 
@@ -294,4 +310,4 @@ int main (void)
     return 77; /* means 'test skipped' for automake */
 }
 
-#endif /* WITH_ESX */
+#endif /* WITH_VMX */