From 3e6f148988ad7d0e61cdc821bd972dec7b9a5300 Mon Sep 17 00:00:00 2001
From: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com>
Date: Thu, 29 Aug 2013 17:18:52 +0200
Subject: [PATCH 10/60] libxkutil: Provide easy access to the libvirt
 capabilities

Introspecting the libvirt capabilities and creating an internal capabilities
data structure. Methods are provided for retrieving default values regarding
architecture, machine and emulator for easy of use in the provider code.

Changed the KVM detection to use the capabilities instead of unique
XML parsing.

Further, xml_parse_test was extendend to display hypervisor capabilities
and defaults.

Signed-off-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com>
Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
---
 libxkutil/Makefile.am          |   2 +
 libxkutil/capability_parsing.c | 551 +++++++++++++++++++++++++++++++++++++++++
 libxkutil/capability_parsing.h |  97 ++++++++
 libxkutil/device_parsing.c     |  29 ---
 libxkutil/device_parsing.h     |   2 -
 libxkutil/xml_parse_test.c     | 201 ++++++++++++++-
 6 files changed, 848 insertions(+), 34 deletions(-)
 create mode 100644 libxkutil/capability_parsing.c
 create mode 100644 libxkutil/capability_parsing.h

diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am
index 8d436ad..dd7be55 100644
--- a/libxkutil/Makefile.am
+++ b/libxkutil/Makefile.am
@@ -7,6 +7,7 @@ noinst_HEADERS = \
	cs_util.h \
	misc_util.h \
	device_parsing.h \
+	capability_parsing.h \
	xmlgen.h \
	infostore.h \
	pool_parsing.h \
@@ -20,6 +21,7 @@ libxkutil_la_SOURCES = \
	cs_util_instance.c \
	misc_util.c \
	device_parsing.c \
+	capability_parsing.c \
	xmlgen.c \
	infostore.c \
	pool_parsing.c \
diff --git a/libxkutil/capability_parsing.c b/libxkutil/capability_parsing.c
new file mode 100644
index 0000000..2acd45b
--- /dev/null
+++ b/libxkutil/capability_parsing.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright IBM Corp. 2013
+ *
+ * Authors:
+ *  Boris Fiuczynski <fiuczy@linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <stdint.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libvirt/libvirt.h>
+#include <libxml/xpath.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include "misc_util.h"
+#include "capability_parsing.h"
+#include "xmlgen.h"
+#include "../src/svpc_types.h"
+
+static void cleanup_cap_machine(struct cap_machine *machine)
+{
+        if (machine == NULL)
+                return;
+        free(machine->name);
+        free(machine->canonical_name);
+}
+
+static void cleanup_cap_domain_info(struct cap_domain_info *cgdi)
+{
+        int i;
+        if (cgdi == NULL)
+                return;
+        free(cgdi->emulator);
+        free(cgdi->loader);
+        for (i = 0; i < cgdi->num_machines; i++)
+                cleanup_cap_machine(&cgdi->machines[i]);
+        free(cgdi->machines);
+}
+
+static void cleanup_cap_domain(struct cap_domain *cgd)
+{
+        if (cgd == NULL)
+                return;
+        free(cgd->typestr);
+        cleanup_cap_domain_info(&cgd->guest_domain_info);
+}
+
+static void cleanup_cap_arch(struct cap_arch *cga)
+{
+        int i;
+        if (cga == NULL)
+                return;
+        free(cga->name);
+        cleanup_cap_domain_info(&cga->default_domain_info);
+        for (i = 0; i < cga->num_domains; i++)
+                cleanup_cap_domain(&cga->domains[i]);
+        free(cga->domains);
+}
+
+static void cleanup_cap_guest(struct cap_guest *cg)
+{
+        if (cg == NULL)
+                return;
+        free(cg->ostype);
+        cleanup_cap_arch(&cg->arch);
+}
+
+static void cleanup_cap_host(struct cap_host *ch)
+{
+        if (ch == NULL)
+                return;
+        free(ch->cpu_arch);
+}
+
+void cleanup_capabilities(struct capabilities **caps)
+{
+        int i;
+        struct capabilities *cap;
+
+        if ((caps == NULL) || (*caps == NULL))
+                return;
+
+        cap = *caps;
+        cleanup_cap_host(&cap->host);
+        for (i = 0; i < cap->num_guests; i++)
+                cleanup_cap_guest(&cap->guests[i]);
+
+        free(cap->guests);
+        free(cap);
+        *caps = NULL;
+}
+
+static void extend_cap_machines(struct cap_domain_info *cg_domaininfo,
+                                char *name, char *canonical_name)
+{
+        struct cap_machine *tmp_list = NULL;
+        tmp_list = realloc(cg_domaininfo->machines,
+                           (cg_domaininfo->num_machines + 1) *
+                           sizeof(struct cap_machine));
+
+        if (tmp_list == NULL) {
+                /* Nothing you can do. Just go on. */
+                CU_DEBUG("Could not alloc space for "
+                         "guest domain info list");
+                return;
+        }
+        cg_domaininfo->machines = tmp_list;
+
+        struct cap_machine *cap_gm =
+                &cg_domaininfo->machines[cg_domaininfo->num_machines];
+        cap_gm->name = name;
+        cap_gm->canonical_name = canonical_name;
+        cg_domaininfo->num_machines++;
+}
+
+static void parse_cap_domain_info(struct cap_domain_info *cg_domaininfo,
+                                  xmlNode *domain_child_node)
+{
+        CU_DEBUG("Capabilities guest domain info element node: %s",
+                 domain_child_node->name);
+
+        if (XSTREQ(domain_child_node->name, "emulator")) {
+                cg_domaininfo->emulator =
+                        get_node_content(domain_child_node);
+        } else if (XSTREQ(domain_child_node->name, "loader")) {
+                cg_domaininfo->loader =
+                        get_node_content(domain_child_node);
+        } else if (XSTREQ(domain_child_node->name, "machine")) {
+                extend_cap_machines(cg_domaininfo,
+                                    get_node_content(domain_child_node),
+                                    get_attr_value(domain_child_node,
+                                                   "canonical"));
+        }
+}
+
+static void parse_cap_domain(struct cap_domain *cg_domain,
+                             xmlNode *guest_dom)
+{
+        CU_DEBUG("Capabilities guest domain node: %s", guest_dom->name);
+
+        xmlNode *child;
+
+        cg_domain->typestr = get_attr_value(guest_dom, "type");
+
+        for (child = guest_dom->children; child != NULL; child = child->next)
+                parse_cap_domain_info(&cg_domain->guest_domain_info, child);
+}
+
+static void parse_cap_arch(struct cap_arch *cg_archinfo,
+                           xmlNode *arch)
+{
+        CU_DEBUG("Capabilities arch node: %s", arch->name);
+
+        xmlNode *child;
+
+        cg_archinfo->name = get_attr_value(arch, "name");
+
+        for (child = arch->children; child != NULL; child = child->next) {
+                if (XSTREQ(child->name, "wordsize")) {
+                        char *wordsize_str;
+                        unsigned int wordsize;
+                        wordsize_str = get_node_content(child);
+                        /* Default to 0 wordsize if garbage */
+                        if (wordsize_str == NULL ||
+                            sscanf(wordsize_str, "%i", &wordsize) != 1)
+                                wordsize = 0;
+                        free(wordsize_str);
+                        cg_archinfo->wordsize = wordsize;
+                } else if (XSTREQ(child->name, "domain")) {
+                        struct cap_domain *tmp_list = NULL;
+                        tmp_list = realloc(cg_archinfo->domains,
+                                           (cg_archinfo->num_domains + 1) *
+                                           sizeof(struct cap_domain));
+                        if (tmp_list == NULL) {
+                                /* Nothing you can do. Just go on. */
+                                CU_DEBUG("Could not alloc space for "
+                                         "guest domain");
+                                continue;
+                        }
+                        memset(&tmp_list[cg_archinfo->num_domains],
+                               0, sizeof(struct cap_domain));
+                        cg_archinfo->domains = tmp_list;
+                        parse_cap_domain(&cg_archinfo->
+                                         domains[cg_archinfo->num_domains],
+                                         child);
+                        cg_archinfo->num_domains++;
+                } else {
+                        /* Check for the default domain child nodes */
+                        parse_cap_domain_info(&cg_archinfo->default_domain_info,
+                                              child);
+                }
+        }
+}
+
+static void parse_cap_guests(xmlNodeSet *nsv, struct cap_guest *cap_guests)
+{
+        xmlNode **nodes = nsv->nodeTab;
+        xmlNode *child;
+        int numGuestNodes = nsv->nodeNr;
+        int i;
+
+        for (i = 0; i < numGuestNodes; i++) {
+                for (child = nodes[i]->children; child != NULL;
+                     child = child->next) {
+                        if (XSTREQ(child->name, "os_type")) {
+                                STRPROP((&cap_guests[i]), ostype, child);
+                        } else if (XSTREQ(child->name, "arch")) {
+                                parse_cap_arch(&cap_guests[i].arch, child);
+                        }
+                }
+        }
+}
+
+static int parse_cap_host_cpu(struct cap_host *cap_host, xmlNode *cpu)
+{
+        xmlNode *child;
+
+        for (child = cpu->children; child != NULL; child = child->next) {
+                if (XSTREQ(child->name, "arch")) {
+                        cap_host->cpu_arch = get_node_content(child);
+                        if (cap_host->cpu_arch != NULL)
+                                return 1; /* success - host arch node found */
+                        else {
+                                CU_DEBUG("Host architecture is not defined");
+                                break;
+                        }
+                }
+        }
+        return 0; /* error - no arch node or empty arch node */
+}
+
+static int parse_cap_host(xmlNodeSet *nsv, struct cap_host *cap_host)
+{
+        xmlNode **nodes = nsv->nodeTab;
+        xmlNode *child;
+        if (nsv->nodeNr < 1)
+                return 0; /* error no node below host */
+
+        for (child = nodes[0]->children; child != NULL; child = child->next) {
+                if (XSTREQ(child->name, "cpu"))
+                        return parse_cap_host_cpu(cap_host, child);
+        }
+        return 0;  /* error - no cpu node */
+}
+
+static void compare_copy_domain_info_machines(
+        struct cap_domain_info *def_gdomi,
+        struct cap_domain_info *cap_gadomi)
+{
+        int i,j;
+        int org_l = cap_gadomi->num_machines;
+        char *cp_name = NULL;
+        char *cp_canonical_name = NULL;
+        bool found;
+
+        for (i = 0; i < def_gdomi->num_machines; i++) {
+                found = false;
+                for (j = 0; j < org_l; j++) {
+                        if (STREQC(def_gdomi->machines[i].name,
+                                   cap_gadomi->machines[j].name)) {
+                                found = true;
+                                continue;
+                                /* found match => check next default */
+                        }
+                }
+                if (!found) { /* no match => insert default */
+                        cp_name = NULL;
+                        cp_canonical_name = NULL;
+                        if (def_gdomi->machines[i].name != NULL)
+                                cp_name = strdup(def_gdomi->machines[i].name);
+                        if (def_gdomi->machines[i].canonical_name != NULL)
+                                cp_canonical_name =
+                                        strdup(def_gdomi->
+                                               machines[i].canonical_name);
+
+                        extend_cap_machines(cap_gadomi,
+                                            cp_name,
+                                            cp_canonical_name);
+                }
+        }
+}
+
+static void extend_defaults_cap_guests(struct capabilities *caps)
+{
+        struct cap_arch *cap_garch;
+        struct cap_domain_info *cap_gadomi;
+        struct cap_domain_info *def_gdomi;
+        int i,j;
+
+        if (caps == NULL)
+                return;
+
+        for (i = 0; i < caps->num_guests; i++) {
+                cap_garch = &caps->guests[i].arch;
+                def_gdomi = &cap_garch->default_domain_info;
+
+                for (j = 0; j < cap_garch->num_domains; j++) {
+                        /* compare guest_domain_info */
+                        cap_gadomi = &cap_garch->domains[j].guest_domain_info;
+                        if (cap_gadomi->emulator == NULL &&
+                            def_gdomi->emulator != NULL)
+                                cap_gadomi->emulator =
+                                        strdup(def_gdomi->emulator);
+                        if (cap_gadomi->loader == NULL &&
+                            def_gdomi->loader != NULL)
+                                cap_gadomi->loader = strdup(def_gdomi->loader);
+
+                        compare_copy_domain_info_machines(def_gdomi,
+                                                          cap_gadomi);
+                }
+        }
+}
+
+static int _get_capabilities(const char *xml, struct capabilities *caps)
+{
+        int len;
+        int ret = 0;
+
+        xmlDoc *xmldoc = NULL;
+        xmlXPathContext *xpathctx = NULL;
+        xmlXPathObject *xpathobj = NULL;
+        const xmlChar *xpathhoststr = (xmlChar *)"//capabilities//host";
+        const xmlChar *xpathgueststr = (xmlChar *)"//capabilities//guest";
+        xmlNodeSet *nsv;
+
+        len = strlen(xml) + 1;
+
+        if ((xmldoc = xmlParseMemory(xml, len)) == NULL)
+                goto err;
+
+        if ((xpathctx = xmlXPathNewContext(xmldoc)) == NULL)
+                goto err;
+
+        /* host node */
+        if ((xpathobj = xmlXPathEvalExpression(xpathhoststr, xpathctx)) == NULL)
+                goto err;
+        if (xmlXPathNodeSetIsEmpty(xpathobj->nodesetval)) {
+                CU_DEBUG("No capabilities host node found!");
+                goto err;
+        }
+
+        nsv = xpathobj->nodesetval;
+        if (!parse_cap_host(nsv, &caps->host))
+                goto err;
+        xmlXPathFreeObject(xpathobj);
+
+        /* all guest nodes */
+        if ((xpathobj = xmlXPathEvalExpression(xpathgueststr, xpathctx)) == NULL)
+                goto err;
+        if (xmlXPathNodeSetIsEmpty(xpathobj->nodesetval)) {
+                CU_DEBUG("No capabilities guest nodes found!");
+                goto err;
+        }
+
+        nsv = xpathobj->nodesetval;
+        caps->guests = calloc(nsv->nodeNr, sizeof(struct cap_guest));
+        if (caps->guests == NULL)
+                goto err;
+        caps->num_guests = nsv->nodeNr;
+
+        parse_cap_guests(nsv, caps->guests);
+        extend_defaults_cap_guests(caps);
+        ret = 1;
+
+ err:
+        xmlXPathFreeObject(xpathobj);
+        xmlXPathFreeContext(xpathctx);
+        xmlFreeDoc(xmldoc);
+        return ret;
+}
+
+int get_caps_from_xml(const char *xml, struct capabilities **caps)
+{
+        CU_DEBUG("In get_caps_from_xml");
+
+        free(*caps);
+        *caps = calloc(1, sizeof(struct capabilities));
+        if (*caps == NULL)
+                goto err;
+
+        if (_get_capabilities(xml, *caps) == 0)
+                goto err;
+
+        return 1;
+
+ err:
+        free(*caps);
+        *caps = NULL;
+        return 0;
+}
+
+int get_capabilities(virConnectPtr conn, struct capabilities **caps)
+{
+        char *caps_xml = NULL;
+        int ret = 0;
+
+        if (conn == NULL) {
+                CU_DEBUG("Unable to connect to libvirt.");
+                return 0;
+        }
+
+        caps_xml = virConnectGetCapabilities(conn);
+
+        if (caps_xml == NULL) {
+                CU_DEBUG("Unable to get capabilities xml.");
+                return 0;
+        }
+
+        ret = get_caps_from_xml(caps_xml, caps);
+
+        free(caps_xml);
+
+        return ret;
+}
+
+struct cap_domain_info *findDomainInfo(struct capabilities *caps,
+                                       const char *os_type,
+                                       const char *arch,
+                                       const char *domain_type)
+{
+        int i,j;
+        struct cap_arch *ar;
+
+        for (i = 0; i < caps->num_guests; i++) {
+                if (os_type == NULL ||
+                    STREQC(caps->guests[i].ostype, os_type)) {
+                        ar = &caps->guests[i].arch;
+                        if (arch == NULL || STREQC(ar->name,arch))
+                                for (j = 0; j < ar->num_domains; j++)
+                                        if (domain_type == NULL ||
+                                            STREQC(ar->domains[j].typestr,
+                                                   domain_type))
+                                                return &ar->domains[j].
+                                                        guest_domain_info;
+                }
+        }
+        return NULL;
+}
+
+static char *_findDefArch(struct capabilities *caps,
+                          const char *os_type,
+                          const char *host_arch)
+{
+        char *ret = NULL;
+        int i;
+
+        for (i = 0; i < caps->num_guests; i++) {
+                if (STREQC(caps->guests[i].ostype, os_type) &&
+                    (host_arch == NULL || (host_arch != NULL &&
+                    STREQC(caps->guests[i].arch.name, host_arch)))) {
+                        ret = caps->guests[i].arch.name;
+                        break;
+                }
+        }
+        return ret;
+}
+
+char *get_default_arch(struct capabilities *caps,
+                       const char *os_type)
+{
+        char *ret = NULL;
+
+        if (caps != NULL && os_type != NULL) {
+                /* search first guest matching os_type and host arch */
+                ret = _findDefArch(caps, os_type, caps->host.cpu_arch);
+                if (ret == NULL) /* search first matching guest */
+                        ret = _findDefArch(caps, os_type, NULL);
+        }
+        return ret;
+}
+
+char *get_default_machine(
+        struct capabilities *caps,
+        const char *os_type,
+        const char *arch,
+        const char *domain_type)
+{
+        char *ret = NULL;
+        struct cap_domain_info *di;
+
+        if (caps != NULL) {
+                di = findDomainInfo(caps, os_type, arch, domain_type);
+                if (di != NULL && di->num_machines > 0) {
+                        ret = di->machines[0].canonical_name ?
+                                di->machines[0].canonical_name :
+                                di->machines[0].name;
+                }
+        }
+        return ret;
+}
+
+char *get_default_emulator(struct capabilities *caps,
+                           const char *os_type,
+                           const char *arch,
+                           const char *domain_type)
+{
+        char *ret = NULL;
+        struct cap_domain_info *di;
+
+        if (caps != NULL) {
+                di = findDomainInfo(caps, os_type, arch, domain_type);
+                if (di != NULL)
+                        ret = di->emulator;
+        }
+        return ret;
+}
+
+bool use_kvm(struct capabilities *caps) {
+        if (host_supports_kvm(caps) && !get_disable_kvm())
+                return true;
+        return false;
+}
+
+bool host_supports_kvm(struct capabilities *caps)
+{
+        bool kvm = false;
+        if (caps != NULL) {
+                if (findDomainInfo(caps, NULL, NULL, "kvm") != NULL)
+                        kvm = true;
+        }
+        return kvm;
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/libxkutil/capability_parsing.h b/libxkutil/capability_parsing.h
new file mode 100644
index 0000000..41a4933
--- /dev/null
+++ b/libxkutil/capability_parsing.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright IBM Corp. 2013
+ *
+ * Authors:
+ *  Boris Fiuczynski <fiuczy@linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#ifndef __CAPABILITY_PARSING_H
+#define __CAPABILITY_PARSING_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct cap_host {
+        char *cpu_arch;
+};
+
+struct cap_machine {
+        char *name;
+        char *canonical_name;
+};
+
+struct cap_domain_info {
+        char *emulator;
+        char *loader;
+        int num_machines;
+        struct cap_machine *machines;
+};
+
+struct cap_domain {
+        char *typestr;
+        struct cap_domain_info guest_domain_info;
+};
+
+struct cap_arch {
+        char *name;
+        unsigned int wordsize;
+        struct cap_domain_info default_domain_info;
+        int num_domains;
+        struct cap_domain *domains;
+};
+
+struct cap_guest {
+        char *ostype;
+        struct cap_arch arch;
+};
+
+struct capabilities {
+        struct cap_host host;
+        int num_guests;
+        struct cap_guest *guests;
+};
+
+int get_caps_from_xml(const char *xml, struct capabilities **caps);
+int get_capabilities(virConnectPtr conn, struct capabilities **caps);
+char *get_default_arch(struct capabilities *caps,
+                       const char *os_type);
+char *get_default_machine(struct capabilities *caps,
+                          const char *os_type,
+                          const char *arch,
+                          const char *domain_type);
+char *get_default_emulator(struct capabilities *caps,
+                           const char *os_type,
+                           const char *arch,
+                           const char *domain_type);
+struct cap_domain_info *findDomainInfo(struct capabilities *caps,
+                                       const char *os_type,
+                                       const char *arch,
+                                       const char *domain_type);
+bool use_kvm(struct capabilities *caps);
+bool host_supports_kvm(struct capabilities *caps);
+void cleanup_capabilities(struct capabilities **caps);
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c
index 7af3953..fa9f998 100644
--- a/libxkutil/device_parsing.c
+++ b/libxkutil/device_parsing.c
@@ -397,35 +397,6 @@ err:
         return 0;
 }

-bool has_kvm_domain_type(xmlNodePtr node)
-{
-        xmlNodePtr child = NULL;
-        char *type = NULL;
-        bool ret = false;
-
-        child = node->children;
-        while (child != NULL) {
-                if (XSTREQ(child->name, "domain")) {
-                        type = get_attr_value(child, "type");
-                        if (XSTREQ(type, "kvm")) {
-                                ret = true;
-                                goto out;
-                        }
-                }
-
-                if (has_kvm_domain_type(child) == 1) {
-                        ret = true;
-                        goto out;
-                }
-
-                child = child->next;
-        }
-
-  out:
-            free(type);
-            return ret;
-}
-
 static int parse_net_device(xmlNode *inode, struct virt_device **vdevs)
 {
         struct virt_device *vdev = NULL;
diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h
index df5080c..14e49b8 100644
--- a/libxkutil/device_parsing.h
+++ b/libxkutil/device_parsing.h
@@ -226,8 +226,6 @@ int attach_device(virDomainPtr dom, struct virt_device *dev);
 int detach_device(virDomainPtr dom, struct virt_device *dev);
 int change_device(virDomainPtr dom, struct virt_device *dev);

-bool has_kvm_domain_type(xmlNodePtr node);
-
 #define XSTREQ(x, y) (STREQ((char *)x, y))
 #define STRPROP(d, p, n) (d->p = get_node_content(n))

diff --git a/libxkutil/xml_parse_test.c b/libxkutil/xml_parse_test.c
index 384593d..af5e508 100644
--- a/libxkutil/xml_parse_test.c
+++ b/libxkutil/xml_parse_test.c
@@ -6,6 +6,7 @@
 #include <libvirt/libvirt.h>

 #include "device_parsing.h"
+#include "capability_parsing.h"
 #include "xmlgen.h"

 static void print_value(FILE *d, const char *name, const char *val)
@@ -25,6 +26,36 @@ static void print_u32(FILE *d, const char *name, uint32_t val)
 }
 #endif

+static char *get_ostype(struct domain *dom)
+{
+        if (dom->type == DOMAIN_XENPV) {
+                return dom->os_info.pv.type;
+        } else if ((dom->type == DOMAIN_XENFV) ||
+                   (dom->type == DOMAIN_KVM) ||
+                   (dom->type == DOMAIN_QEMU)) {
+                return dom->os_info.fv.type;
+        } else if (dom->type == DOMAIN_LXC) {
+                return dom->os_info.lxc.type;
+        } else {
+                return NULL;
+        }
+}
+
+static char *get_domaintype(struct domain *dom)
+{
+        if (dom->type == DOMAIN_XENPV || dom->type == DOMAIN_XENFV) {
+                return "xen";
+        } else if (dom->type == DOMAIN_KVM) {
+                return "kvm";
+        } else if (dom->type == DOMAIN_QEMU) {
+                return "qemu";
+        } else if (dom->type == DOMAIN_LXC) {
+                return "lxc";
+        } else {
+                return NULL;
+        }
+}
+
 static void print_os(struct domain *dom,
                      FILE *d)
 {
@@ -183,6 +214,98 @@ static char *read_from_file(FILE *file)
         return xml;
 }

+static void print_cap_domain_info(struct cap_domain_info *capgdiinfo,
+                                  FILE *d)
+{
+        struct cap_machine capgminfo;
+        int i;
+
+        if (capgdiinfo == NULL)
+                return;
+
+        if (capgdiinfo->emulator != NULL)
+                print_value(d, "  Emulator", capgdiinfo->emulator);
+        if (capgdiinfo->loader != NULL)
+                print_value(d, "  Loader", capgdiinfo->loader);
+        for (i = 0; i < capgdiinfo->num_machines; i++) {
+                capgminfo = capgdiinfo->machines[i];
+                fprintf(d, "  Machine name : %-15s  canonical name : %s\n",
+                        capgminfo.name, capgminfo.canonical_name);
+        }
+        fprintf(d, "\n");
+}
+
+static void print_cap_domains(struct cap_arch caparchinfo,
+                              FILE *d)
+{
+        struct cap_domain capgdinfo;
+        int i;
+        for (i = 0; i < caparchinfo.num_domains; i++) {
+                capgdinfo = caparchinfo.domains[i];
+                print_value(d, "  Type", capgdinfo.typestr);
+                print_cap_domain_info(&capgdinfo.guest_domain_info, d);
+        }
+}
+
+static void print_cap_arch(struct cap_arch caparchinfo,
+                           FILE *d)
+{
+        print_value(d, " Arch name", caparchinfo.name);
+        fprintf(d, " Arch wordsize : %i\n", caparchinfo.wordsize);
+        fprintf(d, "\n  -- Default guest domain settings --\n");
+        print_cap_domain_info(&caparchinfo.default_domain_info, d);
+        fprintf(d, "  -- Guest domains (%i) --\n", caparchinfo.num_domains);
+        print_cap_domains(caparchinfo, d);
+}
+
+static void print_cap_guest(struct cap_guest *capginfo,
+                            FILE *d)
+{
+        print_value(d, "Guest OS type", capginfo->ostype);
+        print_cap_arch(capginfo->arch, d);
+}
+
+static void print_cap_host(struct cap_host *caphinfo,
+                           FILE *d)
+{
+        print_value(d, "Host CPU architecture", caphinfo->cpu_arch);
+}
+
+static void print_capabilities(struct capabilities *capsinfo,
+                               FILE *d)
+{
+        int i;
+        fprintf(d, "\n### Capabilities ###\n");
+        fprintf(d, "-- Host --\n");
+        print_cap_host(&capsinfo->host, d);
+        fprintf(d, "\n-- Guest (%i) --\n", capsinfo->num_guests);
+        for (i = 0; i < capsinfo->num_guests; i++)
+                print_cap_guest(&capsinfo->guests[i], d);
+}
+
+static int capinfo_for_dom(const char *uri,
+                           struct domain *dominfo,
+                           struct capabilities **capsinfo)
+{
+        virConnectPtr conn = NULL;
+        char *caps_xml = NULL;
+        int ret = 0;
+
+        conn = virConnectOpen(uri);
+        if (conn == NULL) {
+                printf("Unable to connect to libvirt\n");
+                goto out;
+        }
+
+        ret = get_capabilities(conn, capsinfo);
+
+ out:
+        free(caps_xml);
+        virConnectClose(conn);
+
+        return ret;
+}
+
 static int dominfo_from_dom(const char *uri,
                             const char *domain,
                             struct domain **d)
@@ -246,12 +369,13 @@ static int dominfo_from_file(const char *fname, struct domain **d)
 static void usage(void)
 {
         printf("xml_parse_test -f [FILE | -] [--xml]\n"
-               "xml_parse_test -d domain [--uri URI] [--xml]\n"
+               "xml_parse_test -d domain [--uri URI] [--xml] [--cap]\n"
                "\n"
                "-f,--file FILE    Parse domain XML from file (or stdin if -)\n"
                "-d,--domain DOM   Display dominfo for a domain from libvirt\n"
                "-u,--uri URI      Connect to libvirt with URI\n"
                "-x,--xml          Dump generated XML instead of summary\n"
+               "-c,--cap          Display the libvirt default capability values for the specified domain\n"
                "-h,--help         Display this help message\n");
 }

@@ -262,7 +386,10 @@ int main(int argc, char **argv)
         char *uri = "xen";
         char *file = NULL;
         bool xml = false;
+        bool cap = false;
         struct domain *dominfo = NULL;
+        struct capabilities *capsinfo = NULL;
+        struct cap_domain_info *capgdinfo = NULL;
         int ret;

         static struct option lopts[] = {
@@ -270,13 +397,14 @@ int main(int argc, char **argv)
                 {"uri",    1, 0, 'u'},
                 {"xml",    0, 0, 'x'},
                 {"file",   1, 0, 'f'},
+                {"cap",    0, 0, 'c'},
                 {"help",   0, 0, 'h'},
                 {0,        0, 0, 0}};

         while (1) {
                 int optidx = 0;

-                c = getopt_long(argc, argv, "d:u:f:xh", lopts, &optidx);
+                c = getopt_long(argc, argv, "d:u:f:xch", lopts, &optidx);
                 if (c == -1)
                         break;

@@ -297,11 +425,14 @@ int main(int argc, char **argv)
                         xml = true;
                         break;

+                case 'c':
+                        cap = true;
+                        break;
+
                 case '?':
                 case 'h':
                         usage();
                         return c == '?';
-
                 };
         }

@@ -326,6 +457,70 @@ int main(int argc, char **argv)
                 print_devices(dominfo, stdout);
         }

+        if (cap && file == NULL) {
+                ret = capinfo_for_dom(uri, dominfo, &capsinfo);
+                if (ret == 0) {
+                        printf("Unable to get capsinfo\n");
+                        return 3;
+                } else {
+                        print_capabilities(capsinfo, stdout);
+                        const char *os_type = get_ostype(dominfo);
+                        const char *dom_type = get_domaintype(dominfo);
+                        const char *def_arch = get_default_arch(capsinfo, os_type);
+
+                        fprintf(stdout, "-- KVM is used: %s\n\n", (use_kvm(capsinfo)?"true":"false"));
+                        fprintf(stdout, "-- For all following default OS type=%s\n", os_type);
+                        fprintf(stdout, "-- Default Arch : %s\n", def_arch);
+
+                        fprintf(stdout,
+                                "-- Default Machine for arch=NULL : %s\n",
+                                get_default_machine(capsinfo, os_type, NULL, NULL));
+                        fprintf(stdout,
+                                "-- Default Machine for arch=%s and domain type=NULL : %s\n",
+                                def_arch,
+                                get_default_machine(capsinfo, os_type, def_arch, NULL));
+                        fprintf(stdout,
+                                "-- Default Machine for arch=%s and domain type=%s : %s\n",
+                                def_arch, dom_type,
+                                get_default_machine(capsinfo, os_type, def_arch, dom_type));
+                        fprintf(stdout,
+                                "-- Default Machine for arch=NULL and domain type=%s : %s\n",
+                                dom_type,
+                                get_default_machine(capsinfo, os_type, NULL, dom_type));
+
+                        fprintf(stdout,
+                                "-- Default Emulator for arch=NULL : %s\n",
+                                get_default_emulator(capsinfo, os_type, NULL, NULL));
+                        fprintf(stdout,
+                                "-- Default Emulator for arch=%s and domain type=NULL : %s\n",
+                                def_arch,
+                                get_default_emulator(capsinfo, os_type, def_arch, NULL));
+                        fprintf(stdout,
+                                "-- Default Emulator for arch=%s and domain type=%s : %s\n",
+                                def_arch, dom_type,
+                                get_default_emulator(capsinfo, os_type, def_arch, dom_type));
+                        fprintf(stdout,
+                                "-- Default Emulator for arch=NULL and domain type=%s : %s\n",
+                                dom_type,
+                                get_default_emulator(capsinfo, os_type, NULL, dom_type));
+
+                        fprintf(stdout, "\n-- Default Domain Search for: \n"
+                                "guest type=hvm - guest arch=* - guest domain type=kvm\n");
+                        capgdinfo = findDomainInfo(capsinfo, "hvm", NULL, "kvm");
+                        print_cap_domain_info(capgdinfo, stdout);
+
+                        fprintf(stdout, "-- Default Domain Search for: \n"
+                                "guest type=* - guest arch=* - guest domain type=*\n");
+                        capgdinfo = findDomainInfo(capsinfo, NULL, NULL, NULL);
+                        print_cap_domain_info(capgdinfo, stdout);
+
+                        cleanup_capabilities(&capsinfo);
+                }
+        } else if (cap) {
+                printf("Need a data source (--domain) to get default capabilities\n");
+                return 4;
+        }
+
         return 0;
 }

--
2.1.0
