2010/12/2 Jean-Baptiste Rouault <jean-baptiste.rouault@xxxxxxxxxxx>: > --- > Âconfigure.ac        Â|  Â7 + > Âinclude/libvirt/virterror.h |  Â1 + > Âpo/POTFILES.in       Â|  Â2 + > Âsrc/Makefile.am       |  24 +- > Âsrc/driver.h        Â|  Â3 +- > Âsrc/libvirt.c        |  15 + > Âsrc/util/virterror.c    Â|  Â3 + > Âsrc/vmware/vmware_conf.c  Â| Â480 +++++++++++++++ > Âsrc/vmware/vmware_conf.h  Â|  82 +++ > Âsrc/vmware/vmware_driver.c Â| 1372 +++++++++++++++++++++++++++++++++++++++++++ > Âsrc/vmware/vmware_driver.h Â|  25 + > Â11 files changed, 2010 insertions(+), 4 deletions(-) > Âcreate mode 100644 src/vmware/vmware_conf.c > Âcreate mode 100644 src/vmware/vmware_conf.h > Âcreate mode 100644 src/vmware/vmware_driver.c > Âcreate mode 100644 src/vmware/vmware_driver.h > diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c > new file mode 100644 > index 0000000..5e873e1 > --- /dev/null > +++ b/src/vmware/vmware_conf.c > @@ -0,0 +1,480 @@ > +/*---------------------------------------------------------------------------*/ > +/* Copyright 2010, diateam (www.diateam.net) > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ÂSee the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ÂUSA > + */ > +/*---------------------------------------------------------------------------*/ > + > +#include <config.h> > + > +#include <sys/utsname.h> > + > +#include "cpu/cpu.h" > +#include "memory.h" > +#include "nodeinfo.h" > +#include "util/files.h" > +#include "uuid.h" > +#include "virterror_internal.h" > +#include "../esx/esx_vmx.h" > + > +#include "vmware_conf.h" > + > +#define VMWARE_MAX_ARG 20 > + > +/* Free all memory associated with a vmware_driver structure */ > +void > +vmwareFreeDriver(struct vmware_driver *driver) > +{ > +  Âif (!driver) > +    Âreturn; virMutexDestroy(&driver->lock) is missing here. > +  ÂvirDomainObjListDeinit(&driver->domains); > +  ÂvirCapabilitiesFree(driver->caps); > +  ÂVIR_FREE(driver); > +} > + > + > +int > +vmwareLoadDomains(struct vmware_driver *driver) > +{ > +  ÂFILE *fp; > +  ÂvirDomainDefPtr vmdef = NULL; > +  ÂvirDomainObjPtr vm = NULL; > +  Âchar vmxPath[1024]; > +  Âchar * vmx = NULL; > +  ÂvmwareDomainPtr pDomain; > +  Âchar *directoryName = NULL; > +  Âchar *fileName = NULL; > +  Âint ret = -1; > +  ÂesxVMX_Context ctx; > + > +  Âctx.parseFileName = esxCopyVMXFileName; > + > +  Âfp = driver->type == > +    ÂTYPE_PLAYER ? popen(VMRUN " -T " "player" " list 2>/dev/null", > +              Â"r") : popen(VMRUN " -T " "ws" > +                     " list 2>/dev/null", "r"); > +  Âif (fp == NULL) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", _("popen failed")); > +    Âreturn -1; > +  Â} > + > +  Âwhile (!feof(fp)) { > +    Âif (fgets(vmxPath, 1024, fp) == NULL) { Use fgets(vmxPath, sizeof(vmxPath), fp) here instead. > +      Âif (feof(fp)) > +        Âbreak; > + > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("Failed to parse vmrun list output")); > +      Âgoto cleanup; > +    Â} > +    Âif (vmxPath[0] != '/') > +      Âcontinue; > + > +    Â/* remove trailing newline */ > +    Âint len = strlen(vmxPath); strlen returns size_t, not int. Also move size_t len to the block of other variables at the beginning of the function. > +    Âif (len && vmxPath[len-1] == '\n') > +      ÂvmxPath[len-1] = '\0'; > + > +    Âif (virFileReadAll(vmxPath, 10000, &vmx) == -1) { > +      Âperror("error reading vmx file"); > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +            Â_("failed to read vmx file %s"), vmxPath); > +      Âgoto cleanup; > +    Â} > + > +    Âif ((vmdef = > +       esxVMX_ParseConfig(&ctx, driver->caps, vmx, > +                ÂesxVI_ProductVersion_ESX4x)) == NULL) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +            Â_("failed to parse config file")); > +      Âgoto cleanup; > +    Â} > + > +    Âif (!(vm = virDomainAssignDef(driver->caps, > +                   Â&driver->domains, vmdef, false))) > +      Âgoto cleanup; > + > +    ÂpDomain = vm->privateData; > + > +    ÂpDomain->vmxPath = strdup(vmxPath); > +    Âif (pDomain->vmxPath == NULL) { > +      ÂvirReportOOMError(); > +      Âgoto no_memory; Just goto cleanup here, as you already reported the OOM error. Now you can remove the no_memory label and avoid the jump backwards to the cleanup label. > +    Â} > + > +    ÂvmwareDomainConfigDisplay(pDomain, vmdef); > + > +    Â//vmrun list only reports running vms > +    Âvm->state = VIR_DOMAIN_RUNNING; > +    Âvm->def->id = driver->nextvmid++; > +    Âvm->persistent = 1; > + > +    ÂvirDomainObjUnlock(vm); > + > +    Âvmdef = NULL; > +    Âvm = NULL; > +  Â} > + > +  Âret = 0; > + > +cleanup: > +  ÂvirDomainDefFree(vmdef); > +  ÂVIR_FORCE_FCLOSE(fp); > +  ÂVIR_FREE(directoryName); > +  ÂVIR_FREE(fileName); > +  ÂVIR_FREE(vmx); > +  Âif (vm) > +    ÂvirDomainObjUnref(vm); > +  Âreturn ret; > + > +no_memory: > +  ÂvirReportOOMError(); > +  Âgoto cleanup; > +} > + > + > +int > +vmwareExtractVersion(struct vmware_driver *driver) > +{ > +  Âunsigned long version = 0; > +  ÂFILE *fp = NULL; > +  Âchar str[50]; > +  Âchar *tmp; > +  Âint ret = -1; > + > +  Âif (driver->type == TYPE_PLAYER) { > +    Âif ((fp = popen("vmplayer -v 2>/dev/null", "r")) == NULL) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", _("popen failed")); > +      Âgoto cleanup; > +    Â} > +    Âif (!feof(fp) && fgets(str, 49, fp)) { > +      Âif ((tmp = STRSKIP(str, "VMware Player ")) == NULL) { > +        ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +              Â_("vmplayer -v parsing error")); > +        Âgoto cleanup; > +      Â} > +      Âif (virParseVersionString(tmp, &version) < 0) { > +        ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +              Â_("version parsing error")); > +        Âgoto cleanup; > +      Â} > +      Âdriver->version = version; > +      Âret = 0; > +    Â} else { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("vmplayer -v reading error")); > +    Â} > +  Â} else if (driver->type == TYPE_WORKSTATION) { > +    Âif ((fp = popen("vmware -v 2>/dev/null", "r")) == NULL) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", _("popen failed")); > +      Âgoto cleanup; > +    Â} > +    Âif (!feof(fp) && fgets(str, 49, fp)) { > +      Âif ((tmp = STRSKIP(str, "VMware Workstation ")) == NULL) { > +        ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +              Â_("vmware -v parsing error")); > +        Âgoto cleanup; > +      Â} > +      Âif (virParseVersionString(tmp, &version) < 0) { > +        ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +              Â_("version parsing error")); > +        Âgoto cleanup; > +      Â} > +      Âdriver->version = version; > +      Âret = 0; > +    Â} else { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("vmware -v reading error")); > +    Â} > +  Â} > + > +cleanup: > +  ÂVIR_FORCE_FCLOSE(fp); > +  Âreturn ret; > +} > + > + > +int > +vmwareParsePath(char *path, char **directory, char **filename) > +{ > +  Âchar *separator; > + > +  Âseparator = strrchr(path, '/'); > + > +  Âif (separator != NULL) { > +    Â*separator++ = '\0'; > + > +    Âif (*separator == '\0') { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +            Â_("path '%s' doesn't reference a file"), path); > +      Âreturn -1; > +    Â} > + > +    Âif ((*directory = strdup(path)) == NULL) > +      Âgoto no_memory; > +    Âif ((*filename = strdup(separator)) == NULL) > +      Âgoto no_memory; > + > +  Â} else { > +    Âif ((*filename = strdup(separator)) == NULL) > +      Âgoto no_memory; > +  Â} > + > +  Âreturn 0; > + > +no_memory: > +  ÂvirReportOOMError(); > +  Âreturn -1; > +} > + > +int > +vmwareVmxPath(virDomainDefPtr vmdef, char **vmxPath) > +{ > +  ÂvirDomainDiskDefPtr disk = NULL; > +  Âchar *directoryName = NULL; > +  Âchar *fileName = NULL; > +  Âint ret = -1; > +  Âint i = 0; > + > +  Â/* > +   * Build VMX URL. Use the source of the first file-based harddisk > +   * to deduce the path for the VMX file. Don't just use the > +   * first disk, because it may be CDROM disk and ISO images are normaly not > +   * located in the virtual machine's directory. This approach > +   * isn't perfect but should work in the majority of cases. > +   */ > +  Âif (vmdef->ndisks < 1) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("Domain XML doesn't contain any disks, " > +           Â"cannot deduce datastore and path for VMX file")); > +    Âgoto cleanup; > +  Â} > + > +  Âfor (i = 0; i < vmdef->ndisks; ++i) { > +    Âif (vmdef->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK && > +      Âvmdef->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) { > +      Âdisk = vmdef->disks[i]; > +      Âbreak; > +    Â} > +  Â} > + > +  Âif (disk == NULL) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("Domain XML doesn't contain any file-based harddisks, " > +           Â"cannot deduce datastore and path for VMX file")); > +    Âgoto cleanup; > +  Â} > + > +  Âif (disk->src == NULL) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("First file-based harddisk has no source, cannot " > +           Â"deduce datastore and path for VMX file")); > +    Âgoto cleanup; > +  Â} > + > +  Âif (vmwareParsePath(disk->src, &directoryName, &fileName) < 0) { > +    Âgoto cleanup; > +  Â} > + > +  Âif (!virFileHasSuffix(fileName, ".vmdk")) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("Expecting source '%s' of first file-based harddisk " > +           Â"to be a VMDK image"), disk->src); > +    Âgoto cleanup; > +  Â} > + > +  Âif (vmwareConstructVmxPath(directoryName, vmdef->name, vmxPath) < 0) { > +    ÂvirReportOOMError(); > +    Âgoto cleanup; > +  Â} > + > +  Âret = 0; > + > + Âcleanup: > +  ÂVIR_FREE(directoryName); > +  ÂVIR_FREE(fileName); > +  Âreturn ret; > +} > + > +int > +vmwareMoveFile(char *srcFile, char *dstFile) > +{ > +  Âconst char *cmdmv[] = > +    Â{ "mv", PROGRAM_SENTINAL, PROGRAM_SENTINAL, NULL }; > + > +  Âif (!virFileExists(srcFile)) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, _("file %s does not exist"), > +          ÂsrcFile); > +    Âreturn -1; > +  Â} > + > +  Âif (STREQ(srcFile, dstFile)) > +    Âreturn 0; > + > +  ÂvmwareSetSentinal(cmdmv, srcFile); > +  ÂvmwareSetSentinal(cmdmv, dstFile); > +  Âif (virRun(cmdmv, NULL) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("failed to move file to %s "), dstFile); > +    Âreturn -1; > +  Â} > + > +  Âreturn 0; > +} > + > +int > +vmwareMakePath(char *srcDir, char *srcName, char *srcExt, char **outpath) > +{ > +  Âif (virAsprintf(outpath, "%s/%s.%s", srcDir, srcName, srcExt) < 0) { > +    ÂvirReportOOMError(); > +    Âreturn -1; > +  Â} > +  Âreturn 0; > +} > + > diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c > new file mode 100644 > index 0000000..5615bef > --- /dev/null > +++ b/src/vmware/vmware_driver.c > +static virDrvOpenStatus > +vmwareOpen(virConnectPtr conn, > +      virConnectAuthPtr auth ATTRIBUTE_UNUSED, > +      int flags ATTRIBUTE_UNUSED) > +{ > +  Âstruct vmware_driver *driver; > + > +  Âif (conn->uri == NULL) { > +    Â/* @TODO accept */ > +    Âreturn VIR_DRV_OPEN_DECLINED; > +  Â} else { > +    Âif (conn->uri->scheme == NULL || > +      Â(STRNEQ(conn->uri->scheme, "vmwareplayer") && > +       STRNEQ(conn->uri->scheme, "vmwarews"))) > +      Âreturn VIR_DRV_OPEN_DECLINED; > + > +    Â/* If server name is given, its for remote driver */ > +    Âif (conn->uri->server != NULL) > +      Âreturn VIR_DRV_OPEN_DECLINED; > + > +    Â/* If path isn't /session, then they typoed, so tell them correct path */ > +    Âif (conn->uri->path == NULL || STRNEQ(conn->uri->path, "/session")) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +            Â("unexpected VMware URI path '%s', try vmwareplayer:///session or vmwarews:///session"), > +            Âconn->uri->path); Should be _() instead of (). Add vmwareError to the list of msg_gen_function's in cfg.mk to let "make syntax-check" verify this. Also you might feed a NULL string for %s, that's not save. Use NULLSTR(conn->uri->path) here in the vmwareError call, or reorder the testing logic. > +      Âreturn VIR_DRV_OPEN_ERROR; > +    Â} > +  Â} > + > +  Â/* We now know the URI is definitely for this driver, so beyond > +   * here, don't return DECLINED, always use ERROR */ You should probably check early if vmrun is available at all, For example like this. char *vmrun = virFindFileInPath(VMRUN); if (vmrun == NULL) { vmwareError(VIR_ERR_INTERNAL_ERROR, _("%s utility is missing"), VMRUN); return VIR_DRV_OPEN_ERROR; } else { VIR_FREE(vmrun); } > +  Âif (VIR_ALLOC(driver) < 0) { > +    ÂvirReportOOMError(); > +    Âreturn VIR_DRV_OPEN_ERROR; > +  Â} > +static const char * > +vmwareGetType(virConnectPtr conn ATTRIBUTE_UNUSED) conn is not unused here, so you don't need to mark it as such. > +{ > +  Âstruct vmware_driver *driver = conn->privateData; > +  Âint type; > + > +  ÂvmwareDriverLock(driver); > +  Âtype = driver->type; > +  ÂvmwareDriverUnlock(driver); > +  Âreturn type == TYPE_PLAYER ? "vmware player" : "vmware workstation"; > +} > +static virDomainPtr > +vmwareDomainDefineXML(virConnectPtr conn, const char *xml) > +{ > +  Âstruct vmware_driver *driver = conn->privateData; > +  ÂvirDomainDefPtr vmdef = NULL; > +  ÂvirDomainObjPtr vm = NULL; > +  ÂvirDomainPtr dom = NULL; > +  Âchar *vmx = NULL; > +  Âchar *directoryName = NULL; > +  Âchar *fileName = NULL; > +  Âchar *vmxPath = NULL; > +  ÂvmwareDomainPtr pDomain = NULL; > +  ÂesxVMX_Context ctx; > + > +  Âctx.formatFileName = esxCopyVMXFileName; > + > +  ÂvmwareDriverLock(driver); > +  Âif ((vmdef = virDomainDefParseString(driver->caps, xml, > +                     VIR_DOMAIN_XML_INACTIVE)) == NULL) > +    Âgoto cleanup; > + > +  Âvm = virDomainFindByName(&driver->domains, vmdef->name); > +  Âif (vm) { > +    ÂvmwareError(VIR_ERR_OPERATION_FAILED, > +          Â_("Already an VMWARE VM active with the id '%s'"), > +          Âvmdef->name); > +    Âgoto cleanup; > +  Â} > + > +  Â/* generate vmx file */ > +  Âvmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef, > +               ÂesxVI_ProductVersion_ESX4x); > +  Âif (vmx == NULL) { > +    ÂvmwareError(VIR_ERR_OPERATION_FAILED, _("cannot create xml")); Don't report your own error here, esxVMX_FormatConfig did this already when it returns NULL. Your error message will overwrite the more detailed error message reported by esxVMX_FormatConfig. > +    Âgoto cleanup; > +  Â} > + > +  Âif (vmwareVmxPath(vmdef, &vmxPath) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("retrieve vmx path.. failed")); > +    Âgoto cleanup; > +  Â} > + > +  Â/* create vmx file */ > +  Âif (virFileWriteStr(vmxPath, vmx) < 0) { This will need the 3. argument for the extended virFileWriteStr function. > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("Failed to write vmx file '%s'"), vmxPath); > +    Âgoto cleanup; > +  Â} > +static int > +vmwareDomainSuspend(virDomainPtr dom) > +{ > +  Âstruct vmware_driver *driver = dom->conn->privateData; > + > +  ÂvirDomainObjPtr vm; > +  Âconst char *cmd[] = { > +   ÂVMRUN, "-T", PROGRAM_SENTINAL, "pause", > +   ÂPROGRAM_SENTINAL, NULL > +  Â}; > +  Âint ret = -1; > + > +  Âif (driver->type == TYPE_PLAYER) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("vmplayer does not support libvirt suspend/resume" > +           Â" (vmware pause/unpause) operation ")); > +    Âreturn ret; > +  Â} > + > +  ÂvmwareDriverLock(driver); > +  Âvm = virDomainFindByUUID(&driver->domains, dom->uuid); > +  ÂvmwareDriverUnlock(driver); > + > +  Âif (!vm) { > +    ÂvmwareError(VIR_ERR_INVALID_DOMAIN, "%s", > +          Â_("no domain with matching uuid")); > +    Âgoto cleanup; > +  Â} > + > +  ÂvmwareSetSentinal(cmd, vmw_types[driver->type]); All access to the driver struct is made with the driver lock held, expect this one. Actually accessing driver->type unlocked should be okay, as driver->type is set in the open function and then only read. In some functions you take the lock to access driver->type in some you don't. Choose one way and then be consistent. > +static int > +vmwareDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) > +{ > +  Âstruct vmware_driver *driver = dom->conn->privateData; > + > +  ÂvirDomainObjPtr vm; > +  Âconst char *cmd[] = { > +    ÂVMRUN, "-T", PROGRAM_SENTINAL, > +    Â"reset", PROGRAM_SENTINAL, NULL > +  Â}; virDomainReboot is meant to reboot the guest OS as in executing the reboot command from inside the guest OS. It's not meant to do a hardware level reset as in pressing the reset button of an actual computer. I'm not sure "vmrun reset" is the right thing here. > +static int > +vmwareDomainSave(virDomainPtr dom, const char *path) > +{ > +  Âstruct vmware_driver *driver = dom->conn->privateData; > +  ÂvirDomainObjPtr vm; > +  Âconst char *cmdsuspend[] = { > +    ÂVMRUN, "-T", PROGRAM_SENTINAL, > +    Â"suspend", PROGRAM_SENTINAL, NULL > +  Â}; > +  Âint ret = -1; > +  Âchar *fDirectoryName = NULL; > +  Âchar *fFileName = NULL; > +  Âchar *tDirectoryName = NULL; > +  Âchar *tFileName = NULL; > +  Âchar *copyPath = NULL; > +  Âchar *copyvmxPath = NULL; > +  Âchar *fvmss = NULL; > +  Âchar *tvmss = NULL; > +  Âchar *fvmem = NULL; > +  Âchar *tvmem = NULL; > +  Âchar *fvmx = NULL; > +  Âchar *tvmx = NULL; > + > +  ÂvmwareDriverLock(driver); > +  Âvm = virDomainFindByUUID(&driver->domains, dom->uuid); > +  ÂvmwareDriverUnlock(driver); > + > +  Âif (!vm) { > +    ÂvmwareError(VIR_ERR_INVALID_DOMAIN, "%s", > +          Â_("no domain with matching uuid")); > +    Âgoto cleanup; > +  Â} > + > +  Â/* vmware suspend */ > +  ÂvmwareSetSentinal(cmdsuspend, vmw_types[driver->type]); > +  ÂvmwareSetSentinal(cmdsuspend, > +           Â((vmwareDomainPtr) vm->privateData)->vmxPath); > + > +  Âif (vm->state != VIR_DOMAIN_RUNNING) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("domain is not in running state")); > +    Âgoto cleanup; > +  Â} > + > +  Âif (virRun(cmdsuspend, NULL) < 0) > +    Âgoto cleanup; > + > +  Â/* create files path */ > +  ÂcopyvmxPath = strdup(((vmwareDomainPtr) vm->privateData)->vmxPath); > +  Âif(copyvmxPath == NULL) { > +    ÂvirReportOOMError(); > +    Âgoto cleanup; > +  Â} > + > +  Âif((copyPath = strdup(path)) == NULL) { > +    ÂvirReportOOMError(); > +    Âgoto cleanup; > +  Â} > + > +  Âif (vmwareParsePath(copyvmxPath, &fDirectoryName, &fFileName) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("failed to parse vmxPath")); Don't report and error here, vmwareParsePath does this already. > +    Âgoto cleanup; > +  Â} > +  Âif (vmwareParsePath(copyPath, &tDirectoryName, &tFileName) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("failed to parse path")); Don't report and error here, vmwareParsePath does this already. > +    Âgoto cleanup; > +  Â} > + > +  Â/* dir */ > +  Âif (virFileMakePath(tDirectoryName) != 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", _("make path error")); > +    Âgoto cleanup; > +  Â} > + > +  ÂvmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmss", &fvmss); > +  ÂvmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmss", &tvmss); > +  ÂvmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmem", &fvmem); > +  ÂvmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmem", &tvmem); > +  ÂvmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmx", &fvmx); > +  ÂvmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmx", &tvmx); The the return values of all this vmwareMakePath calls. > +  Â/* create linker file */ > +  Âint fd; > + > +  Âif ((fd = > +     open(path, O_CREAT | O_WRONLY | O_TRUNC, > +       ÂS_IRUSR | S_IWUSR)) == -1) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("Failed to open linker file '%s'"), path); > +    Âgoto cleanup; > +  Â} > +  Âif (safewrite > +    Â(fd, ((vmwareDomainPtr) vm->privateData)->vmxPath, > +     strlen(((vmwareDomainPtr) vm->privateData)->vmxPath)) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("failed to create linker file")); > +    Âgoto cleanup; > +  Â} > + > +  Â/* we want to let saved VM inside default directory */ > +  Âif (STREQ(fDirectoryName, tDirectoryName)) > +    Âgoto end; > + > +  Â/* move {vmx,vmss,vmem} files */ > +  Âif ((vmwareMoveFile(fvmss, tvmss) < 0) > +    Â|| (vmwareMoveFile(fvmem, tvmem) < 0) > +    Â|| (vmwareMoveFile(fvmx, tvmx) < 0) > +    Â) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("failed to move file")); Don't report and error here, vmwareMoveFile does this already. > +    Âgoto cleanup; > +  Â} > + > + Âend: > +  Âvm->def->id = -1; > +  Âvm->state = VIR_DOMAIN_SHUTOFF; > +  Âret = 0; > + > + Âcleanup: > +  ÂVIR_FREE(fDirectoryName); > +  ÂVIR_FREE(fFileName); > +  ÂVIR_FREE(tDirectoryName); > +  ÂVIR_FREE(tFileName); > +  ÂVIR_FREE(copyPath); > +  ÂVIR_FREE(copyvmxPath); > + > +  ÂVIR_FREE(fvmss); > +  ÂVIR_FREE(tvmss); > +  ÂVIR_FREE(fvmem); > +  ÂVIR_FREE(tvmem); > +  ÂVIR_FREE(fvmx); > +  ÂVIR_FREE(tvmx); > +  Âif (vm) > +    ÂvirDomainObjUnlock(vm); > +  Âreturn ret; > +} > + > +static int > +vmwareDomainRestore(virConnectPtr conn, const char *path) > +{ > +  Âstruct vmware_driver *driver = conn->privateData; > +  ÂvirDomainDefPtr vmdef = NULL; > +  ÂvirDomainPtr dom = NULL; > +  ÂvirDomainObjPtr vm = NULL; > +  Âint ret = -1; > +  Âchar *vmxPath = NULL; > +  Âchar *copypath = NULL; > +  Âchar *copyvmxPath = NULL; > +  Âchar *tDirectoryName = NULL; > +  Âchar *tFileName = NULL; > +  Âchar *fDirectoryName = NULL; > +  Âchar *fFileName = NULL; > +  Âchar *vmx = NULL; > +  Âchar *xml = NULL; > +  Âchar *sep = NULL; > +  Âchar *baseVmss; > +  Âchar *fvmss = NULL; > +  Âchar *tvmss = NULL; > +  Âchar *fvmem = NULL; > +  Âchar *tvmem = NULL; > +  Âchar *fvmx = NULL; > +  Âchar *tvmx = NULL; > +  ÂesxVMX_Context ctx; > + > +  Âctx.parseFileName = esxCopyVMXFileName; > + > +  Âif (!virFileExists(path)) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("file %s does not exist"), path); > +    Âgoto cleanup; > +  Â} > +  Âif (virFileHasSuffix(path, ".vmx")) {    //we want to restore a vm saved in its default directory > +    Âif((tvmx = strdup(path)) == NULL) { > +      ÂvirReportOOMError(); > +      Âgoto cleanup; > +    Â} > + > +    Âif((copypath = strdup(path)) == NULL) { > +      ÂvirReportOOMError(); > +      Âgoto cleanup; > +    Â} > + > +    Âif (vmwareParsePath(copypath, &fDirectoryName, &fFileName) < 0) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("failed to parse path")); Don't report and error here, vmwareParsePath does this already. > +      Âgoto cleanup; > +    Â} > +    Âsep = strrchr(fFileName, '.'); > +    Âif (sep != NULL) > +      Â*sep = '\0'; > +    ÂvmwareMakePath(fFileName, fFileName, (char *) "vmss", &fvmss); You should check the return value of vmwareMakePath > +    ÂbaseVmss = basename(fvmss); > +  Â} else {          Â//we want to restore a vm saved elsewhere > +    Âif (virFileReadAll(path, 1024, &vmxPath) < 0) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("failed to read vmxPath")); > +      Âgoto cleanup; > +    Â} > + > +    Âif (!virFileHasSuffix(vmxPath, ".vmx")) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +            Â_("%s is not a .vmx file"), vmxPath); > +      Âgoto cleanup; > +    Â} > + > +    Â/* move files */ > +    Âif((copyvmxPath = strdup(vmxPath)) == NULL) { > +      ÂvirReportOOMError(); > +      Âgoto cleanup; > +    Â} > + > +    Âif((copypath = strdup(path)) == NULL) { > +      ÂvirReportOOMError(); > +      Âgoto cleanup; > +    Â} > + > +    Âif (vmwareParsePath(copypath, &fDirectoryName, &fFileName) < 0) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("failed to parse path")); Don't report and error here, vmwareMoveFile does this already. > +      Âgoto cleanup; > +    Â} > +    Âif (vmwareParsePath(copyvmxPath, &tDirectoryName, &tFileName) < 0) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("failed to parse vmxPath")); Don't report and error here, vmwareMoveFile does this already. > +      Âgoto cleanup; > +    Â} > + > +    Âsep = strrchr(tFileName, '.'); > +    Âif (sep != NULL) > +      Â*sep = '\0'; > + > +    Âif (virFileMakePath(tDirectoryName) != 0) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("make path error")); > +      Âgoto cleanup; > +    Â} > + > +    ÂvmwareMakePath(fDirectoryName, tFileName, (char *) "vmss", &fvmss); > +    ÂvmwareMakePath(tDirectoryName, tFileName, (char *) "vmss", &tvmss); > +    ÂvmwareMakePath(fDirectoryName, tFileName, (char *) "vmem", &fvmem); > +    ÂvmwareMakePath(tDirectoryName, tFileName, (char *) "vmem", &tvmem); > +    ÂvmwareMakePath(fDirectoryName, tFileName, (char *) "vmx", &fvmx); > +    ÂvmwareMakePath(tDirectoryName, tFileName, (char *) "vmx", &tvmx); > + > +    Âif ((vmwareMoveFile(fvmss, tvmss) < 0) > +      Â|| (vmwareMoveFile(fvmem, tvmem) < 0) > +      Â|| (vmwareMoveFile(fvmx, tvmx) < 0) > +      Â) { > +      ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +            Â_("failed to move files")); Don't report and error here, vmwareMoveFile does this already. > +      Âgoto cleanup; > +    Â} > + > +    ÂbaseVmss = basename(tvmss); > +  Â} > + > +  Âif (virFileReadAll(tvmx, 10000, &vmx) == -1) { > +    Âperror("error reading vmx file"); > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("failed to read vmx file %s"), tvmx); > +    Âgoto cleanup; > +  Â} > + > +  ÂvmwareDriverLock(driver); > +  Âif ((vmdef = > +     esxVMX_ParseConfig(&ctx, driver->caps, vmx, > +              ÂesxVI_ProductVersion_ESX4x)) == NULL) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("failed to parse config file")); Don't report and error here, esxVMX_ParseConfig does this already. > +    Âgoto cleanup; > +  Â} > +  ÂvmwareDriverUnlock(driver); > + > +  Âxml = virDomainDefFormat(vmdef, VIR_DOMAIN_XML_SECURE); > + > +  Âif ((dom = vmwareDomainDefineXML(conn, xml)) == NULL) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("failed to define domain")); Don't report an error here, vmwareDomainDefineXML does this already. > +    Âgoto cleanup; > +  Â} > + > +  Â/* esxVMX_ParseConfig don't care about vmx checkpoint property for now, so we add it here > +   * TODO > +   */ > +  ÂFILE *pFile = NULL; > + > +  Âif ((pFile = fopen(tvmx, "a+")) == NULL) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("failed to reopen vmx file")); > +    Âgoto cleanup; > +  Â} > + > +  Âfputs("checkpoint.vmState = \"", pFile); > +  Âfputs(baseVmss, pFile); > +  Âfputs("\"", pFile); > +  Âfclose(pFile); > + > +  ÂvmwareDriverLock(driver); > +  Âvm = virDomainFindByName(&driver->domains, dom->name); > + > +  Âif (!vm) { > +    ÂvmwareError(VIR_ERR_INVALID_DOMAIN, "%s", > +          Â_("no domain with matching id")); > +    Âgoto cleanup; > +  Â} > + > +  Â/* start */ > +  Âif (vmwareStartVM(driver, vm) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, "%s", > +          Â_("failed to create domain")); Don't report an error here, vmwareStartVM does this already. > +    Âgoto cleanup; > +  Â} > + > +  Âret = 0; > + > + Âcleanup: > +  ÂVIR_FREE(vmxPath); > +  ÂVIR_FREE(copypath); > +  ÂVIR_FREE(copyvmxPath); > +  ÂVIR_FREE(tDirectoryName); > +  ÂVIR_FREE(tFileName); > +  ÂVIR_FREE(fDirectoryName); > +  ÂVIR_FREE(fFileName); > +  ÂVIR_FREE(vmx); > +  ÂVIR_FREE(xml); > + > +  ÂVIR_FREE(fvmss); > +  ÂVIR_FREE(tvmss); > +  ÂVIR_FREE(fvmem); > +  ÂVIR_FREE(tvmem); > +  ÂVIR_FREE(fvmx); > +  ÂVIR_FREE(tvmx); > + > +  Âif (dom) > +    ÂvirUnrefDomain(dom); > +  Âif (vm) > +    ÂvirDomainObjUnlock(vm); > +  ÂvmwareDriverUnlock(driver); > +  Âreturn ret; > +} > + > +static virDomainPtr > +vmwareDomainCreateXML(virConnectPtr conn, const char *xml, > +           Âunsigned int flags ATTRIBUTE_UNUSED) > +{ > +  Âstruct vmware_driver *driver = conn->privateData; > +  ÂvirDomainDefPtr vmdef = NULL; > +  ÂvirDomainObjPtr vm = NULL; > +  ÂvirDomainPtr dom = NULL; > +  Âchar *vmx = NULL; > +  Âchar *vmxPath = NULL; > +  ÂvmwareDomainPtr pDomain = NULL; > +  ÂesxVMX_Context ctx; > + > +  Âctx.formatFileName = esxCopyVMXFileName; > + > +  ÂvmwareDriverLock(driver); > + > +  Âif ((vmdef = virDomainDefParseString(driver->caps, xml, > +                     VIR_DOMAIN_XML_INACTIVE)) == NULL) > +    Âgoto cleanup; > + > +  Âvm = virDomainFindByName(&driver->domains, vmdef->name); > +  Âif (vm) { > +    ÂvmwareError(VIR_ERR_OPERATION_FAILED, > +          Â_("Already an VMWARE VM active with the id '%s'"), > +          Âvmdef->name); > +    Âgoto cleanup; > +  Â} > + > +  Â/* generate vmx file */ > +  Âvmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef, > +               ÂesxVI_ProductVersion_ESX4x); > +  Âif (vmx == NULL) { > +    ÂvmwareError(VIR_ERR_OPERATION_FAILED, _("cannot create xml")); > +    Âgoto cleanup; > +  Â} > + > +  Âif (vmwareVmxPath(vmdef, &vmxPath) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("retrieve vmx path.. failed")); > +    Âgoto cleanup; > +  Â} > + > +  Â/* create vmx file */ > +  Âif (virFileWriteStr(vmxPath, vmx) < 0) { > +    ÂvmwareError(VIR_ERR_INTERNAL_ERROR, > +          Â_("Failed to write vmx file '%s'"), vmxPath); > +    Âgoto cleanup; > +  Â} > + > +  Â/* assign def */ > +  Âif (!(vm = virDomainAssignDef(driver->caps, > +                 Â&driver->domains, vmdef, false))) > +    Âgoto cleanup; > + > +  ÂpDomain = vm->privateData; > +  ÂpDomain->vmxPath = strdup(vmxPath); > + > +  ÂvmwareDomainConfigDisplay(pDomain, vmdef); > +  Âvmdef = NULL; > + > +  Âif (vmwareStartVM(driver, vm) < 0) { > +    ÂvirDomainRemoveInactive(&driver->domains, vm); > +    Âvm = NULL; > +    Âgoto cleanup; > +  Â} > + > +  Âdom = virGetDomain(conn, vm->def->name, vm->def->uuid); > +  Âif (dom) > +    Âdom->id = vm->def->id; > + > +cleanup: > +  ÂvirDomainDefFree(vmdef); > +  ÂVIR_FREE(vmx); > +  ÂVIR_FREE(vmxPath); > +  Âif(vm) > +    ÂvirDomainObjUnlock(vm); > +  ÂvmwareDriverUnlock(driver); > +  Âreturn dom; > +} > +static int > +vmwareDomainUndefine(virDomainPtr dom) > +{ > +  Âstruct vmware_driver *driver = dom->conn->privateData; > +  ÂvirDomainObjPtr vm; > +  Âint ret = -1; > + > +  ÂvmwareDriverLock(driver); > +  Âvm = virDomainFindByUUID(&driver->domains, dom->uuid); > + > +  Âif (!vm) { > +    Âchar uuidstr[VIR_UUID_STRING_BUFLEN]; > + > +    ÂvirUUIDFormat(dom->uuid, uuidstr); > +    ÂvmwareError(VIR_ERR_NO_DOMAIN, > +          Â_("no domain with matching uuid '%s'"), uuidstr); > +    Âgoto cleanup; > +  Â} > + > +  Âif (virDomainObjIsActive(vm)) { > +    ÂvmwareError(VIR_ERR_OPERATION_INVALID, > +          Â"%s", _("cannot delete active domain")); s/delete/undefine/ At the end of my review I noticed that you overwrite already reported errors in many places. I only commented on some of them so you should check for this in the whole driver. I think the next version of this driver will be ready to be added to the official codebase :) Matthias -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list