virConnectGetCapabilities patch, 2007-03-15 (version 2)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




This is the latest version of the capabilities patch, which should address all concerns which have been raised since the last version.

Also attached, example XML produced by different backends.

Note as before this has not been tested in the Xen case, because I don't have access to a working Xen machine (laptop still broken, desktop still lacking working SATA drivers, other desktop still lacking wired network...).

Rich.

--
Emerging Technologies, Red Hat  http://et.redhat.com/~rjones/
64 Baker Street, London, W1U 7DF     Mobile: +44 7866 314 421
 "[Negative numbers] darken the very whole doctrines of the equations
 and make dark of the things which are in their nature excessively
 obvious and simple" (Francis Maseres FRS, mathematician, 1759)
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@xxxxxxxxxx>
+ */
+
+#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@xxxxxxxxxx>
+ */
+
+#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 15:55:51.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,46 @@
     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[] = { 
-    {  "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" },
+struct qemu_arch_info qemudArchs[] = { 
+    /* i686 must be in position 0 */
+    {  "i686", 32, arch_info_x86_machines, "qemu" },
+    /* x86_64 must be in position 1 */
+    {  "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" },
+    { NULL, -1, 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 +173,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 +2352,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 +2385,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 +2447,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 +2485,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 +2516,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 +2560,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 +2578,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 +2603,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 +2623,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 +2646,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 15:54:53.000000000 +0000
@@ -78,6 +78,14 @@
                                          struct qemud_network *network,
                                          struct qemud_network_def *def);
 
+struct qemu_arch_info {
+    const char *arch;
+    int wordsize;
+    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 16:05:56.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,178 @@
     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;
+
+    /* Really, this never fails - look at the man-page. */
+    uname (&utsname);
+
+    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 = bufferVSprintf (xml,
+                        "\
+<capabilities>\n\
+  <host>\n\
+    <cpu>\n\
+      <arch>%s</arch>\n\
+    </cpu>\n\
+  </host>\n",
+                        utsname.machine);
+    if (r == -1) {
+    vir_buffer_failed:
+        bufferFree (xml);
+        qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+        qemudDispatchFailure (server, client, out);
+        return 0;
+    }
+
+    i = -1;
+    if (strcmp (utsname.machine, "i686") == 0) i = 0;
+    else if (strcmp (utsname.machine, "x86_64") == 0) i = 1;
+    if (i >= 0) {
+        /* For the default (PC-like) guest, qemudArchs[0] or [1]. */
+        r = bufferVSprintf (xml,
+                            "\
+\n\
+  <guest>\n\
+    <os_type>hvm</os_type>\n\
+    <arch name=\"%s\">\n\
+      <wordsize>%d</wordsize>\n\
+      <emulator>/usr/bin/%s</emulator>\n\
+      <domain type=\"qemu\"/>\n",
+                            qemudArchs[i].arch,
+                            qemudArchs[i].wordsize,
+                            qemudArchs[i].binary);
+        if (r == -1) goto vir_buffer_failed;
+
+        for (j = 0; qemudArchs[i].machines[j]; ++j) {
+            r = bufferVSprintf (xml,
+                                "\
+      <machine>%s</machine>\n",
+                                qemudArchs[i].machines[j]);
+            if (r == -1) goto vir_buffer_failed;
+        }
+
+        if (have_kqemu) {
+            r = bufferAdd (xml,
+                           "\
+      <domain type=\"kqemu\"/>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        if (have_kvm) {
+            r = bufferAdd (xml,
+                           "\
+      <domain type=\"kvm\">\n\
+        <emulator>/usr/bin/qemu-kvm</emulator>\n\
+      </domain>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        r = bufferAdd (xml,
+                       "\
+    </arch>\n\
+  </guest>\n", -1);
+        if (r == -1) goto vir_buffer_failed;
+
+        /* The "other" PC architecture needs emulation. */
+        i = i ^ 1;
+        r = bufferVSprintf (xml,
+                            "\
+\n\
+  <guest>\n\
+    <os_type>hvm</os_type>\n\
+    <arch name=\"%s\">\n\
+      <wordsize>%d</wordsize>\n\
+      <emulator>/usr/bin/%s</emulator>\n\
+      <domain type=\"qemu\"/>\n",
+                            qemudArchs[i].arch,
+                            qemudArchs[i].wordsize,
+                            qemudArchs[i].binary);
+        if (r == -1) goto vir_buffer_failed;
+        for (j = 0; qemudArchs[i].machines[j]; ++j) {
+            r = bufferVSprintf (xml,
+                                "\
+      <machine>%s</machine>\n",
+                                qemudArchs[i].machines[j]);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        r = bufferAdd (xml,
+                       "\
+    </arch>\n\
+  </guest>\n", -1);
+        if (r == -1) goto vir_buffer_failed;
+    }
+
+    /* The non-PC architectures, qemudArchs[>=2]. */
+    for (i = 2; qemudArchs[i].arch; ++i) {
+        r = bufferVSprintf (xml,
+                            "\
+\n\
+  <guest>\n\
+    <os_type>hvm</os_type>\n\
+    <arch name=\"%s\">\n\
+      <wordsize>%d</wordsize>\n\
+      <emulator>/usr/bin/%s</emulator>\n\
+      <domain type=\"qemu\"/>\n",
+                            qemudArchs[i].arch,
+                            qemudArchs[i].wordsize,
+                            qemudArchs[i].binary);
+        if (r == -1) goto vir_buffer_failed;
+        for (j = 0; qemudArchs[i].machines[j]; ++j) {
+            r = bufferVSprintf (xml,
+                                "\
+      <machine>%s</machine>\n",
+                                qemudArchs[i].machines[j]);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        r = bufferAdd (xml,
+                       "\
+    </arch>\n\
+  </guest>\n", -1);
+        if (r == -1) goto vir_buffer_failed;
+    }
+
+    /* Finish off. */
+    r = bufferAdd (xml,
+                      "\
+</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 +1029,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 16:06:46.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,11 @@
 static testNode *node = NULL;
 static int nextDomID = 1;
 
+#define TEST_MODEL "i686"
+#define TEST_MODEL_WORDSIZE "32"
+
 static const virNodeInfo defaultNodeInfo = {
-    "i686",
+    TEST_MODEL,
     1024*1024*3, /* 3 GB */
     16,
     1400,
@@ -809,6 +814,43 @@
     return (0);
 }
 
+char *
+testGetCapabilities (virConnectPtr conn)
+{
+    static char caps[] = "\
+<capabilities>\n\
+  <host>\n\
+    <cpu>\n\
+      <arch>" TEST_MODEL "</arch>\n\
+      <features>\n\
+        <pae/>\n\
+        <nonpae/>\n\
+      </features>\n\
+    </cpu>\n\
+  </host>\n\
+\n\
+  <guest>\n\
+    <os_type>linux</os_type>\n\
+    <arch name=\"" TEST_MODEL "\">\n\
+      <wordsize>" TEST_MODEL_WORDSIZE "</wordsize>\n\
+      <domain type=\"test\"/>\n\
+    </arch>\n\
+    <features>\n\
+      <pae/>\n\
+      <nonpae/>\n\
+    </features>\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 +1421,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-15 15:11:50.000000000 +0000
+++ libvirt-caps/src/virsh.c	2007-03-15 15:11:53.000000000 +0000
@@ -1550,6 +1550,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[] = {
@@ -2380,6 +2407,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 15:11:52.000000000 +0000
+++ libvirt-caps/src/xen_internal.c	2007-03-15 15:33:23.000000000 +0000
@@ -22,6 +22,9 @@
 #include <sys/ioctl.h>
 #include <limits.h>
 #include <stdint.h>
+#include <regex.h>
+#include <errno.h>
+#include <sys/utsname.h>
 
 /* required for dom0_getdomaininfo_t */
 #include <xen/dom0_ops.h>
@@ -32,6 +35,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 +77,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 +448,7 @@
     xenHypervisorGetVersion, /* version */
     xenHypervisorNumOfMaxVcpus, /* getMaxVcpus */
     NULL, /* nodeGetInfo */
+    xenHypervisorGetCapabilities, /* getCapabilities */
     xenHypervisorListDomains, /* listDomains */
     xenHypervisorNumOfDomains, /* numOfDomains */
     NULL, /* domainCreateLinux */
@@ -470,9 +487,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 +503,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 +1180,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 +1193,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 +1438,242 @@
 }
 
 /**
+ * xenHypervisorGetCapabilities:
+ * @conn: pointer to the connection block
+ *
+ * Return the capabilities of this hypervisor.
+ */
+char *
+xenHypervisorGetCapabilities (virConnectPtr conn)
+{
+    struct utsname utsname;
+    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 *token;
+        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;
+
+    /* Really, this never fails - look at the man-page. */
+    uname (&utsname);
+
+    /* /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].token = token;
+            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 = virBufferVSprintf (xml,
+                           "\
+<capabilities>\n\
+  <host>\n\
+    <cpu>\n\
+      <arch>%s</arch>\n\
+      <features>\n",
+                           utsname.machine);
+    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\
+    </cpu>\n\
+  </host>\n", -1);
+    if (r == -1) goto vir_buffer_failed;
+
+    for (i = 0; i < nr_guest_archs; ++i) {
+        r = virBufferVSprintf (xml,
+                               "\
+\n\
+  <!-- %s -->\n\
+  <guest>\n\
+    <os_type>%s</os_type>\n\
+    <arch name=\"%s\">\n\
+      <wordsize>%d</wordsize>\n\
+      <domain type=\"xen\"></domain>\n\
+      <emulator>/usr/lib%s/xen/bin/qemu-dm</emulator>\n",
+                               guest_archs[i].token,
+                               guest_archs[i].hvm ? "hvm" : "xen",
+                               guest_archs[i].model,
+                               guest_archs[i].bits,
+                               guest_archs[i].bits == 64 ? "64" : "");
+        if (r == -1) goto vir_buffer_failed;
+        if (guest_archs[i].hvm) {
+            r = virBufferAdd (xml,
+                              "\
+      <machine>pc</machine>\n\
+      <machine>isapc</machine>\n\
+      <loader>/usr/lib/xen/boot/hvmloader</loader>\n", -1);
+            if (r == -1) goto vir_buffer_failed;
+        }
+        r = virBufferAdd (xml,
+                          "\
+    </arch>\n\
+    <features>", -1);
+        if (r == -1) goto vir_buffer_failed;
+        if (guest_archs[i].pae) {
+            r = virBufferAdd (xml,
+                              "\
+        <pae/>\n\
+        <nonpae/>\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;
+        }
+        r = virBufferAdd (xml,
+                          "\
+    </features>\n\
+  </guest>\n", -1);
+        if (r == -1) goto vir_buffer_failed;
+    }
+    r = virBufferAdd (xml,
+                      "\
+</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
  *
@@ -1886,6 +2199,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 */
<capabilities>
  <host>
    <cpu>
      <arch>x86_64</arch>
    </cpu>
  </host>

  <guest>
    <os_type>hvm</os_type>
    <arch name="x86_64">
      <wordsize>64</wordsize>
      <emulator>/usr/bin/qemu-system-x86_64</emulator>
      <domain type="qemu"/>
      <machine>pc</machine>
      <machine>isapc</machine>
      <domain type="kqemu"/>
      <domain type="kvm">
        <emulator>/usr/bin/qemu-kvm</emulator>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="i686">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu</emulator>
      <domain type="qemu"/>
      <machine>pc</machine>
      <machine>isapc</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="mips">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-mips</emulator>
      <domain type="qemu"/>
      <machine>mips</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="mipsel">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-mipsel</emulator>
      <domain type="qemu"/>
      <machine>mips</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="sparc">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-sparc</emulator>
      <domain type="qemu"/>
      <machine>sun4m</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="ppc">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-ppc</emulator>
      <domain type="qemu"/>
      <machine>g3bw</machine>
      <machine>mac99</machine>
      <machine>prep</machine>
    </arch>
  </guest>
</capabilities>


<capabilities>
  <host>
    <cpu>
      <arch>x86_64</arch>
    </cpu>
  </host>

  <guest>
    <os_type>hvm</os_type>
    <arch name="x86_64">
      <wordsize>64</wordsize>
      <emulator>/usr/bin/qemu-system-x86_64</emulator>
      <domain type="qemu"/>
      <machine>pc</machine>
      <machine>isapc</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="i686">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu</emulator>
      <domain type="qemu"/>
      <machine>pc</machine>
      <machine>isapc</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="mips">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-mips</emulator>
      <domain type="qemu"/>
      <machine>mips</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="mipsel">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-mipsel</emulator>
      <domain type="qemu"/>
      <machine>mips</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="sparc">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-sparc</emulator>
      <domain type="qemu"/>
      <machine>sun4m</machine>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name="ppc">
      <wordsize>32</wordsize>
      <emulator>/usr/bin/qemu-system-ppc</emulator>
      <domain type="qemu"/>
      <machine>g3bw</machine>
      <machine>mac99</machine>
      <machine>prep</machine>
    </arch>
  </guest>
</capabilities>


<capabilities>
  <host>
    <cpu>
      <arch>i686</arch>
      <features>
        <pae/>
        <nonpae/>
      </features>
    </cpu>
  </host>

  <guest>
    <os_type>linux</os_type>
    <arch name="i686">
      <wordsize>32</wordsize>
      <domain type="test"/>
    </arch>
    <features>
      <pae/>
      <nonpae/>
    </features>
  </guest>
</capabilities>


Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]