diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/configure.in libvirt-caps/configure.in
--- libvirt-cvs/configure.in	2007-03-15 12:54:32.000000000 +0000
+++ libvirt-caps/configure.in	2007-03-15 12:54:32.000000000 +0000
@@ -43,6 +43,8 @@
 AC_PATH_PROG(XMLLINT, xmllint, /usr/bin/xmllint)
 AC_PATH_PROG(XSLTPROC, xsltproc, /usr/bin/xsltproc)
 
+dnl Availability of various common functions.
+AC_CHECK_FUNCS([regexec])
 
 dnl Make sure we have an ANSI compiler
 AM_C_PROTOTYPES
@@ -50,6 +52,8 @@
 
 AM_PROG_LIBTOOL
 
+AM_PROG_CC_C_O
+
 LIBVIRT_COMPILE_WARNINGS(maximum)
 
 dnl Specific dir for HTML output ?
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/.cvsignore libvirt-caps/.cvsignore
--- libvirt-cvs/.cvsignore	2007-02-16 17:06:38.000000000 +0000
+++ libvirt-caps/.cvsignore	2007-03-13 13:20:50.000000000 +0000
@@ -1,3 +1,4 @@
+.git
 Makefile
 aclocal.m4
 autom4te.cache
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/include/libvirt/libvirt.h.in libvirt-caps/include/libvirt/libvirt.h.in
--- libvirt-cvs/include/libvirt/libvirt.h.in	2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps/include/libvirt/libvirt.h.in	2007-03-13 13:20:47.000000000 +0000
@@ -231,10 +231,15 @@
 const char *		virConnectGetType	(virConnectPtr conn);
 int			virConnectGetVersion	(virConnectPtr conn,
 						 unsigned long *hvVer);
-int			virConnectGetMaxVcpus	(virConnectPtr conn,
+/*
+ * Capabilities of the connection / driver.
+ */
+
+int                     virConnectGetMaxVcpus   (virConnectPtr conn,
 						 const char *type);
 int			virNodeGetInfo		(virConnectPtr conn,
 						 virNodeInfoPtr info);
+char *                  virConnectGetCapabilities (virConnectPtr conn);
 
 /*
  * Gather list of running domains
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/include/libvirt/virterror.h libvirt-caps/include/libvirt/virterror.h
--- libvirt-cvs/include/libvirt/virterror.h	2007-02-14 15:40:54.000000000 +0000
+++ libvirt-caps/include/libvirt/virterror.h	2007-03-13 13:20:48.000000000 +0000
@@ -119,6 +119,7 @@
     VIR_ERR_XML_DETAIL, /* detail of an XML error */
     VIR_ERR_INVALID_NETWORK, /* invalid network object */
     VIR_ERR_NETWORK_EXIST, /* the network already exist */
+    VIR_ERR_SYSTEM_ERROR, /* general system call failure */
 } virErrorNumber;
 
 /**
@@ -133,7 +134,7 @@
 /*
  * Errors can be handled as asynchronous callbacks or after the routine
  * failed. They can also be handled globally at the library level, or
- * at the connection level (which then has priority
+ * at the connection level (which then has priority).
  */
 
 virErrorPtr		virGetLastError		(void);
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/proxy/libvirt_proxy.c libvirt-caps/proxy/libvirt_proxy.c
--- libvirt-cvs/proxy/libvirt_proxy.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/proxy/libvirt_proxy.c	2007-03-15 12:55:58.000000000 +0000
@@ -788,9 +788,24 @@
     proxyCloseUnixSocket();
     exit(0);
 }
+
 #else /* WITHOUT_XEN */
 int main(void) {
     fprintf(stderr, "libvirt was compiled without Xen support\n");
     exit(1);
 }
 #endif /* WITH_XEN */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/buf.c libvirt-caps/qemud/buf.c
--- libvirt-cvs/qemud/buf.c	1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps/qemud/buf.c	2007-03-13 13:18:22.000000000 +0000
@@ -0,0 +1,221 @@
+/*
+ * buf.c: buffers for qemud
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include "libvirt/libvirt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "buf.h"
+
+/**
+ * bufferGrow:
+ * @buf:  the buffer
+ * @len:  the minimum free size to allocate
+ *
+ * Grow the available space of an XML buffer.
+ *
+ * Returns the new available space or -1 in case of error
+ */
+static int
+bufferGrow(bufferPtr buf, unsigned int len)
+{
+    int size;
+    char *newbuf;
+
+    if (buf == NULL)
+        return (-1);
+    if (len + buf->use < buf->size)
+        return (0);
+
+    size = buf->use + len + 1000;
+
+    newbuf = (char *) realloc(buf->content, size);
+    if (newbuf == NULL) return -1;
+    buf->content = newbuf;
+    buf->size = size;
+    return (buf->size - buf->use);
+}
+
+/**
+ * bufferAdd:
+ * @buf:  the buffer to dump
+ * @str:  the string
+ * @len:  the number of bytes to add
+ *
+ * Add a string range to an XML buffer. if len == -1, the length of
+ * str is recomputed to the full string.
+ *
+ * Returns 0 successful, -1 in case of internal or API error.
+ */
+int
+bufferAdd(bufferPtr buf, const char *str, int len)
+{
+    unsigned int needSize;
+
+    if ((str == NULL) || (buf == NULL)) {
+        return -1;
+    }
+    if (len == 0)
+        return 0;
+
+    if (len < 0)
+        len = strlen(str);
+
+    needSize = buf->use + len + 2;
+    if (needSize > buf->size) {
+        if (!bufferGrow(buf, needSize)) {
+            return (-1);
+        }
+    }
+    /* XXX: memmove() is 2x slower than memcpy(), do we really need it? */
+    memmove(&buf->content[buf->use], str, len);
+    buf->use += len;
+    buf->content[buf->use] = 0;
+    return (0);
+}
+
+bufferPtr
+bufferNew(unsigned int size)
+{
+    bufferPtr buf;
+
+    if (!(buf = malloc(sizeof(*buf)))) return NULL;
+    if (size && (buf->content = malloc(size))==NULL) {
+        free(buf);
+        return NULL;
+    }
+    buf->size = size;
+    buf->use = 0;
+
+    return buf;
+}
+
+void
+bufferFree(bufferPtr buf)
+{
+    if (buf) {
+        if (buf->content)
+            free(buf->content);
+        free(buf);
+    }
+}
+
+/**
+ * bufferContentAndFree:
+ * @buf: Buffer
+ *
+ * Return the content from the buffer and free (only) the buffer structure.
+ */
+char *
+bufferContentAndFree (bufferPtr buf)
+{
+    char *content;
+
+    content = buf->content;
+
+    /* Try to reduce the size of the block, but if it fails, it doesn't
+     * matter.
+     */
+    if (buf->use < buf->size) {
+        char *old_content = content;
+        content = realloc (content, buf->use);
+        content = content ? content : old_content;
+    }
+
+    free (buf);
+    return content;
+}
+
+/**
+ * bufferVSprintf:
+ * @buf:  the buffer to dump
+ * @format:  the format
+ * @argptr:  the variable list of arguments
+ *
+ * Do a formatted print to an XML buffer.
+ *
+ * Returns 0 successful, -1 in case of internal or API error.
+ */
+int
+bufferVSprintf(bufferPtr buf, const char *format, ...)
+{
+    int size, count;
+    va_list locarg, argptr;
+
+    if ((format == NULL) || (buf == NULL)) {
+        return (-1);
+    }
+    size = buf->size - buf->use - 1;
+    va_start(argptr, format);
+    va_copy(locarg, argptr);
+    while (((count = vsnprintf(&buf->content[buf->use], size, format,
+                               locarg)) < 0) || (count >= size - 1)) {
+        buf->content[buf->use] = 0;
+        va_end(locarg);
+        if (bufferGrow(buf, 1000) < 0) {
+            return (-1);
+        }
+        size = buf->size - buf->use - 1;
+        va_copy(locarg, argptr);
+    }
+    va_end(locarg);
+    buf->use += count;
+    buf->content[buf->use] = 0;
+    return (0);
+}
+
+/**
+ * bufferStrcat:
+ * @buf:  the buffer to dump
+ * @argptr:  the variable list of strings, the last argument must be NULL
+ *
+ * Concatenate strings to an XML buffer.
+ *
+ * Returns 0 successful, -1 in case of internal or API error.
+ */
+int
+bufferStrcat(bufferPtr buf, ...)
+{
+    va_list ap;
+    char *str;
+
+    va_start(ap, buf);
+
+    while ((str = va_arg(ap, char *)) != NULL) {
+        unsigned int len = strlen(str);
+        unsigned int needSize = buf->use + len + 2;
+
+        if (needSize > buf->size) {
+            if (!bufferGrow(buf, needSize))
+                return -1;
+        }
+        memcpy(&buf->content[buf->use], str, len);
+        buf->use += len;
+        buf->content[buf->use] = 0;
+    }
+    va_end(ap);
+    return 0;
+}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/buf.h libvirt-caps/qemud/buf.h
--- libvirt-cvs/qemud/buf.h	1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps/qemud/buf.h	2007-03-13 13:18:24.000000000 +0000
@@ -0,0 +1,37 @@
+/*
+ * buf.h: buffers for qemud
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#ifndef __QEMUD_BUF_H__
+#define __QEMUD_BUF_H__
+
+#include "internal.h"
+
+/**
+ * buffer:
+ *
+ * A buffer structure.
+ */
+typedef struct _buffer buffer;
+typedef buffer *bufferPtr;
+struct _buffer {
+    char *content;          /* The buffer content UTF8 */
+    unsigned int use;       /* The buffer size used */
+    unsigned int size;      /* The buffer size */
+};
+
+bufferPtr bufferNew(unsigned int size);
+void bufferFree(bufferPtr buf);
+char *bufferContentAndFree(bufferPtr buf);
+int bufferAdd(bufferPtr buf, const char *str, int len);
+int bufferVSprintf(bufferPtr buf, const char *format, ...)
+  ATTRIBUTE_FORMAT(printf, 2, 3);
+int bufferStrcat(bufferPtr buf, ...);
+
+#endif                          /* __QEMUD_BUF_H__ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/conf.c libvirt-caps/qemud/conf.c
--- libvirt-cvs/qemud/conf.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/qemud/conf.c	2007-03-15 13:16:47.000000000 +0000
@@ -46,6 +46,7 @@
 #include "driver.h"
 #include "iptables.h"
 #include "uuid.h"
+#include "buf.h"
 
 /* Free all memory associated with a struct qemud_vm object */
 void qemudFreeVMDef(struct qemud_vm_def *def) {
@@ -122,49 +123,44 @@
     return 0;
 }
 
-struct qemu_arch_info {
-    const char *arch;
-    const char **machines;
-    const char *binary;
-};
-
 /* The list of possible machine types for various architectures,
    as supported by QEMU - taken from 'qemu -M ?' for each arch */
 static const char *arch_info_x86_machines[] = {
-    "pc", "isapc"
+    "pc", "isapc", NULL
 };
 static const char *arch_info_mips_machines[] = {
-    "mips"
+    "mips", NULL
 };
 static const char *arch_info_sparc_machines[] = {
-    "sun4m"
+    "sun4m", NULL
 };
 static const char *arch_info_ppc_machines[] = {
-    "g3bw", "mac99", "prep"
+    "g3bw", "mac99", "prep", NULL
 };
 
 /* The archicture tables for supported QEMU archs */
-static struct qemu_arch_info archs[] = { 
+struct qemu_arch_info qemudArchs[] = { 
     {  "i686", arch_info_x86_machines, "qemu" },
     {  "x86_64", arch_info_x86_machines, "qemu-system-x86_64" },
     {  "mips", arch_info_mips_machines, "qemu-system-mips" },
     {  "mipsel", arch_info_mips_machines, "qemu-system-mipsel" },
     {  "sparc", arch_info_sparc_machines, "qemu-system-sparc" },
     {  "ppc", arch_info_ppc_machines, "qemu-system-ppc" },
+    { NULL, NULL, NULL }
 };
 
 /* Return the default architecture if none is explicitly requested*/
 static const char *qemudDefaultArch(void) {
-    return archs[0].arch;
+    return qemudArchs[0].arch;
 }
 
 /* Return the default machine type for a given architecture */
 static const char *qemudDefaultMachineForArch(const char *arch) {
     int i;
 
-    for (i = 0 ; i < (int)(sizeof(archs) / sizeof(struct qemu_arch_info)) ; i++) {
-        if (!strcmp(archs[i].arch, arch)) {
-            return archs[i].machines[0];
+    for (i = 0; qemudArchs[i].arch; i++) {
+        if (!strcmp(qemudArchs[i].arch, arch)) {
+            return qemudArchs[i].machines[0];
         }
     }
 
@@ -175,9 +171,9 @@
 static const char *qemudDefaultBinaryForArch(const char *arch) {
     int i;
 
-    for (i = 0 ; i < (int)(sizeof(archs) / sizeof(struct qemu_arch_info)) ; i++) {
-        if (!strcmp(archs[i].arch, arch)) {
-            return archs[i].binary;
+    for (i = 0 ; qemudArchs[i].arch; i++) {
+        if (!strcmp(qemudArchs[i].arch, arch)) {
+            return qemudArchs[i].binary;
         }
     }
 
@@ -2354,72 +2350,20 @@
     return 0;
 }
 
-/* Simple grow-on-demand string buffer */
-/* XXX re-factor to shared library */
-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) {
-        return -1;
-    }
-    va_end(locarg);
-    buf->used += count;
-
-    buf->data[buf->used] = '\0';
-    return 0;
-}
-
 /* Generate an XML document describing the guest's configuration */
 char *qemudGenerateXML(struct qemud_server *server,
                        struct qemud_vm *vm,
                        struct qemud_vm_def *def,
                        int live) {
-    struct qemudBuffer buf;
+    bufferPtr buf = 0;
     unsigned char *uuid;
     struct qemud_vm_disk_def *disk;
     struct qemud_vm_net_def *net;
     const char *type = NULL;
     int n;
 
-    buf.len = QEMUD_MAX_XML_LEN;
-    buf.used = 0;
-    buf.data = malloc(buf.len);
-
-    if (!buf.data)
+    buf = bufferNew (QEMUD_MAX_XML_LEN);
+    if (!buf)
         goto no_memory;
 
     switch (def->virtType) {
@@ -2439,50 +2383,50 @@
     }
 
     if (qemudIsActiveVM(vm) && live) {
-        if (qemudBufferPrintf(&buf, "<domain type='%s' id='%d'>\n", type, vm->id) < 0)
+        if (bufferVSprintf(buf, "<domain type='%s' id='%d'>\n", type, vm->id) < 0)
             goto no_memory;
     } else {
-        if (qemudBufferPrintf(&buf, "<domain type='%s'>\n", type) < 0)
+        if (bufferVSprintf(buf, "<domain type='%s'>\n", type) < 0)
             goto no_memory;
     }
 
-    if (qemudBufferPrintf(&buf, "  <name>%s</name>\n", def->name) < 0)
+    if (bufferVSprintf(buf, "  <name>%s</name>\n", def->name) < 0)
         goto no_memory;
 
     uuid = def->uuid;
-    if (qemudBufferPrintf(&buf, "  <uuid>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</uuid>\n",
+    if (bufferVSprintf(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 no_memory;
-    if (qemudBufferPrintf(&buf, "  <memory>%d</memory>\n", def->maxmem) < 0)
+    if (bufferVSprintf(buf, "  <memory>%d</memory>\n", def->maxmem) < 0)
         goto no_memory;
-    if (qemudBufferPrintf(&buf, "  <currentMemory>%d</currentMemory>\n", def->memory) < 0)
+    if (bufferVSprintf(buf, "  <currentMemory>%d</currentMemory>\n", def->memory) < 0)
         goto no_memory;
-    if (qemudBufferPrintf(&buf, "  <vcpu>%d</vcpu>\n", def->vcpus) < 0)
+    if (bufferVSprintf(buf, "  <vcpu>%d</vcpu>\n", def->vcpus) < 0)
         goto no_memory;
 
-    if (qemudBufferAdd(&buf, "  <os>\n") < 0)
+    if (bufferAdd(buf, "  <os>\n", -1) < 0)
         goto no_memory;
 
     if (def->virtType == QEMUD_VIRT_QEMU) {
-        if (qemudBufferPrintf(&buf, "    <type arch='%s' machine='%s'>%s</type>\n",
+        if (bufferVSprintf(buf, "    <type arch='%s' machine='%s'>%s</type>\n",
                               def->os.arch, def->os.machine, def->os.type) < 0)
             goto no_memory;
     } else {
-        if (qemudBufferPrintf(&buf, "    <type>%s</type>\n", def->os.type) < 0)
+        if (bufferVSprintf(buf, "    <type>%s</type>\n", def->os.type) < 0)
             goto no_memory;
     }
 
     if (def->os.kernel[0])
-        if (qemudBufferPrintf(&buf, "    <kernel>%s</kernel>\n", def->os.kernel) < 0)
+        if (bufferVSprintf(buf, "    <kernel>%s</kernel>\n", def->os.kernel) < 0)
             goto no_memory;
     if (def->os.initrd[0])
-        if (qemudBufferPrintf(&buf, "    <initrd>%s</initrd>\n", def->os.initrd) < 0)
+        if (bufferVSprintf(buf, "    <initrd>%s</initrd>\n", def->os.initrd) < 0)
             goto no_memory;
     if (def->os.cmdline[0])
-        if (qemudBufferPrintf(&buf, "    <cmdline>%s</cmdline>\n", def->os.cmdline) < 0)
+        if (bufferVSprintf(buf, "    <cmdline>%s</cmdline>\n", def->os.cmdline) < 0)
             goto no_memory;
 
     for (n = 0 ; n < def->os.nBootDevs ; n++) {
@@ -2501,27 +2445,27 @@
             boottype = "net";
             break;
         }
-        if (qemudBufferPrintf(&buf, "    <boot dev='%s'/>\n", boottype) < 0)
+        if (bufferVSprintf(buf, "    <boot dev='%s'/>\n", boottype) < 0)
             goto no_memory;
     }
 
-    if (qemudBufferAdd(&buf, "  </os>\n") < 0)
+    if (bufferAdd(buf, "  </os>\n", -1) < 0)
         goto no_memory;
 
     if (def->features & QEMUD_FEATURE_ACPI) {
-        if (qemudBufferAdd(&buf, "  <features>\n") < 0)
+        if (bufferAdd(buf, "  <features>\n", -1) < 0)
             goto no_memory;
-        if (qemudBufferAdd(&buf, "    <acpi/>\n") < 0)
+        if (bufferAdd(buf, "    <acpi/>\n", -1) < 0)
             goto no_memory;
-        if (qemudBufferAdd(&buf, "  </features>\n") < 0)
+        if (bufferAdd(buf, "  </features>\n", -1) < 0)
             goto no_memory;
     }
 
 
-    if (qemudBufferAdd(&buf, "  <devices>\n") < 0)
+    if (bufferAdd(buf, "  <devices>\n", -1) < 0)
         goto no_memory;
 
-    if (qemudBufferPrintf(&buf, "    <emulator>%s</emulator>\n", def->os.binary) < 0)
+    if (bufferVSprintf(buf, "    <emulator>%s</emulator>\n", def->os.binary) < 0)
         goto no_memory;
 
     disk = def->disks;
@@ -2539,21 +2483,21 @@
             "cdrom",
             "floppy",
         };
-        if (qemudBufferPrintf(&buf, "    <disk type='%s' device='%s'>\n",
+        if (bufferVSprintf(buf, "    <disk type='%s' device='%s'>\n",
                               types[disk->type], devices[disk->device]) < 0)
             goto no_memory;
 
-        if (qemudBufferPrintf(&buf, "      <source %s='%s'/>\n", typeAttrs[disk->type], disk->src) < 0)
+        if (bufferVSprintf(buf, "      <source %s='%s'/>\n", typeAttrs[disk->type], disk->src) < 0)
             goto no_memory;
 
-        if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", disk->dst) < 0)
+        if (bufferVSprintf(buf, "      <target dev='%s'/>\n", disk->dst) < 0)
             goto no_memory;
 
         if (disk->readonly)
-            if (qemudBufferAdd(&buf, "      <readonly/>\n") < 0)
+            if (bufferAdd(buf, "      <readonly/>\n", -1) < 0)
                 goto no_memory;
 
-        if (qemudBufferPrintf(&buf, "    </disk>\n") < 0)
+        if (bufferVSprintf(buf, "    </disk>\n") < 0)
             goto no_memory;
 
         disk = disk->next;
@@ -2570,42 +2514,42 @@
             "network",
             "bridge",
         };
-        if (qemudBufferPrintf(&buf, "    <interface type='%s'>\n",
+        if (bufferVSprintf(buf, "    <interface type='%s'>\n",
                               types[net->type]) < 0)
             goto no_memory;
 
-        if (qemudBufferPrintf(&buf, "      <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
+        if (bufferVSprintf(buf, "      <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
                               net->mac[0], net->mac[1], net->mac[2],
                               net->mac[3], net->mac[4], net->mac[5]) < 0)
             goto no_memory;
 
         switch (net->type) {
         case QEMUD_NET_NETWORK:
-            if (qemudBufferPrintf(&buf, "      <source network='%s'/>\n", net->dst.network.name) < 0)
+            if (bufferVSprintf(buf, "      <source network='%s'/>\n", net->dst.network.name) < 0)
                 goto no_memory;
 
             if (net->dst.network.ifname[0] != '\0') {
-                if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", net->dst.network.ifname) < 0)
+                if (bufferVSprintf(buf, "      <target dev='%s'/>\n", net->dst.network.ifname) < 0)
                     goto no_memory;
             }
             break;
 
         case QEMUD_NET_ETHERNET:
             if (net->dst.ethernet.ifname[0] != '\0') {
-                if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", net->dst.ethernet.ifname) < 0)
+                if (bufferVSprintf(buf, "      <target dev='%s'/>\n", net->dst.ethernet.ifname) < 0)
                     goto no_memory;
             }
             if (net->dst.ethernet.script[0] != '\0') {
-                if (qemudBufferPrintf(&buf, "      <script path='%s'/>\n", net->dst.ethernet.script) < 0)
+                if (bufferVSprintf(buf, "      <script path='%s'/>\n", net->dst.ethernet.script) < 0)
                     goto no_memory;
             }
             break;
 
         case QEMUD_NET_BRIDGE:
-            if (qemudBufferPrintf(&buf, "      <source dev='%s'/>\n", net->dst.bridge.brname) < 0)
+            if (bufferVSprintf(buf, "      <source dev='%s'/>\n", net->dst.bridge.brname) < 0)
                 goto no_memory;
             if (net->dst.bridge.ifname[0] != '\0') {
-                if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", net->dst.bridge.ifname) < 0)
+                if (bufferVSprintf(buf, "      <target dev='%s'/>\n", net->dst.bridge.ifname) < 0)
                     goto no_memory;
             }
             break;
@@ -2614,17 +2558,17 @@
         case QEMUD_NET_CLIENT:
         case QEMUD_NET_MCAST:
             if (net->dst.socket.address[0] != '\0') {
-                if (qemudBufferPrintf(&buf, "      <source address='%s' port='%d'/>\n",
+                if (bufferVSprintf(buf, "      <source address='%s' port='%d'/>\n",
                                       net->dst.socket.address, net->dst.socket.port) < 0)
                     goto no_memory;
             } else {
-                if (qemudBufferPrintf(&buf, "      <source port='%d'/>\n",
+                if (bufferVSprintf(buf, "      <source port='%d'/>\n",
                                       net->dst.socket.port) < 0)
                     goto no_memory;
             }
         }
 
-        if (qemudBufferPrintf(&buf, "    </interface>\n") < 0)
+        if (bufferVSprintf(buf, "    </interface>\n") < 0)
             goto no_memory;
 
         net = net->next;
@@ -2632,20 +2576,20 @@
 
     switch (def->graphicsType) {
     case QEMUD_GRAPHICS_VNC:
-        if (qemudBufferAdd(&buf, "    <graphics type='vnc'") < 0)
+        if (bufferAdd(buf, "    <graphics type='vnc'", -1) < 0)
             goto no_memory;
 
         if (def->vncPort &&
-            qemudBufferPrintf(&buf, " port='%d'",
+            bufferVSprintf(buf, " port='%d'",
                               qemudIsActiveVM(vm) && live ? def->vncActivePort : def->vncPort) < 0)
             goto no_memory;
 
-        if (qemudBufferAdd(&buf, "/>\n") < 0)
+        if (bufferAdd(buf, "/>\n", -1) < 0)
             goto no_memory;
         break;
 
     case QEMUD_GRAPHICS_SDL:
-        if (qemudBufferAdd(&buf, "    <graphics type='sdl'/>\n") < 0)
+        if (bufferAdd(buf, "    <graphics type='sdl'/>\n", -1) < 0)
             goto no_memory;
         break;
 
@@ -2657,20 +2601,19 @@
     if (def->graphicsType == QEMUD_GRAPHICS_VNC) {
     }
 
-    if (qemudBufferAdd(&buf, "  </devices>\n") < 0)
+    if (bufferAdd(buf, "  </devices>\n", -1) < 0)
         goto no_memory;
 
 
-    if (qemudBufferAdd(&buf, "</domain>\n") < 0)
+    if (bufferAdd(buf, "</domain>\n", -1) < 0)
         goto no_memory;
 
-    return buf.data;
+    return bufferContentAndFree (buf);
 
  no_memory:
     qemudReportError(server, VIR_ERR_NO_MEMORY, "xml");
  cleanup:
-    if (buf.data)
-        free(buf.data);
+    if (buf) bufferFree (buf);
     return NULL;
 }
 
@@ -2678,24 +2621,21 @@
 char *qemudGenerateNetworkXML(struct qemud_server *server,
                               struct qemud_network *network ATTRIBUTE_UNUSED,
                               struct qemud_network_def *def) {
-    struct qemudBuffer buf;
+    bufferPtr buf = 0;
     unsigned char *uuid;
 
-    buf.len = QEMUD_MAX_XML_LEN;
-    buf.used = 0;
-    buf.data = malloc(buf.len);
-
-    if (!buf.data)
+    buf = bufferNew (QEMUD_MAX_XML_LEN);
+    if (!buf)
         goto no_memory;
 
-    if (qemudBufferPrintf(&buf, "<network>\n") < 0)
+    if (bufferVSprintf(buf, "<network>\n") < 0)
         goto no_memory;
 
-    if (qemudBufferPrintf(&buf, "  <name>%s</name>\n", def->name) < 0)
+    if (bufferVSprintf(buf, "  <name>%s</name>\n", def->name) < 0)
         goto no_memory;
 
     uuid = def->uuid;
-    if (qemudBufferPrintf(&buf, "  <uuid>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</uuid>\n",
+    if (bufferVSprintf(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],
@@ -2704,62 +2644,61 @@
 
     if (def->forward) {
         if (def->forwardDev[0]) {
-            qemudBufferPrintf(&buf, "  <forward dev='%s'/>\n",
+            bufferVSprintf(buf, "  <forward dev='%s'/>\n",
                               def->forwardDev);
         } else {
-            qemudBufferAdd(&buf, "  <forward/>\n");
+            bufferAdd(buf, "  <forward/>\n", -1);
         }
     }
 
     if ((def->bridge != '\0' || def->disableSTP || def->forwardDelay) &&
-        qemudBufferPrintf(&buf, "  <bridge name='%s' stp='%s' delay='%d' />\n",
+        bufferVSprintf(buf, "  <bridge name='%s' stp='%s' delay='%d' />\n",
                           def->bridge,
                           def->disableSTP ? "off" : "on",
                           def->forwardDelay) < 0)
         goto no_memory;
 
     if (def->ipAddress[0] || def->netmask[0]) {
-        if (qemudBufferAdd(&buf, "  <ip") < 0)
+        if (bufferAdd(buf, "  <ip", -1) < 0)
             goto no_memory;
 
         if (def->ipAddress[0] &&
-            qemudBufferPrintf(&buf, " address='%s'", def->ipAddress) < 0)
+            bufferVSprintf(buf, " address='%s'", def->ipAddress) < 0)
             goto no_memory;
 
         if (def->netmask[0] &&
-            qemudBufferPrintf(&buf, " netmask='%s'", def->netmask) < 0)
+            bufferVSprintf(buf, " netmask='%s'", def->netmask) < 0)
             goto no_memory;
 
-        if (qemudBufferAdd(&buf, ">\n") < 0)
+        if (bufferAdd(buf, ">\n", -1) < 0)
             goto no_memory;
 
         if (def->ranges) {
             struct qemud_dhcp_range_def *range = def->ranges;
-            if (qemudBufferAdd(&buf, "    <dhcp>\n") < 0)
+            if (bufferAdd(buf, "    <dhcp>\n", -1) < 0)
                 goto no_memory;
             while (range) {
-                if (qemudBufferPrintf(&buf, "      <range start='%s' end='%s' />\n",
+                if (bufferVSprintf(buf, "      <range start='%s' end='%s' />\n",
                                       range->start, range->end) < 0)
                     goto no_memory;
                 range = range->next;
             }
-            if (qemudBufferAdd(&buf, "    </dhcp>\n") < 0)
+            if (bufferAdd(buf, "    </dhcp>\n", -1) < 0)
                 goto no_memory;
         }
 
-        if (qemudBufferAdd(&buf, "  </ip>\n") < 0)
+        if (bufferAdd(buf, "  </ip>\n", -1) < 0)
             goto no_memory;
     }
 
-    if (qemudBufferAdd(&buf, "</network>\n") < 0)
+    if (bufferAdd(buf, "</network>\n", -1) < 0)
         goto no_memory;
 
-    return buf.data;
+    return bufferContentAndFree (buf);
 
  no_memory:
     qemudReportError(server, VIR_ERR_NO_MEMORY, "xml");
-    if (buf.data)
-        free(buf.data);
+    if (buf) bufferFree (buf);
     return NULL;
 }
 
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/conf.h libvirt-caps/qemud/conf.h
--- libvirt-cvs/qemud/conf.h	2007-02-23 17:15:18.000000000 +0000
+++ libvirt-caps/qemud/conf.h	2007-03-15 13:04:28.000000000 +0000
@@ -78,6 +78,13 @@
                                          struct qemud_network *network,
                                          struct qemud_network_def *def);
 
+struct qemu_arch_info {
+    const char *arch;
+    const char **machines;
+    const char *binary;
+};
+extern struct qemu_arch_info qemudArchs[];
+
 #endif
 
 /*
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/dispatch.c libvirt-caps/qemud/dispatch.c
--- libvirt-cvs/qemud/dispatch.c	2007-02-23 09:03:25.000000000 +0000
+++ libvirt-caps/qemud/dispatch.c	2007-03-15 13:19:12.000000000 +0000
@@ -23,6 +23,7 @@
 
 #include <config.h>
 
+#include <unistd.h>
 #include <limits.h>
 #include <string.h>
 #include <stdlib.h>
@@ -33,6 +34,8 @@
 #include "internal.h"
 #include "driver.h"
 #include "dispatch.h"
+#include "conf.h"
+#include "buf.h"
 
 
 static int qemudDispatchFailure(struct qemud_server *server ATTRIBUTE_UNUSED,
@@ -100,6 +103,145 @@
     return 0;
 }
 
+static int
+qemudDispatchGetCapabilities (struct qemud_server *server,
+                              struct qemud_client *client,
+                              struct qemud_packet *in,
+                              struct qemud_packet *out)
+{
+    struct utsname utsname;
+    int i, j, r;
+    int have_kqemu = 0;
+    int have_kvm = 0;
+    bufferPtr xml;
+    int len;
+
+    if (in->header.dataSize != 0) return -1;
+
+    have_kqemu = access ("/dev/kqemu", F_OK) == 0;
+    have_kvm = access ("/dev/kvm", F_OK) == 0;
+
+    /* Construct the XML. */
+    xml = bufferNew (1024);
+    if (!xml) {
+        qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+        qemudDispatchFailure (server, client, out);
+        return 0;
+    }
+
+    /* Note: I'm not putting a <host> section in here because it's
+     * not relevant for qemu.
+     */
+    r = bufferAdd (xml,
+                   "\
+<capabilities>\n\
+  <guest>\n\
+    <architectures>\n", -1);
+    if (r == -1) {
+    vir_buffer_failed:
+        bufferFree (xml);
+        qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+        qemudDispatchFailure (server, client, out);
+        return 0;
+    }
+
+    /* First the guest architectures for basic <domain type='qemu'>,
+     * all emulated (even x86 on x86).
+     */
+    for (i = 0; qemudArchs[i].arch; ++i)
+        for (j = 0; qemudArchs[i].machines[j]; ++j) {
+            r = bufferVSprintf (xml,
+                                "\
+      <architecture>\n\
+        <model>%s</model>\n\
+        <machine>%s</machine>\n\
+        <fullvirt/>\n\
+        <domain_type>qemu</domain_type>\n\
+        <machine_type>%s</machine_type>\n\
+        <emulator>%s</emulator>\n\
+      </architecture>\n",
+                                qemudArchs[i].arch,
+                                qemudArchs[i].machines[j],
+                                qemudArchs[i].machines[j],
+                                qemudArchs[i].binary);
+            if (r == -1)
+                goto vir_buffer_failed;
+        }
+
+    /* Really, this never fails - look at the man-page. */
+    uname (&utsname);
+
+    /* If we have kqemu, then there is a <domain type='kqemu'>,
+     * accelerated, but the model is limited to host == guest.
+     */
+    if (have_kqemu) {
+        for (j = 0; qemudArchs[0].machines[j]; ++j) {
+            r = bufferVSprintf (xml,
+                                /* XXX There is no mention of PAE in qemu docs */
+                                "\
+      <architecture>\n\
+        <model>%s</model>\n\
+        <machine>%s</machine>\n\
+        <fullvirt/>\n\
+        <domain_type>kqemu</domain_type>\n\
+        <machine_type>%s</machine_type>\n\
+        <emulator>%s</emulator>\n\
+      </architecture>\n",
+                                utsname.machine,
+                                qemudArchs[0].machines[j],
+                                qemudArchs[0].machines[j],
+                                qemudArchs[0].binary);
+            if (r == -1) goto vir_buffer_failed;
+        }
+    }
+
+    /* If we have kvm, then there is a <domain type='kvm'>,
+     * accelerated, HVM, but the model is limited to host == guest.
+     */
+    if (have_kvm) {
+        for (j = 0; qemudArchs[0].machines[j]; ++j) {
+            r = bufferVSprintf (xml,
+                                /* XXX Does KVM support PAE inside the guest?*/
+                                "\
+      <architecture>\n\
+        <model>%s</model>\n\
+        <machine>%s</machine>\n\
+        <fullvirt/>\n\
+        <domain_type>kvm</domain_type>\n\
+        <machine_type>%s</machine_type>\n\
+        <emulator>%s</emulator>\n\
+      </architecture>\n",
+                                utsname.machine,
+                                qemudArchs[0].machines[j],
+                                qemudArchs[0].machines[j],
+                                qemudArchs[0].binary);
+            if (r == -1) goto vir_buffer_failed;
+        }
+    }
+
+    /* Finish off. */
+    r = bufferAdd (xml,
+                      "\
+    </architectures>\n\
+  </guest>\n\
+</capabilities>\n", -1);
+    if (r == -1) goto vir_buffer_failed;
+
+    /* Copy the XML into the outgoing packet, assuming it's not too large. */
+    len = strlen (xml->content);
+    if (len > QEMUD_MAX_XML_LEN) {
+        bufferFree (xml);
+        qemudReportError (server, VIR_ERR_XML_ERROR, NULL);
+        qemudDispatchFailure (server, client, out);
+        return 0;
+    }
+    out->header.type = QEMUD_PKT_GET_CAPABILITIES;
+    out->header.dataSize = len;
+    strcpy (out->data.getCapabilitiesReply.xml, xml->content);
+    bufferFree (xml);
+    return 0;
+}
+
 static int qemudDispatchListDomains(struct qemud_server *server, struct qemud_client *client,
                                     struct qemud_packet *in, struct qemud_packet *out) {
     int i, ndomains, domains[QEMUD_MAX_NUM_DOMAINS];
@@ -854,6 +996,7 @@
     qemudDispatchDomainSetAutostart,
     qemudDispatchNetworkGetAutostart,
     qemudDispatchNetworkSetAutostart,
+    qemudDispatchGetCapabilities,
 };
 
 clientFunc funcsTransmitRO[QEMUD_PKT_MAX] = {
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/internal.h libvirt-caps/qemud/internal.h
--- libvirt-cvs/qemud/internal.h	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/qemud/internal.h	2007-03-15 12:54:35.000000000 +0000
@@ -39,8 +39,12 @@
 #ifndef ATTRIBUTE_UNUSED
 #define ATTRIBUTE_UNUSED __attribute__((unused))
 #endif
+#ifndef ATTRIBUTE_FORMAT
+#define ATTRIBUTE_FORMAT(args...) __attribute__((__format__ (args)))
+#endif
 #else
 #define ATTRIBUTE_UNUSED
+#define ATTRIBUTE_FORMAT(...)
 #endif
 
 #define UUID_LEN 16
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/Makefile.am libvirt-caps/qemud/Makefile.am
--- libvirt-cvs/qemud/Makefile.am	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/qemud/Makefile.am	2007-03-15 12:54:35.000000000 +0000
@@ -11,7 +11,8 @@
                 conf.c conf.h \
                 bridge.c bridge.h \
                 iptables.c iptables.h \
-                uuid.c uuid.h
+                uuid.c uuid.h \
+		buf.c buf.h
 #-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L
 libvirt_qemud_CFLAGS = \
         -I$(top_srcdir)/include -I$(top_builddir)/include $(LIBXML_CFLAGS) \
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/protocol.h libvirt-caps/qemud/protocol.h
--- libvirt-cvs/qemud/protocol.h	2007-02-23 09:03:25.000000000 +0000
+++ libvirt-caps/qemud/protocol.h	2007-03-13 13:18:32.000000000 +0000
@@ -68,6 +68,7 @@
     QEMUD_PKT_DOMAIN_SET_AUTOSTART,
     QEMUD_PKT_NETWORK_GET_AUTOSTART,
     QEMUD_PKT_NETWORK_SET_AUTOSTART,
+    QEMUD_PKT_GET_CAPABILITIES,
 
     QEMUD_PKT_MAX,
 } qemud_packet_type;
@@ -125,6 +126,9 @@
         uint32_t threads;
     } getNodeInfoReply;
     struct {
+        char xml[QEMUD_MAX_XML_LEN];
+    } getCapabilitiesReply;
+    struct {
         int32_t numDomains;
         int32_t domains[QEMUD_MAX_NUM_DOMAINS];
     } listDomainsReply;
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/driver.h libvirt-caps/src/driver.h
--- libvirt-cvs/src/driver.h	2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps/src/driver.h	2007-03-13 13:17:17.000000000 +0000
@@ -48,6 +48,8 @@
 typedef int
 	(*virDrvNodeGetInfo)		(virConnectPtr conn,
 					 virNodeInfoPtr info);
+typedef char *
+	(*virDrvGetCapabilities) (virConnectPtr conn);
 typedef int
 	(*virDrvListDomains)		(virConnectPtr conn,
 					 int *ids,
@@ -164,6 +166,7 @@
 	virDrvGetVersion		version;
 	virDrvGetMaxVcpus		getMaxVcpus;
 	virDrvNodeGetInfo		nodeGetInfo;
+    virDrvGetCapabilities   getCapabilities;
 	virDrvListDomains		listDomains;
 	virDrvNumOfDomains		numOfDomains;
 	virDrvDomainCreateLinux		domainCreateLinux;
@@ -283,3 +286,17 @@
 }
 #endif /* __cplusplus */
 #endif /* __VIR_DRIVER_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/internal.h libvirt-caps/src/internal.h
--- libvirt-cvs/src/internal.h	2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps/src/internal.h	2007-03-13 13:18:12.000000000 +0000
@@ -239,3 +239,17 @@
 }
 #endif                          /* __cplusplus */
 #endif                          /* __VIR_INTERNAL_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/libvirt.c libvirt-caps/src/libvirt.c
--- libvirt-cvs/src/libvirt.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/libvirt.c	2007-03-15 12:54:35.000000000 +0000
@@ -1711,6 +1711,37 @@
     return(0);
 }
 
+/**
+ * virConnectGetCapabilities:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Return capabilities of the hypervisor / driver.
+ *
+ * Returns NULL in case of error, or a pointer to an opaque
+ * virCapabilities structure (virCapabilitiesPtr).
+ *
+ * The client must free the returned string after use.
+ */
+char *
+virConnectGetCapabilities (virConnectPtr conn)
+{
+    int i;
+
+    if (!VIR_IS_CONNECT (conn)) {
+        virLibConnError (conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return NULL;
+    }
+
+    for (i = 0; i < conn->nb_drivers; i++) {
+        if (conn->drivers[i] && conn->drivers[i]->getCapabilities) {
+            return conn->drivers[i]->getCapabilities (conn);
+        }
+    }
+
+    virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__);
+    return NULL;
+}
+
 /************************************************************************
  *									*
  *		Handling of defined but not running domains		*
@@ -2971,3 +3002,17 @@
     virLibConnError(network->conn, VIR_ERR_CALL_FAILED, __FUNCTION__);
     return (-1);
 }
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/libvirt_sym.version libvirt-caps/src/libvirt_sym.version
--- libvirt-cvs/src/libvirt_sym.version	2007-03-13 13:14:44.000000000 +0000
+++ libvirt-caps/src/libvirt_sym.version	2007-03-13 13:18:09.000000000 +0000
@@ -53,6 +53,7 @@
 	virConnResetLastError;
 	virDefaultErrorFunc;
 	virNodeGetInfo;
+	virConnectGetCapabilities;
 
 	virDomainSetVcpus;
 	virDomainPinVcpu;
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/proxy_internal.c libvirt-caps/src/proxy_internal.c
--- libvirt-cvs/src/proxy_internal.c	2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps/src/proxy_internal.c	2007-03-13 13:17:07.000000000 +0000
@@ -52,6 +52,7 @@
     xenProxyGetVersion, /* version */
     NULL, /* getMaxVcpus */
     xenProxyNodeGetInfo, /* nodeGetInfo */
+    NULL, /* getCapabilities */
     xenProxyListDomains, /* listDomains */
     xenProxyNumOfDomains, /* numOfDomains */
     NULL, /* domainCreateLinux */
@@ -1044,3 +1045,17 @@
 
     return(ostype);
 }
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/proxy_internal.h libvirt-caps/src/proxy_internal.h
--- libvirt-cvs/src/proxy_internal.h	2006-11-07 16:28:16.000000000 +0000
+++ libvirt-caps/src/proxy_internal.h	2007-03-13 13:18:13.000000000 +0000
@@ -78,8 +78,8 @@
     union {
         char       str[4080];   /* extra char array */
         int        arg[1020];   /* extra int array */
-	virDomainInfo dinfo;	/* domain information */
-	virNodeInfo   ninfo;	/* node information */
+        virDomainInfo dinfo;	/* domain information */
+        virNodeInfo   ninfo;	/* node information */
     } extra;
 };
 typedef struct _virProxyFullPacket virProxyFullPacket;
@@ -93,3 +93,17 @@
 }
 #endif                          /* __cplusplus */
 #endif /* __LIBVIR_PROXY_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/qemu_internal.c libvirt-caps/src/qemu_internal.c
--- libvirt-cvs/src/qemu_internal.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/qemu_internal.c	2007-03-15 12:54:35.000000000 +0000
@@ -452,6 +452,31 @@
 }
 
 
+static char *
+qemuGetCapabilities (virConnectPtr conn)
+{
+    struct qemud_packet req, reply;
+    char *xml;
+
+    /* Punt the request across to the daemon, because the daemon
+     * has tables describing available architectures.
+     */
+    req.header.type = QEMUD_PKT_GET_CAPABILITIES;
+    req.header.dataSize = 0;
+
+    if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+        return NULL;
+    }
+
+    xml = strdup (reply.data.getCapabilitiesReply.xml);
+    if (!xml) {
+        qemuError (conn, NULL, VIR_ERR_NO_MEMORY, NULL);
+        return NULL;
+    }
+
+    return xml;
+}
+
 static int qemuNumOfDomains(virConnectPtr conn) {
     struct qemud_packet req, reply;
 
@@ -1172,6 +1197,7 @@
     qemuGetVersion, /* version */
     NULL, /* getMaxVcpus */
     qemuNodeGetInfo, /* nodeGetInfo */
+    qemuGetCapabilities, /* getCapabilities */
     qemuListDomains, /* listDomains */
     qemuNumOfDomains, /* numOfDomains */
     qemuDomainCreateLinux, /* domainCreateLinux */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/test.c libvirt-caps/src/test.c
--- libvirt-cvs/src/test.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/test.c	2007-03-15 13:39:03.000000000 +0000
@@ -44,6 +44,7 @@
                    unsigned long *hvVer);
 int testNodeGetInfo(virConnectPtr conn,
                     virNodeInfoPtr info);
+char *testGetCapabilities (virConnectPtr conn);
 int testNumOfDomains(virConnectPtr conn);
 int testListDomains(virConnectPtr conn,
                     int *ids,
@@ -97,6 +98,7 @@
     testGetVersion, /* version */
     NULL, /* getMaxVcpus */
     testNodeGetInfo, /* nodeGetInfo */
+    testGetCapabilities, /* getCapabilities */
     testListDomains, /* listDomains */
     testNumOfDomains, /* numOfDomains */
     testDomainCreateLinux, /* domainCreateLinux */
@@ -179,8 +181,10 @@
 static testNode *node = NULL;
 static int nextDomID = 1;
 
+#define TEST_MODEL "i686"
+
 static const virNodeInfo defaultNodeInfo = {
-    "i686",
+    TEST_MODEL,
     1024*1024*3, /* 3 GB */
     16,
     1400,
@@ -809,6 +813,37 @@
     return (0);
 }
 
+char *
+testGetCapabilities (virConnectPtr conn)
+{
+    static char caps[] = "\
+<capabilities>\n\
+  <host>\n\
+    <features>\n\
+      <pae/>\n\
+    </features>\n\
+  <host>\n\
+  <guest>\n\
+    <architectures>\n\
+      <architecture>\n\
+        <model>" TEST_MODEL "</model>\n\
+        <pae/>\n\
+        <fullvirt/>\n\
+        <domain_type>test</domain_type>\n\
+      </architecture>\n\
+    </architectures>\n\
+  </guest>\n\
+</capabilities>\n\
+";
+
+    char *caps_copy = strdup (caps);
+    if (!caps_copy) {
+        testError(conn, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__);
+        return NULL;
+    }
+    return caps_copy;
+}
+
 int testNumOfDomains(virConnectPtr conn)
 {
     int numActive = 0, i;
@@ -1379,6 +1414,11 @@
 #endif /* WITH_TEST */
 
 /*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
  * Local variables:
  *  indent-tabs-mode: nil
  *  c-indent-level: 4
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/virsh.c libvirt-caps/src/virsh.c
--- libvirt-cvs/src/virsh.c	2007-03-09 14:39:48.000000000 +0000
+++ libvirt-caps/src/virsh.c	2007-03-13 13:17:20.000000000 +0000
@@ -1545,6 +1545,33 @@
 }
 
 /*
+ * "capabilities" command
+ */
+static vshCmdInfo info_capabilities[] = {
+    {"syntax", "capabilities"},
+    {"help", gettext_noop("capabilities")},
+    {"desc", gettext_noop("Returns capabilities of hypervisor/driver.")},
+    {NULL, NULL}
+};
+
+static int
+cmdCapabilities (vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+    char *caps;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    if ((caps = virConnectGetCapabilities (ctl->conn)) == NULL) {
+        vshError(ctl, FALSE, _("failed to get capabilities"));
+        return FALSE;
+    }
+    vshPrint (ctl, "%s\n", caps);
+
+    return TRUE;
+}
+
+/*
  * "dumpxml" command
  */
 static vshCmdInfo info_dumpxml[] = {
@@ -2375,6 +2402,7 @@
  */
 static vshCmdDef commands[] = {
     {"autostart", cmdAutostart, opts_autostart, info_autostart},
+    {"capabilities", cmdCapabilities, NULL, info_capabilities},
     {"connect", cmdConnect, opts_connect, info_connect},
     {"console", cmdConsole, opts_console, info_console},
     {"create", cmdCreate, opts_create, info_create},
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/virterror.c libvirt-caps/src/virterror.c
--- libvirt-cvs/src/virterror.c	2007-02-14 15:40:54.000000000 +0000
+++ libvirt-caps/src/virterror.c	2007-03-13 13:18:16.000000000 +0000
@@ -604,6 +604,26 @@
 	    else
 	        errmsg = _("network %s exists already");
             break;
+    case VIR_ERR_SYSTEM_ERROR:
+        if (info == NULL)
+            errmsg = _("system call error");
+        else
+            errmsg = "%s";
+        break;
     }
     return (errmsg);
 }
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xend_internal.c libvirt-caps/src/xend_internal.c
--- libvirt-cvs/src/xend_internal.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/xend_internal.c	2007-03-15 12:54:35.000000000 +0000
@@ -72,6 +72,7 @@
     xenDaemonGetVersion, /* version */
     NULL, /* getMaxVcpus */
     xenDaemonNodeGetInfo, /* nodeGetInfo */
+    NULL, /* getCapabilities */
     xenDaemonListDomains, /* listDomains */
     xenDaemonNumOfDomains, /* numOfDomains */
     xenDaemonCreateLinux, /* domainCreateLinux */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xen_internal.c libvirt-caps/src/xen_internal.c
--- libvirt-cvs/src/xen_internal.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/xen_internal.c	2007-03-15 13:42:39.000000000 +0000
@@ -22,6 +22,8 @@
 #include <sys/ioctl.h>
 #include <limits.h>
 #include <stdint.h>
+#include <regex.h>
+#include <errno.h>
 
 /* required for dom0_getdomaininfo_t */
 #include <xen/dom0_ops.h>
@@ -32,6 +34,8 @@
 /* required for shutdown flags */
 #include <xen/sched.h>
 
+#include "xml.h"
+
 /* #define DEBUG */
 /*
  * so far there is 2 versions of the structures usable for doing
@@ -72,6 +76,17 @@
 static int dom_interface_version = -1;
 static int kb_per_pages = 0;
 
+/* Regular expressions used by xenHypervisorGetCapabilities, and
+ * compiled once by xenHypervisorInit.  Note that these are POSIX.2
+ * extended regular expressions (regex(7)).
+ */
+static const char *flags_hvm_re = "^flags[[:blank:]]+:.* (vmx|svm)[[:space:]]";
+static regex_t flags_hvm_rec;
+static const char *flags_pae_re = "^flags[[:blank:]]+:.* pae[[:space:]]";
+static regex_t flags_pae_rec;
+static const char *xen_cap_re = "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(x86_32|x86_64|ia64)(p|be)?";
+static regex_t xen_cap_rec;
+
 /*
  * The content of the structures for a getdomaininfolist system hypercall
  */
@@ -432,6 +447,7 @@
     xenHypervisorGetVersion, /* version */
     xenHypervisorNumOfMaxVcpus, /* getMaxVcpus */
     NULL, /* nodeGetInfo */
+    xenHypervisorGetCapabilities, /* getCapabilities */
     xenHypervisorListDomains, /* listDomains */
     xenHypervisorNumOfDomains, /* numOfDomains */
     NULL, /* domainCreateLinux */
@@ -470,9 +486,9 @@
 
 /**
  * virXenError:
- * @conn: the connection if available
  * @error: the error number
  * @info: extra information string
+ * @value: extra information number
  *
  * Handle an error at the xend daemon interface
  */
@@ -486,7 +502,31 @@
 
     errmsg = __virErrorMsg(error, info);
     __virRaiseError(NULL, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
-                    errmsg, info, NULL, value, 0, errmsg, info, value);
+                    errmsg, info, NULL, value, 0, errmsg, info);
+}
+
+/**
+ * virXenPerror:
+ * @conn: the connection (if available)
+ * @msg: name of system call or file (as in perror(3))
+ *
+ * Raise error from a failed system call, using errno as the source.
+ */
+static void
+virXenPerror (virConnectPtr conn, const char *msg)
+{
+    char *msg_s;
+
+    msg_s = malloc (strlen (msg) + 10);
+    if (msg_s) {
+        strcpy (msg_s, msg);
+        strcat (msg_s, ": %s");
+    }
+
+    __virRaiseError (conn, NULL, NULL,
+                     VIR_FROM_XEN, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
+                     msg, NULL, NULL, errno, 0,
+                     msg_s ? msg_s : msg, strerror (errno));
 }
 
 /**
@@ -1139,7 +1179,7 @@
 static int
 xenHypervisorInit(void)
 {
-    int fd, ret, cmd;
+    int fd, ret, cmd, errcode;
     hypercall_t hc;
     v0_hypercall_t v0_hc;
     xen_getdomaininfo info;
@@ -1152,6 +1192,42 @@
     initialized = 1;
     in_init = 1;
 
+    /* Compile regular expressions used by xenHypervisorGetCapabilities.
+     * Note that errors here are really internal errors since these
+     * regexps should never fail to compile.
+     */
+    errcode = regcomp (&flags_hvm_rec, flags_hvm_re, REG_EXTENDED);
+    if (errcode != 0) {
+        char error[100];
+        regerror (errcode, &flags_hvm_rec, error, sizeof error);
+        regfree (&flags_hvm_rec);
+        virXenError (VIR_ERR_INTERNAL_ERROR, error, 0);
+        in_init = 0;
+        return -1;
+    }
+    errcode = regcomp (&flags_pae_rec, flags_pae_re, REG_EXTENDED);
+    if (errcode != 0) {
+        char error[100];
+        regerror (errcode, &flags_pae_rec, error, sizeof error);
+        regfree (&flags_pae_rec);
+        regfree (&flags_hvm_rec);
+        virXenError (VIR_ERR_INTERNAL_ERROR, error, 0);
+        in_init = 0;
+        return -1;
+    }
+    errcode = regcomp (&xen_cap_rec, xen_cap_re, REG_EXTENDED);
+    if (errcode != 0) {
+        char error[100];
+        regerror (errcode, &xen_cap_rec, error, sizeof error);
+        regfree (&xen_cap_rec);
+        regfree (&flags_pae_rec);
+        regfree (&flags_hvm_rec);
+        virXenError (VIR_ERR_INTERNAL_ERROR, error, 0);
+        in_init = 0;
+        return -1;
+    }
+
+    /* Xen hypervisor version detection begins. */
     ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
     if (ret < 0) {
         hypervisor_version = -1;
@@ -1361,6 +1437,235 @@
 }
 
 /**
+ * xenHypervisorGetCapabilities:
+ * @conn: pointer to the connection block
+ *
+ * Return the capabilities of this hypervisor.
+ */
+char *
+xenHypervisorGetCapabilities (virConnectPtr conn)
+{
+    char line[1024], *str, *token;
+    regmatch_t subs[3];
+    char *saveptr;
+    FILE *fp;
+    int i, r;
+
+    char hvm_type[4] = ""; /* "vmx" or "svm" (or "" if not in CPU). */
+    int host_pae = 0;
+    const int max_guest_archs = 32;
+    struct {
+        const char *model;
+        int bits;
+        int hvm;
+        int pae;
+        int ia64_be;
+    } guest_archs[max_guest_archs];
+    int nr_guest_archs = 0;
+
+    virBufferPtr xml;
+    char *xml_str;
+
+    /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
+     * It's not clear if this will work on IA64, let alone other
+     * architectures and non-Linux. (XXX)
+     */
+    fp = fopen ("/proc/cpuinfo", "r");
+    if (fp == NULL) {
+        if (errno == ENOENT)
+            goto nocpuinfo;
+        virXenPerror (conn, "/proc/cpuinfo");
+        return NULL;
+    }
+
+    while (fgets (line, sizeof line, fp)) {
+        if (regexec (&flags_hvm_rec, line, 1, subs, 0) == 0
+            && subs[0].rm_so != -1)
+            strncpy (hvm_type,
+                     &line[subs[0].rm_so], subs[0].rm_eo-subs[0].rm_so+1);
+        else if (regexec (&flags_hvm_rec, line, 0, NULL, 0) == 0)
+            host_pae = 1;
+    }
+
+    fclose (fp);
+
+ nocpuinfo:
+    /* Most of the useful info is in /sys/hypervisor/properties/capabilities
+     * which is documented in the code in xen-unstable.hg/xen/arch/.../setup.c.
+     *
+     * It is a space-separated list of supported guest architectures.
+     *
+     * For x86:
+     *    TYP-VER-ARCH[p]
+     *    ^   ^   ^    ^
+     *    |   |   |    +-- PAE supported
+     *    |   |   +------- x86_32 or x86_64
+     *    |   +----------- the version of Xen, eg. "3.0"
+     *    +--------------- "xen" or "hvm" for para or full virt respectively
+     *
+     * For PPC this file appears to be always empty (?)
+     *
+     * For IA64:
+     *    TYP-VER-ARCH[be]
+     *    ^   ^   ^    ^
+     *    |   |   |    +-- Big-endian supported
+     *    |   |   +------- always "ia64"
+     *    |   +----------- the version of Xen, eg. "3.0"
+     *    +--------------- "xen" or "hvm" for para or full virt respectively
+     */
+    fp = fopen ("/sys/hypervisor/properties/capabilities", "r");
+    if (fp == NULL) {
+        if (errno == ENOENT)
+            goto noxencaps;
+        virXenPerror (conn, "/sys/hypervisor/properties/capabilities");
+        return NULL;
+    }
+
+    /* Expecting one line in this file - ignore any more. */
+    if (!fgets (line, sizeof line, fp)) {
+        fclose (fp);
+        goto noxencaps;
+    }
+
+    fclose (fp);
+
+    /* Split the line into tokens.  strtok_r is OK here because we "own"
+     * this buffer.  Parse out the features from each token.
+     */
+    for (str = line, nr_guest_archs = 0;
+         nr_guest_archs < max_guest_archs
+             && (token = strtok_r (str, " ", &saveptr)) != NULL;
+         str = NULL) {
+        if (regexec (&xen_cap_rec, token, 3, subs, 0) == 0) {
+            guest_archs[nr_guest_archs].hvm =
+                strncmp (&token[subs[0].rm_so], "hvm", 3) == 0;
+            if (strncmp (&token[subs[1].rm_so], "x86_32", 6) == 0) {
+                guest_archs[nr_guest_archs].model = "i686";
+                guest_archs[nr_guest_archs].bits = 32;
+            }
+            else if (strncmp (&token[subs[1].rm_so], "x86_64", 6) == 0) {
+                guest_archs[nr_guest_archs].model = "x86_64";
+                guest_archs[nr_guest_archs].bits = 64;
+            }
+            else if (strncmp (&token[subs[1].rm_so], "ia64", 4) == 0) {
+                guest_archs[nr_guest_archs].model = "ia64";
+                guest_archs[nr_guest_archs].bits = 64;
+            }
+            else {
+                guest_archs[nr_guest_archs].model = ""; /* can never happen */
+            }
+            guest_archs[nr_guest_archs].pae =
+                guest_archs[nr_guest_archs].ia64_be = 0;
+            if (subs[2].rm_so != -1) {
+                if (strncmp (&token[subs[2].rm_so], "p", 1) == 0)
+                    guest_archs[nr_guest_archs].pae = 1;
+                else if (strncmp (&token[subs[2].rm_so], "be", 2) == 0)
+                    guest_archs[nr_guest_archs].ia64_be = 1;
+            }
+            nr_guest_archs++;
+        }
+    }
+
+ noxencaps:
+    /* Construct the final XML. */
+    xml = virBufferNew (1024);
+    if (!xml) return NULL;
+    r = virBufferAdd (xml,
+                      "\
+<capabilities>\n\
+  <host>\n\
+    <features>\n", -1);
+    if (r == -1) return NULL;
+
+    if (strcmp (hvm_type, "") != 0) {
+        r = virBufferVSprintf (xml,
+                               "\
+      <%s/>\n",
+                               hvm_type);
+        if (r == -1) {
+        vir_buffer_failed:
+            virBufferFree (xml);
+            return NULL;
+        }
+    }
+    if (host_pae) {
+        r = virBufferAdd (xml, "\
+      <pae/>\n", -1);
+        if (r == -1) goto vir_buffer_failed;
+    }
+    r = virBufferAdd (xml,
+                      "\
+    </features>\n\
+  </host>\n\
+  <guest>\n\
+    <architectures>\n", -1);
+    if (r == -1) goto vir_buffer_failed;
+
+    for (i = 0; i < nr_guest_archs; ++i) {
+        r = virBufferVSprintf (xml,
+                               "\
+      <architecture>\n\
+        <model>%s</model>\n\
+        <domain_type>xen</domain_type>\n",
+                               guest_archs[i].model);
+        if (r == -1) goto vir_buffer_failed;
+        if (guest_archs[i].hvm) {
+            r = virBufferAdd (xml,
+                              "\
+        <fullvirt/>\n\
+        <loader>/usr/lib/xen/boot/hvmloader</loader>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        } else {
+            r = virBufferAdd (xml,
+                              "\
+        <paravirt>xen</paravirt>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        if (guest_archs[i].pae) {
+            r = virBufferAdd (xml,
+                              "\
+        <pae/>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        if (guest_archs[i].ia64_be) {
+            r = virBufferAdd (xml,
+                              "\
+        <ia64_be/>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        if (guest_archs[i].bits == 64) {
+            r = virBufferAdd (xml,
+                              "\
+        <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        } else {
+            r = virBufferAdd (xml,
+                              "\
+        <emulator>/usr/lib/xen/bin/qemu-dm</emulator>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        r = virBufferAdd (xml,
+                          "\
+      </architecture>\n", -1);
+        if (r == -1) goto vir_buffer_failed;
+    }
+    r = virBufferAdd (xml,
+                      "\
+    </architectures>\n\
+  </guest>\n\
+</capabilities>\n", -1);
+    if (r == -1) goto vir_buffer_failed;
+    xml_str = strdup (xml->content);
+    if (!xml_str) {
+        virXenError(VIR_ERR_NO_MEMORY, "strdup", 0);
+        goto vir_buffer_failed;
+    }
+    virBufferFree (xml);
+
+    return xml_str;
+}
+
+/**
  * xenHypervisorNumOfDomains:
  * @conn: pointer to the connection block
  *
@@ -1884,6 +2189,11 @@
 
 #endif /* WITH_XEN */
 /*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
  * Local variables:
  *  indent-tabs-mode: nil
  *  c-indent-level: 4
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xen_internal.h libvirt-caps/src/xen_internal.h
--- libvirt-cvs/src/xen_internal.h	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/xen_internal.h	2007-03-15 12:54:35.000000000 +0000
@@ -22,6 +22,8 @@
 int	xenHypervisorClose		(virConnectPtr conn);
 int	xenHypervisorGetVersion		(virConnectPtr conn,
 				 	 unsigned long *hvVer);
+char *
+        xenHypervisorGetCapabilities    (virConnectPtr conn);
 unsigned long
         xenHypervisorGetDomMaxMemory	(virConnectPtr conn,
 					 int id);
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xm_internal.c libvirt-caps/src/xm_internal.c
--- libvirt-cvs/src/xm_internal.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/xm_internal.c	2007-03-15 12:54:36.000000000 +0000
@@ -78,6 +78,7 @@
     NULL, /* version */
     NULL, /* getMaxVcpus */
     NULL, /* nodeGetInfo */
+    NULL, /* getCapabilities */
     NULL, /* listDomains */
     NULL, /* numOfDomains */
     NULL, /* domainCreateLinux */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xml.h libvirt-caps/src/xml.h
--- libvirt-cvs/src/xml.h	2007-02-14 16:16:13.000000000 +0000
+++ libvirt-caps/src/xml.h	2007-03-13 13:17:17.000000000 +0000
@@ -29,6 +29,7 @@
 int virBufferAdd(virBufferPtr buf, const char *str, int len);
 int virBufferVSprintf(virBufferPtr buf, const char *format, ...);
 int virBufferStrcat(virBufferPtr buf, ...);
+
 char *virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int xendConfigVersion);
 unsigned char *virParseUUID(char **ptr, const char *uuid);
 char *virParseXMLDevice(virConnectPtr conn, char *xmldesc, int hvm, int xendConfigVersion);
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xs_internal.c libvirt-caps/src/xs_internal.c
--- libvirt-cvs/src/xs_internal.c	2007-03-15 12:54:37.000000000 +0000
+++ libvirt-caps/src/xs_internal.c	2007-03-15 12:54:36.000000000 +0000
@@ -47,6 +47,7 @@
     NULL, /* version */
     NULL, /* getMaxVcpus */
     NULL, /* nodeGetInfo */
+    NULL, /* getCapabilities */
     xenStoreListDomains, /* listDomains */
     NULL, /* numOfDomains */
     NULL, /* domainCreateLinux */
