[Libvir] [PATCH 6/6] Inactive domain support: xm config backend

Daniel P. Berrange berrange at redhat.com
Wed Nov 15 02:33:26 UTC 2006


This is the main patch. It adds a new 'xm config file' backend driver to
libvirt. This basically just scans /etc/xen for config files, reads them
and turns them into libvirt XML to create domains. Similarly it can accept
libvirt XML and create config files from it.

Some important points

 - It can override /etc/xen with LIBVIRT_XM_CONFIG_DIR env variable
 - It only re-scans /etc/xen every X seconds & caches parsed config
   files in-memory to avoid parsing / I/O overhead
 - Automatically generates a UUID if the config file doesn;t have one
 - Skips over a blacklist of files from /etc/xen which are known to
   not be valid config files to avoid too many error messages
 - Filters list of inactive domains to strip out any which are currently
   running (acccording to XenD)
 - Allows changing of VCPUS, memory & max memory config settings and
   writes changes back out to disk
 - Can start, create, delete domains from disk

Regards,
Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
-------------- next part --------------
Index: src/Makefile.am
===================================================================
RCS file: /data/cvs/libvirt/src/Makefile.am,v
retrieving revision 1.29
diff -c -r1.29 Makefile.am
*** src/Makefile.am	21 Sep 2006 15:24:37 -0000	1.29
--- src/Makefile.am	15 Nov 2006 02:33:59 -0000
***************
*** 27,33 ****
  		virterror.c					\
  		driver.h					\
  		proxy_internal.c proxy_internal.h		\
! 		conf.c conf.h
  
  bin_PROGRAMS = virsh
  
--- 27,34 ----
  		virterror.c					\
  		driver.h					\
  		proxy_internal.c proxy_internal.h		\
! 		conf.c conf.h                                   \
!                 xm_internal.c xm_internal.h
  
  bin_PROGRAMS = virsh
  
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.12
diff -c -r1.12 driver.h
*** src/driver.h	30 Aug 2006 14:21:03 -0000	1.12
--- src/driver.h	15 Nov 2006 02:33:59 -0000
***************
*** 21,27 ****
      VIR_DRV_XEN_STORE = 2,
      VIR_DRV_XEN_DAEMON = 3,
      VIR_DRV_TEST = 4,
!     VIR_DRV_XEN_PROXY = 5
  } virDrvNo;
  
  
--- 21,28 ----
      VIR_DRV_XEN_STORE = 2,
      VIR_DRV_XEN_DAEMON = 3,
      VIR_DRV_TEST = 4,
!     VIR_DRV_XEN_PROXY = 5,
!     VIR_DRV_XEN_XM = 6
  } virDrvNo;
  
  
Index: src/internal.h
===================================================================
RCS file: /data/cvs/libvirt/src/internal.h,v
retrieving revision 1.24
diff -c -r1.24 internal.h
*** src/internal.h	21 Sep 2006 15:24:37 -0000	1.24
--- src/internal.h	15 Nov 2006 02:34:00 -0000
***************
*** 84,90 ****
  #define VIR_IS_DOMAIN(obj)		((obj) && (obj)->magic==VIR_DOMAIN_MAGIC)
  #define VIR_IS_CONNECTED_DOMAIN(obj)	(VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn))
  
! #define MAX_DRIVERS 5
  
  /*
   * Flags for Xen connections
--- 84,90 ----
  #define VIR_IS_DOMAIN(obj)		((obj) && (obj)->magic==VIR_DOMAIN_MAGIC)
  #define VIR_IS_CONNECTED_DOMAIN(obj)	(VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn))
  
! #define MAX_DRIVERS 10
  
  /*
   * Flags for Xen connections
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.48
diff -c -r1.48 libvirt.c
*** src/libvirt.c	8 Nov 2006 13:53:29 -0000	1.48
--- src/libvirt.c	15 Nov 2006 02:34:01 -0000
***************
*** 28,33 ****
--- 28,34 ----
  #include "xen_internal.h"
  #include "xend_internal.h"
  #include "xs_internal.h"
+ #include "xm_internal.h"
  #include "proxy_internal.h"
  #include "xml.h"
  #include "test.h"
***************
*** 76,81 ****
--- 77,83 ----
      xenProxyRegister();
      xenDaemonRegister();
      xenStoreRegister();
+     xenXMRegister();
      testRegister();
      return(0);
  }
Index: src/xm_internal.c
===================================================================
RCS file: src/xm_internal.c
diff -N src/xm_internal.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/xm_internal.c	15 Nov 2006 02:57:26 -0000
***************
*** 0 ****
--- 1,1366 ----
+ /*
+  * xm_internal.h: helper routines for dealing with inactive domains
+  *
+  * Copyright (C) 2006
+  *
+  *      Daniel Berrange <berrange at redhat.com>
+  *
+  *  This file is subject to the terms and conditions of the GNU Lesser General
+  *  Public License. See the file COPYING.LIB in the main directory of this
+  *  archive for more details.
+  */
+ 
+ #include <dirent.h>
+ #include <time.h>
+ #include <sys/stat.h>
+ 
+ #include <unistd.h>
+ #include <stdint.h>
+ #include <xen/dom0_ops.h>
+ 
+ #include <libxml/parser.h>
+ #include <libxml/tree.h>
+ #include <libxml/xpath.h>
+ 
+ 
+ #include "xm_internal.h"
+ #include "xend_internal.h"
+ #include "conf.h"
+ #include "hash.h"
+ #include "internal.h"
+ #include "xml.h"
+ 
+ typedef struct xenXMConfCache *xenXMConfCachePtr;
+ typedef struct xenXMConfCache {
+     time_t refreshedAt;
+     char filename[PATH_MAX];
+     virConfPtr conf;
+ } xenXMConfCache;
+ 
+ static char configDir[PATH_MAX];
+ static virHashTablePtr configCache = NULL;
+ static int nconnections = 0;
+ static time_t lastRefresh = 0;
+ 
+ #define XM_REFRESH_INTERVAL 10
+ 
+ #define XM_CONFIG_DIR "/etc/xen"
+ #define XM_EXAMPLE_PREFIX "xmexample"
+ #define XEND_CONFIG_FILE "xend-config.sxp"
+ #define XEND_PCI_CONFIG_PREFIX "xend-pci-"
+ #define QEMU_IF_SCRIPT "qemu-ifup"
+ 
+ static virDriver xenXMDriver = {
+     VIR_DRV_XEN_XM,
+     "XenXM",
+     (DOM0_INTERFACE_VERSION >> 24) * 1000000 +
+     ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 +
+     (DOM0_INTERFACE_VERSION & 0xFFFF),
+     NULL, /* init */
+     xenXMOpen, /* open */
+     xenXMClose, /* close */
+     xenXMGetType, /* type */
+     NULL, /* version */
+     NULL, /* nodeGetInfo */
+     NULL, /* listDomains */
+     NULL, /* numOfDomains */
+     NULL, /* domainCreateLinux */
+     NULL, /* domainLookupByID */
+     xenXMDomainLookupByUUID, /* domainLookupByUUID */
+     xenXMDomainLookupByName, /* domainLookupByName */
+     NULL, /* domainSuspend */
+     NULL, /* domainResume */
+     NULL, /* domainShutdown */
+     NULL, /* domainReboot */
+     NULL, /* domainDestroy */
+     NULL, /* domainFree */
+     NULL, /* domainGetName */
+     NULL, /* domainGetID */
+     NULL, /* domainGetUUID */
+     NULL, /* domainGetOSType */
+     xenXMDomainGetMaxMemory, /* domainGetMaxMemory */
+     xenXMDomainSetMaxMemory, /* domainSetMaxMemory */
+     xenXMDomainSetMemory, /* domainMaxMemory */
+     xenXMDomainGetInfo, /* domainGetInfo */
+     NULL, /* domainSave */
+     NULL, /* domainRestore */
+     xenXMDomainSetVcpus, /* domainSetVcpus */
+     NULL, /* domainPinVcpu */
+     NULL, /* domainGetVcpus */
+     xenXMDomainDumpXML, /* domainDumpXML */
+     xenXMListDefinedDomains, /* listDefinedDomains */
+     xenXMNumOfDefinedDomains, /* numOfDefinedDomains */
+     xenXMDomainCreate, /* domainCreate */
+     xenXMDomainDefineXML, /* domainDefineXML */
+     xenXMDomainUndefine, /* domainUndefine */
+ };
+ 
+ static void
+ xenXMError(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_XEND, error, VIR_ERR_ERROR,
+                     errmsg, info, NULL, 0, 0, errmsg, info);
+ }
+ 
+ void xenXMRegister(void)
+ {
+     char *envConfigDir;
+     virRegisterDriver(&xenXMDriver);
+ 
+     if ((envConfigDir = getenv("LIBVIRT_XM_CONFIG_DIR")) != NULL) {
+         strncpy(configDir, envConfigDir, PATH_MAX-1);
+         configDir[PATH_MAX-1] = '\0';
+     } else {
+         strcpy(configDir, XM_CONFIG_DIR);
+     }
+ }
+ 
+ 
+ /* Remove any configs which were not refreshed recently */
+ static int xenXMConfigReaper(const void *payload, const char *key ATTRIBUTE_UNUSED, const void *data) {
+     time_t now = *(const time_t *)data;
+     xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
+ 
+     if (entry->refreshedAt != now)
+         return 1;
+     return 0;
+ }
+ 
+ /* Convenience method to grab a int from the config file object */
+ static int xenXMConfigGetInt(virConfPtr conf, const char *name, long *value) {
+     virConfValuePtr val;
+     if (!value || !name || !conf)
+         return -1;
+ 
+     if (!(val = virConfGetValue(conf, name))) {
+         return -1;
+     }
+ 
+     if (val->type == VIR_CONF_LONG) {
+         *value = val->l;
+     } else if (val->type == VIR_CONF_STRING) {
+         char *ret;
+         if (!val->str)
+             return -1;
+         *value = strtol(val->str, &ret, 10);
+         if (ret == val->str)
+             return -1;
+     } else {
+         return -1;
+     }
+     return 0;
+ }
+ 
+ 
+ /* Convenience method to grab a string from the config file object */
+ static int xenXMConfigGetString(virConfPtr conf, const char *name, const char **value) {
+     virConfValuePtr val;
+     if (!value || !name || !conf)
+         return -1;
+     *value = NULL;
+     if (!(val = virConfGetValue(conf, name))) {
+         return -1;
+     }
+     if (val->type != VIR_CONF_STRING)
+         return -1;
+     if (!val->str)
+         return -1;
+     *value = val->str;
+     return 0;
+ }
+ 
+ /* Convenience method to grab a string UUID from the config file object */
+ static int xenXMConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid) {
+     virConfValuePtr val;
+     char *rawuuid = (char *)uuid;
+     if (!uuid || !name || !conf)
+         return -1;
+     if (!(val = virConfGetValue(conf, name))) {
+         return -1;
+     }
+ 
+     if (val->type != VIR_CONF_STRING)
+         return -1;
+     if (!val->str)
+         return -1;
+ 
+     if (!virParseUUID(&rawuuid, val->str))
+         return -1;
+ 
+     return 0;
+ }
+ 
+ /* Generate a rnadom UUID - used if domain doesn't already
+    have one in its config */
+ static void xenXMConfigGenerateUUID(unsigned char *uuid) {
+     int i;
+     for (i = 0 ; i < 16 ; i++) {
+         uuid[i] = (unsigned char)(1 + (int) (256.0 * (rand() / (RAND_MAX + 1.0))));
+     }
+ }
+ 
+ /* Ensure that a config object has a valid UUID in it,
+    if it doesn't then (re-)generate one */
+ static int xenXMConfigEnsureUUID(virConfPtr conf) {
+     unsigned char uuid[16];
+ 
+     /* If there is no uuid...*/
+     if (xenXMConfigGetUUID(conf, "uuid", uuid) < 0) {
+         virConfValuePtr value;
+         char uuidstr[37];
+ 
+         value = malloc(sizeof(virConfValue));
+         if (!value) {
+             return -1;
+         }
+ 
+         /* ... then generate one */
+         xenXMConfigGenerateUUID(uuid);
+         snprintf(uuidstr, 37,
+                  "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</uuid>\n",
+                  uuid[0], uuid[1], uuid[2], uuid[3],
+                  uuid[4], uuid[5], uuid[6], uuid[7],
+                  uuid[8], uuid[9], uuid[10], uuid[11],
+                  uuid[12], uuid[13], uuid[14], uuid[15]);
+         uuidstr[36] = '\0';
+ 
+         value->type = VIR_CONF_STRING;
+         value->str = strdup(uuidstr);
+         if (!value->str) {
+             free(value);
+             return -1;
+         }
+ 
+         /* And stuff the UUID back into the config file */
+         if (virConfSetValue(conf, "uuid", value) < 0)
+             return -1;
+     }
+     return 0;
+ }
+ 
+ /* Release memory associated with a cached config object */
+ static void xenXMConfigFree(void *payload, const char *key ATTRIBUTE_UNUSED) {
+     xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
+     virConfFree(entry->conf);
+     free(entry);
+ }
+ 
+ 
+ /* This method is called by various methods to scan /etc/xen
+    (or whatever directory was set by  LIBVIRT_XM_CONFIG_DIR
+    environment variable) and process any domain configs. It
+    has rate-limited so never rescans more frequently than
+    once every X seconds */
+ static int xenXMConfigCacheRefresh(void) {
+     DIR *dh;
+     struct dirent *ent;
+     time_t now = time(NULL);
+     int ret = -1;
+ 
+     if (now == ((time_t)-1)) {
+         return -1;
+     }
+ 
+     /* Rate limit re-scans */
+     if ((now - lastRefresh) < XM_REFRESH_INTERVAL)
+         return 0;
+ 
+     lastRefresh = now;
+ 
+     /* Process the files in the config dir */
+     if (!(dh = opendir(configDir))) {
+         return -1;
+     }
+ 
+     while ((ent = readdir(dh))) {
+         xenXMConfCachePtr entry;
+         struct stat st;
+         int newborn = 0;
+         char path[PATH_MAX];
+ 
+         /* Skip a bunch of cruft that clearly aren't config files*/
+         /* Like 'dot' files */
+         if (!strncmp(ent->d_name, ".", 1))
+             continue;
+         /* The XenD server config file */
+         if (!strncmp(ent->d_name, XEND_CONFIG_FILE, strlen(XEND_CONFIG_FILE)))
+             continue;
+         /* Random PCI config cruft */
+         if (!strncmp(ent->d_name, XEND_PCI_CONFIG_PREFIX, strlen(XEND_PCI_CONFIG_PREFIX)))
+             continue;
+         /* The example domain configs */
+         if (!strncmp(ent->d_name, XM_EXAMPLE_PREFIX, strlen(XM_EXAMPLE_PREFIX)))
+             continue;
+         /* The QEMUU networking script */
+         if (!strncmp(ent->d_name, QEMU_IF_SCRIPT, strlen(QEMU_IF_SCRIPT)))
+             continue;
+ 
+         /* Editor backups */
+         if (ent->d_name[0] == '#')
+             continue;
+         if (ent->d_name[strlen(ent->d_name)-1] == '~')
+             continue;
+ 
+         /* Build the full file path */
+         if ((strlen(XM_CONFIG_DIR) + 1 + strlen(ent->d_name) + 1) > PATH_MAX)
+             continue;
+         strcpy(path, XM_CONFIG_DIR);
+         strcat(path, "/");
+         strcat(path, ent->d_name);
+ 
+         /* Skip anything which isn't a file (takes care of scripts/ subdir */
+         if ((stat(path, &st) < 0) ||
+             !S_ISREG(st.st_mode)) {
+             continue;
+         }
+ 
+         /* If we already have a matching entry and it is not
+            modified, then carry on to next one*/
+         if ((entry = virHashLookup(configCache, ent->d_name))) {
+             if (entry->refreshedAt >= st.st_mtime) {
+                 entry->refreshedAt = now;
+                 continue;
+             }
+         }
+ 
+         if (entry) { /* Existing entry which needs refresh */
+             virConfFree(entry->conf);
+             entry->conf = NULL;
+         } else { /* Completely new entry */
+             newborn = 1;
+             if (!(entry = malloc(sizeof(xenXMConfCache)))) {
+                 goto cleanup;
+             }
+             memcpy(entry->filename, path, PATH_MAX);
+         }
+         entry->refreshedAt = now;
+ 
+         if (!(entry->conf = virConfReadFile(entry->filename)) ||
+             xenXMConfigEnsureUUID(entry->conf) < 0) {
+             if (!newborn) {
+                 virHashRemoveEntry(configCache, ent->d_name, NULL);
+             }
+             free(entry);
+             continue;
+         }
+ 
+         /* If its a completely new entry, it must be stuck into
+            the cache (refresh'd entries are already registered) */
+         if (newborn) {
+             if (virHashAddEntry(configCache, ent->d_name, entry) < 0) {
+                 virConfFree(entry->conf);
+                 free(entry);
+                 goto cleanup;
+             }
+         }
+     }
+ 
+     /* Reap all entries which were not changed, by comparing
+        their refresh timestamp - the timestamp should match
+        'now' if they were refreshed. If timestamp doesn't match
+        then the config is no longer on disk */
+     virHashRemoveSet(configCache, xenXMConfigReaper, xenXMConfigFree, (const void*) &now);
+     ret = 0;
+ 
+  cleanup:
+     if (dh)
+         closedir(dh);
+ 
+     return ret;
+ }
+ 
+ 
+ /*
+  * Open a 'connection' to the config file directory ;-)
+  * We just create a hash table to store config files in.
+  * We only support a single directory, so repeated calls
+  * to open all end up using the same cache of files
+  */
+ int xenXMOpen(virConnectPtr conn ATTRIBUTE_UNUSED, const char *name, int flags ATTRIBUTE_UNUSED) {
+     if (name &&
+         strcasecmp(name, "xen")) {
+         return -1;
+     }
+ 
+     if (nconnections == 0) {
+         configCache = virHashCreate(50);
+         if (!configCache)
+             return -1;
+     }
+     nconnections++;
+ 
+     return 0;
+ }
+ 
+ /*
+  * Free the config files in the cache if this is the
+  * last connection
+  */
+ int xenXMClose(virConnectPtr conn ATTRIBUTE_UNUSED) {
+     if (!nconnections--) {
+         virHashFree(configCache, xenXMConfigFree);
+         configCache = NULL;
+     }
+     return 0;
+ }
+ 
+ /* 
+  * Our backend type
+  */
+ const char *xenXMGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
+     return "XenXM";
+ }
+ 
+ /*
+  * Since these are all offline domains, we only return info about
+  * VCPUs and memory. 
+  */
+ int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) {
+     xenXMConfCachePtr entry;
+     long vcpus;
+     long mem;
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(-1);
+     }
+ 
+     if (domain->handle != -1)
+         return (-1);
+ 
+     if (!(entry = virHashLookup(configCache, domain->name)))
+         return (-1);
+ 
+     memset(info, 0, sizeof(virDomainInfo));
+     if (xenXMConfigGetInt(entry->conf, "memory", &mem) < 0 ||
+         mem < 0)
+         info->memory = 64 * 1024;
+     else
+         info->memory = (unsigned long)mem * 1024;
+     if (xenXMConfigGetInt(entry->conf, "maxmem", &mem) < 0 ||
+         mem < 0)
+         info->maxMem = info->memory;
+     else
+         info->maxMem = (unsigned long)mem * 1024;
+ 
+     if (xenXMConfigGetInt(entry->conf, "vcpus", &vcpus) < 0 ||
+         vcpus < 0)
+         info->nrVirtCpu = 1;
+     else
+         info->nrVirtCpu = (unsigned short)vcpus;
+     info->state = VIR_DOMAIN_SHUTOFF;
+     info->cpuTime = 0;
+ 
+     return 0;
+ 
+ }
+ 
+ /*
+  * Turn a config record into a lump of XML describing the
+  * domain, suitable for later feeding for virDomainCreateLinux
+  */
+ char *xenXMDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED) {
+     virBufferPtr buf;
+     xenXMConfCachePtr entry;
+     char *xml;
+     const char *name;
+     unsigned char uuid[16];
+     const char *str;
+     int hvm = 0;
+     long val;
+     virConfValuePtr list;
+ 
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(NULL);
+     }
+     if (domain->handle != -1)
+         return (NULL);
+     if (!(entry = virHashLookup(configCache, domain->name)))
+         return(NULL);
+ 
+     if (xenXMConfigGetString(entry->conf, "name", &name) < 0)
+         return(NULL);
+     if (xenXMConfigGetUUID(entry->conf, "uuid", uuid) < 0)
+         return(NULL);
+ 
+     buf = virBufferNew(4096);
+ 
+     virBufferAdd(buf, "<domain type='xen'>\n", -1);
+     virBufferVSprintf(buf, "  <name>%s</name>\n", name);
+     virBufferVSprintf(buf,
+                       "  <uuid>%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x</uuid>\n",
+                       uuid[0], uuid[1], uuid[2], uuid[3],
+                       uuid[4], uuid[5], uuid[6], uuid[7],
+                       uuid[8], uuid[9], uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+ 
+     if ((xenXMConfigGetString(entry->conf, "builder", &str) == 0) &&
+         !strcmp(str, "hvm"))
+         hvm = 1;
+ 
+     if (hvm) {
+         virBufferAdd(buf, "  <os>\n", -1);
+         virBufferAdd(buf, "    <type>hvm</type>\n", -1);
+         if (xenXMConfigGetString(entry->conf, "kernel", &str) == 0)
+             virBufferVSprintf(buf, "    <loader>%s</loader>\n", str);
+         virBufferAdd(buf, "  </os>\n", -1);
+     } else {
+ 
+         if (xenXMConfigGetString(entry->conf, "bootloader", &str) == 0)
+             virBufferVSprintf(buf, "  <bootloader>%s</bootloader>\n", str);
+         if (xenXMConfigGetString(entry->conf, "kernel", &str) == 0) {
+             virBufferAdd(buf, "  <os>\n", -1);
+             virBufferAdd(buf, "    <type>linux</type>\n", -1);
+             virBufferVSprintf(buf, "    <kernel>%s</kernel>\n", str);
+             if (xenXMConfigGetString(entry->conf, "ramdisk", &str) == 0)
+                 virBufferVSprintf(buf, "    <initrd>%s</initrd>\n", str);
+             if (xenXMConfigGetString(entry->conf, "extra", &str) == 0)
+                 virBufferVSprintf(buf, "    <cmdline>%s</cmdline>\n", str);
+             virBufferAdd(buf, "  </os>\n", -1);
+         }
+     }
+ 
+     if (xenXMConfigGetInt(entry->conf, "memory", &val) < 0)
+         val = 64;
+     virBufferVSprintf(buf, "  <memory>%ld</memory>\n", val * 1024);
+ 
+     if (xenXMConfigGetInt(entry->conf, "vcpus", &val) < 0)
+         val = 1;
+     virBufferVSprintf(buf, "  <vcpu>%ld</vcpu>\n", val);
+ 
+ 
+ 
+     if (xenXMConfigGetString(entry->conf, "on_poweroff", &str) < 0)
+         str = "destroy";
+     virBufferVSprintf(buf, "  <on_poweroff>%s</on_poweroff>\n", str);
+ 
+     if (xenXMConfigGetString(entry->conf, "on_reboot", &str) < 0)
+         str = "restart";
+     virBufferVSprintf(buf, "  <on_reboot>%s</on_reboot>\n", str);
+ 
+     if (xenXMConfigGetString(entry->conf, "on_crash", &str) < 0)
+         str = "restart";
+     virBufferVSprintf(buf, "  <on_crash>%s</on_crash>\n", str);
+ 
+ 
+     if (hvm) {
+         virBufferAdd(buf, "  <features>\n", -1);
+         if (xenXMConfigGetInt(entry->conf, "pae", &val) == 0 &&
+             val)
+             virBufferAdd(buf, "    <pae/>\n", -1);
+         if (xenXMConfigGetInt(entry->conf, "acpi", &val) == 0 &&
+             val)
+             virBufferAdd(buf, "    <acpi/>\n", -1);
+         if (xenXMConfigGetInt(entry->conf, "apic", &val) == 0 &&
+             val)
+             virBufferAdd(buf, "    <apic/>\n", -1);
+         virBufferAdd(buf, "  </features>\n", -1);
+     }
+ 
+     virBufferAdd(buf, "  <devices>\n", -1);
+ 
+     list = virConfGetValue(entry->conf, "disk");
+     while (list && list->type == VIR_CONF_LIST) {
+         virConfValuePtr el = list->list;
+         int block = 0;
+         char dev[NAME_MAX];
+         char src[PATH_MAX];
+         char drvName[NAME_MAX] = "";
+         char drvType[NAME_MAX] = "";
+         char *device;
+         char *mode;
+         char *path;
+ 
+         if ((el== NULL) || (el->type != VIR_CONF_STRING) || (el->str == NULL))
+             goto skipdisk;
+ 
+         if (!(device = index(el->str, ',')) || device[0] == '\0')
+             goto skipdisk;
+         device++;
+         if (!(mode = index(device, ',')) || mode[0] == '\0')
+             goto skipdisk;
+         mode++;
+ 
+         if (!(path = index(el->str, ':')) || path[0] == '\0' || path > device)
+             goto skipdisk;
+ 
+         strncpy(drvName, el->str, (path-el->str));
+         if (!strcmp(drvName, "tap")) {
+             if (!(path = index(el->str+4, ':')) || path[0] == '\0' || path > device)
+                 goto skipdisk;
+ 
+             strncpy(drvType, el->str+4, (path-(el->str+4)));
+         }
+         if ((device-path) > PATH_MAX)
+             goto skipdisk;
+ 
+         strncpy(src, path+1, (device-(path+1))-1);
+         src[(device-(path+1))-1] = '\0';
+ 
+         if (!strcmp(drvName, "phy")) {
+             block = 1;
+         }
+ 
+         if ((mode-device-1) > (NAME_MAX-1)) {
+             goto skipdisk;
+         }
+         strncpy(dev, device, (mode-device-1));
+         dev[(mode-device-1)] = '\0';
+ 
+         virBufferVSprintf(buf, "    <disk type='%s' device='disk'>\n", block ? "block" : "file");
+         if (drvType[0])
+             virBufferVSprintf(buf, "      <driver name='%s' type='%s'/>\n", drvName, drvType);
+         else
+             virBufferVSprintf(buf, "      <driver name='%s'/>\n", drvName);
+         virBufferVSprintf(buf, "      <source %s='%s'/>\n", block ? "dev" : "file", src);
+         virBufferVSprintf(buf, "      <target dev='%s'/>\n", dev);
+         if (*mode == 'r')
+             virBufferAdd(buf, "      <readonly/>\n", -1);
+         virBufferAdd(buf, "    </disk>\n", -1);
+ 
+     skipdisk:
+         list = list->next;
+     }
+ 
+     list = virConfGetValue(entry->conf, "vif");
+     while (list && list->type == VIR_CONF_LIST) {
+         virConfValuePtr el = list->list;
+         int type = -1;
+         char script[PATH_MAX];
+         char ip[16];
+         char mac[18];
+         char *key;
+ 
+         mac[0] = '\0';
+         script[0] = '\0';
+         ip[0] = '\0';
+ 
+         if ((el== NULL) || (el->type != VIR_CONF_STRING) || (el->str == NULL))
+             goto skipnic;
+ 
+         key = el->str;
+         while (key) {
+             char *data;
+             char *nextkey = index(key, ',');
+ 
+             if (!(data = index(key, '=')) || (data[0] == '\0'))
+                 goto skipnic;
+             data++;
+ 
+             if (!strncmp(key, "mac=", 4)) {
+                 int len = nextkey ? (nextkey - data) : 17;
+                 if (len > 17)
+                     len = 17;
+                 strncpy(mac, data, len);
+                 mac[len] = '\0';
+             } else if (!strncmp(key, "bridge=", 7)) {
+                 type = 1;
+             } else if (!strncmp(key, "script=", 7)) {
+                 int len = nextkey ? (nextkey - data) : PATH_MAX-1;
+                 if (len > (PATH_MAX-1))
+                     len = PATH_MAX-1;
+                 strncpy(script, data, len);
+                 script[len] = '\0';
+             } else if (!strncmp(key, "ip=", 3)) {
+                 int len = nextkey ? (nextkey - data) : 15;
+                 if (len > 15)
+                     len = 15;
+                 strncpy(ip, data, len);
+                 ip[len] = '\0';
+             }
+ 
+             while (nextkey && (nextkey[0] == ',' ||
+                                nextkey[0] == ' ' ||
+                                nextkey[0] == '\t'))
+                 nextkey++;
+             key = nextkey;
+         }
+ 
+         /* XXX Forcing to pretend its a bridge */
+         if (type == -1) {
+             type = 1;
+         }
+ 
+         virBufferAdd(buf, "    <interface type='bridge'>\n", -1);
+         if (mac[0])
+             virBufferVSprintf(buf, "      <mac address='%s'/>\n", mac);
+         if (script[0])
+             virBufferVSprintf(buf, "      <script path='%s'/>\n", script);
+         if (ip[0])
+             virBufferVSprintf(buf, "      <ip address='%s'/>\n", ip);
+         virBufferAdd(buf, "    </interface>\n", -1);
+ 
+     skipnic:
+         list = list->next;
+     }
+ 
+     if (xenXMConfigGetInt(entry->conf, "vnc", &val) == 0 && val) {
+         long display;
+         long unused = 1;
+         if (xenXMConfigGetInt(entry->conf, "vncunused", &unused) < 0)
+             unused = 1;
+         if (xenXMConfigGetInt(entry->conf, "vncdisplay", &display) < 0)
+             display = 0;
+ 
+         if (unused) {
+             virBufferAdd(buf, "    <graphics type='vnc' port='-1'/>\n", -1);
+         } else {
+             virBufferVSprintf(buf, "    <graphics type='vnc' port='%d'/>\n", (5900+display));
+         }
+     }
+     if (xenXMConfigGetInt(entry->conf, "sdl", &val) == 0 && val) {
+         virBufferAdd(buf, "    <graphics type='sdl'/>\n", -1);
+     }
+ 
+     virBufferAdd(buf, "  </devices>\n", -1);
+ 
+     virBufferAdd(buf, "</domain>\n", -1);
+ 
+     xml = buf->content;
+     buf->content = NULL;
+     virBufferFree(buf);
+     return xml;
+ }
+ 
+ 
+ /*
+  * Update amount of memory in the config file
+  */
+ int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory) {
+     xenXMConfCachePtr entry;
+     virConfValuePtr value;
+ 
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(-1);
+     }
+     if (domain->conn->flags & VIR_CONNECT_RO)
+         return (-1);
+     if (domain->handle != -1)
+         return (-1);
+ 
+     if (!(entry = virHashLookup(configCache, domain->name)))
+         return (-1);
+ 
+     if (!(value = malloc(sizeof(virConfValue))))
+         return (-1);
+ 
+     value->type = VIR_CONF_LONG;
+     value->l = (memory/1024);
+ 
+     if (virConfSetValue(entry->conf, "memory", value) < 0)
+         return (-1);
+ 
+     /* If this fails, should we try to undo our changes to the
+      * in-memory representation of the config file. I say not!
+      */
+     if (virConfWriteFile(entry->filename, entry->conf) < 0)
+         return (-1);
+ 
+     return 0;
+ }
+ 
+ /*
+  * Update maximum memory limit in config
+  */
+ int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) {
+     xenXMConfCachePtr entry;
+     virConfValuePtr value;
+ 
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(-1);
+     }
+     if (domain->conn->flags & VIR_CONNECT_RO)
+         return (-1);
+     if (domain->handle != -1)
+         return (-1);
+ 
+     if (!(entry = virHashLookup(configCache, domain->name)))
+         return (-1);
+ 
+     if (!(value = malloc(sizeof(virConfValue))))
+         return (-1);
+ 
+     value->type = VIR_CONF_LONG;
+     value->l = (memory/1024);
+ 
+     if (virConfSetValue(entry->conf, "maxmem", value) < 0)
+         return (-1);
+ 
+     /* If this fails, should we try to undo our changes to the
+      * in-memory representation of the config file. I say not!
+      */
+     if (virConfWriteFile(entry->filename, entry->conf) < 0)
+         return (-1);
+ 
+     return 0;
+ }
+ 
+ /*
+  * Get max memory limit from config
+  */
+ unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain) {
+     xenXMConfCachePtr entry;
+     long val;
+ 
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(-1);
+     }
+     if (domain->handle != -1)
+         return (-1);
+ 
+     if (!(entry = virHashLookup(configCache, domain->name)))
+         return (-1);
+ 
+     if (xenXMConfigGetInt(entry->conf, "maxmem", &val) < 0 ||
+         val < 0)
+         if (xenXMConfigGetInt(entry->conf, "memory", &val) < 0 ||
+             val < 0)
+             val = 64;
+ 
+     return val * 1024;
+ }
+ 
+ /*
+  * Set the VCPU count in config
+  */
+ int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) {
+     xenXMConfCachePtr entry;
+     virConfValuePtr value;
+ 
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(-1);
+     }
+     if (domain->conn->flags & VIR_CONNECT_RO)
+         return (-1);
+     if (domain->handle != -1)
+         return (-1);
+ 
+     if (!(entry = virHashLookup(configCache, domain->name)))
+         return (-1);
+ 
+     if (!(value = malloc(sizeof(virConfValue))))
+         return (-1);
+ 
+     value->type = VIR_CONF_LONG;
+     value->l = vcpus;
+ 
+     if (virConfSetValue(entry->conf, "vcpus", value) < 0)
+         return (-1);
+ 
+     /* If this fails, should we try to undo our changes to the
+      * in-memory representation of the config file. I say not!
+      */
+     if (virConfWriteFile(entry->filename, entry->conf) < 0)
+         return (-1);
+ 
+     return 0;
+ }
+ 
+ /*
+  * Find an inactive domain based on its name
+  */
+ virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname) {
+     xenXMConfCachePtr entry;
+     virDomainPtr ret;
+     unsigned char uuid[16];
+     if (!VIR_IS_CONNECT(conn)) {
+         xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+         return (NULL);
+     }
+     if (domname == NULL) {
+         xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+         return (NULL);
+     }
+ 
+     if (xenXMConfigCacheRefresh() < 0)
+         return (NULL);
+ 
+     if (!(entry = virHashLookup(configCache, domname))) {
+         return (NULL);
+     }
+ 
+ 
+     if (xenXMConfigGetUUID(entry->conf, "uuid", uuid) < 0) {
+         return (NULL);
+     }
+ 
+     if (!(ret = virGetDomain(conn, domname, uuid))) {
+         return (NULL);
+     }
+     ret->handle = -1;
+ 
+     return ret;
+ }
+ 
+ 
+ /*
+  * Hash table iterator to search for a domain based on UUID
+  */
+ static int xenXMDomainSearchForUUID(const void *payload, const char *name ATTRIBUTE_UNUSED, const void *data) {
+     unsigned char uuid[16];
+     const unsigned char *wantuuid = (const unsigned char *)data;
+     const xenXMConfCachePtr entry = (const xenXMConfCachePtr)payload;
+ 
+     if (xenXMConfigGetUUID(entry->conf, "uuid", uuid) < 0) {
+         return 0;
+     }
+ 
+     if (!memcmp(uuid, wantuuid, 16))
+         return 1;
+ 
+     return 0;
+ }
+ 
+ /*
+  * Find an inactive domain based on its UUID
+  */
+ virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
+                                      const unsigned char *uuid) {
+     xenXMConfCachePtr entry;
+     virDomainPtr ret;
+     const char *domname;
+ 
+     if (!VIR_IS_CONNECT(conn)) {
+         xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+         return (NULL);
+     }
+     if (uuid == NULL) {
+         xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+         return (NULL);
+     }
+ 
+     if (xenXMConfigCacheRefresh() < 0)
+         return (NULL);
+ 
+     if (!(entry = virHashSearch(configCache, xenXMDomainSearchForUUID, (const void *)uuid))) {
+         return (NULL);
+     }
+ 
+     if (xenXMConfigGetString(entry->conf, "name", &domname) < 0) {
+         return (NULL);
+     }
+ 
+     if (!(ret = virGetDomain(conn, domname, uuid))) {
+         return (NULL);
+     }
+ 
+     return ret;
+ }
+ 
+ 
+ /*
+  * Start a domain from an existing defined config file
+  */
+ int xenXMDomainCreate(virDomainPtr domain) {
+     char *xml;
+     char *sexpr;
+     int ret, xendConfigVersion;
+     unsigned char uuid[16];
+ 
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(-1);
+     }
+ 
+     if (domain->handle != -1)
+         return (-1);
+     if (domain->conn->flags & VIR_CONNECT_RO)
+         return (-1);
+ 
+     if (!(xml = xenXMDomainDumpXML(domain, 0)))
+         return (-1);
+ 
+     if ((xendConfigVersion = xend_get_config_version(domain->conn)) < 0) {
+         xenXMError(domain->conn, VIR_ERR_INTERNAL_ERROR, "cannot determine xend config version");
+         return (-1);
+     }
+     printf("'%s'\n", xml);
+     if (!(sexpr = virDomainParseXMLDesc(xml, NULL, xendConfigVersion))) {
+         free(xml);
+         return (-1);
+     }
+     free(xml);
+     printf("'%s'\n", sexpr);
+     ret = xenDaemonDomainCreateLinux(domain->conn, sexpr);
+     free(sexpr);
+     if (ret != 0) {
+         fprintf(stderr, "Failed to create domain %s\n", domain->name);
+         return (-1);
+     }
+ 
+     ret = xend_wait_for_devices(domain->conn, domain->name);
+     if (ret != 0) {
+         fprintf(stderr, "Failed to get devices for domain %s\n", domain->name);
+         return (-1);
+     }
+ 
+     if ((ret = xenDaemonDomainLookupByName_ids(domain->conn, domain->name, uuid)) < 0) {
+         return (-1);
+     }
+     domain->handle = ret;
+ 
+     ret = xenDaemonDomainResume(domain);
+     if (ret != 0) {
+         fprintf(stderr, "Failed to resume new domain %s\n", domain->name);
+         xenDaemonDomainDestroy(domain);
+         domain->handle = -1;
+         return (-1);
+     }
+ 
+     return 0;
+ }
+ 
+ /*
+  * Convenience method to set an int config param
+  * based on an XPath expression
+  */
+ static
+ int xenXMConfigSetIntFromXPath(virConfPtr conf, xmlXPathContextPtr ctxt,
+                                const char *setting, const char *xpath,
+                                int allowMissing, long scale) {
+     xmlXPathObjectPtr obj;
+     virConfValuePtr value = NULL;
+     long intval;
+     char *strend;
+     int ret = -1;
+ 
+     obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+     if ((obj == NULL) && allowMissing)
+         return 0;
+ 
+     if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+         (obj->stringval == NULL) || (obj->stringval[0] == 0))
+         goto error;
+ 
+     intval = strtol((char *)obj->stringval, &strend, 10);
+     if (strend == (char *)obj->stringval)
+         goto error;
+ 
+     if (!(value = malloc(sizeof(virConfValue))))
+         goto error;
+ 
+     value->type = VIR_CONF_LONG;
+     value->next = NULL;
+     if (scale > 0)
+         value->l = intval * scale;
+     else if (scale < 0)
+         value->l = intval / (-1*scale);
+     else
+         value->l = intval;
+ 
+     if (virConfSetValue(conf, setting, value) < 0)
+         goto error;
+ 
+     ret = 0;
+ 
+  error:
+     if (obj)
+         xmlXPathFreeObject(obj);
+ 
+     return ret;
+ }
+ 
+ /*
+  * Convenience method to set a string param
+  * based on an XPath expression
+  */
+ static
+ int xenXMConfigSetStringFromXPath(virConfPtr conf, xmlXPathContextPtr ctxt,
+                                   const char *setting, const char *xpath,
+                                   int allowMissing) {
+     xmlXPathObjectPtr obj;
+     virConfValuePtr value = NULL;
+     int ret = -1;
+ 
+     obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+     if ((obj == NULL) && allowMissing)
+         return 0;
+ 
+     if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+         (obj->stringval == NULL) || (obj->stringval[0] == 0))
+         goto error;
+ 
+     if (!(value = malloc(sizeof(virConfValue))))
+         goto error;
+ 
+     value->type = VIR_CONF_STRING;
+     value->next = NULL;
+     if (!(value->str = strdup((char*)obj->stringval)))
+         goto error;
+ 
+     if (virConfSetValue(conf, setting, value) < 0)
+         goto error;
+ 
+     ret = 0;
+ 
+  error:
+     if (obj)
+         xmlXPathFreeObject(obj);
+ 
+     return ret;
+ }
+ 
+ 
+ /*
+  * Create a config file for a domain, based on an XML
+  * document describing its config
+  */
+ virDomainPtr xenXMDomainDefineXML(virConnectPtr conn, const char *xml) {
+     virDomainPtr ret;
+     char filename[PATH_MAX];
+     unsigned char uuid[16];
+     xmlDocPtr doc = NULL;
+     xmlNodePtr node;
+     xmlXPathObjectPtr obj = NULL;
+     xmlXPathContextPtr ctxt = NULL;
+     xmlChar *prop = NULL;
+     virConfPtr conf = NULL;
+     virConfValuePtr value = NULL;
+     xenXMConfCachePtr entry = NULL;
+ 
+     if (!VIR_IS_CONNECT(conn)) {
+         xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+         return (NULL);
+     }
+     if (xml == NULL) {
+         xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+         return (NULL);
+     }
+     if (conn->flags & VIR_CONNECT_RO)
+         return (NULL);
+ 
+     if (xenXMConfigCacheRefresh() < 0)
+         return (NULL);
+ 
+     doc = xmlReadDoc((const xmlChar *) xml, "domain.xml", NULL,
+                      XML_PARSE_NOENT | XML_PARSE_NONET |
+                      XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+     if (doc == NULL) {
+         return (NULL);
+     }
+     node = xmlDocGetRootElement(doc);
+     if ((node == NULL) || (!xmlStrEqual(node->name, BAD_CAST "domain")))
+         goto error;
+ 
+     prop = xmlGetProp(node, BAD_CAST "type");
+     if (prop != NULL) {
+         if (!xmlStrEqual(prop, BAD_CAST "xen")) {
+             goto error;
+         }
+         xmlFree(prop);
+         prop = NULL;
+     }
+     if (!(ctxt = xmlXPathNewContext(doc)))
+         goto error;
+ 
+     if (!(conf = virConfNew()))
+         goto error;
+ 
+     if (xenXMConfigSetStringFromXPath(conf, ctxt, "name", "string(/domain/name)", 0) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetStringFromXPath(conf, ctxt, "uuid", "string(/domain/uuid)", 0) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetIntFromXPath(conf, ctxt, "memory", "string(/domain/memory)", 0, -1024) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetIntFromXPath(conf, ctxt, "vcpus", "string(/domain/vcpu)", 0, 0) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetIntFromXPath(conf, ctxt, "pae", "string(count(/domain/features/pae))", 0, 0) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetIntFromXPath(conf, ctxt, "acpi", "string(count(/domain/features/acpi))", 0, 0) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetIntFromXPath(conf, ctxt, "apic", "string(count(/domain/features/apic))", 0, 0) < 0)
+         goto error;
+ 
+ 
+     if (xenXMConfigSetStringFromXPath(conf, ctxt, "on_poweroff", "string(/domain/on_poweroff)", 1) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetStringFromXPath(conf, ctxt, "on_reboot", "string(/domain/on_reboot)", 1) < 0)
+         goto error;
+ 
+     if (xenXMConfigSetStringFromXPath(conf, ctxt, "on_crash", "string(/domain/on_crash)", 1) < 0)
+         goto error;
+ 
+ 
+     if (!(value = virConfGetValue(conf, "name")) || value->type != VIR_CONF_STRING || value->str == NULL)
+         goto error;
+ 
+     if (virHashLookup(configCache, value->str) != 0)
+         goto error;
+ 
+     if ((strlen(configDir) + 1 + strlen(value->str) + 1) > PATH_MAX)
+         goto error;
+ 
+     strcpy(filename, configDir);
+     strcat(filename, "/");
+     strcat(filename, value->str);
+ 
+     if (virConfWriteFile(filename, conf) < 0)
+         goto error;
+ 
+     if (!(entry = malloc(sizeof(xenXMConfCache))))
+         goto error;
+     memset(entry, 0, sizeof(xenXMConfCache));
+ 
+     if ((entry->refreshedAt = time(NULL)) == ((time_t)-1))
+         goto error;
+ 
+     memmove(entry->filename, filename, PATH_MAX);
+     entry->conf = conf;
+ 
+     if (xenXMConfigGetUUID(conf, "uuid", uuid) < 0)
+         goto error;
+ 
+     printf("Adding entry %s\n", value->str);
+     if (virHashAddEntry(configCache, value->str, entry) < 0)
+         goto error;
+     entry = NULL;
+ 
+     if (!(ret = virGetDomain(conn, value->str, uuid)))
+         goto error;
+     ret->handle = -1;
+ 
+     return ret;
+ 
+  error:
+     if (entry)
+         free(entry);
+     if (conf)
+         virConfFree(conf);
+     if (prop != NULL)
+         xmlFree(prop);
+     if (obj != NULL)
+         xmlXPathFreeObject(obj);
+     if (ctxt != NULL)
+         xmlXPathFreeContext(ctxt);
+     if (doc != NULL)
+         xmlFreeDoc(doc);
+     return NULL;
+ }
+ 
+ /*
+  * Delete a domain from disk
+  */
+ int xenXMDomainUndefine(virDomainPtr domain) {
+     xenXMConfCachePtr entry;
+     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+         xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                    __FUNCTION__);
+         return(-1);
+     }
+ 
+     if (domain->handle != -1)
+         return (-1);
+     if (domain->conn->flags & VIR_CONNECT_RO)
+         return (-1);
+ 
+     if (!(entry = virHashLookup(configCache, domain->name)))
+         return (-1);
+ 
+     if (unlink(entry->filename) < 0)
+         return (-1);
+ 
+     if (virHashRemoveEntry(configCache, domain->name, xenXMConfigFree) < 0)
+         return (-1);
+ 
+     return 0;
+ }
+ 
+ struct xenXMListIteratorContext {
+     virConnectPtr conn;
+     int max;
+     int count;
+     const char **names;
+ };
+ 
+ static void xenXMListIterator(const void *payload ATTRIBUTE_UNUSED, const char *name, const void *data) {
+     struct xenXMListIteratorContext *ctx = (struct xenXMListIteratorContext *)data;
+     virDomainPtr dom = NULL;
+ 
+     if (ctx->count == ctx->max)
+         return;
+ 
+     dom = xenDaemonDomainLookupByName(ctx->conn, name);
+     if (!dom) {
+         ctx->names[ctx->count] = strdup(name);
+         ctx->count++;
+     } else {
+         virDomainFree(dom);
+     }
+ }
+ 
+ 
+ /*
+  * List all defined domains, filtered to remove any which
+  * are currently running
+  */
+ int xenXMListDefinedDomains(virConnectPtr conn, const char **names, int maxnames) {
+     struct xenXMListIteratorContext ctx;
+ 
+     if (!VIR_IS_CONNECT(conn)) {
+         xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+         return (-1);
+     }
+ 
+     if (xenXMConfigCacheRefresh() < 0)
+         return -1;
+ 
+     if (maxnames > virHashSize(configCache))
+         maxnames = virHashSize(configCache);
+ 
+     ctx.conn = conn;
+     ctx.count = 0;
+     ctx.max = maxnames;
+     ctx.names = names;
+ 
+     virHashForEach(configCache, xenXMListIterator, &ctx);
+     return ctx.count;
+ }
+ 
+ /*
+  * Return the maximum number of defined domains - not filtered
+  * based on number running
+  */
+ int xenXMNumOfDefinedDomains(virConnectPtr conn) {
+     if (!VIR_IS_CONNECT(conn)) {
+         xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+         return (-1);
+     }
+ 
+     if (xenXMConfigCacheRefresh() < 0)
+         return -1;
+ 
+     return virHashSize(configCache);
+ }
+ 
+ /*
+  * Local variables:
+  *  indent-tabs-mode: nil
+  *  c-indent-level: 4
+  *  c-basic-offset: 4
+  *  tab-width: 4
+  * End:
+  */
Index: src/xm_internal.h
===================================================================
RCS file: src/xm_internal.h
diff -N src/xm_internal.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/xm_internal.h	15 Nov 2006 02:57:26 -0000
***************
*** 0 ****
--- 1,47 ----
+ /*
+  * xm_internal.h: helper routines for dealing with inactive domains
+  *
+  * Copyright (C) 2006
+  *
+  *      Daniel Berrange <berrange at redhat.com>
+  *
+  *  This file is subject to the terms and conditions of the GNU Lesser General
+  *  Public License. See the file COPYING.LIB in the main directory of this
+  *  archive for more details.
+  */
+ 
+ #ifndef _LIBVIRT_XM_INTERNAL_H_
+ #define _LIBVIRT_XM_INTERNAL_H_
+ 
+ #include "libvirt/libvirt.h"
+ 
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ 
+ void xenXMRegister(void);
+ int xenXMOpen(virConnectPtr conn, const char *name, int flags);
+ int xenXMClose(virConnectPtr conn);
+ const char *xenXMGetType(virConnectPtr conn);
+ int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
+ char *xenXMDomainDumpXML(virDomainPtr domain, int flags);
+ int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory);
+ int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
+ unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain);
+ int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus);
+ virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname);
+ virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
+ 				     const unsigned char *uuid);
+ 
+ int xenXMListDefinedDomains(virConnectPtr conn, const char **names, int maxnames);
+ int xenXMNumOfDefinedDomains(virConnectPtr conn);
+ 
+ int xenXMDomainCreate(virDomainPtr domain);
+ virDomainPtr xenXMDomainDefineXML(virConnectPtr con, const char *xml);
+ int xenXMDomainUndefine(virDomainPtr domain);
+ 
+ 
+ #ifdef __cplusplus
+ }
+ #endif
+ #endif


More information about the libvir-list mailing list