+Sun Apr 9 13:10:34 EDT 2006 Daniel Veillard <veillard@redhat.com>
+
+ * TODO src/hash.[ch] src/internal.h src/libvirt.c src/xend_internal.c
+ src/xs_internal.c: implementing domain pointers unification, thread
+ safety and reference counting for domain and connections, this was
+ the last critical change needed before making further progresses at
+ the API level. Still a couple fo things TODO for this, unification
+ at the Python level and adding UUID to hash. All domain/connect alloc
+ and free routines are now centralized in hash.c
+ * docs/APIchunk1.html docs/libvirt-api.xml docs/libvirt-refs.xml
+ docs/html/libvirt-libvirt.html: regenerated the docs, that doesn't
+ change the API.
+
Thu Apr 6 11:32:46 CEST 2006 Karel Zak <kzak@redhat.com>
* src/virsh.c: use stdout for standard outputs, improve
-Absolute TODOs:
-- thread protection, reentrancy, refcounting, etc ...
-
TODO:
- Create() API, how do we best keep flexibility and allow various
specific environment and space for evolution (VMX)
to return a non-None object
- Add uuid to XML format
- add error handling hooks at the python level
+- object unicity for domains at the Python level
+- UUID lookup in hash.c
virsh TODO:
- decide where will be default directory for domains configurations (/etc/xen/domains/* ?)
- UUID based lookup and naming
- Error API similar to libxml2 structured API
- extract error messages from the Xend rpc
+- thread protection, reentrancy, refcounting, etc ...
<a href="html/libvirt-libvirt.html#virDomainSave">virDomainSave</a><br />
</dd></dl><h2>Letter k:</h2><dl><dt>kept</dt><dd><a href="html/libvirt-libvirt.html#virDomainFree">virDomainFree</a><br />
</dd><dt>kernel</dt><dd><a href="html/libvirt-libvirt.html#_virDomainKernel">_virDomainKernel</a><br />
-</dd><dt>kilobytes</dt><dd><a href="html/libvirt-libvirt.html#virDomainGetMaxMemory">virDomainGetMaxMemory</a><br />
+</dd><dt>kilobytes</dt><dd><a href="html/libvirt-libvirt.html#_virNodeInfo">_virNodeInfo</a><br />
+<a href="html/libvirt-libvirt.html#virDomainGetMaxMemory">virDomainGetMaxMemory</a><br />
<a href="html/libvirt-libvirt.html#virDomainSetMaxMemory">virDomainSetMaxMemory</a><br />
</dd><dt>knowing</dt><dd><a href="html/libvirt-libvirt.html#virDomainShutdown">virDomainShutdown</a><br />
</dd></dl><h2>Letter l:</h2><dl><dt>lack</dt><dd><a href="html/libvirt-libvirt.html#virConnectGetVersion">virConnectGetVersion</a><br />
<a href="html/libvirt-libvirt.html#virDomainShutdown">virDomainShutdown</a><br />
<a href="html/libvirt-libvirt.html#virDomainSuspend">virDomainSuspend</a><br />
<a href="html/libvirt-virterror.html#virGetLastError">virGetLastError</a><br />
-</dd><dt>megabytes</dt><dd><a href="html/libvirt-libvirt.html#_virNodeInfo">_virNodeInfo</a><br />
</dd><dt>mem</dt><dd><a href="html/libvirt-libvirt.html#_virNodeInfo">_virNodeInfo</a><br />
</dd><dt>memory</dt><dd><a href="html/libvirt-libvirt.html#_virDomainInfo">_virDomainInfo</a><br />
<a href="html/libvirt-libvirt.html#_virNodeInfo">_virNodeInfo</a><br />
}
</pre><h3><a name="virNodeInfo" id="virNodeInfo">Structure virNodeInfo</a></h3><pre class="programlisting">Structure virNodeInfo<br />struct _virNodeInfo {
charmodel[32] model : string indicating the CPU model
- unsigned long memory : memory size in megabytes
+ unsigned long memory : memory size in kilobytes
unsigned int cpus : the number of active CPUs
unsigned int mhz : expected CPU frequency
unsigned int nodes : the number of NUMA cell, 1 for uniform
<typedef name='virErrorPtr' file='virterror' type='virError *'/>
<struct name='virNodeInfo' file='libvirt' type='struct _virNodeInfo'>
<field name='model' type='charmodel[32]' info=' string indicating the CPU model'/>
- <field name='memory' type='unsigned long' info=' memory size in megabytes'/>
+ <field name='memory' type='unsigned long' info=' memory size in kilobytes'/>
<field name='cpus' type='unsigned int' info=' the number of active CPUs'/>
<field name='mhz' type='unsigned int' info=' expected CPU frequency'/>
<field name='nodes' type='unsigned int' info=' the number of NUMA cell, 1 for uniform mem access'/>
<ref name='_virDomainKernel'/>
</word>
<word name='kilobytes'>
+ <ref name='_virNodeInfo'/>
<ref name='virDomainGetMaxMemory'/>
<ref name='virDomainSetMaxMemory'/>
</word>
<ref name='virDomainSuspend'/>
<ref name='virGetLastError'/>
</word>
- <word name='megabytes'>
- <ref name='_virNodeInfo'/>
- </word>
<word name='mem'>
<ref name='_virNodeInfo'/>
</word>
/*
- * hash.c: chained hash tables
+ * hash.c: chained hash tables for domain and domain/connection deallocations
*
* Reference: Your favorite introductory book on algorithms
*
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
*
* Author: breese@users.sourceforge.net
+ * Daniel Veillard <veillard@redhat.com>
*/
#include <string.h>
#include <stdlib.h>
+#include <libxml/threads.h>
+#include "internal.h"
#include "hash.h"
#define MAX_HASH_LEN 8
return (-1);
}
}
+
+/************************************************************************
+ * *
+ * Domain and Connections allocations *
+ * *
+ ************************************************************************/
+
+/**
+ * virHashError:
+ * @conn: the connection if available
+ * @error: the error noumber
+ * @info: extra information string
+ *
+ * Handle an error at the connection level
+ */
+static void
+virHashError(virConnectPtr conn, virErrorNumber error, const char *info)
+{
+ const char *errmsg;
+
+ if (error == VIR_ERR_OK)
+ return;
+
+ errmsg = __virErrorMsg(error, info);
+ __virRaiseError(conn, NULL, VIR_FROM_NONE, error, VIR_ERR_ERROR,
+ errmsg, info, NULL, 0, 0, errmsg, info);
+}
+
+
+/**
+ * virDomainFreeName:
+ * @domain: a domain object
+ *
+ * Destroy the domain object, this is just used by the domain hash callback.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+static int
+virDomainFreeName(virDomainPtr domain, const char *name ATTRIBUTE_UNUSED)
+{
+ return (virDomainFree(domain));
+}
+
+/**
+ * virGetConnect:
+ *
+ * Allocates a new hypervisor connection structure
+ *
+ * Returns a new pointer or NULL in case of error.
+ */
+virConnectPtr
+virGetConnect(void) {
+ virConnectPtr ret;
+
+ ret = (virConnectPtr) malloc(sizeof(virConnect));
+ if (ret == NULL) {
+ virHashError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
+ goto failed;
+ }
+ memset(ret, 0, sizeof(virConnect));
+ ret->magic = VIR_CONNECT_MAGIC;
+ ret->nb_drivers = 0;
+ ret->domains = virHashCreate(20);
+ if (ret->domains == NULL)
+ goto failed;
+ ret->domains_mux = xmlNewMutex();
+ if (ret->domains_mux == NULL)
+ goto failed;
+
+ ret->uses = 1;
+ return(ret);
+
+failed:
+ if (ret != NULL) {
+ if (ret->domains != NULL)
+ virHashFree(ret->domains, (virHashDeallocator) virDomainFreeName);
+ if (ret->domains_mux != NULL)
+ xmlFreeMutex(ret->domains_mux);
+ free(ret);
+ }
+ return(NULL);
+}
+
+/**
+ * virFreeConnect:
+ * @conn: the hypervisor connection
+ *
+ * Release the connection. if the use count drops to zero, the structure is
+ * actually freed.
+ *
+ * Returns the reference count or -1 in case of failure.
+ */
+int
+virFreeConnect(virConnectPtr conn) {
+ int ret;
+
+ if ((!VIR_IS_CONNECT(conn)) || (conn->domains_mux == NULL)) {
+ virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ xmlMutexLock(conn->domains_mux);
+ conn->uses--;
+ ret = conn->uses;
+ if (ret > 0) {
+ xmlMutexUnlock(conn->domains_mux);
+ return(ret);
+ }
+
+ if (conn->domains != NULL)
+ virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName);
+ if (conn->domains_mux != NULL)
+ xmlFreeMutex(conn->domains_mux);
+ free(conn);
+ return(0);
+}
+
+/**
+ * virGetDomain:
+ * @conn: the hypervisor connection
+ * @name: pointer to the domain name or NULL
+ * @uuid: pointer to the uuid or NULL
+ *
+ * Lookup if the domain is already registered for that connection,
+ * if yes return a new pointer to it, if no allocate a new structure,
+ * and register it in the table. In any case a corresponding call to
+ * virFreeDomain() is needed to not leak data.
+ *
+ * Returns a pointer to the domain, or NULL in case of failure
+ */
+virDomainPtr
+virGetDomain(virConnectPtr conn, const char *name, const char *uuid) {
+ virDomainPtr ret = NULL;
+
+ if ((!VIR_IS_CONNECT(conn)) || ((name == NULL) && (uuid == NULL)) ||
+ (conn->domains_mux == NULL)) {
+ virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(NULL);
+ }
+ xmlMutexLock(conn->domains_mux);
+
+ /* TODO search by UUID first as they are better differenciators */
+
+ ret = (virDomainPtr) virHashLookup(conn->domains, name);
+ if (ret != NULL) {
+ /* TODO check the UUID */
+ goto done;
+ }
+
+ /*
+ * not found, allocate a new one
+ */
+ ret = (virDomainPtr) malloc(sizeof(virDomain));
+ if (ret == NULL) {
+ virHashError(conn, VIR_ERR_NO_MEMORY, "Allocating domain");
+ goto error;
+ }
+ memset(ret, 0, sizeof(virDomain));
+ ret->name = strdup(name);
+ if (ret->name == NULL) {
+ virHashError(conn, VIR_ERR_NO_MEMORY, "Allocating domain");
+ goto error;
+ }
+ ret->magic = VIR_DOMAIN_MAGIC;
+ ret->conn = conn;
+ if (uuid != NULL)
+ memcpy(&(ret->uuid[0]), uuid, 16);
+
+ if (virHashAddEntry(conn->domains, name, ret) < 0) {
+ virHashError(conn, VIR_ERR_INTERNAL_ERROR,
+ "Failed to add domain to connectio hash table");
+ goto error;
+ }
+ conn->uses++;
+done:
+ ret->uses++;
+ xmlMutexUnlock(conn->domains_mux);
+ return(ret);
+
+error:
+ xmlMutexUnlock(conn->domains_mux);
+ if (ret != NULL) {
+ if (ret->name != NULL)
+ free(ret->name );
+ free(ret);
+ }
+ return(NULL);
+}
+
+/**
+ * virFreeDomain:
+ * @conn: the hypervisor connection
+ * @domain: the domain to release
+ *
+ * Release the given domain, if the reference count drops to zero, then
+ * the domain is really freed.
+ *
+ * Returns the reference count or -1 in case of failure.
+ */
+int
+virFreeDomain(virConnectPtr conn, virDomainPtr domain) {
+ int ret = 0;
+
+ if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_DOMAIN(domain)) ||
+ (domain->conn != conn) || (conn->domains_mux == NULL)) {
+ virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ xmlMutexLock(conn->domains_mux);
+
+ /*
+ * decrement the count for the domain
+ */
+ domain->uses--;
+ ret = domain->uses;
+ if (ret > 0)
+ goto done;
+
+ /* TODO search by UUID first as they are better differenciators */
+
+ if (virHashRemoveEntry(conn->domains, domain->name, NULL) < 0) {
+ virHashError(conn, VIR_ERR_INTERNAL_ERROR,
+ "domain missing from connection hash table");
+ goto done;
+ }
+ domain->magic = -1;
+ domain->handle = -1;
+ if (domain->path != NULL)
+ free(domain->path);
+ if (domain->name)
+ free(domain->name);
+ free(domain);
+
+ /*
+ * decrement the count for the connection
+ */
+ conn->uses--;
+ if (conn->uses > 0)
+ goto done;
+
+ if (conn->domains != NULL)
+ virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName);
+ if (conn->domains_mux != NULL)
+ xmlFreeMutex(conn->domains_mux);
+ free(conn);
+ return(0);
+
+done:
+ xmlMutexUnlock(conn->domains_mux);
+ return(ret);
+}
+
/*
- * Summary: Chained hash tables
- * Description: This module implements the hash table support used in
- * various places in the library.
+ * Summary: Chained hash tables and domain/connections handling
+ * Description: This module implements the hash table and allocation and
+ * deallocation of domains and connections
*
* Copy: Copyright (C) 2005 Red Hat, Inc.
*
* Author: Bjorn Reese <bjorn.reese@systematic.dk>
+ * Daniel Veillard <veillard@redhat.com>
*/
#ifndef __VIR_HASH_H__
/*
* The hash table.
*/
- typedef struct _virHashTable virHashTable;
- typedef virHashTable *virHashTablePtr;
+typedef struct _virHashTable virHashTable;
+typedef virHashTable *virHashTablePtr;
/*
* function types:
*
* Callback to free data from a hash.
*/
- typedef void (*virHashDeallocator) (void *payload, char *name);
+typedef void (*virHashDeallocator) (void *payload, char *name);
/*
* Constructor and destructor.
*/
- virHashTablePtr virHashCreate(int size);
- void
- virHashFree(virHashTablePtr table, virHashDeallocator f);
- int virHashSize(virHashTablePtr table);
+virHashTablePtr virHashCreate(int size);
+void virHashFree(virHashTablePtr table, virHashDeallocator f);
+int virHashSize(virHashTablePtr table);
/*
* Add a new entry to the hash table.
*/
- int virHashAddEntry(virHashTablePtr table,
- const char *name, void *userdata);
- int virHashUpdateEntry(virHashTablePtr table,
- const char *name,
- void *userdata, virHashDeallocator f);
+int virHashAddEntry(virHashTablePtr table,
+ const char *name, void *userdata);
+int virHashUpdateEntry(virHashTablePtr table,
+ const char *name,
+ void *userdata, virHashDeallocator f);
/*
* Remove an entry from the hash table.
*/
- int virHashRemoveEntry(virHashTablePtr table,
- const char *name, virHashDeallocator f);
+int virHashRemoveEntry(virHashTablePtr table,
+ const char *name, virHashDeallocator f);
/*
* Retrieve the userdata.
*/
- void *virHashLookup(virHashTablePtr table, const char *name);
+void *virHashLookup(virHashTablePtr table, const char *name);
#ifdef __cplusplus
}
struct _virConnect {
unsigned int magic; /* specific value to check */
+ int uses; /* reference count */
/* the list of available drivers for that connection */
virDriverPtr drivers[MAX_DRIVERS];
int nb_drivers;
*/
struct _virDomain {
unsigned int magic; /* specific value to check */
+ int uses; /* reference count */
virConnectPtr conn; /* pointer back to the connection */
char *name; /* the domain external name */
char *path; /* the domain internal path */
char *virDomainGetVMInfo(virDomainPtr domain,
const char *vm, const char *name);
+/************************************************************************
+ * *
+ * API for error handling *
+ * *
+ ************************************************************************/
void __virRaiseError(virConnectPtr conn,
virDomainPtr dom,
int domain,
int int1, int int2, const char *msg, ...);
const char *__virErrorMsg(virErrorNumber error, const char *info);
+/************************************************************************
+ * *
+ * API for domain/connections (de)allocations *
+ * *
+ ************************************************************************/
+
+virConnectPtr virGetConnect (void);
+int virFreeConnect (virConnectPtr conn);
+virDomainPtr virGetDomain (virConnectPtr conn,
+ const char *name,
+ const char *uuid);
+int virFreeDomain (virConnectPtr conn,
+ virDomainPtr domain);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
#include "xen_internal.h"
#include "xend_internal.h"
#include "xs_internal.h"
-#include "hash.h"
#include "xml.h"
* - memory wrappers for malloc/free ?
*/
-static int virDomainFreeName(virDomainPtr domain, const char *name);
-
static virDriverPtr virDriverTab[MAX_DRIVERS];
static int initialized = 0;
if (!initialized)
virInitialize();
- ret = (virConnectPtr) malloc(sizeof(virConnect));
+ ret = virGetConnect();
if (ret == NULL) {
virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
goto failed;
}
- memset(ret, 0, sizeof(virConnect));
- ret->magic = VIR_CONNECT_MAGIC;
- ret->nb_drivers = 0;
for (i = 0;i < MAX_DRIVERS;i++) {
if ((virDriverTab[i] != NULL) && (virDriverTab[i]->open != NULL)) {
goto failed;
}
- ret->domains = virHashCreate(20);
- if (ret->domains == NULL)
- goto failed;
- ret->domains_mux = xmlNewMutex();
- if (ret->domains_mux == NULL)
- goto failed;
- ret->flags = 0;
-
return (ret);
failed:
if ((ret->drivers[i] != NULL) && (ret->drivers[i]->close != NULL))
ret->drivers[i]->close(ret);
}
- if (ret->domains != NULL)
- virHashFree(ret->domains, (virHashDeallocator) virDomainFreeName);
- if (ret->domains_mux != NULL)
- xmlFreeMutex(ret->domains_mux);
- free(ret);
+ virFreeConnect(ret);
}
return (NULL);
}
if (!initialized)
virInitialize();
- ret = (virConnectPtr) malloc(sizeof(virConnect));
+ ret = virGetConnect();
if (ret == NULL) {
virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
goto failed;
}
- memset(ret, 0, sizeof(virConnect));
- ret->magic = VIR_CONNECT_MAGIC;
- ret->nb_drivers = 0;
for (i = 0;i < MAX_DRIVERS;i++) {
if ((virDriverTab[i] != NULL) && (virDriverTab[i]->open != NULL)) {
virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name);
goto failed;
}
-
- ret->domains = virHashCreate(20);
- if (ret->domains == NULL)
- goto failed;
- ret->domains_mux = xmlNewMutex();
- if (ret->domains_mux == NULL)
- goto failed;
ret->flags = VIR_CONNECT_RO;
return (ret);
if ((ret->drivers[i] != NULL) && (ret->drivers[i]->close != NULL))
ret->drivers[i]->close(ret);
}
- if (ret->domains != NULL)
- virHashFree(ret->domains, (virHashDeallocator) virDomainFreeName);
- if (ret->domains_mux != NULL)
- xmlFreeMutex(ret->domains_mux);
- free(ret);
+ virFreeConnect(ret);
}
return (NULL);
}
-/**
- * virDomainFreeName:
- * @domain: a domain object
- *
- * Destroy the domain object, this is just used by the domain hash callback.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-static int
-virDomainFreeName(virDomainPtr domain, const char *name ATTRIBUTE_UNUSED)
-{
- return (virDomainFree(domain));
-}
-
/**
* virConnectClose:
* @conn: pointer to the hypervisor connection
int
virConnectClose(virConnectPtr conn)
{
- int i;
-
if (!VIR_IS_CONNECT(conn))
return (-1);
- virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName);
- conn->domains = NULL;
- xmlFreeMutex(conn->domains_mux);
- conn->domains_mux = NULL;
- for (i = 0;i < conn->nb_drivers;i++) {
- if ((conn->drivers[i] != NULL) && (conn->drivers[i]->close != NULL))
- conn->drivers[i]->close(conn);
- }
- conn->magic = -1;
- free(conn);
+ if (virFreeConnect(conn) < 0)
+ return (-1);
return (0);
}
}
free(names);
}
+ if (name == NULL)
+ goto error;
- ret = (virDomainPtr) malloc(sizeof(virDomain));
+ ret = virGetDomain(conn, name, &uuid[0]);
if (ret == NULL) {
+ virLibConnError(conn, VIR_ERR_NO_MEMORY, "Allocating domain");
goto error;
}
- memset(ret, 0, sizeof(virDomain));
- ret->magic = VIR_DOMAIN_MAGIC;
- ret->conn = conn;
ret->handle = id;
ret->path = path;
- ret->name = name;
- memcpy(&ret->uuid[0], uuid, 16);
- if (ret->name == NULL) {
- goto error;
- }
+ if (name != NULL)
+ free(name);
return (ret);
- error:
- if (ret != NULL)
- free(ret);
+error:
+ if (name != NULL)
+ free(name);
if (path != NULL)
free(path);
return (NULL);
if (name == NULL)
return (NULL);
- ret = (virDomainPtr) malloc(sizeof(virDomain));
+ ret = virGetDomain(conn, name, &uuid[0]);
if (ret == NULL) {
if (name != NULL)
free(name);
return (NULL);
}
- memset(ret, 0, sizeof(virDomain));
- ret->magic = VIR_DOMAIN_MAGIC;
- ret->conn = conn;
ret->handle = id;
- ret->name = name;
- ret->path = 0;
- memcpy(ret->uuid, uuid, 16);
return (ret);
}
virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
return (-1);
}
- domain->magic = -1;
- domain->handle = -1;
- if (domain->path != NULL)
- free(domain->path);
- if (domain->name)
- free(domain->name);
- free(domain);
- return (0);
+ if (virFreeDomain(domain->conn, domain) < 0)
+ return (-1);
+ return(0);
}
/**
static virDomainPtr
sexpr_to_domain(virConnectPtr conn, struct sexpr *root)
{
- virDomainPtr ret;
+ virDomainPtr ret = NULL;
char *dst_uuid = NULL;
+ char uuid[16];
const char *name;
if ((conn == NULL) || (root == NULL))
return(NULL);
- ret = (virDomainPtr) malloc(sizeof(virDomain));
+ dst_uuid = (char *) &uuid[0];
+ if (sexpr_uuid(&dst_uuid, root, "domain/uuid") == NULL)
+ goto error;
+ name = sexpr_node(root, "domain/name");
+ if (name == NULL)
+ goto error;
+
+ ret = virGetDomain(conn, name, &uuid[0]);
if (ret == NULL) {
virXendError(conn, VIR_ERR_NO_MEMORY, "Allocating domain");
return(NULL);
}
- memset(ret, 0, sizeof(virDomain));
- ret->magic = VIR_DOMAIN_MAGIC;
- ret->conn = conn;
ret->handle = sexpr_int(root, "domain/domid");
if (ret->handle < 0)
goto error;
- dst_uuid = (char *) &(ret->uuid[0]);
- if (sexpr_uuid(&dst_uuid, root, "domain/uuid") == NULL)
- goto error;
- name = sexpr_node(root, "domain/name");
- if (name == NULL)
- goto error;
- ret->name = strdup(name);
- if (ret->name == NULL)
- goto error;
return (ret);
+
error:
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
"failed to parse Xend domain informations");
- if (ret->name != NULL)
- free(ret->name );
- free(ret);
+ if (ret != NULL)
+ virFreeDomain(conn, ret);
return(NULL);
}
if (!found)
return(NULL);
- ret = (virDomainPtr) malloc(sizeof(virDomain));
- if (ret == NULL)
+ ret = virGetDomain(conn, name, NULL);
+ if (ret == NULL) {
+ virXenStoreError(conn, VIR_ERR_NO_MEMORY, "Allocating domain");
+ if (path != NULL)
+ free(path);
goto done;
- memset(ret, 0, sizeof(virDomain));
- ret->magic = VIR_DOMAIN_MAGIC;
- ret->conn = conn;
+ }
ret->handle = id;
ret->path = path;
- ret->name = strdup(name);
done:
if (xenddomain != NULL)