[Libvir] [QEMU 3/3] the qemu driver & daemon

Daniel P. Berrange berrange at redhat.com
Thu Aug 31 21:09:16 UTC 2006


On Mon, Aug 28, 2006 at 04:55:09AM -0400, Daniel Veillard wrote:
> I scanned quickly the protocol part but I need to get my head around it :-)
> That's a lot of code ! One think I would like is to try to get all commenting
> at the same level, i.e. having every function carrying a comment header, 
> That's something I will help with, maybe as a side effect of reviewing the
> code. Tell me how we could do that ? Maybe I could start with the simplest
> code from qemud.

I'm attaching an updated patch which has many many more comments in it, and
also has much better error reporting - nearly all errors are propagated 
back to libvirt with formal codes & messages.

Other changes previously suggested (re-factoring shared code, etc) are yet
to be done.

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 --------------
diff --exclude docs --exclude CVS -ruN libvirt-pristine/configure.in libvirt-qemu/configure.in
--- libvirt-pristine/configure.in	2006-08-29 18:27:07.000000000 -0400
+++ libvirt-qemu/configure.in	2006-08-30 08:42:25.000000000 -0400
@@ -256,5 +256,6 @@
           libvirt.pc libvirt.spec \
 	  include/libvirt/Makefile include/libvirt/libvirt.h \
 	  python/Makefile python/tests/Makefile \
+          qemud/Makefile \
           tests/Makefile proxy/Makefile \
           tests/virshdata/Makefile tests/confdata/Makefile)
diff --exclude docs --exclude CVS -ruN libvirt-pristine/Makefile.am libvirt-qemu/Makefile.am
--- libvirt-pristine/Makefile.am	2006-06-28 14:19:13.000000000 -0400
+++ libvirt-qemu/Makefile.am	2006-08-27 17:05:39.000000000 -0400
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = src include docs @PYTHON_SUBDIR@ tests proxy
+SUBDIRS = src include docs @PYTHON_SUBDIR@ tests proxy qemud
 
 EXTRA_DIST = libvirt.spec.in libvirt.spec COPYING.LIB \
              libvirt.pc.in libvirt.pc TODO AUTHORS ChangeLog \
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/config.c libvirt-qemu/qemud/config.c
--- libvirt-pristine/qemud/config.c	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/config.c	2006-08-30 22:19:20.000000000 -0400
@@ -0,0 +1,840 @@
+
+#include <dirent.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.h>
+
+#include "protocol.h"
+#include "internal.h"
+#include "config.h"
+#include "driver.h"
+
+/* XXX re-factor to shared lib */
+static int qemudParseUUID(const char *uuid,
+			  unsigned char *rawuuid) {
+    const char *cur;
+    int i;
+
+    /*
+     * do a liberal scan allowing '-' and ' ' anywhere between character
+     * pairs as long as there is 32 of them in the end.
+     */
+    cur = uuid;
+    for (i = 0;i < 16;) {
+        rawuuid[i] = 0;
+        if (*cur == 0)
+	    goto error;
+	if ((*cur == '-') || (*cur == ' ')) {
+	    cur++;
+	    continue;
+	}
+	if ((*cur >= '0') && (*cur <= '9'))
+	    rawuuid[i] = *cur - '0';
+	else if ((*cur >= 'a') && (*cur <= 'f'))
+	    rawuuid[i] = *cur - 'a' + 10;
+	else if ((*cur >= 'A') && (*cur <= 'F'))
+	    rawuuid[i] = *cur - 'A' + 10;
+	else
+	    goto error;
+	rawuuid[i] *= 16;
+	cur++;
+        if (*cur == 0)
+	    goto error;
+	if ((*cur >= '0') && (*cur <= '9'))
+	    rawuuid[i] += *cur - '0';
+	else if ((*cur >= 'a') && (*cur <= 'f'))
+	    rawuuid[i] += *cur - 'a' + 10;
+	else if ((*cur >= 'A') && (*cur <= 'F'))
+	    rawuuid[i] += *cur - 'A' + 10;
+	else
+	    goto error;
+        i++;
+	cur++;
+    }
+
+    return 0;
+
+error:
+    qemudSetError(QEMUD_ERR_MALFORMED_UUID, "uuid is not well-formed");
+    return -1;
+}
+
+
+/* Take an XML domain node pointing to a disk device,
+ * grok it attributes / child & a create/populate
+ * a qemud_vm_disk_def object with the info.
+ * Return NULL on failure */
+static struct qemud_vm_disk_def *qemudParseDiskXML(xmlNodePtr node) {
+  struct qemud_vm_disk_def *disk = calloc(1, sizeof(struct qemud_vm_disk_def));
+  xmlNodePtr cur;
+  xmlChar *device = NULL;
+  xmlChar *source = NULL;
+  xmlChar *target = NULL;
+  xmlChar *type = NULL;
+  int typ = 0;
+
+  type = xmlGetProp(node, BAD_CAST "type");
+  if (type != NULL) {
+    if (xmlStrEqual(type, BAD_CAST "file"))
+      typ = QEMUD_DISK_FILE;
+    else if (xmlStrEqual(type, BAD_CAST "block"))
+      typ = QEMUD_DISK_BLOCK;
+    else {
+      qemudSetError(QEMUD_ERR_ILLEGAL_DISK_CONFIG, "unknown disk type");
+      goto error;
+    }
+    xmlFree(type);
+    type = NULL;
+  }
+
+  device = xmlGetProp(node, BAD_CAST "device");
+  
+  cur = node->children;
+  while (cur != NULL) {
+    if (cur->type == XML_ELEMENT_NODE) {
+      if ((source == NULL) &&
+	  (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+	
+	if (typ == QEMUD_DISK_FILE)
+	  source = xmlGetProp(cur, BAD_CAST "file");
+	else
+	  source = xmlGetProp(cur, BAD_CAST "dev");
+      } else if ((target == NULL) &&
+		 (xmlStrEqual(cur->name, BAD_CAST "target"))) {
+	target = xmlGetProp(cur, BAD_CAST "dev");
+      } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
+	disk->readonly = 1;
+      }
+    }
+    cur = cur->next;
+  }
+
+  if (source == NULL) {
+    qemudSetError(QEMUD_ERR_ILLEGAL_DISK_CONFIG, "missing disk source");
+    goto error;
+  }
+  if (target == NULL) {
+    qemudSetError(QEMUD_ERR_ILLEGAL_DISK_CONFIG, "missing disk target");
+    goto error;
+  }
+
+  if (device &&
+      !strcmp((const char *)device, "floppy") &&
+      strcmp((const char *)target, "fda") &&
+      strcmp((const char *)target, "fdb")) {
+    qemudSetError(QEMUD_ERR_ILLEGAL_DISK_CONFIG, "illegal floppy device name");
+    goto error;
+  }
+  
+  if (device &&
+      !strcmp((const char *)device, "cdrom") &&
+      strcmp((const char *)target, "hdc")) {
+    qemudSetError(QEMUD_ERR_ILLEGAL_DISK_CONFIG, "illegal cdrom device name");
+    goto error;
+  }
+
+  if (device &&
+      !strcmp((const char *)device, "cdrom"))
+    disk->readonly = 1;
+
+  if ((!device || !strcmp((const char *)device, "disk")) &&
+      strcmp((const char *)target, "hda") &&
+      strcmp((const char *)target, "hdb") &&
+      strcmp((const char *)target, "hdc") &&
+      strcmp((const char *)target, "hdd")) {
+    qemudSetError(QEMUD_ERR_ILLEGAL_DISK_CONFIG, "illegal harddrive device name");
+    goto error;
+  }
+
+  strncpy(disk->src, (const char *)source, NAME_MAX-1);
+  disk->src[NAME_MAX-1] = '\0';
+
+  strncpy(disk->dst, (const char *)target, NAME_MAX-1);
+  disk->dst[NAME_MAX-1] = '\0';
+  disk->type = typ;
+
+  if (!device)
+    disk->device = QEMUD_DISK_DISK;
+  else if (!strcmp((const char *)device, "disk"))
+    disk->device = QEMUD_DISK_DISK;
+  else if (!strcmp((const char *)device, "cdrom"))
+    disk->device = QEMUD_DISK_CDROM;
+  else if (!strcmp((const char *)device, "floppy"))
+    disk->device = QEMUD_DISK_FLOPPY;
+  else {
+    qemudSetError(QEMUD_ERR_ILLEGAL_DISK_CONFIG, "unknown device type");
+    goto error;
+  }
+
+  xmlFree(target);
+  xmlFree(source);
+
+  return disk;
+  
+ error:
+  if (type)
+    xmlFree(type);
+  if (target)
+    xmlFree(target);
+  if (source)
+    xmlFree(source);
+  free(disk);
+  return NULL;
+}
+
+
+/* Take an XML doc and grok its nodes/atttributes to populate
+ * the hardware definition in the qemud_vm instance 
+ * returns -1 on failure, 0 on success
+ */
+static int qemudParseXML(xmlDocPtr xml,
+			 struct qemud_vm *vm) {
+  xmlNodePtr root = NULL;
+  xmlChar *prop = NULL;
+  xmlXPathContextPtr ctxt = NULL;
+  xmlXPathObjectPtr obj = NULL;
+  char *conv = NULL;
+
+  root = xmlDocGetRootElement(xml);
+  if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) {
+    qemudSetError(QEMUD_ERR_XML_NO_ROOT, "no root element named 'domain'");
+    goto error;
+  }
+
+  if (!(prop = xmlGetProp(root, BAD_CAST "type")) ||
+      strcmp((char *)prop, "qemu")) {
+    qemudSetError(QEMUD_ERR_XML_WRONG_TYPE, "wrong domain type");
+    goto error;
+  }
+  free(prop);
+  prop = NULL;
+
+  ctxt = xmlXPathNewContext(xml);
+  if (ctxt == NULL) {
+    qemudSetError(QEMUD_ERR_GENERIC, "cannot create xpath context");
+    goto error;
+  }
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    qemudSetError(QEMUD_ERR_XML_MISSING_NAME, NULL);
+    goto error;
+  }
+  if (strlen((const char *)obj->stringval) >= QEMUD_MAX_NAME_LEN) {
+    qemudSetError(QEMUD_ERR_NAME_OVERFLOW, NULL);
+    goto error;
+  }
+  strcpy(vm->def.name, (const char *)obj->stringval);
+  xmlXPathFreeObject(obj);
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    qemudSetError(QEMUD_ERR_XML_MISSING_UUID, NULL);
+    goto error;
+  }
+  if (qemudParseUUID((const char *)obj->stringval, vm->def.uuid) < 0) {
+    goto error;
+  }
+  xmlXPathFreeObject(obj);
+
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/memory[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    vm->def.memory = 64 * 1024;
+  } else {
+    conv = NULL;
+    vm->def.memory = strtoll((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      qemudSetError(QEMUD_ERR_GENERIC, "malformed number for domain memory");
+      goto error;
+    }
+  }
+  if (obj) {
+    xmlXPathFreeObject(obj);
+    obj = NULL;
+  }
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/vcpu[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    vm->def.vcpus = 1;
+  } else {
+    conv = NULL;
+    vm->def.vcpus = strtoll((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      qemudSetError(QEMUD_ERR_GENERIC, "malformed number for domain cpus");
+      goto error;
+    }
+  }
+  if (obj) {
+    xmlXPathFreeObject(obj);
+    obj = NULL;
+  }
+
+  obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+      (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
+    vm->def.graphicsType = QEMUD_GRAPHICS_NONE;
+  } else {
+    prop = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "type");
+    if (!strcmp((char *)prop, "vnc")) {
+      vm->def.graphicsType = QEMUD_GRAPHICS_VNC;
+      prop = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "port");
+      if (prop) {
+	conv = NULL;
+	vm->def.vncPort = strtoll((const char*)prop, &conv, 10);
+      } else {
+	vm->def.vncPort = 0;
+      }
+    }
+  }
+
+  /* analyze of the devices */
+  obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
+      (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
+    for (int i = 0; i < obj->nodesetval->nodeNr; i++) {
+      struct qemud_vm_disk_def *disk;
+      if (!(disk = qemudParseDiskXML(obj->nodesetval->nodeTab[i]))) {
+	goto error;
+      }
+      vm->def.ndisks++;
+      disk->next = vm->def.disks;
+      vm->def.disks = disk;
+    }
+  }
+  xmlXPathFreeObject(obj);
+
+  return 0;
+
+ error:
+  if (prop)
+    free(prop);
+  if (obj)
+    xmlXPathFreeObject(obj);
+  return -1;
+}
+
+
+/* Construct a command line for launching qemu according
+ * to the hardware definition of the passed in qemud_vm
+ * instance.
+ * argv: populated with a char ** array containing the args
+ * which is NULL terminated. Callers job to free the argv,
+ * and all non-NULL elements within
+ * argc: popilated with number of elements in argv - including
+ * the trailing NULL.
+ * Returns -1 on failure, 0 on success
+ */
+int qemudBuildCommandLine(struct qemud_vm *vm,
+			  char ***argv,
+			  int *argc) {
+  int n = 0;
+  char memory[50];
+  char vcpus[50];
+  struct qemud_vm_disk_def *disk = vm->def.disks;
+
+  *argc = 1 + /* qemu */
+    2 * vm->def.ndisks + /* disks*/
+    2 + /* memory*/
+    2 + /* cpus */
+    (vm->def.graphicsType == QEMUD_GRAPHICS_VNC ? 2 : 0) + /* graphics */
+    1; /* NULL */
+
+  sprintf(memory, "%d", vm->def.memory/1024);
+  sprintf(vcpus, "%d", vm->def.vcpus);
+
+  if (!(*argv = malloc(sizeof(char *) * *argc))) {
+    qemudSetError(QEMUD_ERR_NO_MEMORY, "cannot allocate command line");
+    return -1;
+  }
+  (*argv)[n++] = strdup("qemu");
+  (*argv)[n++] = strdup("-m");
+  (*argv)[n++] = strdup(memory);
+  (*argv)[n++] = strdup("-smp");
+  (*argv)[n++] = strdup(vcpus);
+
+  while (disk) {
+    char dev[NAME_MAX];
+    char file[PATH_MAX];
+    if (!strcmp(disk->dst, "hdc") &&
+	disk->device == QEMUD_DISK_CDROM)
+      snprintf(dev, NAME_MAX, "-%s", "cdrom");
+    else
+      snprintf(dev, NAME_MAX, "-%s", disk->dst);
+    snprintf(file, PATH_MAX, "%s", disk->src);
+
+    (*argv)[n++] = strdup(dev);
+    (*argv)[n++] = strdup(file);
+
+    disk = disk->next;
+  }
+  
+  if (vm->def.graphicsType == QEMUD_GRAPHICS_VNC) {
+    char port[10];
+    snprintf(port, 10, "%d", vm->def.vncPort - 5900);
+    (*argv)[n++] = strdup("-vnc");
+    (*argv)[n++] = strdup(port);
+  }
+
+  (*argv)[n++] = NULL;
+
+  return 0;
+}
+
+
+/* Recursively free all memory associated with the
+ * passed in qemud_vm object. The object must already
+ * have been removed from the active/inactive vms
+ * list in the qemud_server object.
+ */
+void qemudFreeVM(struct qemud_vm *vm) {
+  struct qemud_vm_disk_def *disk = vm->def.disks;
+  struct qemud_vm_net_def *net = vm->def.nets;
+
+  while (disk) {
+    struct qemud_vm_disk_def *prev = disk;
+    disk = disk->next;
+    free(prev);
+  }
+  while (net) {
+    struct qemud_vm_net_def *prev = net;
+    net = net->next;
+    free(prev);
+  }
+
+  free(vm);
+}
+
+/* Constructs a path to a domain's config file
+ * name: filename of the domain config
+ * ext: optional extension, if 'name' doesn't already include it
+ * buf: buffer to populate with config file path
+ * buflen: max length of buf arg, including NULL
+ * Returns 0 on success, and buf is filled with fully
+ * qualified config path. Returns -1 on failure
+ */
+static
+int qemudMakeConfigPath(struct qemud_server *server,
+			const char *name,
+			const char *ext,
+			char *buf,
+			unsigned int buflen) {
+  if ((strlen(server->configDir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) > buflen) {
+    qemudSetError(QEMUD_ERR_PATH_OVERFLOW, "config file path too long");
+    return -1;
+  }
+
+  strcpy(buf, server->configDir);
+  strcat(buf, "/");
+  strcat(buf, name);
+  if (ext)
+    strcat(buf, ext);
+  return 0;
+}
+
+
+/* Save the hardware definition of a VM to its
+ * persistent config file backing store.
+ * Returns 0 on success, -1 on failure
+ */
+static int qemudSaveConfig(struct qemud_server *server ATTRIBUTE_UNUSED,
+			   struct qemud_vm *vm) {
+  char *xml;
+  int fd, ret = -1;
+  int towrite;
+  struct stat sb;
+
+  if (!(xml = qemudGenerateXML(vm))) {
+    return -1;
+  }
+
+#if DEBUG
+  printf("Save VM %s\n", vm->configFile);
+#endif
+
+  if (stat(server->configDir, &sb) < 0) {
+    if (errno == ENOENT) {
+      if (mkdir(server->configDir, 0700) < 0) {
+	qemudSetError(QEMUD_ERR_GENERIC, "cannot create config directory");
+	return -1;
+      }
+    } else {
+      qemudSetError(QEMUD_ERR_GENERIC, "cannot state config directory");
+      return -1;
+    }
+  } else if (!S_ISDIR(sb.st_mode)) {
+    qemudSetError(QEMUD_ERR_GENERIC, "config directory is not a directory");
+    return -1;
+  }
+
+  if ((fd = open(vm->configFile,
+		 O_WRONLY | O_CREAT | O_TRUNC,
+		 S_IRUSR | S_IWUSR )) < 0) {
+    qemudSetError(QEMUD_ERR_GENERIC, "cannot create config file");
+    goto cleanup;
+  }
+
+  towrite = strlen(xml);
+  if (write(fd, xml, towrite) != towrite) {
+    qemudSetError(QEMUD_ERR_GENERIC, "cannot create config file");
+    goto cleanup;
+  }
+
+  if (close(fd) < 0) {
+    qemudSetError(QEMUD_ERR_GENERIC, "cannot save config file");
+    goto cleanup;
+  }
+
+  ret = 0;
+
+ cleanup:
+
+  free(xml);
+
+  return ret;
+}
+
+
+/* Load & parse a config file, constructing a qemud_vm
+ * object to reppresent it in memory. The returned qemud_vm
+ * object is not hooked into the qemud_server's active or
+ * inactive VM list
+ * file: path to the config file, or NULL
+ * doc: the raw XML document data 
+ * save: whether to save the config after parsing the XML
+ */
+struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server,
+				    const char *file,
+				    const char *doc,
+				    int save) {
+  struct qemud_vm *vm = NULL;
+  xmlDocPtr xml;
+
+#if DEBUG
+  printf("Load VM %s\n", file);
+#endif
+  if (!(xml = xmlReadDoc(BAD_CAST doc, file ? file : "domain.xml", NULL,
+                         XML_PARSE_NOENT | XML_PARSE_NONET |
+                         XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+    qemudSetError(QEMUD_ERR_CONFIG_MALFORMED, "cannot parse XML file");
+    return NULL;
+  }
+
+  if (!(vm = calloc(1, sizeof(struct qemud_vm)))) {
+    qemudSetError(QEMUD_ERR_NO_MEMORY, "cannot allocated machine");
+    return NULL;
+  }
+
+  vm->stdout = -1;
+  vm->stderr = -1;
+  vm->monitor = -1;
+  vm->pid = -1;
+  vm->def.id = -1;
+
+  if (qemudParseXML(xml, vm) < 0) {
+    xmlFreeDoc(xml);
+    qemudFreeVM(vm);
+    return NULL;
+  }
+  xmlFreeDoc(xml);
+
+  if (qemudFindVMByUUID(server, vm->def.uuid)) {
+    qemudSetError(QEMUD_ERR_DUPLICATE_DOMAIN, "domain with duplicate uuid");
+    qemudFreeVM(vm);
+    return NULL;
+  }
+
+  if (qemudFindVMByName(server, vm->def.name)) {
+    qemudSetError(QEMUD_ERR_DUPLICATE_DOMAIN, "domain with duplicate name");
+    qemudFreeVM(vm);
+    return NULL;
+  }
+
+  if (file) {
+    strncpy(vm->configFile, file, PATH_MAX);
+    vm->configFile[PATH_MAX-1] = '\0';
+  } else {
+    if (save) {
+      if (qemudMakeConfigPath(server, vm->def.name, ".xml", vm->configFile, PATH_MAX) < 0) {
+	qemudFreeVM(vm);
+	return NULL;
+      }
+
+      if (qemudSaveConfig(server, vm) < 0) {
+	qemudFreeVM(vm);
+	return NULL;
+      }
+    } else {
+      vm->configFile[0] = '\0';
+    }
+  }
+
+  return vm;
+}
+
+
+/* Load a VM froma config file & hook it into the inactive
+ * VMs linked listed in the server.
+ * file: path to the config file to load
+ */
+static void qemudLoadConfig(struct qemud_server *server,
+			    const char *file) {
+  FILE *fh;
+  struct stat st;
+  struct qemud_vm *vm;
+  char xml[QEMUD_MAX_XML_LEN];
+  int ret;
+
+  if (!(fh = fopen(file, "r"))) {
+    return;
+  }
+
+  if (fstat(fileno(fh), &st) < 0)
+    goto cleanup;
+
+  if (st.st_size >= QEMUD_MAX_XML_LEN)
+    goto cleanup;
+
+  if ((ret = fread(xml, st.st_size, 1, fh)) != 1) {
+#if DEBUG
+    printf("Couldn't read %d\n", ret);
+#endif
+    goto cleanup;
+  }
+  xml[st.st_size] = '\0';
+
+  if ((vm = qemudLoadConfigXML(server, file, xml, 1))) {
+    vm->next = server->inactivevms;
+    server->inactivevms = vm;
+    server->ninactivevms++;
+  }
+  
+ cleanup:
+  fclose(fh);
+}
+
+
+/* Scan the directory containing config files for domains
+ * and load them into memory, hooking them into the 
+ * inactive domains linked list
+ */
+int qemudScanConfigs(struct qemud_server *server) {
+  DIR *dir;
+  struct dirent *entry;
+
+  if (!(dir = opendir(server->configDir))) {
+    if (errno == ENOENT)
+      return 0;
+    return -1;
+  }
+
+  while ((entry = readdir(dir))) {
+    char file[PATH_MAX];
+    if (entry->d_name[0] == '.')
+      continue;
+
+    if (qemudMakeConfigPath(server, entry->d_name, NULL, file, PATH_MAX) < 0)
+      continue;
+
+    qemudLoadConfig(server, file);
+  }
+
+  closedir(dir);
+ 
+  return 0;
+}
+
+
+/* XXX - following is copied from src/xml.c - refactor */
+struct qemudBuffer {
+  char *data;
+  int len;
+  int used;
+};
+
+static
+int qemudBufferAdd(struct qemudBuffer *buf, const char *str) {
+  int need = strlen(str);
+  
+  if ((need+1) > (buf->len-buf->used)) {
+    return -1;
+  }
+  
+  memcpy(buf->data + buf->used, str, need+1);
+  buf->used += need;
+
+  return 0;
+}
+
+
+static
+int qemudBufferPrintf(struct qemudBuffer *buf,
+		      const char *format, ...) {
+  int size, count;
+  va_list locarg, argptr;
+
+  if ((format == NULL) || (buf == NULL)) {
+    return -1;
+  }
+  size = buf->len - buf->used - 1;
+  va_start(argptr, format);
+  va_copy(locarg, argptr);
+
+  if ((count = vsnprintf(&buf->data[buf->used],
+			 size,
+			 format,
+			 locarg)) >= size) {
+    qemudSetError(QEMUD_ERR_NO_MEMORY, "cannot increase buffer size");
+    return -1;
+  }
+  va_end(locarg);
+  buf->used += count;
+
+  buf->data[buf->used] = '\0';
+  return 0;
+}
+
+
+/* Generate an XML document representing the hardware 
+ * definition for the virtual machine. 
+ * Returns the XML doc on success, NULL on failure. It
+ * is the callers responsibility to free the doc if
+ * it is non-NULL
+ */
+char *qemudGenerateXML(struct qemud_vm *vm) {
+  struct qemudBuffer buf;
+  unsigned char *uuid;
+  struct qemud_vm_disk_def *disk;
+  struct qemud_vm_net_def *net;
+
+  buf.len = QEMUD_MAX_XML_LEN;
+  buf.used = 0;
+  buf.data = malloc(buf.len);
+  
+  if (vm->def.id >= 0) {
+    if (qemudBufferPrintf(&buf, "<domain type='qemu' id='%d'>\n", vm->def.id) < 0)
+      goto cleanup;
+  } else {
+    if (qemudBufferAdd(&buf, "<domain type='qemu'>\n") < 0)
+      goto cleanup;
+  }
+
+  if (qemudBufferPrintf(&buf, "  <name>%s</name>\n", vm->def.name) < 0)
+    goto cleanup;
+
+  uuid = vm->def.uuid;
+  if (qemudBufferPrintf(&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]) < 0)
+    goto cleanup;
+  if (qemudBufferPrintf(&buf, "  <memory>%d</memory>\n", vm->def.memory) < 0)
+    goto cleanup;
+  if (qemudBufferPrintf(&buf, "  <vcpu>%d</vcpu>\n", vm->def.vcpus) < 0)
+    goto cleanup;
+
+  if (qemudBufferAdd(&buf, "  <devices>\n") < 0)
+    goto cleanup;
+
+  disk = vm->def.disks;
+  while (disk) {
+    const char *types[] = {
+      "block",
+      "file",
+    };
+    const char *typeAttrs[] = {
+      "dev",
+      "file",
+    };
+    const char *devices[] = {
+      "disk",
+      "cdrom",
+      "floppy",
+    };
+    if (qemudBufferPrintf(&buf, "    <disk type='%s' device='%s'>\n", 
+			  types[disk->type], devices[disk->device]) < 0)
+      goto cleanup;
+
+    if (qemudBufferPrintf(&buf, "      <source %s='%s'/>\n", typeAttrs[disk->type], disk->src) < 0)
+      goto cleanup;
+
+    if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", disk->dst) < 0)
+      goto cleanup;
+
+    if (disk->readonly)
+      if (qemudBufferAdd(&buf, "      <readonly/>\n") < 0)
+	goto cleanup;
+
+    if (qemudBufferPrintf(&buf, "    </disk>\n") < 0)
+      goto cleanup;
+
+    disk = disk->next;
+  }
+
+  net = vm->def.nets;
+
+  if (vm->def.graphicsType == QEMUD_GRAPHICS_VNC) {
+    if (vm->def.vncPort) {
+      qemudBufferPrintf(&buf, "    <graphics type='vnc' port='%d'/>\n", vm->def.vncPort);
+    } else {
+      qemudBufferPrintf(&buf, "    <graphics type='vnc'/>\n");
+    }
+  }
+
+  if (qemudBufferAdd(&buf, "  </devices>\n") < 0)
+    goto cleanup;
+
+
+  if (qemudBufferAdd(&buf, "</domain>\n") < 0)
+    goto cleanup;
+
+  return buf.data;
+
+ cleanup:
+  printf("Fail\n");
+  free(buf.data);
+  return NULL;
+}
+
+
+/* Remove a config file from disk */
+int qemudDeleteConfigXML(struct qemud_vm *vm) {
+  if (!vm->configFile[0]) {
+    qemudSetError(QEMUD_ERR_GENERIC, "domain has no config file");
+    return -1;
+  }
+
+#if DEBUG
+  printf("Delete VM %s\n", vm->configFile);
+#endif
+
+  if (unlink(vm->configFile) < 0) {
+    if (errno == ENOENT)
+      qemudSetError(QEMUD_ERR_NO_DOMAIN, "no such domain");
+    else if (errno == EPERM || errno == EACCES)
+      qemudSetError(QEMUD_ERR_READONLY, "unlink request denied");
+    else
+      qemudSetError(QEMUD_ERR_GENERIC, "unlink failed");
+
+    return -1;
+  }
+
+  vm->configFile[0] = '\0';
+
+  return 0;
+}
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/config.h libvirt-qemu/qemud/config.h
--- libvirt-pristine/qemud/config.h	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/config.h	2006-08-27 18:10:25.000000000 -0400
@@ -0,0 +1,22 @@
+
+#ifndef __QEMUD_CONFIG_H
+#define __QEMUD_CONFIG_H
+
+#include "internal.h"
+
+int qemudBuildCommandLine(struct qemud_vm *vm,
+			  char ***argv,
+			  int *argc);
+
+void qemudFreeVM(struct qemud_vm *vm);
+struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server,
+				    const char *file,
+				    const char *doc,
+				    int persist);
+int qemudScanConfigs(struct qemud_server *server);
+char *qemudGenerateXML(struct qemud_vm *vm);
+
+int qemudDeleteConfigXML(struct qemud_vm *vm);
+
+
+#endif
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/dispatch.c libvirt-qemu/qemud/dispatch.c
--- libvirt-pristine/qemud/dispatch.c	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/dispatch.c	2006-08-30 22:17:45.000000000 -0400
@@ -0,0 +1,474 @@
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <libvirt/virterror.h>
+
+#include "internal.h"
+#include "driver.h"
+#include "dispatch.h"
+
+/* This file is just a massive set of functions to (de-)serialize
+ * wire messages to/from the functions in drivers.h
+ *
+ * Contract of wire protocol says that given an incoming packet
+ * with XXXRequest body, the return packet must either be the
+ * corresponding XXXXReply body, or a failureReply body.
+ *
+ * Anything odd / unexpected happens on the wire, we terminate
+ * with extreme prejudice.
+ *
+ * We're also paranoid about strings thoughout - we don't trust
+ * the client to have null-terminated them, so explicitly add
+ * a NULL in the last character position before dealing with
+ * any strings
+ */
+
+/* Fill out the reply message with error details */
+static int qemudDispatchFailure(struct qemud_server *server ATTRIBUTE_UNUSED,
+				struct qemud_client *client ATTRIBUTE_UNUSED,
+				struct qemud_packet *out) {
+  const char *msg;
+  out->header.type = QEMUD_PKT_FAILURE;
+  out->header.dataSize = sizeof(out->data.failureReply);
+  out->data.failureReply.code = qemudGetLastError(&msg);
+  if (msg) {
+    strncpy(out->data.failureReply.message, msg, QEMUD_MAX_ERROR_LEN-1);
+    out->data.failureReply.message[QEMUD_MAX_ERROR_LEN-1] = '\0';
+  } else {
+    out->data.failureReply.message[0] = '\0';
+  }
+  qemudClearLastError();
+  return 0;
+}
+
+static int qemudDispatchGetProtocolVersion(struct qemud_server *server ATTRIBUTE_UNUSED,
+					   struct qemud_client *client ATTRIBUTE_UNUSED,
+					   struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != 0)
+    return -1;
+
+  out->header.type = QEMUD_PKT_GET_PROTOCOL_VERSION;
+  out->header.dataSize = sizeof(out->data.getProtocolVersionReply);
+  out->data.getProtocolVersionReply.version = QEMUD_PROTOCOL_VERSION;
+  return 0;
+}
+
+static int qemudDispatchGetVersion(struct qemud_server *server, struct qemud_client *client,
+				   struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != 0)
+    return -1;
+
+  int version = qemudGetVersion(server);
+  if (version < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_GET_VERSION;
+    out->header.dataSize = sizeof(out->data.getVersionReply);
+    out->data.getVersionReply.version = version;
+  }
+  return 0;
+}
+static int qemudDispatchListDomains(struct qemud_server *server, struct qemud_client *client,
+				    struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != 0)
+    return -1;
+
+  int ndomains = qemudListDomains(server,
+				  out->data.listDomainsReply.domains,
+				  QEMUD_MAX_NUM_DOMAINS);
+  if (ndomains < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_LIST_DOMAINS;
+    out->header.dataSize = sizeof(out->data.listDomainsReply);
+    out->data.listDomainsReply.numDomains = ndomains;
+  }
+  return 0;
+}
+static int qemudDispatchNumDomains(struct qemud_server *server, struct qemud_client *client,
+				   struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != 0)
+    return -1;
+
+  int ndomains = qemudNumDomains(server);
+  if (ndomains < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_NUM_DOMAINS;
+    out->header.dataSize = sizeof(out->data.numDomainsReply);
+    out->data.numDomainsReply.numDomains = ndomains;
+  }
+  return 0;
+}
+static int qemudDispatchDomainCreate(struct qemud_server *server, struct qemud_client *client,
+				     struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainCreateRequest))
+    return -1;
+
+  in->data.domainCreateRequest.xml[QEMUD_MAX_XML_LEN-1] ='\0';
+
+  struct qemud_vm *vm = qemudDomainCreate(server, in->data.domainCreateRequest.xml);
+  if (!vm) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_CREATE;
+    out->header.dataSize = sizeof(out->data.domainCreateReply);
+    out->data.domainCreateReply.id = vm->def.id;
+    memcpy(out->data.domainCreateReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN);
+    strncpy(out->data.domainCreateReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1);
+    out->data.domainCreateReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+  }
+  return 0;
+}
+static int qemudDispatchDomainLookupByID(struct qemud_server *server, struct qemud_client *client,
+					 struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainLookupByIDRequest))
+    return -1;
+
+  struct qemud_vm *vm = qemudFindVMByID(server, in->data.domainLookupByIDRequest.id);
+  if (!vm) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_ID;
+    out->header.dataSize = sizeof(out->data.domainLookupByIDReply);
+    memcpy(out->data.domainLookupByIDReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN);
+    strncpy(out->data.domainLookupByIDReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1);
+    out->data.domainLookupByIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+  }
+  return 0;
+}
+static int qemudDispatchDomainLookupByUUID(struct qemud_server *server, struct qemud_client *client,
+					   struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainLookupByUUIDRequest))
+    return -1;
+
+  struct qemud_vm *vm = qemudFindVMByUUID(server, in->data.domainLookupByUUIDRequest.uuid);
+  if (!vm) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID;
+    out->header.dataSize = sizeof(out->data.domainLookupByUUIDReply);
+    out->data.domainLookupByUUIDReply.id = vm->def.id;
+    strncpy(out->data.domainLookupByUUIDReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1);
+    out->data.domainLookupByUUIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+  }
+  return 0;
+}
+static int qemudDispatchDomainLookupByName(struct qemud_server *server, struct qemud_client *client,
+					   struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainLookupByNameRequest))
+    return -1;
+
+  /* Paranoia NULL termination */
+  in->data.domainLookupByNameRequest.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+  struct qemud_vm *vm = qemudFindVMByName(server, in->data.domainLookupByNameRequest.name);
+  if (!vm) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME;
+    out->header.dataSize = sizeof(out->data.domainLookupByNameReply);
+    out->data.domainLookupByNameReply.id = vm->def.id;
+    memcpy(out->data.domainLookupByNameReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN);
+  }
+  return 0;
+}
+static int qemudDispatchDomainSuspend(struct qemud_server *server, struct qemud_client *client,
+				      struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainSuspendRequest))
+    return -1;
+
+  int ret = qemudDomainSuspend(server, in->data.domainSuspendRequest.id);
+  if (ret < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_SUSPEND;
+    out->header.dataSize = 0;
+  }
+  return 0;
+}
+static int qemudDispatchDomainResume(struct qemud_server *server, struct qemud_client *client,
+				     struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainResumeRequest))
+    return -1;
+
+  int ret = qemudDomainResume(server, in->data.domainResumeRequest.id);
+  if (ret < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_RESUME;
+    out->header.dataSize =0;
+  }
+  return 0;
+}
+static int qemudDispatchDomainDestroy(struct qemud_server *server, struct qemud_client *client,
+				      struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainDestroyRequest))
+    return -1;
+
+  int ret = qemudDomainDestroy(server, in->data.domainDestroyRequest.id);
+  if (ret < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_DESTROY;
+    out->header.dataSize = 0;
+  }
+  return 0;
+}
+static int qemudDispatchDomainGetInfo(struct qemud_server *server, struct qemud_client *client,
+				      struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainGetInfoRequest))
+    return -1;
+
+  int ret = qemudDomainGetInfo(server, in->data.domainGetInfoRequest.uuid,
+			       &out->data.domainGetInfoReply.runstate,
+			       &out->data.domainGetInfoReply.cpuTime,
+			       &out->data.domainGetInfoReply.memory,
+			       &out->data.domainGetInfoReply.nrVirtCpu);
+  if (ret < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_GET_INFO;
+    out->header.dataSize = sizeof(out->data.domainGetInfoReply);
+  }
+  return 0;
+}
+static int qemudDispatchDomainSave(struct qemud_server *server, struct qemud_client *client,
+				   struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainSaveRequest))
+    return -1;
+
+  /* Paranoia NULL termination */
+  in->data.domainSaveRequest.file[PATH_MAX-1] ='\0';
+
+  int ret = qemudDomainSave(server,
+			    in->data.domainSaveRequest.id,
+			    in->data.domainSaveRequest.file);
+  if (ret < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_SAVE;
+    out->header.dataSize = 0;
+  }
+  return 0;
+}
+static int qemudDispatchDomainRestore(struct qemud_server *server, struct qemud_client *client,
+				      struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainRestoreRequest))
+    return -1;
+
+  /* Paranoia null termination */
+  in->data.domainRestoreRequest.file[PATH_MAX-1] ='\0';
+
+  int id = qemudDomainRestore(server, in->data.domainRestoreRequest.file);
+  if (id < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_RESTORE;
+    out->header.dataSize = sizeof(out->data.domainRestoreReply);
+    out->data.domainRestoreReply.id = id;
+  }
+  return 0;
+}
+static int qemudDispatchDumpXML(struct qemud_server *server, struct qemud_client *client,
+				struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainDumpXMLRequest))
+    return -1;
+
+  int ret = qemudDomainDumpXML(server, in->data.domainDumpXMLRequest.uuid,
+			      out->data.domainDumpXMLReply.xml, QEMUD_MAX_XML_LEN);
+  if (ret < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DUMP_XML;
+    out->header.dataSize = sizeof(out->data.domainDumpXMLReply);
+  }
+  return 0;
+}
+static int qemudDispatchListDefinedDomains(struct qemud_server *server, struct qemud_client *client,
+					   struct qemud_packet *in, struct qemud_packet *out) {
+  char **names;
+  int i;
+  if (in->header.dataSize != 0)
+    return -1;
+
+  if (!(names = malloc(sizeof(char *)*QEMUD_MAX_NUM_DOMAINS)))
+    return -1;
+
+  for (i = 0 ; i < QEMUD_MAX_NUM_DOMAINS ; i++) {
+    names[i] = out->data.listDefinedDomainsReply.domains[i];
+  }
+
+  int ndomains = qemudListDefinedDomains(server,
+					 names,
+					 QEMUD_MAX_NUM_DOMAINS);
+  free(names);
+  if (ndomains < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_LIST_DEFINED_DOMAINS;
+    out->header.dataSize = sizeof(out->data.listDefinedDomainsReply);
+    out->data.listDefinedDomainsReply.numDomains = ndomains;
+  }
+  return 0;
+}
+static int qemudDispatchNumDefinedDomains(struct qemud_server *server, struct qemud_client *client,
+					  struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != 0)
+    return -1;
+
+  int ndomains = qemudNumDefinedDomains(server);
+  if (ndomains < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_NUM_DEFINED_DOMAINS;
+    out->header.dataSize = sizeof(out->data.numDefinedDomainsReply);
+    out->data.numDefinedDomainsReply.numDomains = ndomains;
+  }
+  return 0;
+}
+static int qemudDispatchDomainStart(struct qemud_server *server, struct qemud_client *client,
+				    struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainStartRequest))
+    return -1;
+
+  struct qemud_vm *vm = qemudFindVMByUUID(server, in->data.domainStartRequest.uuid);
+  if (!vm || qemudDomainStart(server, vm) < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_START;
+    out->header.dataSize = sizeof(out->data.domainStartReply);
+    out->data.domainStartReply.id = vm->def.id;
+  }
+  return 0;
+}
+static int qemudDispatchDomainDefine(struct qemud_server *server, struct qemud_client *client,
+				     struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainDefineRequest))
+    return -1;
+
+  in->data.domainDefineRequest.xml[QEMUD_MAX_XML_LEN-1] ='\0';
+
+  struct qemud_vm *vm = qemudDomainDefine(server, in->data.domainDefineRequest.xml);
+  if (!vm) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_DEFINE;
+    out->header.dataSize = sizeof(out->data.domainDefineReply);
+    memcpy(out->data.domainDefineReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN);
+    strncpy(out->data.domainDefineReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1);
+    out->data.domainDefineReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+  }
+  return 0;
+}
+static int qemudDispatchDomainUndefine(struct qemud_server *server, struct qemud_client *client,
+				       struct qemud_packet *in, struct qemud_packet *out) {
+  if (in->header.dataSize != sizeof(in->data.domainUndefineRequest))
+    return -1;
+
+  int ret = qemudDomainUndefine(server, in->data.domainUndefineRequest.uuid);
+  if (ret < 0) {
+    if (qemudDispatchFailure(server, client, out) < 0)
+      return -1;
+  } else {
+    out->header.type = QEMUD_PKT_DOMAIN_UNDEFINE;
+    out->header.dataSize = 0;
+  }
+  return 0;
+}
+
+
+typedef int (*clientFunc)(struct qemud_server *server, struct qemud_client *client,
+			  struct qemud_packet *in, struct qemud_packet *out);
+
+
+/* One per message type recorded in qemud_packet_type enum */
+clientFunc funcs[] = {
+  NULL, /* FAILURE code */
+  qemudDispatchGetProtocolVersion,
+  qemudDispatchGetVersion,
+  qemudDispatchListDomains,
+  qemudDispatchNumDomains,
+  qemudDispatchDomainCreate,
+  qemudDispatchDomainLookupByID,
+  qemudDispatchDomainLookupByUUID,
+  qemudDispatchDomainLookupByName,
+  qemudDispatchDomainSuspend,
+  qemudDispatchDomainResume,
+  qemudDispatchDomainDestroy,
+  qemudDispatchDomainGetInfo,
+  qemudDispatchDomainSave,
+  qemudDispatchDomainRestore,
+  qemudDispatchDumpXML,
+  qemudDispatchListDefinedDomains,
+  qemudDispatchNumDefinedDomains,
+  qemudDispatchDomainStart,
+  qemudDispatchDomainDefine,
+  qemudDispatchDomainUndefine
+};
+
+/*
+ * Returns -1 if message processing failed - eg, illegal header sizes,
+ * a memory error dealing with stuff, or any other bad stuff which
+ * should trigger immediate client disconnect, with extreme prejudice
+ *
+ * Return 0 if message processing succeeded. NB, this does not mean
+ * the operation itself succeeded - success/failure of the operation
+ * is recorded by the return message type - either it matches the
+ * incoming type, or is QEMUD_PKT_FAILURE
+ */
+int qemudDispatch(struct qemud_server *server, struct qemud_client *client,
+		  struct qemud_packet *in, struct qemud_packet *out) {
+#if DEBUG
+  printf("> Dispatching request %d\n", in->header.type);
+#endif
+
+  memset(out, 0, sizeof(struct qemud_packet));
+
+  if (in->header.type >= (sizeof(funcs)/sizeof(clientFunc))) {
+#if DEBUG
+    printf("Illegal request type\n");
+#endif
+    return -1;
+  }
+
+  if (in->header.type == QEMUD_PKT_FAILURE) {
+#if DEBUG
+    printf("Illegal request type\n");
+#endif
+    return -1;
+  }
+
+  if ((funcs[in->header.type])(server, client, in, out) < 0) {
+#if DEBUG
+    printf("Dispatch failed\n");
+#endif
+    return -1;
+  }
+
+#if DEBUG
+  printf("< Returning reply %d (%d bytes)\n",
+	 out->header.type, out->header.dataSize);
+#endif
+
+  return 0;
+}
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/dispatch.h libvirt-qemu/qemud/dispatch.h
--- libvirt-pristine/qemud/dispatch.h	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/dispatch.h	2006-08-27 17:05:39.000000000 -0400
@@ -0,0 +1,11 @@
+
+#ifndef QEMUD_DISPATCH_H
+#define QEMUD_DISPATCH_H
+
+#include "internal.h"
+
+
+int qemudDispatch(struct qemud_server *server, struct qemud_client *client,
+		  struct qemud_packet *in, struct qemud_packet *out);
+
+#endif
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/driver.c libvirt-qemu/qemud/driver.c
--- libvirt-pristine/qemud/driver.c	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/driver.c	2006-08-30 21:28:47.000000000 -0400
@@ -0,0 +1,284 @@
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "internal.h"
+#include "driver.h"
+#include "config.h"
+
+struct qemud_vm *qemudFindVMByID(const struct qemud_server *server, int id) {
+  struct qemud_vm *vm = server->activevms;
+
+  while (vm) {
+    if (vm->def.id == id)
+      return vm;
+    vm = vm->next;
+  }
+
+  qemudSetError(QEMUD_ERR_NO_DOMAIN, "no domain matching id");
+  return NULL;
+}
+
+struct qemud_vm *qemudFindVMByUUID(const struct qemud_server *server,
+				   const unsigned char *uuid) {
+  struct qemud_vm *vm = server->activevms;
+
+  while (vm) {
+    if (!memcmp(vm->def.uuid, uuid, QEMUD_UUID_RAW_LEN))
+      return vm;
+    vm = vm->next;
+  }
+
+  vm = server->inactivevms;
+  while (vm) {
+    if (!memcmp(vm->def.uuid, uuid, QEMUD_UUID_RAW_LEN))
+      return vm;
+    vm = vm->next;
+  }
+
+  qemudSetError(QEMUD_ERR_NO_DOMAIN, "no domain matching uuid");
+  return NULL;
+}
+
+struct qemud_vm *qemudFindVMByName(const struct qemud_server *server,
+				   const char *name) {
+  struct qemud_vm *vm = server->activevms;
+
+  while (vm) {
+    if (!strcmp(vm->def.name, name))
+      return vm;
+    vm = vm->next;
+  }
+
+  vm = server->inactivevms;
+  while (vm) {
+    if (!strcmp(vm->def.name, name))
+      return vm;
+    vm = vm->next;
+  }
+
+  qemudSetError(QEMUD_ERR_NO_DOMAIN, "no domain matching name");
+  return NULL;
+}
+
+int qemudGetVersion(struct qemud_server *server) {
+  return server->qemuVersion;
+}
+
+int qemudListDomains(struct qemud_server *server, int *ids, int nids) {
+  struct qemud_vm *vm = server->activevms;
+  int got = 0;
+  while (vm && got < nids) {
+    ids[got] = vm->def.id;
+    vm = vm->next;
+    got++;
+  }
+  return got;
+}
+int qemudNumDomains(struct qemud_server *server) {
+  return server->nactivevms;
+}
+struct qemud_vm *qemudDomainCreate(struct qemud_server *server, const char *xml) {
+  struct qemud_vm *vm;
+
+  if (!(vm = qemudLoadConfigXML(server, NULL, xml, 0))) {
+    return NULL;
+  }
+
+  if (qemudStartVMDaemon(server, vm) < 0) {
+    qemudFreeVM(vm);
+    return NULL;
+  }
+
+  vm->next = server->activevms;
+  server->activevms = vm;
+  server->nactivevms++;
+  server->nvmfds += 2;
+
+  return vm;
+}
+
+int qemudDomainSuspend(struct qemud_server *server, int id) {
+  struct qemud_vm *vm = qemudFindVMByID(server, id);
+  if (!vm)
+    return -1;
+  if (vm->pid == -1) {
+    qemudSetError(QEMUD_ERR_DOMAIN_INACTIVE, "domain is not active");
+    return -1;
+  }
+  return -1;
+}
+
+int qemudDomainResume(struct qemud_server *server, int id) {
+  struct qemud_vm *vm = qemudFindVMByID(server, id);
+  if (!vm)
+    return -1;
+  if (vm->pid == -1) {
+    qemudSetError(QEMUD_ERR_DOMAIN_INACTIVE, "domain is not active");
+    return -1;
+  }
+  return -1;
+}
+
+int qemudDomainDestroy(struct qemud_server *server, int id) {
+  struct qemud_vm *vm = qemudFindVMByID(server, id);
+  if (!vm)
+    return -1;
+  if (vm->pid == -1) {
+    qemudSetError(QEMUD_ERR_DOMAIN_INACTIVE, "domain is not active");
+    return -1;
+  }
+
+  if (qemudShutdownVMDaemon(server, vm) < 0)
+    return -1;
+  return 0;
+}
+
+int qemudDomainGetInfo(struct qemud_server *server, const unsigned char *uuid,
+		       int *runstate,
+		       unsigned long long *cputime,
+		       unsigned long *memory,
+		       unsigned int *nrVirtCpu) {
+  struct qemud_vm *vm = qemudFindVMByUUID(server, uuid);
+  if (!vm)
+    return -1;
+
+  if (vm->pid == -1) {
+    *runstate = QEMUD_STATE_STOPPED;
+  } else {
+    /* XXX in future need to add PAUSED */
+    *runstate = QEMUD_STATE_RUNNING;
+  }
+
+  *cputime = 0;
+  *memory = vm->def.memory;
+  *nrVirtCpu = vm->def.vcpus;
+  return 0;
+}
+int qemudDomainSave(struct qemud_server *server, int id,
+		    const char *path ATTRIBUTE_UNUSED) {
+  struct qemud_vm *vm = qemudFindVMByID(server, id);
+  if (!vm)
+    return -1;
+  if (vm->pid == -1) {
+    qemudSetError(QEMUD_ERR_DOMAIN_INACTIVE, "domain is not active");
+    return -1;
+  }
+  return -1;
+}
+int qemudDomainRestore(struct qemud_server *server ATTRIBUTE_UNUSED,
+		       const char *path ATTRIBUTE_UNUSED) {
+
+  return -1;
+}
+int qemudDomainDumpXML(struct qemud_server *server, const unsigned char *uuid, char *xml, int xmllen) {
+  struct qemud_vm *vm = qemudFindVMByUUID(server, uuid);
+  char *vmxml;
+  if (!vm)
+    return -1;
+
+  vmxml = qemudGenerateXML(vm);
+  if (!vmxml)
+    return -1;
+
+  strncpy(xml, vmxml, xmllen);
+  xml[xmllen-1] = '\0';
+
+  return 0;
+}
+int qemudListDefinedDomains(struct qemud_server *server, char *const*names, int nnames) {
+  struct qemud_vm *vm = server->inactivevms;
+  int got = 0;
+  while (vm && got < nnames) {
+    strncpy(names[got], vm->def.name, QEMUD_MAX_NAME_LEN-1);
+    names[got][QEMUD_MAX_NAME_LEN-1] = '\0';
+    vm = vm->next;
+    got++;
+  }
+  return got;
+}
+int qemudNumDefinedDomains(struct qemud_server *server) {
+  return server->ninactivevms;
+}
+int qemudDomainStart(struct qemud_server *server, struct qemud_vm *vm) {
+  struct qemud_vm *prev = NULL, *curr = server->inactivevms;
+
+  if (vm->pid != -1) {
+    qemudSetError(QEMUD_ERR_DOMAIN_INACTIVE, "domain is still active");
+    return -1;
+  }
+
+  if (qemudStartVMDaemon(server, vm) < 0) {
+    return -1;
+  }
+
+  while (curr) {
+    if (curr == vm) {
+      if (prev)
+	prev->next = curr->next;
+      else
+	server->inactivevms = curr->next;
+      server->ninactivevms--;
+      break;
+    }
+    prev = curr;
+    curr = curr->next;
+  }
+
+  vm->next = server->activevms;
+  server->activevms = vm;
+  server->nactivevms++;
+  server->nvmfds += 2;
+
+  return 0;
+}
+
+struct qemud_vm *qemudDomainDefine(struct qemud_server *server, const char *xml) {
+  struct qemud_vm *vm;
+
+  if (!(vm = qemudLoadConfigXML(server, NULL, xml, 1))) {
+    return NULL;
+  }
+
+  vm->next = server->inactivevms;
+  server->inactivevms = vm;
+  server->ninactivevms++;
+
+  return vm;
+}
+
+int qemudDomainUndefine(struct qemud_server *server, const unsigned char *uuid) {
+  struct qemud_vm *vm = qemudFindVMByUUID(server, uuid);
+  struct qemud_vm *prev = NULL, *curr = server->inactivevms;
+
+  if (!vm)
+    return -1;
+
+  if (vm->pid != -1)
+    return -1;
+
+  if (qemudDeleteConfigXML(vm) < 0)
+    return -1;
+
+  while (curr) {
+    if (curr == vm) {
+      if (prev) {
+	prev->next = curr->next;
+      } else {
+	server->inactivevms = curr->next;
+      }
+      server->ninactivevms--;
+      break;
+    }
+
+    prev = curr;
+    curr = curr->next;
+  }
+
+  qemudFreeVM(vm);
+
+  return 0;
+}
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/driver.h libvirt-qemu/qemud/driver.h
--- libvirt-pristine/qemud/driver.h	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/driver.h	2006-08-27 17:05:39.000000000 -0400
@@ -0,0 +1,53 @@
+
+#ifndef QEMUD_DRIVER_H
+#define QEMUD_DRIVER_H
+
+#include "internal.h"
+
+struct qemud_vm *qemudFindVMByID(const struct qemud_server *server,
+				 int id);
+struct qemud_vm *qemudFindVMByUUID(const struct qemud_server *server,
+				   const unsigned char *uuid);
+struct qemud_vm *qemudFindVMByName(const struct qemud_server *server,
+				   const char *name);
+
+int qemudGetVersion(struct qemud_server *server);
+int qemudListDomains(struct qemud_server *server,
+		     int *ids,
+		     int nids);
+int qemudNumDomains(struct qemud_server *server);
+struct qemud_vm *qemudDomainCreate(struct qemud_server *server,
+				   const char *xml);
+int qemudDomainSuspend(struct qemud_server *server,
+		       int id);
+int qemudDomainResume(struct qemud_server *server,
+		      int id);
+int qemudDomainDestroy(struct qemud_server *server,
+		       int id);
+int qemudDomainGetInfo(struct qemud_server *server,
+		       const unsigned char *uuid,
+		       int *runstate,
+		       unsigned long long *cputime,
+		       unsigned long *memory,
+		       unsigned int *nrVirtCpu);
+int qemudDomainSave(struct qemud_server *server,
+		    int id,
+		    const char *path);
+int qemudDomainRestore(struct qemud_server *server,
+		       const char *path);
+int qemudDomainDumpXML(struct qemud_server *server,
+		       const unsigned char *uuid,
+		       char *xml,
+		       int xmllen);
+int qemudListDefinedDomains(struct qemud_server *server,
+			    char *const*names,
+			    int nnames);
+int qemudNumDefinedDomains(struct qemud_server *server);
+int qemudDomainStart(struct qemud_server *server,
+		     struct qemud_vm *vm);
+struct qemud_vm *qemudDomainDefine(struct qemud_server *server,
+				   const char *xml);
+int qemudDomainUndefine(struct qemud_server *server,
+			const unsigned char *uuid);
+
+#endif
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/error.h libvirt-qemu/qemud/error.h
--- libvirt-pristine/qemud/error.h	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/error.h	2006-08-30 19:15:53.000000000 -0400
@@ -0,0 +1 @@
+
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/internal.h libvirt-qemu/qemud/internal.h
--- libvirt-pristine/qemud/internal.h	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/internal.h	2006-08-30 20:00:37.000000000 -0400
@@ -0,0 +1,202 @@
+
+#ifndef QEMUD_INTERNAL_H__
+#define QEMUD_INTERNAL_H__
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "protocol.h"
+
+#ifdef __GNUC__
+#ifdef HAVE_ANSIDECL_H
+#include <ansidecl.h>
+#endif
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+#endif
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#define UUID_LEN 16
+
+struct qemud_client {
+  /* The socket to the client */
+  int fd;
+  /* 1 if this client should be restricted to readonly ops only */
+  int readonly;
+  /* If this is 0 we are processing next incoming packet,
+     incomingReceived gives how much we've got so far. Expected
+     amount is header size + data size listed in header;
+     If this is 1 we are sending back a reply - and not interested
+     in any further incoming data until we've finished sending.
+     outgoingSent is how much we've dispatched so far.
+     Again total send size is header + data size listed in header */
+  int tx;
+  struct qemud_packet incoming;
+  unsigned int incomingReceived;
+  struct qemud_packet outgoing;
+  unsigned int outgoingSent;
+  /* Next client connection, or NULL */
+  struct qemud_client *next;
+};
+
+/* Two difference types of disk backend storage supported */
+enum qmeud_vm_disk_type {
+  QEMUD_DISK_BLOCK,
+  QEMUD_DISK_FILE
+};
+
+/* Three different types of emulated device */
+enum qemud_vm_disk_device {
+  QEMUD_DISK_DISK,
+  QEMUD_DISK_CDROM,
+  QEMUD_DISK_FLOPPY,
+};
+
+struct qemud_vm_disk_def {
+  int type; /* One of qemud_vm_disk_type */
+  int device; /* One of qemud_vm_disk_device */
+  char src[PATH_MAX]; /* Path to backend storage in host */
+  char dst[NAME_MAX]; /* Name of device within guest */
+  int readonly; /* 1 if the dev is to be readonly */
+
+  /* Next disk device, or NULL */
+  struct qemud_vm_disk_def *next;
+};
+
+#define QEMUD_MAC_ADDRESS_LEN 6
+
+/* QEMU has a whole tonne of different network setups */
+enum qemud_vm_net_type {
+  QEMUD_NET_USER,
+  QEMUD_NET_TAP,
+  QEMUD_NET_SERVER,
+  QEMUD_NET_CLIENT,
+  QEMUD_NET_MCAST,
+  QEMUD_NET_VDE
+};
+
+struct qemud_vm_net_def {
+  int type; /* One of qemud_vm_net_type */
+  int vlan; /* VLAN number */
+  unsigned char mac[QEMUD_MAC_ADDRESS_LEN]; /* Mac address */
+  union {
+    struct { /* If type == QEMUD_NET_TAP */
+      char ifname[NAME_MAX];
+      char script[PATH_MAX];
+    } tap;
+    struct { /* If type == QEMUD_NET_SERVER */
+      struct sockaddr_in listen;
+      int port;
+    } server;
+    struct { /* If type == QEMUD_NET_CLIENT */
+      struct sockaddr_in connect;
+      int port;
+    } client;
+    struct { /* If type == QEMUD_NET_MCAST */
+      struct sockaddr_in group;
+      int port;
+    } mcast;
+    struct { /* If type == QEMUD_NET_VDE */
+      char vlan[PATH_MAX];
+    } vde;
+  } dst;
+
+  /* Next network device, or NULL */
+  struct qemud_vm_net_def *next;
+};
+
+enum qemud_vm_boot_order {
+  QEMUD_BOOT_FLOPPY,
+  QEMUD_BOOT_CDROM,
+  QEMUD_BOOT_DISK
+};
+
+enum qemud_vm_graphics_type {
+  QEMUD_GRAPHICS_NONE,
+  QEMUD_GRAPHICS_VNC
+};
+
+struct qemud_vm_def {
+  int id; /* Unique identifier for lifetime of qemud process */
+  unsigned char uuid[QEMUD_UUID_RAW_LEN]; /* Globally unique ID */
+  char name[QEMUD_MAX_NAME_LEN]; /* A unique name for VM on this host */
+
+  int memory; /* Memory in KB */
+  int vcpus; /* Number of virtual CPUs - no tech limit;
+		effective limit according to guest OS scalability */
+
+  int bootOrder[3]; /* One of qemud_vm_boot_order */
+
+  int graphicsType;  /* One of qemud_vm_graphics_types */
+  int vncPort; /* TCP port number if graphicsType == QEMUD_GRAPHICS_VNC */
+
+  int ndisks; /* Number of disks configured */
+  struct qemud_vm_disk_def *disks; /* Pointer to first disk in linked list */
+
+  int nnets; /* Number of net devs configured */
+  struct qemud_vm_net_def *nets; /* Pointer to first net dev in linked list */
+};
+
+struct qemud_vm {
+  int stdout; /* Read end of pipe attached to qemu's stdout; -1 if inactive */
+  int stderr; /* Read end of pipe attached to qemu's stderr; -1 if inactive */
+  int monitor; /* Pipe to monitor TTy; -1 if not active */
+  int pid; /* PID of qemu child processes; -1 if inactive */
+
+  char configFile[PATH_MAX]; /* Path to persistent config file. '' if transient */
+
+  struct qemud_vm_def def; /* Hardware definition */
+
+  struct qemud_vm *next; /* Next VM, or NULL */
+};
+
+struct qemud_server {
+  int fd; /* Handle for server socket to libvirt */
+  int qemuVersion; /* QEMU version number encoded (major *1000*1000)+(minor*1000)+micro */
+  int nclients; /* Total number of clients */
+  struct qemud_client *clients; /* First client in linked list */
+  int nvmfds; /* Number of active file handles associated with VMs */
+  int nactivevms; /* Number of active VMs */
+  struct qemud_vm *activevms; /* First active vm in linked list */
+  int ninactivevms; /* Number of inactive VMs */
+  struct qemud_vm *inactivevms; /* First inactive VM in linked list */
+  int nextvmid; /* Next unique VM id to be allocated */
+  char configDir[PATH_MAX]; /* Directory storing VM config files */
+};
+
+/* Start an inactive VM
+ * Returns 0 on success; -1 on failure
+ */
+int qemudStartVMDaemon(struct qemud_server *server,
+		       struct qemud_vm *vm);
+
+/* Shutdown an active VM
+ * Returns 0 on success; -1 on failure
+ */
+int qemudShutdownVMDaemon(struct qemud_server *server,
+			  struct qemud_vm *vm);
+
+/* Set an error message,
+ * code: one of qemud_error_code
+ * msg: string description of problem
+ */
+void qemudSetError(int code,
+		   const char *msg);
+
+/* Get last error code
+ * msg: pointer to location to receive error msg (read only)
+ * Returns error code, or 0 if no current erro
+ */
+int qemudGetLastError(const char **msg);
+
+/* Clears the current error code
+ */
+void qemudClearLastError(void);
+
+#endif
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/Makefile.am libvirt-qemu/qemud/Makefile.am
--- libvirt-pristine/qemud/Makefile.am	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/Makefile.am	2006-08-27 17:54:39.000000000 -0400
@@ -0,0 +1,17 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = @LIBXML_CFLAGS@
+
+libexec_PROGRAMS = qemud
+
+qemud_SOURCES = qemud.c internal.h protocol.h \
+                driver.c driver.h \
+                dispatch.c dispatch.h \
+                config.c config.h
+qemud_CFLAGS = -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L -std=c99 \
+        -I$(top_srcdir)/include -I$(top_builddir)/include $(LIBXML_CFLAGS) \
+        -Werror -Wall -Wextra
+qemud_LDFLAGS = $(LIBXML_LIBS)
+qemud_DEPENDENCIES =
+qemud_LDADD =
+
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/protocol.h libvirt-qemu/qemud/protocol.h
--- libvirt-pristine/qemud/protocol.h	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/protocol.h	2006-08-30 22:57:44.000000000 -0400
@@ -0,0 +1,203 @@
+
+#ifndef QEMUD_PROTOCOL_H__
+#define QEMUD_PROTOCOL_H__
+
+/* The set of message types allowed on wire */
+enum  qemud_packet_type {
+  QEMUD_PKT_FAILURE,
+  QEMUD_PKT_GET_PROTOCOL_VERSION,
+  QEMUD_PKT_GET_VERSION,
+  QEMUD_PKT_LIST_DOMAINS,
+  QEMUD_PKT_NUM_DOMAINS,
+  QEMUD_PKT_DOMAIN_CREATE,
+  QEMUD_PKT_DOMAIN_LOOKUP_BY_ID,
+  QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID,
+  QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME,
+  QEMUD_PKT_DOMAIN_SUSPEND,
+  QEMUD_PKT_DOMAIN_RESUME,
+  QEMUD_PKT_DOMAIN_DESTROY,
+  QEMUD_PKT_DOMAIN_GET_INFO,
+  QEMUD_PKT_DOMAIN_SAVE,
+  QEMUD_PKT_DOMAIN_RESTORE,
+  QEMUD_PKT_DUMP_XML,
+  QEMUD_PKT_LIST_DEFINED_DOMAINS,
+  QEMUD_PKT_NUM_DEFINED_DOMAINS,
+  QEMUD_PKT_DOMAIN_START,
+  QEMUD_PKT_DOMAIN_DEFINE,
+  QEMUD_PKT_DOMAIN_UNDEFINE,
+  QEMUD_PKT_MAX
+};
+
+/* Error conditions which can be returned */
+enum qemud_error {
+  QEMUD_ERR_GENERIC = 1,
+  QEMUD_ERR_NO_MEMORY,
+  QEMUD_ERR_NO_DOMAIN,
+  QEMUD_ERR_READONLY,
+  QEMUD_ERR_DOMAIN_INACTIVE,
+  QEMUD_ERR_DOMAIN_ACTIVE,
+  QEMUD_ERR_CONFIG_MALFORMED,
+  QEMUD_ERR_DUPLICATE_DOMAIN,
+  QEMUD_ERR_PATH_OVERFLOW,
+  QEMUD_ERR_MALFORMED_UUID,
+  QEMUD_ERR_ILLEGAL_DISK_CONFIG,
+  QEMUD_ERR_XML_NO_ROOT,
+  QEMUD_ERR_XML_WRONG_TYPE,
+  QEMUD_ERR_XML_MISSING_NAME,
+  QEMUD_ERR_XML_MISSING_UUID,
+  QEMUD_ERR_NAME_OVERFLOW,
+};
+
+/* If we break protocol compatability, this is
+ * going to be increased */
+#define QEMUD_PROTOCOL_VERSION 1
+
+/* Max lengths for various arrays - this length
+ * includes the trailing NULL, if appropriate
+ */
+#define QEMUD_UUID_RAW_LEN 16
+#define QEMUD_MAX_NAME_LEN 50
+#define QEMUD_MAX_XML_LEN 4096
+#define QEMUD_MAX_ERROR_LEN 1024
+#define QEMUD_MAX_NUM_DOMAINS 100
+
+/* Domain runtime state - may expand over time */
+enum qemud_domain_runstate {
+  QEMUD_STATE_RUNNING = 1,
+  QEMUD_STATE_PAUSED,
+  QEMUD_STATE_STOPPED,
+};
+
+
+struct qemud_packet_header {
+  /* One of the qemud_packet_type constants */
+  unsigned int type;
+  /* Stores the size of the data struct matching
+     the type arg. The exact size is dependnant
+     on the memory the union qemudPacketData which
+     matches the type field above.
+     Must be <= sizeof(union qemudPacketData) */
+  unsigned int dataSize;
+};
+
+/* Most qemud_packet_type constants have both a
+ * XXXRequest & XXXReply field - but some have
+ * either no params, or no reply. That said, there
+ * is always possibility of a failureReply for any
+ * of the request types */
+union qemud_packet_data {
+  struct { /* QEMUD_PKT_FAILURE */
+    int code;
+    char message[QEMUD_MAX_ERROR_LEN];
+  } failureReply;
+  struct { /* QEMUD_PKT_GET_PROTOCOL_VERSION */
+    int version;
+  } getProtocolVersionReply;
+  struct { /* QEMUD_PKT_GET_VERSION */
+    int version;
+  } getVersionReply;
+  struct { /* QEMUD_PKT_LIST_DOMAINS */
+    int numDomains;
+    int domains[QEMUD_MAX_NUM_DOMAINS];
+  } listDomainsReply;
+  struct { /* QEMUD_PKT_NUM_DOMAINS */
+    int numDomains;
+  } numDomainsReply;
+  struct { /* QEMUD_PKT_DOMAIN_CREATE */
+    char xml[QEMUD_MAX_XML_LEN];
+  } domainCreateRequest;
+  struct { /* QEMUD_PKT_DOMAIN_CREATE */
+    int id;
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+    char name[QEMUD_MAX_NAME_LEN];
+  } domainCreateReply;
+  struct { /* QEMUD_PKT_DOMAIN_LOOKUP_BY_ID */
+    int id;
+  } domainLookupByIDRequest;
+  struct { /* QEMUD_PKT_DOMAIN_LOOKUP_BY_ID */
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+    char name[QEMUD_MAX_NAME_LEN];
+  } domainLookupByIDReply;
+  struct { /* QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME */
+    char name[QEMUD_MAX_NAME_LEN];
+  } domainLookupByNameRequest;
+  struct { /* QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME */
+    int id;
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+  } domainLookupByNameReply;
+  struct { /* QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID */
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+  } domainLookupByUUIDRequest;
+  struct { /* QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID */
+    int id;
+    char name[QEMUD_MAX_NAME_LEN];
+  } domainLookupByUUIDReply;
+  struct { /* QEMUD_PKT_DOMAIN_SUSPEND */
+    int id;
+  } domainSuspendRequest;
+  struct { /* QEMUD_PKT_DOMAIN_RESUME */
+    int id;
+  } domainResumeRequest;
+  struct { /* QEMUD_PKT_DOMAIN_DESTROY */
+    int id;
+  } domainDestroyRequest;
+  struct { /* QEMUD_PKT_DOMAIN_GET_INFO */
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+  } domainGetInfoRequest;
+  struct { /* QEMUD_PKT_DOMAIN_GET_INFO */
+    int runstate;
+    unsigned long long cpuTime;
+    unsigned long memory;
+    unsigned int nrVirtCpu;
+  } domainGetInfoReply;
+  struct { /* QEMUD_PKT_DOMAIN_SAVE */
+    int id;
+    char file[PATH_MAX];
+  } domainSaveRequest;
+  struct { /* QEMUD_PKT_DOMAIN_RESTORE */
+    char file[PATH_MAX];
+  } domainRestoreRequest;
+  struct { /* QEMUD_PKT_DOMAIN_RESTORE */
+    int id;
+  } domainRestoreReply;
+  struct { /* QEMUD_PKT_DUMP_XML */
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+  } domainDumpXMLRequest;
+  struct { /* QEMUD_PKT_DUMP_XML */
+    char xml[QEMUD_MAX_XML_LEN];
+  } domainDumpXMLReply;
+  struct { /* QEMUD_PKT_LIST_DEFINED_DOMAINS */
+    int numDomains;
+    char domains[QEMUD_MAX_NUM_DOMAINS][QEMUD_MAX_NAME_LEN];
+  } listDefinedDomainsReply;
+  struct { /* QEMUD_PKT_NUM_DEFINED_DOMAINS */
+    int numDomains;
+  } numDefinedDomainsReply;
+  struct { /* QEMUD_PKT_DOMAIN_START */
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+  } domainStartRequest;
+  struct { /* QEMUD_PKT_DOMAIN_START */
+    int id;
+  } domainStartReply;
+  struct { /* QEMUD_PKT_DOMAIN_DEFINE */
+    char xml[QEMUD_MAX_XML_LEN];
+  } domainDefineRequest;
+  struct { /* QEMUD_PKT_DOMAIN_DEFINE */
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+    char name[QEMUD_MAX_NAME_LEN];
+  } domainDefineReply;
+  struct { /* QEMUD_PKT_DOMAIN_UNDEFINE */
+    unsigned char uuid[QEMUD_UUID_RAW_LEN];
+  } domainUndefineRequest;
+};
+
+/* A single packet on the wire contains header & data.
+ * header is always fixed size. data is the size of the
+ * particular union member matching header->type */
+struct qemud_packet {
+  struct qemud_packet_header header;
+  union qemud_packet_data data;
+};
+
+
+#endif
diff --exclude docs --exclude CVS -ruN libvirt-pristine/qemud/qemud.c libvirt-qemu/qemud/qemud.c
--- libvirt-pristine/qemud/qemud.c	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/qemud.c	2006-08-30 22:06:42.000000000 -0400
@@ -0,0 +1,795 @@
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "dispatch.h"
+#include "config.h"
+
+static void reapchild(int sig ATTRIBUTE_UNUSED) {
+  /* We explicitly waitpid the child later */
+}
+
+
+static int errorCode = 0;
+static char *errorMsg = NULL;
+
+void qemudSetError(int code,
+		   const char *msg) {
+  qemudClearLastError();
+  errorCode = code;
+  errorMsg = msg ? strdup(msg) : NULL;
+}
+
+int qemudGetLastError(const char **msg) {
+  if (msg)
+    *msg = errorMsg;
+  return errorCode;
+}
+
+void qemudClearLastError(void) {
+  if (errorMsg) {
+    free(errorMsg);
+    errorMsg = NULL;
+  }
+  errorCode = 0;
+}
+
+
+/* Enables the CLOSE-ON-EXEC flag for the passed in
+   file handle */
+static int qemudSetCloseExec(int fd) {
+  int flags;
+  if ((flags = fcntl(fd, F_GETFD)) < 0) {
+    return -1;
+  }
+  flags |= FD_CLOEXEC;
+  if ((fcntl(fd, F_SETFD, flags)) < 0) {
+    return -1;
+  }
+  return 0;
+}
+
+
+/* Enables non blocking IO operation for the passed
+   in file handle */
+static int qemudSetNonBlock(int fd) {
+  int flags;
+  if ((flags = fcntl(fd, F_GETFL)) < 0) {
+    return -1;
+  }
+  flags |= O_NONBLOCK;
+  if ((fcntl(fd, F_SETFL, flags)) < 0) {
+    return -1;
+  }
+  return 0;
+}
+
+
+/* Does the traiditional double-fork() routine
+   to go daemon & dis-inherit terminal & IO
+   streams */
+static int qemudGoDaemon(void) {
+  int pid = fork();
+  switch (pid) {
+  case 0:
+    {
+      int stdinfd = -1;
+      int stdoutfd = -1;
+      if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0)
+	goto cleanup;
+      if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0)
+	goto cleanup;
+      if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+	goto cleanup;
+      if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+	goto cleanup;
+      if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+	goto cleanup;
+      if (close(stdinfd) < 0)
+	goto cleanup;
+      stdinfd = -1;
+      if (close(stdoutfd) < 0)
+	goto cleanup;
+      stdoutfd = -1;
+
+      int open_max = sysconf (_SC_OPEN_MAX);
+      for (int i = 0; i < open_max; i++)
+	if (i != STDIN_FILENO &&
+	    i != STDOUT_FILENO &&
+	    i != STDERR_FILENO)
+	  close(i);
+
+      if (setsid() < 0)
+	goto cleanup;
+
+      int nextpid = fork();
+      switch (nextpid) {
+      case 0:
+	return 0;
+      case -1:
+	return -1;
+      default:
+	return nextpid;
+      }
+
+      cleanup:
+      if (stdoutfd != -1)
+	close(stdoutfd);
+      if (stdinfd != -1)
+	close(stdinfd);
+      return -1;
+
+    }
+
+  case -1:
+    return -1;
+
+  default:
+    {
+      int got, status = 0;
+      /* We wait to make sure the next child forked
+	 successfully */
+      if ((got = waitpid(pid, &status, 0)) < 0 ||
+	  got != pid ||
+	status != 0) {
+	return -1;
+      }
+      
+      return pid;
+    }
+  }
+}
+
+
+/* General startup / initialization bits & pieces */
+static struct qemud_server *qemudInitialize(void) {
+  struct qemud_server *server;
+  struct passwd *pw;
+  int uid, ret;
+  char path[PATH_MAX];
+  struct sockaddr_un addr;
+
+  if (!(server = calloc(1, sizeof(struct qemud_server))))
+    return NULL;
+
+  server->fd = -1;
+  /* XXX extract actual lversion */
+  server->qemuVersion = (0*1000000)+(8*1000)+(0);
+  /* We don't have a dom-0, so start from 1 */
+  server->nextvmid = 1;
+
+  /* First off, figure out out socket path based on user
+     home directory */
+  if ((uid = geteuid()) < 0) {
+    goto cleanup;
+  }
+  if (!(pw = getpwuid(uid))) {
+    goto cleanup;
+  }
+
+  if ((ret = snprintf(path, PATH_MAX, "%s/.qemud", pw->pw_dir)) > PATH_MAX) {
+    goto cleanup;
+  }
+
+  if ((ret = snprintf(server->configDir, PATH_MAX, "%s/.qemud.d", pw->pw_dir)) > PATH_MAX) {
+    goto cleanup;
+  }
+
+
+  /* Open & bind to the socket, in abstract namespace */
+  if ((server->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+    goto cleanup;
+  }
+
+  if (qemudSetCloseExec(server->fd) < 0)
+    goto cleanup;
+  if (qemudSetNonBlock(server->fd) < 0)
+    goto cleanup;
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  addr.sun_path[0] = '\0'; /* Abstract namespace */
+  strncpy(&addr.sun_path[1], path, (sizeof(addr)-4)-2);
+
+  if (bind(server->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    goto cleanup;
+  }
+  /* Only matching userid to connect to us for now */
+  if (fchmod(server->fd, S_IRUSR | S_IWUSR) < 0)
+    goto cleanup;
+
+  if (listen(server->fd, 30) < 0) {
+    goto cleanup;
+  }
+
+  /* Load all pre-existing virtual machine configs */
+  if (qemudScanConfigs(server) < 0) {
+    goto cleanup;
+  }
+
+  return server;
+
+ cleanup:
+  if (server->fd != -1)
+    close(server->fd);
+  if (server)
+    free(server);
+  return NULL;
+}
+
+
+/* Handles new incoming connection attempts.
+ * Accepts the connection & sets up a client
+ * state structure
+ */
+static int qemudDispatchServer(struct qemud_server *server) {
+  int fd;
+  struct sockaddr_un addr;
+  unsigned int addrlen = sizeof(addr);
+  struct qemud_client *client;
+
+  if ((fd = accept(server->fd, (struct sockaddr *)&addr, &addrlen)) < 0) {
+    if (errno == EAGAIN)
+      return 0;
+    return -1;
+  }
+
+  if (qemudSetCloseExec(fd) < 0) {
+    close(fd);
+    return -1;
+  }
+
+  if (qemudSetNonBlock(fd) < 0) {
+    close(fd);
+    return -1;
+  }
+
+  client = calloc(1, sizeof(struct qemud_client));
+  client->fd = fd;
+  client->next = server->clients;
+  server->clients = client;
+  server->nclients++;
+
+  return 0;
+}
+
+
+/* Starts an inactive virtual machine */
+int qemudStartVMDaemon(struct qemud_server *server,
+		       struct qemud_vm *vm) {
+  char **argv = NULL;
+  int argc = 0;
+  int pid;
+  int i, ret = -1;
+  int pipeout[2] = {-1,-1};
+  int pipeerr[2] = {-1,-1};
+
+  if (qemudBuildCommandLine(vm, &argv, &argc) < 0)
+    return -1;
+
+  printf("Spawn QEMU '");
+  for (i = 0 ; i < argc; i++) {
+    printf("%s", argv[i]);
+    if (i == (argc-1))
+      printf("'\n");
+    else
+      printf(" ");
+  }
+
+
+  if (pipe(pipeout) < 0)
+    goto cleanup;
+  if (qemudSetCloseExec(pipeout[0]))
+    goto cleanup;
+
+  if (pipe(pipeerr) < 0)
+    goto cleanup;
+  if (qemudSetCloseExec(pipeerr[0]))
+    goto cleanup;
+
+  if ((pid = fork()) < 0)
+    goto cleanup;
+
+  if (pid) {
+    close(pipeout[1]);
+    close(pipeerr[1]);
+    qemudSetNonBlock(pipeout[0]);
+    qemudSetNonBlock(pipeerr[0]);
+    vm->def.id = server->nextvmid++;
+    vm->pid = pid;
+    vm->stdout = pipeout[0];
+    vm->stderr = pipeerr[0];
+  } else {
+    int null;
+    /* Connect stdin to /dev/null */
+    if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0)
+      _exit(1);
+    if (dup2(null, STDIN_FILENO) < 0)
+      _exit(1);
+
+    /* Connect stdout/err to pipe */
+    if (dup2(pipeout[1], STDOUT_FILENO) < 0)
+      _exit(1);
+    if (dup2(pipeerr[1], STDERR_FILENO) < 0)
+      _exit(1);
+
+    int open_max = sysconf (_SC_OPEN_MAX);
+    for (i = 0; i < open_max; i++)
+      if (i != STDOUT_FILENO &&
+	  i != STDERR_FILENO &&
+	  i != STDIN_FILENO)
+	close(i);
+
+    /* Exec qemu process */
+    execvp(argv[0], argv);
+
+    /* Should never get here, but just in case */
+    _exit(1);
+  }
+
+  ret = 0;
+
+ cleanup:
+  
+  for (i = 0 ; i < argc ; i++) {
+    free(argv[i]);
+  }
+  free(argv);
+
+  return ret;
+}
+
+
+/* If something went wrong with client, then drop its
+   connection with extreme prejudice */
+static void qemudDispatchClientFailure(struct qemud_server *server, struct qemud_client *client) {
+  struct qemud_client *tmp = server->clients;
+  struct qemud_client *prev = NULL;
+  while (tmp) {
+    if (tmp == client) {
+      if (prev == NULL)
+	server->clients = client->next;
+      else
+	prev->next = client->next;
+      server->nclients--;
+      break;
+    }
+    prev = tmp;
+    tmp = tmp->next;
+  }
+  close(client->fd);
+  free(client);
+}
+
+
+/*
+ * Disptach an incoming message from a client, and
+ * switch into transmit mode for sending the reply
+ */
+static int qemudDispatchClientRequest(struct qemud_server *server, struct qemud_client *client) {
+  if (qemudDispatch(server,
+		    client,
+		    &client->incoming,
+		    &client->outgoing) < 0) {
+    return -1;
+  }
+
+  client->outgoingSent = 0;
+  client->tx = 1;
+  client->incomingReceived = 0;
+
+  return 0;
+}
+
+/* Handle incoming client data, and possibly
+ * dispatch an incoming mesage if its complete
+ */
+static void qemudDispatchClientRead(struct qemud_server *server, struct qemud_client *client) {
+  char *data = (char *)&client->incoming;
+  unsigned int got = client->incomingReceived;
+  int want;
+  int ret;
+
+ restart:
+  /* Either calculate how much of packet body is outstanding */
+  if (got >= sizeof(struct qemud_packet_header)) {
+    want = sizeof(struct qemud_packet_header) + client->incoming.header.dataSize - got;
+  } else { /* Or how much of header is outstanding */
+    want = sizeof(struct qemud_packet_header) - got;
+  }
+
+  /* Read as much as possible - we're non-blocking remember */
+  if ((ret = read(client->fd, data+got, want)) <= 0) {
+    if (errno != EAGAIN) {
+      qemudDispatchClientFailure(server, client);
+      return;
+    }
+    return;
+  }
+  got += ret;
+  client->incomingReceived += ret;
+
+  /* If we've finished header, move onto body */
+  if (client->incomingReceived == sizeof(struct qemud_packet_header)) {
+    /* Client lied about dataSize, kill with prejudice */
+    if (client->incoming.header.dataSize > sizeof(union qemud_packet_data)) {
+#if DEBUG
+      printf("Bogus data size %u\n", client->incoming.header.dataSize);
+#endif
+      qemudDispatchClientFailure(server, client);
+      return;
+    }
+    /* We reached omplete header size, go back & do body now */
+    if (client->incoming.header.dataSize) {
+#if DEBUG
+      printf("- Restarting recv to process body (%d bytes)\n", client->incoming.header.dataSize);
+#endif
+      goto restart;
+    }
+  }
+
+  /* If we've finished body too, then dispatch the request */
+  if (ret == want) {
+    if (qemudDispatchClientRequest(server, client) < 0)
+      qemudDispatchClientFailure(server, client);
+  }
+}
+
+/* Handles transmission of a reply to the client */
+static void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_client *client) {
+  char *data = (char *)&client->outgoing;
+  int sent = client->outgoingSent;
+  int todo = sizeof(struct qemud_packet_header) + client->outgoing.header.dataSize - sent;
+  int ret;
+
+  /* Write as much as possible - we're non-blocking so maybe not all */
+  if ((ret = write(client->fd, data+sent, todo)) < 0) {
+    if (errno != EAGAIN) {
+      qemudDispatchClientFailure(server, client);
+      return;
+    }
+    return;
+  }
+  client->outgoingSent += ret;
+
+  /* If we've sent entire packet, then switch back to receive mode */
+  if (todo == ret) {
+    client->tx = 0;
+  }
+}
+
+
+/* Deals with incoming log data from qemu process on its stdout/err */
+static int qemudVMData(struct qemud_server *server ATTRIBUTE_UNUSED,
+		       struct qemud_vm *vm, int fd) {
+  char buf[4096];
+  if (vm->pid < 0)
+    return 0;
+
+  for (;;) {
+    int ret = read(fd, buf, 4096);
+    if (ret < 0) {
+      if (errno == EAGAIN)
+	return 0;
+      return -1;
+    }
+    if (ret == 0) {
+      return 0;
+    }
+    /* Save it to a logfile */
+    write(STDOUT_FILENO, "[", 1);
+    write(STDOUT_FILENO, buf, ret);
+    write(STDOUT_FILENO, "]", 1);
+  }
+}
+
+/* Forceably kill of qemu, reading any outstanding log data */
+int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
+  struct qemud_vm *prev = NULL, *curr = server->activevms;
+
+  /* Already cleanup */
+  if (vm->pid < 0)
+    return 0;
+
+#if DEBUG
+  printf("Do VM cleanup\n");
+#endif
+  kill(vm->pid, SIGTERM);
+
+  /* Move VM from active -> inactive list,
+     possibly discarding VM if it had no
+     config file backing store */
+  while (curr) {
+    if (curr == vm) {
+      if (prev) {
+	prev->next = curr->next;
+      } else {
+	server->activevms = curr->next;
+      }
+      server->nactivevms--;
+
+      if (vm->configFile[0]) {
+	curr->next = server->inactivevms;
+	server->inactivevms = curr;
+	server->ninactivevms++;
+      }
+      break;
+    }
+    prev = curr;
+    curr = curr->next;
+  }
+
+  /* Suck in any outstanding stdout/err data */
+  qemudVMData(server, vm, curr->stdout);
+  qemudVMData(server, vm, curr->stderr);
+  close(curr->stdout);
+  close(curr->stderr);
+  curr->stdout = -1;
+  curr->stderr = -1;
+  server->nvmfds -= 2;
+
+  /* It ought to be dea by now */
+  if (waitpid(vm->pid, NULL, WNOHANG) != vm->pid) {
+    /*  But we may need to be really forceful */
+    kill(vm->pid, SIGKILL);
+    if (waitpid(vm->pid, NULL, 0) != vm->pid) {
+      return -1;
+    }
+  }
+
+  vm->pid = -1;
+  vm->def.id = -1;
+
+  /* If no backing store, then just throw away this vm */
+  if (!vm->configFile[0]) {
+    qemudFreeVM(vm);
+  }
+
+  return 0;
+}
+
+/* Handle incoming log data from QEMU stdout/err */
+static int qemudDispatchVMLog(struct qemud_server *server, struct qemud_vm *vm, int fd) {
+  if (qemudVMData(server, vm, fd) < 0)
+    if (qemudShutdownVMDaemon(server, vm) < 0)
+      return -1;
+  return 0;
+}
+/* Process monitor IO - TODO */
+static int qemudDispatchVMMonitor(struct qemud_server *server ATTRIBUTE_UNUSED,
+				  struct qemud_vm *vm ATTRIBUTE_UNUSED) {
+  return -1;
+}
+
+/* Handle error condition on IO streams */
+static int qemudDispatchVMFailure(struct qemud_server *server, struct qemud_vm *vm,
+				  int fd ATTRIBUTE_UNUSED) {
+  if (qemudShutdownVMDaemon(server, vm) < 0)
+    return -1;
+  return 0;
+}
+
+
+/* Looks at poll revents and invokes appropriate dispatchers
+ * depending on which condiitons were set */
+static int qemudDispatchPoll(struct qemud_server *server, struct pollfd *fds) {
+  struct qemud_client *client = server->clients;
+  struct qemud_vm *vm = server->activevms;
+  int ret = 0;
+  int fd = 0;
+  /* Incoming client connection */
+  if (fds[fd].revents)
+    if (qemudDispatchServer(server) < 0)
+      return -1;
+  fd++;
+
+  /* Client data read/write */
+  while (client) {
+    struct qemud_client *next = client->next;
+    if (fds[fd].revents) {
+      if (fds[fd].revents == POLLOUT)
+	qemudDispatchClientWrite(server, client);
+      else if (fds[fd].revents == POLLIN)
+	qemudDispatchClientRead(server, client);
+      else
+	qemudDispatchClientFailure(server, client);
+    }
+    fd++;
+    client = next;
+  }
+
+  /* VM data read/write */
+  while (vm) {
+    struct qemud_vm *next = vm->next;
+    int failed = 0,
+      stdoutfd = vm->stdout,
+      stderrfd = vm->stderr,
+      monitorfd = vm->monitor;
+    if (stdoutfd != -1) {
+      if (fds[fd].revents) {
+	if (fds[fd].revents == POLLIN) {
+	  if (qemudDispatchVMLog(server, vm, fds[fd].fd) < 0)
+	    failed = 1;
+	} else {
+	  if (qemudDispatchVMFailure(server, vm, fds[fd].fd) < 0)
+	    failed = 1;
+	}
+      }
+      fd++;
+    }
+    if (stderrfd != -1) {
+      if (!failed) {
+	if (fds[fd].revents) {
+	  if (fds[fd].revents == POLLIN) {
+	    if (qemudDispatchVMLog(server, vm, fds[fd].fd) < 0)
+	      failed = 1;
+	  } else {
+	    if (qemudDispatchVMFailure(server, vm, fds[fd].fd) < 0)
+	      failed = 1;
+	  }
+	}
+      }
+      fd++;
+    }
+    if (monitorfd != -1) {
+      if (!failed) {
+	if (fds[fd].revents) {
+	  if (fds[fd].revents == POLLIN) {
+	    if (qemudDispatchVMMonitor(server, vm) < 0)
+	      failed = 1;
+	  } else {
+	    if (qemudDispatchVMFailure(server, vm, fds[fd].fd) < 0)
+	      failed = 1;
+	  }
+	}
+      }
+      fd++;
+    }
+    vm = next;
+    if (failed)
+      ret = -1;
+  }
+  return ret;
+}
+
+
+/* Fill up the poll data with any FD's which we
+ * want to monitor 
+ */
+static void qemudPreparePoll(struct qemud_server *server, struct pollfd *fds) {
+  int  fd = 0;
+
+  fds[fd].fd = server->fd;
+  fds[fd].events = POLLIN;
+  fd++;
+
+  for (struct qemud_client *client = server->clients ; client ; client = client->next) {
+    fds[fd].fd = client->fd;
+    /* Refuse to read more from client if tx is pending to
+       rate limit */
+    if (client->tx)
+      fds[fd].events = POLLOUT | POLLERR | POLLHUP;
+    else
+      fds[fd].events = POLLIN | POLLERR | POLLHUP;
+    fd++;
+  }
+  /* See if any active VMs have handles which need monitoring */
+  for (struct qemud_vm *vm = server->activevms ; vm ; vm = vm->next) {
+    if (vm->stdout != -1) {
+      fds[fd].fd = vm->stdout;
+      fds[fd].events = POLLIN | POLLERR | POLLHUP;
+      fd++;
+    }
+    if (vm->stderr != -1) {
+      fds[fd].fd = vm->stderr;
+      fds[fd].events = POLLIN | POLLERR | POLLHUP;
+      fd++;
+    }
+    if (vm->monitor != -1) {
+      fds[fd].fd = vm->monitor;
+      fds[fd].events = POLLIN | POLLERR | POLLHUP;
+      fd++;
+    }
+  }
+}
+
+
+/* One iteration of the poll event loop. Returns -1
+ * if an error occurred, of the loop needs to be
+ * shutdown through lack ofactivity
+ */
+static int qemudOneLoop(struct qemud_server *server) {
+  int nfds = 1 + server->nclients + server->nvmfds;
+  struct pollfd fds[nfds];
+  int timeout = -1;
+  int ret;
+
+  /* If nothing happens for 30 secs, quit */
+  if (!server->nclients &&
+      !server->nactivevms)
+    timeout = 30;
+
+  /* Determine which handles need monitoring */
+  qemudPreparePoll(server, fds);
+
+ retry:
+
+  if ((ret = poll(fds, nfds, timeout * 1000)) < 0) {
+    if (errno == EINTR) {
+      goto retry;
+    }
+    return -1;
+  }
+
+  /* We timeed out, so shutdown */
+  if (ret == 0)
+    return -1;
+
+  /* Dispatch events we were notified on */
+  if (qemudDispatchPoll(server, fds) < 0)
+    return -1;
+
+
+  return 0;
+}
+
+
+/* Run the event loop for ever */
+static int qemudRunLoop(struct qemud_server *server) {
+  int ret;
+
+  while ((ret = qemudOneLoop(server)) == 0)
+    ;
+
+  return ret == -1 ? -1 : 0;
+}
+
+/* Pre-quite cleanup */
+static void qemudCleanup(struct qemud_server *server) {
+  close(server->fd);
+  free(server);
+}
+
+
+int main(void) {
+  int godaemon = 0;
+
+  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+    return 3;
+  if (signal(SIGCHLD, reapchild) == SIG_ERR)
+    return 3;
+
+  /* XXX switch on command line flag */
+  if (godaemon) {
+    int pid = qemudGoDaemon();
+    if (pid < 0)
+      return 1;
+    if (pid > 0)
+      return 0;
+  }
+
+  struct qemud_server *server = qemudInitialize();
+
+  if (!server)
+    return 2;
+
+  qemudRunLoop(server);
+
+  qemudCleanup(server);
+
+  return 0;
+}
diff --exclude docs --exclude CVS -ruN libvirt-pristine/src/driver.h libvirt-qemu/src/driver.h
--- libvirt-pristine/src/driver.h	2006-08-30 10:21:03.000000000 -0400
+++ libvirt-qemu/src/driver.h	2006-08-30 18:57:32.000000000 -0400
@@ -21,7 +21,8 @@
     VIR_DRV_XEN_STORE = 2,
     VIR_DRV_XEN_DAEMON = 3,
     VIR_DRV_TEST = 4,
-    VIR_DRV_XEN_PROXY = 5
+    VIR_DRV_XEN_PROXY = 5,
+    VIR_DRV_QEMU = 6
 } virDrvNo;
 
 
diff --exclude docs --exclude CVS -ruN libvirt-pristine/src/internal.h libvirt-qemu/src/internal.h
--- libvirt-pristine/src/internal.h	2006-06-28 14:19:13.000000000 -0400
+++ libvirt-qemu/src/internal.h	2006-08-27 17:05:39.000000000 -0400
@@ -79,7 +79,7 @@
 #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
+#define MAX_DRIVERS 10
 
 /*
  * Flags for Xen connections
diff --exclude docs --exclude CVS -ruN libvirt-pristine/src/libvirt.c libvirt-qemu/src/libvirt.c
--- libvirt-pristine/src/libvirt.c	2006-08-30 10:21:03.000000000 -0400
+++ libvirt-qemu/src/libvirt.c	2006-08-30 18:59:30.000000000 -0400
@@ -31,6 +31,7 @@
 #include "proxy_internal.h"
 #include "xml.h"
 #include "test.h"
+#include "qemu_internal.h"
 
 /*
  * TODO:
@@ -74,6 +75,7 @@
     xenDaemonRegister();
     xenStoreRegister();
     testRegister();
+    qemuRegister();
     return(0);
 }
 
@@ -432,6 +434,7 @@
 	        return(0);
 	}
     }
+
     return (-1);
 }
 
diff --exclude docs --exclude CVS -ruN libvirt-pristine/src/Makefile.am libvirt-qemu/src/Makefile.am
--- libvirt-pristine/src/Makefile.am	2006-08-29 18:27:07.000000000 -0400
+++ libvirt-qemu/src/Makefile.am	2006-08-30 22:17:04.000000000 -0400
@@ -1,6 +1,8 @@
 ## Process this file with automake to produce Makefile.in
 
 INCLUDES = -I$(top_builddir)/include -I at top_srcdir@/include @LIBXML_CFLAGS@ \
+           -I$(top_srcdir)/qemud \
+           -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L \
 	   -DBINDIR=\""$(libexecdir)"\"
 DEPS = libvirt.la
 LDADDS = @STATIC_BINARIES@ libvirt.la
@@ -25,6 +27,7 @@
 		sexpr.c sexpr.h					\
 		virterror.c					\
 		driver.h					\
+		qemu_internal.c qemu_internal.h                 \
 		proxy_internal.c proxy_internal.h		\
 		conf.c conf.h
 
diff --exclude docs --exclude CVS -ruN libvirt-pristine/src/qemu_internal.c libvirt-qemu/src/qemu_internal.c
--- libvirt-pristine/src/qemu_internal.c	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/src/qemu_internal.c	2006-08-30 23:03:21.000000000 -0400
@@ -0,0 +1,837 @@
+/*
+ * test.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Berrange <berrange at redhat.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <limits.h>
+#include <paths.h>
+
+#include "internal.h"
+#include "qemu_internal.h"
+#include "xml.h"
+#include "protocol.h"
+
+static virDriver qemuDriver = {
+  VIR_DRV_QEMU,
+  "QEMU",
+  LIBVIR_VERSION_NUMBER,
+  NULL, /* init */
+  qemuOpen, /* open */
+  qemuClose, /* close */
+  NULL, /* type */
+  qemuGetVersion, /* version */
+  qemuNodeGetInfo, /* nodeGetInfo */
+  qemuListDomains, /* listDomains */
+  qemuNumOfDomains, /* numOfDomains */
+  qemuDomainCreateLinux, /* domainCreateLinux */
+  qemuLookupDomainByID, /* domainLookupByID */
+  qemuLookupDomainByUUID, /* domainLookupByUUID */
+  qemuLookupDomainByName, /* domainLookupByName */
+  qemuPauseDomain, /* domainSuspend */
+  qemuResumeDomain, /* domainResume */
+  qemuShutdownDomain, /* domainShutdown */
+  NULL, /* domainReboot */
+  qemuDestroyDomain, /* domainDestroy */
+  NULL, /* domainFree */
+  NULL, /* domainGetName */
+  NULL, /* domainGetID */
+  NULL, /* domainGetUUID */
+  NULL, /* domainGetOSType */
+  NULL, /* domainGetMaxMemory */
+  NULL, /* domainSetMaxMemory */
+  NULL, /* domainSetMemory */
+  qemuGetDomainInfo, /* domainGetInfo */
+  qemuSaveDomain, /* domainSave */
+  qemuRestoreDomain, /* domainRestore */
+  NULL, /* domainSetVcpus */
+  NULL, /* domainPinVcpu */
+  NULL, /* domainGetVcpus */
+  qemuDomainDumpXML, /* domainDumpXML */
+  qemuListDefinedDomains, /* listDomains */
+  qemuNumOfDefinedDomains, /* numOfDomains */
+  qemuDomainCreate, /* domainCreate */
+  qemuDomainDefineXML, /* domainDefineXML */
+  qemuUndefine, /* domainUndefine */
+};
+
+
+static void
+qemuError(virConnectPtr con,
+	  virDomainPtr dom,
+	  virErrorNumber error,
+	  const char *info)
+{
+  const char *errmsg;
+
+  if (error == VIR_ERR_OK)
+    return;
+
+  errmsg = __virErrorMsg(error, info);
+  __virRaiseError(con, dom, VIR_FROM_XEN, error, VIR_ERR_ERROR,
+		  errmsg, info, NULL, 0, 0, errmsg, info, 0);
+}
+
+/* If the returned packet type does not match the outgoing packet
+   type then something went wrong. Usually this is a QEMU_PKT_FAILURE
+   which indicates the operation requested failed. This deserializes
+   the error message & dispatches it via libvirt error handling.
+   Occasionally return type type is totally bogus, which triggers
+   an internal error */
+static void qemuPacketError(virConnectPtr con,
+			    virDomainPtr dom,
+			    struct qemud_packet *pkt) {
+  if (!pkt) {
+    qemuError(con, dom, VIR_ERR_INTERNAL_ERROR, "Malformed data packet");
+    return;
+  }
+  if (pkt->header.type == QEMUD_PKT_FAILURE) {
+    int code;
+    /* Paranoia in case remote side didn't terminate it */
+    if (pkt->data.failureReply.message[0])
+      pkt->data.failureReply.message[QEMUD_MAX_ERROR_LEN-1] = '\0';
+
+    switch (pkt->data.failureReply.code) {
+      case QEMUD_ERR_GENERIC:
+	code = VIR_ERR_INTERNAL_ERROR;
+	break;
+
+      case QEMUD_ERR_NO_MEMORY:
+	code = VIR_ERR_NO_MEMORY;
+	break;
+
+      case QEMUD_ERR_NO_DOMAIN:
+	code = VIR_ERR_INVALID_ARG;
+	break;
+
+      case QEMUD_ERR_READONLY:
+	code = VIR_ERR_OPERATION_DENIED;
+	break;
+
+      case QEMUD_ERR_DOMAIN_INACTIVE:
+	code = VIR_ERR_INVALID_ARG;
+	break;
+
+      case QEMUD_ERR_DOMAIN_ACTIVE:
+	code = VIR_ERR_INVALID_ARG;
+	break;
+
+      case QEMUD_ERR_CONFIG_MALFORMED:
+	code = VIR_ERR_XML_ERROR;
+	break;
+
+      case QEMUD_ERR_DUPLICATE_DOMAIN:
+	code = VIR_ERR_DOM_EXIST;
+	break;
+
+      case QEMUD_ERR_PATH_OVERFLOW:
+	code = VIR_ERR_INTERNAL_ERROR;
+	break;
+
+      case QEMUD_ERR_MALFORMED_UUID:
+	code = VIR_ERR_XML_ERROR;
+	break;
+
+      case QEMUD_ERR_ILLEGAL_DISK_CONFIG:
+	code = VIR_ERR_XML_ERROR;
+	break;
+
+      case QEMUD_ERR_XML_NO_ROOT:
+	code = VIR_ERR_XML_ERROR;
+	break;
+
+      case QEMUD_ERR_XML_WRONG_TYPE:
+	code = VIR_ERR_XML_ERROR;
+	break;
+
+      case QEMUD_ERR_XML_MISSING_NAME:
+	code = VIR_ERR_NO_NAME;
+	break;
+
+      case QEMUD_ERR_XML_MISSING_UUID:
+	code = VIR_ERR_XML_ERROR;
+	break;
+
+      case QEMUD_ERR_NAME_OVERFLOW:
+	code = VIR_ERR_INTERNAL_ERROR;
+	break;
+
+    default:
+	code = VIR_ERR_INTERNAL_ERROR;
+	break;
+    }
+
+    qemuError(con, dom, code,
+	      pkt->data.failureReply.message[0] ?
+	      pkt->data.failureReply.message : NULL);
+  } else {
+    qemuError(con, dom, VIR_ERR_INTERNAL_ERROR, "Incorrect reply type");
+  }
+}
+
+void qemuRegister(void) {
+  virRegisterDriver(&qemuDriver);
+}
+
+/**
+ * qemuFindServerPath:
+ *
+ * Tries to find the path to the qemud binary.
+ * 
+ * Returns path on success or NULL in case of error.
+ */
+static const char *
+qemuFindServerPath(void)
+{
+    static const char *serverPaths[] = {
+        BINDIR "/qemud",
+        BINDIR "/qemud_dbg",
+        NULL
+    };
+    int i;
+    const char *debugQemuD = getenv("QEMU_DEBUG_SERVER");
+
+    if (debugQemuD)
+        return(debugQemuD);
+
+    for (i = 0; serverPaths[i]; i++) {
+        if (access(serverPaths[i], X_OK | R_OK) == 0) {
+            return serverPaths[i];
+        }
+    }
+    return NULL;
+}
+
+
+/**
+ * qemuForkServer:
+ *
+ * Forks and try to launch the qemu server
+ *
+ * Returns 0 in case of success or -1 in case of detected error.
+ */
+static int
+qemuForkServer(void)
+{
+    const char *proxyPath = qemuFindServerPath();
+    int ret, pid, status;
+
+    if (!proxyPath) {
+        fprintf(stderr, "failed to find qemud\n");
+	return(-1);
+    }
+
+    /* Become a daemon */
+    pid = fork();
+    if (pid == 0) {
+        int stdinfd = -1;
+	int stdoutfd = -1;
+	int i;
+	/* Dup stdin & oout onto /dev/null - we can't just close
+	   them since then a socket connection might end up with
+	   fd 0/1/2 and if something printf()'s then bad stuff
+	   happens */
+	if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0)
+	    goto cleanup;
+	if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0)
+	    goto cleanup;
+	if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+	    goto cleanup;
+	if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+	    goto cleanup;
+	if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+	    goto cleanup;
+	if (close(stdinfd) < 0)
+	    goto cleanup;
+	stdinfd = -1;
+	if (close(stdoutfd) < 0)
+	    goto cleanup;
+	stdoutfd = -1;
+
+	int open_max = sysconf (_SC_OPEN_MAX);
+	for (i = 0; i < open_max; i++)
+	  if (i != STDIN_FILENO &&
+	      i != STDOUT_FILENO &&
+	      i != STDERR_FILENO)
+	    close(i);
+
+        setsid();
+        if (fork() == 0) {
+            execl(proxyPath, proxyPath, NULL);
+            fprintf(stderr, "failed to exec %s\n", proxyPath);
+        }
+        /*
+         * calling exit() generate troubles for termination handlers
+         */
+        _exit(0);
+
+    cleanup:
+	if (stdoutfd != -1)
+	    close(stdoutfd);
+	if (stdinfd != -1)
+	    close(stdinfd);
+	_exit(-1);
+    }
+
+    /*
+     * do a waitpid on the intermediate process to avoid zombies.
+     */
+retry_wait:
+    ret = waitpid(pid, &status, 0);
+    if (ret < 0) {
+        if (errno == EINTR)
+            goto retry_wait;
+    }
+
+    return (0);
+}
+
+/**
+ * qemuOpenClientSocket:
+ * @path: the fileame for the socket
+ *
+ * try to connect to the socket open by qemud
+ *
+ * Returns the associated file descriptor or -1 in case of failure
+ */
+static int
+qemuOpenClientSocket(const char *path) {
+    int fd;
+    struct sockaddr_un addr;
+    int trials = 0;
+
+retry:
+    fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+	return(-1);
+    }
+
+    /*
+     * Abstract socket do not hit the filesystem, way more secure and
+     * garanteed to be atomic
+     */
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    addr.sun_path[0] = '\0';
+    strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2);
+
+    /*
+     * now bind the socket to that address and listen on it
+     */
+    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+	close(fd);
+	if (trials < 3) {
+	    if (qemuForkServer() < 0)
+	        return(-1);
+	    trials++;
+	    /* Give the server a little time to startup */
+	    usleep(5000 * trials * trials);
+	    goto retry;
+	}
+	return (-1);
+    }
+
+    return (fd);
+}
+
+static int qemuProcessRequest(virConnectPtr conn,
+			      virDomainPtr dom,
+			      struct qemud_packet *req,
+			      struct qemud_packet *reply) {
+  char *out = (char *)req;
+  int outDone = 0;
+  int outLeft = sizeof(struct qemud_packet_header) + req->header.dataSize;
+  char *in = (char *)reply;
+  int inGot = 0;
+  int inLeft = sizeof(struct qemud_packet_header);
+
+  /* printf("Send request %d\n", req->header.type);*/
+
+  /* Block sending entire outgoing packet */
+  while (outLeft) {
+    int got = write(conn->handle, out+outDone, outLeft);
+    if (got < 0) {
+      return -1;
+    }
+    outDone += got;
+    outLeft -= got;
+  }
+
+  /* Block waiting for header to come back */
+  while (inLeft) {
+    int done = read(conn->handle, in+inGot, inLeft);
+    if (done <= 0) {
+      return -1;
+    }
+    inGot += done;
+    inLeft -= done;
+  }
+
+  /* Validate header isn't bogus (bigger than
+     maximum defined packet size) */
+  if (reply->header.dataSize > sizeof(union qemud_packet_data)) {
+    /*
+      printf("Got type %ds body %d (max %ld)\n", reply->header.type, reply->header.dataSize, sizeof(union qemud_packet_data));
+      printf("%ld == %ld + %ld\n", sizeof(struct qemud_packet), sizeof(struct qemud_packet_header), sizeof(union qemud_packet_data));
+    */
+    qemuPacketError(conn, dom, NULL);
+    return -1;
+  }
+
+  /* Now block reading in body */
+  inLeft = reply->header.dataSize;
+  while (inLeft) {
+    int done = read(conn->handle, in+inGot, inLeft);
+    if (done <= 0) {
+      return -1;
+    }
+    inGot += done;
+    inLeft -= done;
+  }
+
+  /* Ensure return type matches outgoing type, otherwise report 
+     the error */
+  if (reply->header.type != req->header.type) {
+    qemuPacketError(conn, dom, reply);
+    return -1;
+  }
+
+  return 0;
+}
+
+static int qemuOpenConnection(const char *uri) {
+  struct passwd *pw;
+  int uid;
+  char path[PATH_MAX];
+
+  if (!strcmp(uri, "/system")) {
+    uid = 0;
+  } else if (!strcmp(uri, "/session")) {
+    if ((uid = geteuid()) < 0) {
+      return -1;
+    }
+  } else {
+    return -1;
+  }
+
+  if (!(pw = getpwuid(uid)))
+    return -1;
+
+  if (snprintf(path, PATH_MAX, "%s/.qemud", pw->pw_dir) == PATH_MAX) {
+    return -1;
+  }
+
+  return qemuOpenClientSocket(path);
+}
+
+int qemuOpen(virConnectPtr conn,
+             const char *name,
+             int flags){
+  xmlURIPtr uri;
+  int fd;
+
+  if (!name) {
+    return -1;
+  }
+
+  uri = xmlParseURI(name);
+  if (uri == NULL) {
+    if (!(flags & VIR_DRV_OPEN_QUIET))
+      qemuError(conn, NULL, VIR_ERR_NO_SUPPORT, name);
+    return(-1);
+  }
+
+  /* Only handle schemes starting qemu:/// */
+  if (!uri->scheme ||
+      strcmp(uri->scheme, "qemu") ||
+      !uri->path) {
+    xmlFreeURI(uri);
+    return -1;
+  }
+
+  fd = qemuOpenConnection(uri->path);
+  xmlFreeURI(uri);
+
+  if (fd < 0) {
+    return -1;
+  }
+
+  conn->handle = fd;
+
+  return 0;
+}
+
+int qemuClose  (virConnectPtr conn) {
+  if (conn->handle != -1) {
+    close(conn->handle);
+    conn->handle = -1;
+  }
+  return 0;
+}
+
+int qemuGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
+	           unsigned long *hvVer){
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_GET_VERSION;
+  req.header.dataSize = 0;
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  *hvVer = reply.data.getVersionReply.version;
+  return 0;
+}
+
+int qemuNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
+	            virNodeInfoPtr info){
+  /* XXX implement me - how do we do it portably ?  */
+  info->cores = 1;
+  info->threads = 1;
+  info->sockets = 1;
+  info->nodes = 1;
+  strcpy(info->model, "i686");
+  info->mhz = 6000;
+  info->cpus = 1;
+  info->memory = 1024*1024;
+  return 0;
+}
+
+int qemuNumOfDomains(virConnectPtr conn){
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_NUM_DOMAINS;
+  req.header.dataSize = 0;
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  return reply.data.numDomainsReply.numDomains;
+}
+
+int qemuListDomains(virConnectPtr conn,
+	            int *ids,
+	            int maxids){
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_LIST_DOMAINS;
+  req.header.dataSize = 0;
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  if (reply.data.listDomainsReply.numDomains > maxids)
+    return -1;
+
+  memmove(ids,
+	  reply.data.listDomainsReply.domains,
+	  sizeof(int)*reply.data.listDomainsReply.numDomains);
+
+  return reply.data.listDomainsReply.numDomains;
+}
+
+virDomainPtr
+qemuDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
+		      unsigned int flags ATTRIBUTE_UNUSED){
+  struct qemud_packet req, reply;
+  virDomainPtr dom;
+
+  if (strlen(xmlDesc) > (QEMUD_MAX_XML_LEN-1)) {
+    return NULL;
+  }
+
+  req.header.type = QEMUD_PKT_DOMAIN_CREATE;
+  req.header.dataSize = sizeof(req.data.domainCreateRequest);
+  strcpy(req.data.domainCreateRequest.xml, xmlDesc);
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return NULL;
+  }
+
+  /* Paranoia, just in case */
+  reply.data.domainCreateReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+  if (!(dom = virGetDomain(conn,
+			   reply.data.domainCreateReply.name,
+			   reply.data.domainCreateReply.uuid)))
+    return NULL;
+
+  dom->handle = reply.data.domainCreateReply.id;
+  return dom;
+}
+
+virDomainPtr qemuLookupDomainByID(virConnectPtr conn,
+			          int id){
+  struct qemud_packet req, reply;
+  virDomainPtr dom;
+
+  req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_ID;
+  req.header.dataSize = sizeof(req.data.domainLookupByIDRequest);
+  req.data.domainLookupByIDRequest.id = id;
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return NULL;
+  }
+
+  /* Paranoia, just in case */
+  reply.data.domainLookupByIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+  if (!(dom = virGetDomain(conn,
+			   reply.data.domainLookupByIDReply.name,
+			   reply.data.domainLookupByIDReply.uuid)))
+    return NULL;
+
+  dom->handle = id;
+  return dom;
+}
+
+virDomainPtr qemuLookupDomainByUUID(virConnectPtr conn,
+			            const unsigned char *uuid){
+  struct qemud_packet req, reply;
+  virDomainPtr dom;
+
+  req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID;
+  req.header.dataSize = sizeof(req.data.domainLookupByUUIDRequest);
+  memmove(req.data.domainLookupByUUIDRequest.uuid, uuid, QEMUD_UUID_RAW_LEN);
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return NULL;
+  }
+
+  /* Paranoia, just in case */
+  reply.data.domainLookupByUUIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+  if (!(dom = virGetDomain(conn,
+			   reply.data.domainLookupByUUIDReply.name,
+			   uuid)))
+    return NULL;
+
+  dom->handle = reply.data.domainLookupByUUIDReply.id;
+  return dom;
+}
+virDomainPtr qemuLookupDomainByName(virConnectPtr conn,
+			            const char *name){
+  struct qemud_packet req, reply;
+  virDomainPtr dom;
+
+  if (strlen(name) > (QEMUD_MAX_NAME_LEN-1))
+    return NULL;
+
+  req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME;
+  req.header.dataSize = sizeof(req.data.domainLookupByNameRequest);
+  strcpy(req.data.domainLookupByNameRequest.name, name);
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return NULL;
+  }
+
+  if (!(dom = virGetDomain(conn,
+			   name,
+			   reply.data.domainLookupByNameReply.uuid)))
+    return NULL;
+
+  dom->handle = reply.data.domainLookupByNameReply.id;
+  return dom;
+}
+int qemuShutdownDomain(virDomainPtr domain){
+  return qemuDestroyDomain(domain);
+}
+int qemuDestroyDomain(virDomainPtr domain){
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_DOMAIN_DESTROY;
+  req.header.dataSize = sizeof(req.data.domainDestroyRequest);
+  req.data.domainDestroyRequest.id = domain->handle;
+
+  if (qemuProcessRequest(domain->conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  return 0;
+}
+int qemuResumeDomain(virDomainPtr domain ATTRIBUTE_UNUSED){
+  return -1;
+}
+int qemuPauseDomain(virDomainPtr domain ATTRIBUTE_UNUSED){
+  return -1;
+}
+int qemuGetDomainInfo(virDomainPtr domain,
+	              virDomainInfoPtr info){
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_DOMAIN_GET_INFO;
+  req.header.dataSize = sizeof(req.data.domainGetInfoRequest);
+  memmove(req.data.domainGetInfoRequest.uuid, domain->uuid, QEMUD_UUID_RAW_LEN);
+
+  if (qemuProcessRequest(domain->conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  memset(info, 0, sizeof(virDomainInfo));
+  switch (reply.data.domainGetInfoReply.runstate) {
+  case QEMUD_STATE_RUNNING:
+    info->state = VIR_DOMAIN_RUNNING;
+    break;
+
+  case QEMUD_STATE_PAUSED:
+    info->state = VIR_DOMAIN_PAUSED;
+    break;
+
+  case QEMUD_STATE_STOPPED:
+    info->state = VIR_DOMAIN_SHUTOFF;
+    break;
+
+  default:
+    return -1;
+  }
+  info->maxMem = reply.data.domainGetInfoReply.memory;
+  info->memory = reply.data.domainGetInfoReply.memory;
+  info->nrVirtCpu = reply.data.domainGetInfoReply.nrVirtCpu;
+  info->cpuTime = reply.data.domainGetInfoReply.cpuTime;
+
+  return 0;
+}
+char * qemuDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED){
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_DUMP_XML;
+  req.header.dataSize = sizeof(req.data.domainDumpXMLRequest);
+  memmove(req.data.domainDumpXMLRequest.uuid, domain->uuid, QEMUD_UUID_RAW_LEN);
+
+  if (qemuProcessRequest(domain->conn, NULL, &req, &reply) < 0) {
+    return NULL;
+  }
+
+  /* Paranoia, just in case */
+  reply.data.domainDumpXMLReply.xml[QEMUD_MAX_XML_LEN-1] = '\0';
+
+  return strdup(reply.data.domainDumpXMLReply.xml);
+}
+
+int qemuSaveDomain(virDomainPtr domain ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED){
+  return -1;
+}
+int qemuRestoreDomain(virConnectPtr conn ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED){
+  return -1;
+}
+int qemuNumOfDefinedDomains(virConnectPtr conn){
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_NUM_DEFINED_DOMAINS;
+  req.header.dataSize = 0;
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  return reply.data.numDefinedDomainsReply.numDomains;
+}
+
+int qemuListDefinedDomains(virConnectPtr conn,
+			   const char **names,
+			   int maxnames){
+  struct qemud_packet req, reply;
+  int i;
+
+  req.header.type = QEMUD_PKT_LIST_DEFINED_DOMAINS;
+  req.header.dataSize = 0;
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  if (reply.data.listDefinedDomainsReply.numDomains > maxnames)
+    return -1;
+
+  for (i = 0 ; i < reply.data.listDefinedDomainsReply.numDomains ; i++) {
+    reply.data.listDefinedDomainsReply.domains[i][QEMUD_MAX_NAME_LEN-1] = '\0';
+    names[i] = strdup(reply.data.listDefinedDomainsReply.domains[i]);
+  }
+
+  return reply.data.listDefinedDomainsReply.numDomains;
+}
+int qemuDomainCreate(virDomainPtr dom) {
+  struct qemud_packet req, reply;
+
+  req.header.type = QEMUD_PKT_DOMAIN_START;
+  req.header.dataSize = sizeof(req.data.domainStartRequest);
+  memcpy(req.data.domainStartRequest.uuid, dom->uuid, QEMUD_UUID_RAW_LEN);
+
+  if (qemuProcessRequest(dom->conn, NULL, &req, &reply) < 0) {
+    return -1;
+  }
+
+  dom->handle = reply.data.domainStartReply.id;
+
+  return 0;
+}
+
+virDomainPtr qemuDomainDefineXML(virConnectPtr conn, const char *xml) {
+  struct qemud_packet req, reply;
+  virDomainPtr dom;
+
+  if (strlen(xml) > (QEMUD_MAX_XML_LEN-1)) {
+    return NULL;
+  }
+
+  req.header.type = QEMUD_PKT_DOMAIN_DEFINE;
+  req.header.dataSize = sizeof(req.data.domainDefineRequest);
+  strcpy(req.data.domainDefineRequest.xml, xml);
+
+  if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+    return NULL;
+  }
+
+  /* Paranoia, just in case */
+  reply.data.domainDefineReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+  if (!(dom = virGetDomain(conn,
+			   reply.data.domainDefineReply.name,
+			   reply.data.domainDefineReply.uuid)))
+    return NULL;
+
+  dom->handle = -1;
+  return dom;
+}
+
+int qemuUndefine(virDomainPtr dom) {
+  struct qemud_packet req, reply;
+  int ret = 0;
+
+  req.header.type = QEMUD_PKT_DOMAIN_UNDEFINE;
+  req.header.dataSize = sizeof(req.data.domainUndefineRequest);
+  memcpy(req.data.domainUndefineRequest.uuid, dom->uuid, QEMUD_UUID_RAW_LEN);
+
+  if (qemuProcessRequest(dom->conn, NULL, &req, &reply) < 0) {
+    ret = -1;
+    goto cleanup;
+  }
+
+ cleanup:
+  if (virFreeDomain(dom->conn, dom) < 0)
+    ret = -1;
+
+  return ret;
+}
diff --exclude docs --exclude CVS -ruN libvirt-pristine/src/qemu_internal.h libvirt-qemu/src/qemu_internal.h
--- libvirt-pristine/src/qemu_internal.h	1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/src/qemu_internal.h	2006-08-27 17:05:39.000000000 -0400
@@ -0,0 +1,62 @@
+/*
+ * qemu_internal.h: A backend for managing QEMU machines
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_QEMU_INTERNAL_H__
+#define __VIR_QEMU_INTERNAL_H__
+
+#include <libvirt/virterror.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  
+  void qemuRegister(void);
+  int qemuOpen(virConnectPtr conn,
+	       const char *name,
+	       int flags);
+  int qemuClose  (virConnectPtr conn);
+  int qemuGetVersion(virConnectPtr conn,
+		     unsigned long *hvVer);
+  int qemuNodeGetInfo(virConnectPtr conn,
+		      virNodeInfoPtr info);
+  int qemuNumOfDomains(virConnectPtr conn);
+  int qemuListDomains(virConnectPtr conn,
+		      int *ids,
+		      int maxids);
+  int qemuNumOfDefinedDomains(virConnectPtr conn);
+  int qemuListDefinedDomains(virConnectPtr conn,
+			     const char **names,
+			     int maxnames);
+  virDomainPtr
+  qemuDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
+			unsigned int flags);
+  virDomainPtr qemuLookupDomainByID(virConnectPtr conn,
+				    int id);
+  virDomainPtr qemuLookupDomainByUUID(virConnectPtr conn,
+				      const unsigned char *uuid);
+  virDomainPtr qemuLookupDomainByName(virConnectPtr conn,
+				      const char *name);
+  int qemuShutdownDomain(virDomainPtr domain);
+  int qemuDestroyDomain(virDomainPtr domain);
+  int qemuResumeDomain(virDomainPtr domain);
+  int qemuPauseDomain(virDomainPtr domain);
+  int qemuGetDomainInfo(virDomainPtr domain,
+			virDomainInfoPtr info);
+  char * qemuDomainDumpXML(virDomainPtr domain, int flags);
+  int qemuSaveDomain(virDomainPtr domain, const char *file);
+  int qemuRestoreDomain(virConnectPtr conn, const char *file);
+  int qemuDomainCreate(virDomainPtr conn);
+  virDomainPtr qemuDomainDefineXML(virConnectPtr conn, const char *xml);
+  int qemuUndefine(virDomainPtr dom);
+
+#ifdef __cplusplus
+}
+#endif
+#endif                          /* __VIR_QEMU_INTERNAL_H__ */
diff --exclude docs --exclude CVS -ruN libvirt-pristine/src/virsh.c libvirt-qemu/src/virsh.c
--- libvirt-pristine/src/virsh.c	2006-08-30 10:32:32.000000000 -0400
+++ libvirt-qemu/src/virsh.c	2006-08-30 19:00:13.000000000 -0400
@@ -2284,7 +2284,8 @@
     /* basic connection to hypervisor, for Xen connections unless
        we're root open a read only connections. Allow 'test' HV
        to be RW all the time though */
-    if (ctl->uid == 0 || (ctl->name && !strncmp(ctl->name, "test", 4)))
+    if (ctl->uid == 0 || (ctl->name && (!strncmp(ctl->name, "test", 4) ||
+					!strncmp(ctl->name, "qemu", 4))))
         ctl->conn = virConnectOpen(ctl->name);
     else
         ctl->conn = virConnectOpenReadOnly(ctl->name);


More information about the libvir-list mailing list