This is the second version of this patch. I'll just summarise what's changed below rather than reiterating what it does over again. I believe this addresses everyone's concerns, _except_ for a rather long email from Dan to which I'm going to provide a separate reply.

Changes over previous patch:

* strjoin is gone, and replaced by virBuffer* [DV]
** however, in order to do that I had to duplicate the buffer handling code for qemud (since qemud doesn't link with libvirt and the virBuffer* code depends on other internals of libvirt). * <bits> is now optional, and where it's too hard to determine it reliably, we don't include it in the XML output [DV, danpb]
* <domain><type> -> <domain_type> [markmc]

Rich.
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/configure.in libvirt-caps-tmp/configure.in
--- libvirt-cvs/configure.in	2007-03-12 10:39:29.000000000 +0000
+++ libvirt-caps-tmp/configure.in	2007-03-12 10:42:24.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-tmp/.cvsignore
--- libvirt-cvs/.cvsignore	2007-03-12 10:39:29.000000000 +0000
+++ libvirt-caps-tmp/.cvsignore	2007-03-12 10:42:23.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-tmp/include/libvirt/libvirt.h.in
--- libvirt-cvs/include/libvirt/libvirt.h.in	2007-03-12 10:39:42.000000000 +0000
+++ libvirt-caps-tmp/include/libvirt/libvirt.h.in	2007-03-12 10:45:43.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-tmp/include/libvirt/virterror.h
--- libvirt-cvs/include/libvirt/virterror.h	2007-03-12 10:39:42.000000000 +0000
+++ libvirt-caps-tmp/include/libvirt/virterror.h	2007-03-12 10:45:45.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-tmp/proxy/libvirt_proxy.c
--- libvirt-cvs/proxy/libvirt_proxy.c	2007-03-12 10:39:46.000000000 +0000
+++ libvirt-caps-tmp/proxy/libvirt_proxy.c	2007-03-12 10:45:58.000000000 +0000
@@ -786,3 +786,17 @@
     proxyCloseUnixSocket();
     exit(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/conf.c libvirt-caps-tmp/qemud/conf.c
--- libvirt-cvs/qemud/conf.c	2007-03-12 10:39:24.000000000 +0000
+++ libvirt-caps-tmp/qemud/conf.c	2007-03-12 10:42:01.000000000 +0000
@@ -122,8 +122,13 @@
     return 0;
 }
 
+/* NB: I've stored "bits" here but in future it may be that the
+ * qemu-system-* binaries are able to emulate machines with different
+ * register sizes.  That doesn't happen at present though.
+ */
 struct qemu_arch_info {
     const char *arch;
+    int bits;
     const char **machines;
     const char *binary;
 };
@@ -145,12 +150,12 @@
 
 /* The archicture tables for supported QEMU archs */
 static struct qemu_arch_info archs[] = { 
-    {  "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" },
+    {  "i686", 32, arch_info_x86_machines, "qemu" },
+    {  "x86_64", 64, arch_info_x86_machines, "qemu-system-x86_64" },
+    {  "mips", 32, arch_info_mips_machines, "qemu-system-mips" },
+    {  "mipsel", 32, arch_info_mips_machines, "qemu-system-mipsel" },
+    {  "sparc", 32, arch_info_sparc_machines, "qemu-system-sparc" },
+    {  "ppc", 32, arch_info_ppc_machines, "qemu-system-ppc" },
 };
 
 /* Return the default architecture if none is explicitly requested*/
@@ -211,6 +216,24 @@
     return path;
 }
 
+/* Return the list of architectures.  Useful for getCapabilities. */
+int
+qemudGetGuestArchitectures (struct qemud_guest_arch **archs_rtn)
+{
+    const int n = sizeof archs / sizeof archs[0];
+    int i;
+
+    *archs_rtn = malloc (sizeof (struct qemud_guest_arch) * n);
+    if (!*archs_rtn) return -1;
+
+    for (i = 0; i < n; ++i) {
+        (*archs_rtn)[i].model = archs[i].arch;
+        (*archs_rtn)[i].bits = archs[i].bits;
+    }
+
+    return n;
+}
+
 
 static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) {
     pid_t child;
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/conf.h libvirt-caps-tmp/qemud/conf.h
--- libvirt-cvs/qemud/conf.h	2007-03-12 10:39:24.000000000 +0000
+++ libvirt-caps-tmp/qemud/conf.h	2007-03-12 10:42:01.000000000 +0000
@@ -78,6 +78,13 @@
                                          struct qemud_network *network,
                                          struct qemud_network_def *def);
 
+struct qemud_guest_arch {
+    const char *model;
+    int bits;
+};
+
+int         qemudGetGuestArchitectures (struct qemud_guest_arch **archs);
+
 #endif
 
 /*
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/dispatch.c libvirt-caps-tmp/qemud/dispatch.c
--- libvirt-cvs/qemud/dispatch.c	2007-03-12 10:39:26.000000000 +0000
+++ libvirt-caps-tmp/qemud/dispatch.c	2007-03-12 13:47:00.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 "qemud_xml.h"
 
 
 static int qemudDispatchFailure(struct qemud_server *server ATTRIBUTE_UNUSED,
@@ -100,6 +103,137 @@
     return 0;
 }
 
+static int
+qemudDispatchGetCapabilities (struct qemud_server *server,
+                              struct qemud_client *client,
+                              struct qemud_packet *in,
+                              struct qemud_packet *out)
+{
+    struct utsname utsname;
+    struct qemud_guest_arch *guest_archs;
+    int nr_guest_archs, i, 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;
+    }
+
+    r = bufferAdd (xml,
+                      "\
+<capabilities>\n\
+  <domain_type>qemu</domain_type>\n\
+  <guest_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).
+     */
+    nr_guest_archs = qemudGetGuestArchitectures (&guest_archs);
+    if (nr_guest_archs == -1) {
+        bufferFree (xml);
+        qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+        qemudDispatchFailure (server, client, out);
+        return 0;
+    }
+    for (i = 0; i < nr_guest_archs; ++i) {
+        r = bufferVSprintf (xml,
+                               "\
+    <guest_architecture>\n\
+      <model>%s</model>\n\
+      <bits>%d</bits>\n\
+      <features>\n\
+        <emulated/>\n\
+      </features>\n\
+    </guest_architecture>\n",
+                               guest_archs[i].model,
+                               guest_archs[i].bits);
+        if (r == -1) {
+            free (guest_archs);
+            goto vir_buffer_failed;
+        }
+    }
+    free (guest_archs);
+
+    /* 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) {
+        r = bufferVSprintf (xml,
+                               /* XXX There is no mention of PAE in qemu docs */
+                               "\
+    <guest_architecture>\n\
+      <domain_type>kqemu</domain_type>\n\
+      <model>%s</model>\n\
+      <features>\n\
+        <accelerated/>\n\
+      </features>\n\
+    </guest_architecture>\n",
+                               utsname.machine);
+        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) {
+        r = bufferVSprintf (xml,
+                               /* XXX Does KVM support PAE inside the guest? */
+                               "\
+    <guest_architecture>\n\
+      <domain_type>kvm</domain_type>\n\
+      <model>%s</model>\n\
+      <features>\n\
+        <hvm/>\n\
+        <accelerated/>\n\
+      </features>\n\
+    </guest_architecture>\n",
+                               utsname.machine);
+        if (r == -1) goto vir_buffer_failed;
+    }
+
+    /* Finally build the full capabilities. */
+    r = bufferAdd (xml,
+                      "\
+  </guest_architectures>\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 +988,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/Makefile.am libvirt-caps-tmp/qemud/Makefile.am
--- libvirt-cvs/qemud/Makefile.am	2007-03-12 10:39:27.000000000 +0000
+++ libvirt-caps-tmp/qemud/Makefile.am	2007-03-12 14:06:20.000000000 +0000
@@ -10,7 +10,8 @@
                 conf.c conf.h \
                 bridge.c bridge.h \
                 iptables.c iptables.h \
-                uuid.c uuid.h
+                uuid.c uuid.h \
+		qemud_xml.c qemud_xml.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-tmp/qemud/protocol.h
--- libvirt-cvs/qemud/protocol.h	2007-03-12 10:39:29.000000000 +0000
+++ libvirt-caps-tmp/qemud/protocol.h	2007-03-12 10:42:15.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/qemud/qemud_xml.c libvirt-caps-tmp/qemud/qemud_xml.c
--- libvirt-cvs/qemud/qemud_xml.c	1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps-tmp/qemud/qemud_xml.c	2007-03-12 13:46:28.000000000 +0000
@@ -0,0 +1,195 @@
+/*
+ * qemud_xml.c: buffers for qemud
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <[EMAIL PROTECTED]>
+ */
+
+#include "libvirt/libvirt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "qemud_xml.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);
+    }
+}
+
+/**
+ * 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/qemud_xml.h libvirt-caps-tmp/qemud/qemud_xml.h
--- libvirt-cvs/qemud/qemud_xml.h	1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps-tmp/qemud/qemud_xml.h	2007-03-12 13:44:40.000000000 +0000
@@ -0,0 +1,33 @@
+/*
+ * qemud_xml.h: buffers for qemud
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <[EMAIL PROTECTED]>
+ */
+
+#ifndef __QEMUD_XML_H__
+#define __QEMUD_XML_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);
+int bufferAdd(bufferPtr buf, const char *str, int len);
+int bufferVSprintf(bufferPtr buf, const char *format, ...);
+int bufferStrcat(bufferPtr buf, ...);
+
+#endif                          /* __QEMUD_XML_H__ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/driver.h libvirt-caps-tmp/src/driver.h
--- libvirt-cvs/src/driver.h	2007-03-12 10:40:28.000000000 +0000
+++ libvirt-caps-tmp/src/driver.h	2007-03-12 10:48:28.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-tmp/src/internal.h
--- libvirt-cvs/src/internal.h	2007-03-12 10:40:32.000000000 +0000
+++ libvirt-caps-tmp/src/internal.h	2007-03-12 10:48:32.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-tmp/src/libvirt.c
--- libvirt-cvs/src/libvirt.c	2007-03-12 10:40:26.000000000 +0000
+++ libvirt-caps-tmp/src/libvirt.c	2007-03-12 10:48:22.000000000 +0000
@@ -1701,6 +1701,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		*
@@ -2961,3 +2992,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-tmp/src/libvirt_sym.version
--- libvirt-cvs/src/libvirt_sym.version	2007-03-12 11:09:50.000000000 +0000
+++ libvirt-caps-tmp/src/libvirt_sym.version	2007-03-12 14:07:55.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-tmp/src/proxy_internal.c
--- libvirt-cvs/src/proxy_internal.c	2007-03-12 10:40:33.000000000 +0000
+++ libvirt-caps-tmp/src/proxy_internal.c	2007-03-12 10:50:13.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-tmp/src/proxy_internal.h
--- libvirt-cvs/src/proxy_internal.h	2007-03-12 10:40:33.000000000 +0000
+++ libvirt-caps-tmp/src/proxy_internal.h	2007-03-12 10:50: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-tmp/src/qemu_internal.c
--- libvirt-cvs/src/qemu_internal.c	2007-03-12 10:40:22.000000000 +0000
+++ libvirt-caps-tmp/src/qemu_internal.c	2007-03-12 10:48:12.000000000 +0000
@@ -451,6 +451,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;
 
@@ -1171,6 +1196,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-tmp/src/test.c
--- libvirt-cvs/src/test.c	2007-03-12 10:40:24.000000000 +0000
+++ libvirt-caps-tmp/src/test.c	2007-03-12 12:47:18.000000000 +0000
@@ -43,6 +43,7 @@
                    unsigned long *hvVer);
 int testNodeGetInfo(virConnectPtr conn,
                     virNodeInfoPtr info);
+char *testGetCapabilities (virConnectPtr conn);
 int testNumOfDomains(virConnectPtr conn);
 int testListDomains(virConnectPtr conn,
                     int *ids,
@@ -96,6 +97,7 @@
     testGetVersion, /* version */
     NULL, /* getMaxVcpus */
     testNodeGetInfo, /* nodeGetInfo */
+    testGetCapabilities, /* getCapabilities */
     testListDomains, /* listDomains */
     testNumOfDomains, /* numOfDomains */
     testDomainCreateLinux, /* domainCreateLinux */
@@ -178,8 +180,11 @@
 static testNode *node = NULL;
 static int nextDomID = 1;
 
+#define TEST_MODEL "i686"
+#define TEST_MODEL_BITS "32"
+
 static const virNodeInfo defaultNodeInfo = {
-    "i686",
+    TEST_MODEL,
     1024*1024*3, /* 3 GB */
     16,
     1400,
@@ -808,6 +813,35 @@
     return (0);
 }
 
+char *
+testGetCapabilities (virConnectPtr conn)
+{
+    static char caps[] = "\
+<capabilities>\n\
+  <domain_type>test</domain_type>\n\
+  <host_features>\n\
+  </host_features>\n\
+  <guest_architectures>\n\
+    <guest_architecture>\n\
+      <model>" TEST_MODEL "</model>\n\
+      <bits>" TEST_MODEL_BITS "</bits>\n\
+      <guest_features>\n\
+        <accelerated/>\n\
+        <pae/>\n\
+      </guest_features>\n\
+    </guest_architecture>\n\
+  </guest_architectures>\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;
@@ -1377,6 +1411,11 @@
 }
 
 /*
+ * 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-tmp/src/virsh.c
--- libvirt-cvs/src/virsh.c	2007-03-12 10:40:35.000000000 +0000
+++ libvirt-caps-tmp/src/virsh.c	2007-03-12 10:50:15.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-tmp/src/virterror.c
--- libvirt-cvs/src/virterror.c	2007-03-12 10:40:36.000000000 +0000
+++ libvirt-caps-tmp/src/virterror.c	2007-03-12 10:50: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-tmp/src/xend_internal.c
--- libvirt-cvs/src/xend_internal.c	2007-03-12 10:40:28.000000000 +0000
+++ libvirt-caps-tmp/src/xend_internal.c	2007-03-12 10:48:24.000000000 +0000
@@ -68,6 +68,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-tmp/src/xen_internal.c
--- libvirt-cvs/src/xen_internal.c	2007-03-12 10:40:20.000000000 +0000
+++ libvirt-caps-tmp/src/xen_internal.c	2007-03-12 13:14:33.000000000 +0000
@@ -20,6 +20,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>
@@ -30,6 +32,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
@@ -70,6 +74,15 @@
 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 *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
  */
@@ -430,6 +443,7 @@
     xenHypervisorGetVersion, /* version */
     xenHypervisorNumOfMaxVcpus, /* getMaxVcpus */
     NULL, /* nodeGetInfo */
+    xenHypervisorGetCapabilities, /* getCapabilities */
     xenHypervisorListDomains, /* listDomains */
     xenHypervisorNumOfDomains, /* numOfDomains */
     NULL, /* domainCreateLinux */
@@ -468,9 +482,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
  */
@@ -484,7 +498,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));
 }
 
 /**
@@ -1137,7 +1175,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;
@@ -1150,6 +1188,31 @@
     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 (&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_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;
@@ -1359,6 +1422,204 @@
 }
 
 /**
+ * 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 hvm_enabled_in_bios = 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);
+    }
+
+    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:
+    /* If HVM in CPU, is it enabled also in the BIOS? */
+    if (strcmp (hvm_type, "") != 0) {
+        for (i = 0; i < nr_guest_archs; ++i)
+            if (guest_archs[i].hvm) {
+                hvm_enabled_in_bios = 1;
+                break;
+            }
+    }
+
+    /* Construct the final XML. */
+    xml = virBufferNew (1024);
+    if (!xml) return NULL;
+    r = virBufferAdd (xml,
+                      "\
+<capabilities>\n\
+  <domain_type>xen</domain_type>\n\
+  <host_features>\n", -1);
+    if (r == -1) return NULL;
+
+    if (strcmp (hvm_type, "") != 0) {
+        r = virBufferVSprintf (xml,
+                               "\
+    <hvm>\n\
+      <type>%s</type>\n\
+      <bios_setting>%s</bios_setting>\n\
+    </hvm>\n",
+                               hvm_type,
+                               hvm_enabled_in_bios ? "enabled" : "disabled");
+        if (r == -1) {
+        vir_buffer_failed:
+            virBufferFree (xml);
+            return NULL;
+        }
+    }
+    r = virBufferAdd (xml,
+                      "\
+  </host_features>\n\
+  <guest_architectures>\n", -1);
+    if (r == -1) goto vir_buffer_failed;
+
+    for (i = 0; i < nr_guest_archs; ++i) {
+        r = virBufferVSprintf (xml,
+                               "\
+    <guest_architecture>\n\
+      <model>%s</model>\n\
+      <bits>%d</bits>\n\
+      <guest_features>%s%s%s<accelerated/></guest_features>\n\
+    </guest_architecture>\n",
+                               guest_archs[i].model,
+                               guest_archs[i].bits,
+                               guest_archs[i].hvm ? "<hvm/> " : "",
+                               guest_archs[i].pae ? "<pae/> " : "",
+                               guest_archs[i].ia64_be ? "<ia64_be/> " : "");
+        if (r == -1) goto vir_buffer_failed;
+    }
+    r = virBufferAdd (xml,
+                      "\
+  </guest_architectures>\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
  *
@@ -1881,6 +2142,11 @@
 }
 
 /*
+ * 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-tmp/src/xen_internal.h
--- libvirt-cvs/src/xen_internal.h	2007-03-12 10:40:28.000000000 +0000
+++ libvirt-caps-tmp/src/xen_internal.h	2007-03-12 10:48:28.000000000 +0000
@@ -25,6 +25,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-tmp/src/xm_internal.c
--- libvirt-cvs/src/xm_internal.c	2007-03-12 10:40:31.000000000 +0000
+++ libvirt-caps-tmp/src/xm_internal.c	2007-03-12 10:48:31.000000000 +0000
@@ -77,6 +77,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-tmp/src/xml.h
--- libvirt-cvs/src/xml.h	2007-03-12 10:40:36.000000000 +0000
+++ libvirt-caps-tmp/src/xml.h	2007-03-12 13:40:11.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-tmp/src/xs_internal.c
--- libvirt-cvs/src/xs_internal.c	2007-03-12 10:40:21.000000000 +0000
+++ libvirt-caps-tmp/src/xs_internal.c	2007-03-12 10:48:12.000000000 +0000
@@ -46,6 +46,7 @@
     NULL, /* version */
     NULL, /* getMaxVcpus */
     NULL, /* nodeGetInfo */
+    NULL, /* getCapabilities */
     xenStoreListDomains, /* listDomains */
     NULL, /* numOfDomains */
     NULL, /* domainCreateLinux */
--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to