This patch:* Adds virConnectGetCapabilities which returns an XML description of the capabilities of the driver or hypervisor under this connection (see below for more about the XML format).
* Adds virsh capabilities command. * Checks the Python binding works. Caveats:* Xen implementation (in xen_internal.c) is not tested because I don't have a working Xen machine right now. QEMU, test and remote work however.
Example: $ virsh -c test:///default capabilities | tidy -xml -i -q <capabilities> <domain> <type>test</type> </domain> <host_features></host_features> <guest_architectures> <guest_architecture> <model>i686</model> <bits>32</bits> <guest_features> <accelerated /> <pae /> </guest_features> </guest_architecture> </guest_architectures> </capabilities> $ virsh -c qemu:///session capabilities | tidy -xml -i -q <capabilities> <domain> <type>qemu</type> </domain> <guest_architectures> <guest_architecture> <model>i686</model> <bits>32</bits> <features> <emulated /> </features> </guest_architecture> <guest_architecture> <model>x86_64</model> <bits>64</bits> <features> <emulated /> </features> </guest_architecture> [... other archs deleted ...] </guest_architectures> </capabilities> XML format:The <capabilities> node contains information about the host and a list of supported architectures for guests. About the host we return:
<domain> <type> The default type acceptable when creating a domain. <host_features> <hvm> Does the host CPU support HVM? <type> Type of HVM (eg. "vmx") <bios_setting> "enabled" or "disabled" About the guest architectures we can return: <guest_architecture> <model> The (virtualised) CPU <bits> Bits <domain> <type> If different from the default type (eg. for kqemu) <features> <hvm> Full virt guest? <accelerated> Accelerated (eg. Xen or kqemu) <emulated> Emulated (eg. qemu or bochs) (and a few other esoteric flags here) 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-tmp/configure.in --- libvirt-cvs/configure.in 2007-03-06 12:00:03.000000000 +0000 +++ libvirt-caps-tmp/configure.in 2007-03-09 13:08:57.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-02-16 17:06:38.000000000 +0000 +++ libvirt-caps-tmp/.cvsignore 2007-03-09 13:08:57.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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/include/libvirt/libvirt.h.in 2007-03-09 13:08:57.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-02-14 15:40:54.000000000 +0000 +++ libvirt-caps-tmp/include/libvirt/virterror.h 2007-03-09 13:08:57.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-02 11:05:16.000000000 +0000 +++ libvirt-caps-tmp/proxy/libvirt_proxy.c 2007-03-09 13:08:57.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/proxy/Makefile.am libvirt-caps-tmp/proxy/Makefile.am --- libvirt-cvs/proxy/Makefile.am 2007-03-02 11:05:16.000000000 +0000 +++ libvirt-caps-tmp/proxy/Makefile.am 2007-03-09 13:08:57.000000000 +0000 @@ -10,7 +10,8 @@ libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xend_internal.c \ @top_srcdir@/src/xen_internal.c @top_srcdir@/src/virterror.c \ @top_srcdir@/src/sexpr.c @top_srcdir@/src/xml.c \ - @top_srcdir@/src/xs_internal.c + @top_srcdir@/src/xs_internal.c \ + @top_srcdir@/src/lib.c @top_srcdir@/src/lib.h libvirt_proxy_LDFLAGS = libvirt_proxy_DEPENDENCIES = libvirt_proxy_LDADD = 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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/qemud/conf.c 2007-03-09 13:08:57.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-02-23 17:15:18.000000000 +0000 +++ libvirt-caps-tmp/qemud/conf.h 2007-03-09 13:08:57.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-02-23 09:03:25.000000000 +0000 +++ libvirt-caps-tmp/qemud/dispatch.c 2007-03-09 13:08:57.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 "lib.h" static int qemudDispatchFailure(struct qemud_server *server ATTRIBUTE_UNUSED, @@ -100,6 +103,149 @@ return 0; } +static int +qemudDispatchGetCapabilities (struct qemud_server *server, + struct qemud_client *client, + struct qemud_packet *in, + struct qemud_packet *out) +{ + char *xml, *xml_guest_archs; + int len; + struct utsname utsname; + struct qemud_guest_arch *guest_archs; + int nr_guest_archs, i; + int have_kqemu = 0; + int have_kvm = 0; + + 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. */ + /* First the guest architectures for basic <domain type='qemu'>, + * all emulated (even x86 on x86). + */ + xml_guest_archs = NULL; + nr_guest_archs = qemudGetGuestArchitectures (&guest_archs); + for (i = 0; i < nr_guest_archs; ++i) { + char bits[16]; + snprintf (bits, sizeof bits, "%d", guest_archs[i].bits); + + char *old_xml = xml_guest_archs; + xml_guest_archs = strjoin + ("\n", + xml_guest_archs, + "<guest_architecture>", + "<model>", guest_archs[i].model, "</model>", + "<bits>", bits, "</bits>", + "<features>", + "<emulated/>", + "</features>", + "</guest_architecture>", + NULL); + free (old_xml); + if (!xml_guest_archs) { + qemudReportError (server, VIR_ERR_NO_MEMORY, NULL); + qemudDispatchFailure (server, client, out); + free (guest_archs); + free (xml_guest_archs); + return 0; + } + } + free (guest_archs); + + /* Really, this never fails - look at the man-page. */ + uname (&utsname); + + /* 32 or 64 bit host? */ + const char *bits = strstr (utsname.machine, "64") != NULL ? "64" : "32"; + + /* If we have kqemu, then there is a <domain type='kqemu'>, + * accelerated, but the model is limited to host == guest. + */ + if (have_kqemu) { + char *old_xml = xml_guest_archs; + xml_guest_archs = strjoin + ("\n", + xml_guest_archs, + "<guest_architecture>", + "<domain><type>kqemu</type></domain>", + "<model>", utsname.machine, "</model>", + "<bits>", bits, "</bits>", + "<features>", + "<accelerated/>", + /* XXX There is no mention of PAE in the qemu docs. */ + "</features>", + "</guest_architecture>", + NULL); + free (old_xml); + if (!xml_guest_archs) { + qemudReportError (server, VIR_ERR_NO_MEMORY, NULL); + qemudDispatchFailure (server, client, out); + free (xml_guest_archs); + return 0; + } + } + + /* If we have kvm, then there is a <domain type='kvm'>, + * accelerated, HVM, but the model is limited to host == guest. + */ + if (have_kvm) { + char *old_xml = xml_guest_archs; + xml_guest_archs = strjoin + ("\n", + xml_guest_archs, + "<guest_architecture>", + "<domain><type>kvm</type></domain>", + "<model>", utsname.machine, "</model>", + "<bits>", bits, "</bits>", + "<features>", + "<hvm/>", + "<accelerated/>", + /* XXX Does KVM support PAE inside the guest? */ + "</features>", + "</guest_architecture>", + NULL); + free (old_xml); + if (!xml_guest_archs) { + qemudReportError (server, VIR_ERR_NO_MEMORY, NULL); + qemudDispatchFailure (server, client, out); + free (xml_guest_archs); + return 0; + } + } + + /* Finally build the full capabilities. */ + xml = strjoin + ("\n", + "<capabilities>", + "<domain><type>qemu</type></domain>", + "<guest_architectures>", + xml_guest_archs, + "</guest_architectures>", + "</capabilities>", + NULL); + free (xml_guest_archs); + if (!xml) { + qemudReportError (server, VIR_ERR_NO_MEMORY, NULL); + qemudDispatchFailure (server, client, out); + return 0; + } + + /* Copy the XML into the outgoing packet, assuming it's not too large. */ + len = strlen (xml); + if (len > QEMUD_MAX_XML_LEN) { + qemudReportError (server, VIR_ERR_XML_ERROR, NULL); + qemudDispatchFailure (server, client, out); + return -1; + } + out->header.type = QEMUD_PKT_GET_CAPABILITIES; + out->header.dataSize = len; + strcpy (out->data.getCapabilitiesReply.xml, 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 +1000,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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/qemud/Makefile.am 2007-03-09 13:08:57.000000000 +0000 @@ -10,10 +10,12 @@ conf.c conf.h \ bridge.c bridge.h \ iptables.c iptables.h \ - uuid.c uuid.h + uuid.c uuid.h \ + @top_srcdir@/src/lib.c @top_srcdir@/src/lib.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) \ + -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src \ + $(LIBXML_CFLAGS) \ $(WARN_CFLAGS) -DLOCAL_STATE_DIR="\"$(localstatedir)\"" \ -DSYSCONF_DIR="\"$(sysconfdir)\"" libvirt_qemud_LDFLAGS = $(LIBXML_LIBS) $(SYSFS_LIBS) 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-02-23 09:03:25.000000000 +0000 +++ libvirt-caps-tmp/qemud/protocol.h 2007-03-09 13:08:57.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-tmp/src/driver.h --- libvirt-cvs/src/driver.h 2007-03-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/src/driver.h 2007-03-09 13:08:57.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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/src/internal.h 2007-03-09 13:08:57.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/lib.c libvirt-caps-tmp/src/lib.c --- libvirt-cvs/src/lib.c 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-caps-tmp/src/lib.c 2007-03-09 13:08:57.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * lib.c: some private library functions shared between libvirt source + * files + * + * Copyright (C) 2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Note: The linker script ensures that these functions are not exported + * from libvirt, even though they are not static. + */ + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "lib.h" + +/** + * strjoin: + * @sep: Separator string + * @str1: First string to join + * + * Join a list of strings, placing @sep between each + * string. The list of strings begins at @str1 and finishes + * with a NULL. + * + * If @str1 is NULL, it is treated as the empty string. + * + * Returns the joined string, or NULL if memory could not be + * allocated. + */ +char * +strjoin (const char *sep, const char *str1, ...) +{ + int len, seplen; + char *str, *rtn, *tmp; + va_list v1, v2; + + va_start (v1, str1); + va_copy (v2, v1); + + /* Find out how much memory to allocate. */ + len = str1 ? strlen (str1) : 0; + seplen = strlen (sep); + while ((str = va_arg (v1, char *)) != 0) + len += seplen + strlen (str); + len++; /* for the \0-terminator */ + + va_end (v1); + + /* Copy the strings. */ + tmp = rtn = malloc (len); + if (!rtn) goto done; + + if (str1) { + strcpy (tmp, str1); + tmp += strlen (str1); + } + while ((str = va_arg (v2, char *)) != 0) { + strcpy (tmp, sep); + tmp += seplen; + strcpy (tmp, str); + tmp += strlen (str); + } + + done: + va_end (v2); + return rtn; +} + +/* + * 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/lib.h libvirt-caps-tmp/src/lib.h --- libvirt-cvs/src/lib.h 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-caps-tmp/src/lib.h 2007-03-09 13:08:57.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * lib.c: some private library functions shared between libvirt source + * files + * + * Copyright (C) 2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + */ + +#ifndef __VIR_LIB_H__ +#define __VIR_LIB_H__ + +char *strjoin (const char *sep, const char *str1, ...); + +#endif /* __VIR_LIB_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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/src/libvirt.c 2007-03-09 13:08:57.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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/src/libvirt_sym.version 2007-03-09 13:08:57.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/Makefile.am libvirt-caps-tmp/src/Makefile.am --- libvirt-cvs/src/Makefile.am 2007-03-02 11:05:16.000000000 +0000 +++ libvirt-caps-tmp/src/Makefile.am 2007-03-09 13:08:57.000000000 +0000 @@ -18,6 +18,7 @@ libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) libvirt_la_SOURCES = \ libvirt.c internal.h \ + lib.c lib.h \ hash.c hash.h \ test.c test.h \ xml.c xml.h \ 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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/src/proxy_internal.c 2007-03-09 13:08:57.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 2006-11-07 16:28:16.000000000 +0000 +++ libvirt-caps-tmp/src/proxy_internal.h 2007-03-09 13:08:57.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-09 12:23:50.000000000 +0000 +++ libvirt-caps-tmp/src/qemu_internal.c 2007-03-09 13:08:57.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-09 12:23:51.000000000 +0000 +++ libvirt-caps-tmp/src/test.c 2007-03-09 13:08:57.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</type></domain>\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-09 14:39:48.000000000 +0000 +++ libvirt-caps-tmp/src/virsh.c 2007-03-09 14:39:59.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-02-14 15:40:54.000000000 +0000 +++ libvirt-caps-tmp/src/virterror.c 2007-03-09 13:10:41.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-09 12:23:51.000000000 +0000 +++ libvirt-caps-tmp/src/xend_internal.c 2007-03-09 13:12:25.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-09 12:23:51.000000000 +0000 +++ libvirt-caps-tmp/src/xen_internal.c 2007-03-09 13:12:25.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 "lib.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,207 @@ } /** + * 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; + + 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; + const char *bits; + int hvm; + int pae; + int ia64_be; + } guest_archs[max_guest_archs]; + int nr_guest_archs = 0; + + char *xml, *xml_host_features, *xml_guest_archs; + + /* /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. */ + if (strcmp (hvm_type, "") == 0) + xml_host_features = strdup (""); + else + xml_host_features = strjoin + ("\n" + "<hvm>", + "<type>", hvm_type, "</type>", + "<bios_setting>", + hvm_enabled_in_bios ? "enabled" : "disabled", + "</bios_setting>", + "</hvm>", + NULL); + if (!xml_host_features) { + virXenError (VIR_ERR_NO_MEMORY, __FUNCTION__, 0); + return NULL; + } + + xml_guest_archs = NULL; + for (i = 0; i < nr_guest_archs; ++i) { + char *old_xml = xml_guest_archs; + xml_guest_archs = strjoin + ("\n", + xml_guest_archs, + "<guest_architecture>", + "<model>", guest_archs[i].model, "</model>", + "<bits>", guest_archs[i].bits, "</bits>", + "<guest_features>", + guest_archs[i].hvm ? "<hvm/>" : "", + guest_archs[i].pae ? "<pae/>" : "", + guest_archs[i].ia64_be ? "<ia64_be/>" : "", + "<accelerated/>", + "</guest_features>", + "</guest_architecture>", + NULL); + free (old_xml); + if (!xml_guest_archs) { + virXenError (VIR_ERR_NO_MEMORY, __FUNCTION__, 0); + free (xml_host_features); + return NULL; + } + } + + xml = strjoin + ("\n", + "<capabilities>", + "<domain><type>xen</type></domain>", + "<host_features>", + xml_host_features, + "</host_features>", + "<guest_architectures>", + xml_guest_archs, + "</guest_architectures>", + "</capabilities>\n", + NULL); + free (xml_host_features); + free (xml_guest_archs); + if (!xml) { + virXenError (VIR_ERR_NO_MEMORY, __FUNCTION__, 0); + return NULL; + } + + return xml; +} + +/** * xenHypervisorNumOfDomains: * @conn: pointer to the connection block * @@ -1881,6 +2145,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-09 12:23:51.000000000 +0000 +++ libvirt-caps-tmp/src/xen_internal.h 2007-03-09 13:12:25.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-09 12:23:51.000000000 +0000 +++ libvirt-caps-tmp/src/xm_internal.c 2007-03-09 13:12:25.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/xs_internal.c libvirt-caps-tmp/src/xs_internal.c --- libvirt-cvs/src/xs_internal.c 2007-03-09 12:23:51.000000000 +0000 +++ libvirt-caps-tmp/src/xs_internal.c 2007-03-09 13:12:25.000000000 +0000 @@ -46,6 +46,7 @@ NULL, /* version */ NULL, /* getMaxVcpus */ NULL, /* nodeGetInfo */ + NULL, /* getCapabilities */ xenStoreListDomains, /* listDomains */ NULL, /* numOfDomains */ NULL, /* domainCreateLinux */
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature