3ec523
From 64041dc7d34d7af3fd611d194bf2ab56729a13fa Mon Sep 17 00:00:00 2001
3ec523
From: Michal Privoznik <mprivozn@redhat.com>
3ec523
Date: Tue, 16 Sep 2014 19:52:54 -0400
3ec523
Subject: [PATCH] domaincaps: Expose UEFI binary path, if it exists
3ec523
3ec523
Check to see if the UEFI binary mentioned in qemu.conf actually
3ec523
exists, and if so expose it in domcapabilities like
3ec523
3ec523
<loader ...>
3ec523
  <value>/path/to/ovmf</value>
3ec523
</loader>
3ec523
3ec523
We introduce some generic domcaps infrastructure for handling
3ec523
a dynamic list of string values, it may be of use for future bits.
3ec523
3ec523
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
3ec523
(cherry picked from commit f05b6a918e283929f5d837cd1668cdcdb3834b9a)
3ec523
---
3ec523
 docs/formatdomaincaps.html.in                      |  6 +++
3ec523
 docs/schemas/domaincaps.rng                        | 17 +++++---
3ec523
 src/conf/domain_capabilities.c                     | 29 +++++++++++++
3ec523
 src/conf/domain_capabilities.h                     |  8 ++++
3ec523
 src/qemu/qemu_capabilities.c                       | 32 +++++++++++---
3ec523
 src/qemu/qemu_capabilities.h                       |  7 +++-
3ec523
 src/qemu/qemu_driver.c                             |  6 ++-
3ec523
 tests/domaincapsschemadata/domaincaps-full.xml     |  2 +
3ec523
 .../domaincaps-qemu_1.6.50-1.xml                   |  1 +
3ec523
 tests/domaincapstest.c                             | 49 +++++++++++++++++++---
3ec523
 10 files changed, 140 insertions(+), 17 deletions(-)
3ec523
3ec523
diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in
3ec523
index 34d746d..6959dfe 100644
3ec523
--- a/docs/formatdomaincaps.html.in
3ec523
+++ b/docs/formatdomaincaps.html.in
3ec523
@@ -105,6 +105,7 @@
3ec523
   ...
3ec523
   <os supported='yes'>
3ec523
     <loader supported='yes'>
3ec523
+      <value>/usr/share/OVMF/OVMF_CODE.fd</value>
3ec523
       <enum name='type'>
3ec523
         <value>rom</value>
3ec523
         <value>pflash</value>
3ec523
@@ -122,6 +123,11 @@
3ec523
     

For the loader element, the following can occur:

3ec523
 
3ec523
     
3ec523
+      
value
3ec523
+      
List of known loader paths. Currently this is only used
3ec523
+      to advertise known locations of OVMF binaries for qemu. Binaries
3ec523
+      will only be listed if they actually exist on disk.
3ec523
+
3ec523
       
type
3ec523
       
Whether loader is a typical BIOS (rom) or
3ec523
       an UEFI binary (pflash). This refers to
3ec523
diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng
3ec523
index ad8d966..f4a555f 100644
3ec523
--- a/docs/schemas/domaincaps.rng
3ec523
+++ b/docs/schemas/domaincaps.rng
3ec523
@@ -47,6 +47,9 @@
3ec523
   <define name='loader'>
3ec523
     <element name='loader'>
3ec523
       <ref name='supported'/>
3ec523
+      <optional>
3ec523
+        <ref name='value'/>
3ec523
+      </optional>
3ec523
       <ref name='enum'/>
3ec523
     </element>
3ec523
   </define>
3ec523
@@ -85,6 +88,14 @@
3ec523
     </element>
3ec523
   </define>
3ec523
 
3ec523
+  <define name='value'>
3ec523
+    <zeroOrMore>
3ec523
+      <element name='value'>
3ec523
+        <text/>
3ec523
+      </element>
3ec523
+    </zeroOrMore>
3ec523
+  </define>
3ec523
+
3ec523
   <define name='supported'>
3ec523
     <attribute name='supported'>
3ec523
       <choice>
3ec523
@@ -100,11 +111,7 @@
3ec523
         <attribute name='name'>
3ec523
           <text/>
3ec523
         </attribute>
3ec523
-        <zeroOrMore>
3ec523
-          <element name='value'>
3ec523
-            <text/>
3ec523
-          </element>
3ec523
-        </zeroOrMore>
3ec523
+        <ref name='value'/>
3ec523
       </element>
3ec523
     </zeroOrMore>
3ec523
   </define>
3ec523
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
3ec523
index 5a3c8e7..7c59912 100644
3ec523
--- a/src/conf/domain_capabilities.c
3ec523
+++ b/src/conf/domain_capabilities.c
3ec523
@@ -48,12 +48,28 @@ VIR_ONCE_GLOBAL_INIT(virDomainCaps)
3ec523
 
3ec523
 
3ec523
 static void
3ec523
+virDomainCapsStringValuesFree(virDomainCapsStringValuesPtr values)
3ec523
+{
3ec523
+    size_t i;
3ec523
+
3ec523
+    if (!values || !values->values)
3ec523
+        return;
3ec523
+
3ec523
+    for (i = 0; i < values->nvalues; i++)
3ec523
+        VIR_FREE(values->values[i]);
3ec523
+    VIR_FREE(values->values);
3ec523
+}
3ec523
+
3ec523
+
3ec523
+static void
3ec523
 virDomainCapsDispose(void *obj)
3ec523
 {
3ec523
     virDomainCapsPtr caps = obj;
3ec523
 
3ec523
     VIR_FREE(caps->path);
3ec523
     VIR_FREE(caps->machine);
3ec523
+
3ec523
+    virDomainCapsStringValuesFree(&caps->os.loader.values);
3ec523
 }
3ec523
 
3ec523
 
3ec523
@@ -156,6 +172,18 @@ virDomainCapsEnumFormat(virBufferPtr buf,
3ec523
     return ret;
3ec523
 }
3ec523
 
3ec523
+
3ec523
+static void
3ec523
+virDomainCapsStringValuesFormat(virBufferPtr buf,
3ec523
+                                virDomainCapsStringValuesPtr values)
3ec523
+{
3ec523
+    size_t i;
3ec523
+
3ec523
+    for (i = 0; i < values->nvalues; i++)
3ec523
+        virBufferEscapeString(buf, "<value>%s</value>\n", values->values[i]);
3ec523
+}
3ec523
+
3ec523
+
3ec523
 #define FORMAT_PROLOGUE(item)                                       \
3ec523
     do {                                                            \
3ec523
         virBufferAsprintf(buf, "<" #item " supported='%s'%s\n",     \
3ec523
@@ -185,6 +213,7 @@ virDomainCapsLoaderFormat(virBufferPtr buf,
3ec523
 {
3ec523
     FORMAT_PROLOGUE(loader);
3ec523
 
3ec523
+    virDomainCapsStringValuesFormat(buf, &loader->values);
3ec523
     ENUM_PROCESS(loader, type, virDomainLoaderTypeToString);
3ec523
     ENUM_PROCESS(loader, readonly, virTristateBoolTypeToString);
3ec523
 
3ec523
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
3ec523
index 768646b..597ac75 100644
3ec523
--- a/src/conf/domain_capabilities.h
3ec523
+++ b/src/conf/domain_capabilities.h
3ec523
@@ -37,6 +37,13 @@ struct _virDomainCapsEnum {
3ec523
     unsigned int values; /* Bitmask of values supported in the corresponding enum */
3ec523
 };
3ec523
 
3ec523
+typedef struct _virDomainCapsStringValues virDomainCapsStringValues;
3ec523
+typedef virDomainCapsStringValues *virDomainCapsStringValuesPtr;
3ec523
+struct _virDomainCapsStringValues {
3ec523
+    char **values;  /* raw string values */
3ec523
+    size_t nvalues; /* number of strings */
3ec523
+};
3ec523
+
3ec523
 typedef struct _virDomainCapsDevice virDomainCapsDevice;
3ec523
 typedef virDomainCapsDevice *virDomainCapsDevicePtr;
3ec523
 struct _virDomainCapsDevice {
3ec523
@@ -47,6 +54,7 @@ typedef struct _virDomainCapsLoader virDomainCapsLoader;
3ec523
 typedef virDomainCapsLoader *virDomainCapsLoaderPtr;
3ec523
 struct _virDomainCapsLoader {
3ec523
     virDomainCapsDevice device;
3ec523
+    virDomainCapsStringValues values;   /* Info about values for the element */
3ec523
     virDomainCapsEnum type;     /* Info about virDomainLoader */
3ec523
     virDomainCapsEnum readonly; /* Info about readonly:virTristateBool */
3ec523
 };
3ec523
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
3ec523
index d2e5f47..651bacd 100644
3ec523
--- a/src/qemu/qemu_capabilities.c
3ec523
+++ b/src/qemu/qemu_capabilities.c
3ec523
@@ -3611,10 +3611,30 @@ virQEMUCapsGetDefaultMachine(virQEMUCapsPtr qemuCaps)
3ec523
 static int
3ec523
 virQEMUCapsFillDomainLoaderCaps(virQEMUCapsPtr qemuCaps,
3ec523
                                 virDomainCapsLoaderPtr loader,
3ec523
-                                virArch arch)
3ec523
+                                virArch arch,
3ec523
+                                virQEMUDriverConfigPtr cfg)
3ec523
 {
3ec523
+    size_t i;
3ec523
+
3ec523
     loader->device.supported = true;
3ec523
 
3ec523
+    if (VIR_ALLOC_N(loader->values.values, cfg->nloader) < 0)
3ec523
+        return -1;
3ec523
+
3ec523
+    for (i = 0; i < cfg->nloader; i++) {
3ec523
+        const char *filename = cfg->loader[i];
3ec523
+
3ec523
+        if (!virFileExists(filename)) {
3ec523
+            VIR_DEBUG("loader filename=%s does not exist", filename);
3ec523
+            continue;
3ec523
+        }
3ec523
+
3ec523
+        if (VIR_STRDUP(loader->values.values[loader->values.nvalues],
3ec523
+                       filename) < 0)
3ec523
+            return -1;
3ec523
+        loader->values.nvalues++;
3ec523
+    }
3ec523
+
3ec523
     VIR_DOMAIN_CAPS_ENUM_SET(loader->type,
3ec523
                              VIR_DOMAIN_LOADER_TYPE_ROM);
3ec523
 
3ec523
@@ -3636,12 +3656,13 @@ virQEMUCapsFillDomainLoaderCaps(virQEMUCapsPtr qemuCaps,
3ec523
 static int
3ec523
 virQEMUCapsFillDomainOSCaps(virQEMUCapsPtr qemuCaps,
3ec523
                             virDomainCapsOSPtr os,
3ec523
-                            virArch arch)
3ec523
+                            virArch arch,
3ec523
+                            virQEMUDriverConfigPtr cfg)
3ec523
 {
3ec523
     virDomainCapsLoaderPtr loader = &os->loader;
3ec523
 
3ec523
     os->device.supported = true;
3ec523
-    if (virQEMUCapsFillDomainLoaderCaps(qemuCaps, loader, arch) < 0)
3ec523
+    if (virQEMUCapsFillDomainLoaderCaps(qemuCaps, loader, arch, cfg) < 0)
3ec523
         return -1;
3ec523
     return 0;
3ec523
 }
3ec523
@@ -3725,7 +3746,8 @@ virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCapsPtr qemuCaps,
3ec523
 
3ec523
 int
3ec523
 virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
3ec523
-                          virQEMUCapsPtr qemuCaps)
3ec523
+                          virQEMUCapsPtr qemuCaps,
3ec523
+                          virQEMUDriverConfigPtr cfg)
3ec523
 {
3ec523
     virDomainCapsOSPtr os = &domCaps->os;
3ec523
     virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
3ec523
@@ -3734,7 +3756,7 @@ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
3ec523
 
3ec523
     domCaps->maxvcpus = maxvcpus;
3ec523
 
3ec523
-    if (virQEMUCapsFillDomainOSCaps(qemuCaps, os, domCaps->arch) < 0 ||
3ec523
+    if (virQEMUCapsFillDomainOSCaps(qemuCaps, os, domCaps->arch, cfg) < 0 ||
3ec523
         virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk) < 0 ||
3ec523
         virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev) < 0)
3ec523
         return -1;
3ec523
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
3ec523
index 828bba3..cf69e59 100644
3ec523
--- a/src/qemu/qemu_capabilities.h
3ec523
+++ b/src/qemu/qemu_capabilities.h
3ec523
@@ -324,7 +324,12 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps,
3ec523
                                    virQEMUCapsPtr kvmbinCaps,
3ec523
                                    virArch guestarch);
3ec523
 
3ec523
+/* Forward declaration */
3ec523
+typedef struct _virQEMUDriverConfig virQEMUDriverConfig;
3ec523
+typedef virQEMUDriverConfig *virQEMUDriverConfigPtr;
3ec523
+
3ec523
 int virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
3ec523
-                              virQEMUCapsPtr qemuCaps);
3ec523
+                              virQEMUCapsPtr qemuCaps,
3ec523
+                              virQEMUDriverConfigPtr cfg);
3ec523
 
3ec523
 #endif /* __QEMU_CAPABILITIES_H__*/
3ec523
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
3ec523
index 9c1644c..0d895c6 100644
3ec523
--- a/src/qemu/qemu_driver.c
3ec523
+++ b/src/qemu/qemu_driver.c
3ec523
@@ -17133,12 +17133,15 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn,
3ec523
     int virttype; /* virDomainVirtType */
3ec523
     virDomainCapsPtr domCaps = NULL;
3ec523
     int arch = virArchFromHost(); /* virArch */
3ec523
+    virQEMUDriverConfigPtr cfg = NULL;
3ec523
 
3ec523
     virCheckFlags(0, ret);
3ec523
 
3ec523
     if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0)
3ec523
         return ret;
3ec523
 
3ec523
+    cfg = virQEMUDriverGetConfig(driver);
3ec523
+
3ec523
     if (qemuHostdevHostSupportsPassthroughLegacy())
3ec523
         virttype = VIR_DOMAIN_VIRT_KVM;
3ec523
     else
3ec523
@@ -17205,11 +17208,12 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn,
3ec523
     if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
3ec523
         goto cleanup;
3ec523
 
3ec523
-    if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps) < 0)
3ec523
+    if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, cfg) < 0)
3ec523
         goto cleanup;
3ec523
 
3ec523
     ret = virDomainCapsFormat(domCaps);
3ec523
  cleanup:
3ec523
+    virObjectUnref(cfg);
3ec523
     virObjectUnref(domCaps);
3ec523
     virObjectUnref(qemuCaps);
3ec523
     return ret;
3ec523
diff --git a/tests/domaincapsschemadata/domaincaps-full.xml b/tests/domaincapsschemadata/domaincaps-full.xml
3ec523
index 9722772..96202bc 100644
3ec523
--- a/tests/domaincapsschemadata/domaincaps-full.xml
3ec523
+++ b/tests/domaincapsschemadata/domaincaps-full.xml
3ec523
@@ -6,6 +6,8 @@
3ec523
   <vcpu max='255'/>
3ec523
   <os supported='yes'>
3ec523
     <loader supported='yes'>
3ec523
+      <value>/foo/bar</value>
3ec523
+      <value>/tmp/my_path</value>
3ec523
       <enum name='type'>
3ec523
         <value>rom</value>
3ec523
         <value>pflash</value>
3ec523
diff --git a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
3ec523
index 568cecb..346ef65 100644
3ec523
--- a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
3ec523
+++ b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
3ec523
@@ -5,6 +5,7 @@
3ec523
   <arch>x86_64</arch>
3ec523
   <os supported='yes'>
3ec523
     <loader supported='yes'>
3ec523
+      <value>/usr/share/OVMF/OVMF_CODE.fd</value>
3ec523
       <enum name='type'>
3ec523
         <value>rom</value>
3ec523
         <value>pflash</value>
3ec523
diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
3ec523
index 0c4b09f..8543963 100644
3ec523
--- a/tests/domaincapstest.c
3ec523
+++ b/tests/domaincapstest.c
3ec523
@@ -34,6 +34,27 @@ typedef int (*virDomainCapsFill)(virDomainCapsPtr domCaps,
3ec523
 #define SET_ALL_BITS(x) \
3ec523
     memset(&(x.values), 0xff, sizeof(x.values))
3ec523
 
3ec523
+static int ATTRIBUTE_SENTINEL
3ec523
+fillStringValues(virDomainCapsStringValuesPtr values, ...)
3ec523
+{
3ec523
+    int ret = 0;
3ec523
+    va_list list;
3ec523
+    const char *str;
3ec523
+
3ec523
+    va_start(list, values);
3ec523
+    while ((str = va_arg(list, const char *))) {
3ec523
+        if (VIR_REALLOC_N(values->values, values->nvalues + 1) < 0 ||
3ec523
+            VIR_STRDUP(values->values[values->nvalues], str) < 0) {
3ec523
+            ret = -1;
3ec523
+            break;
3ec523
+        }
3ec523
+        values->nvalues++;
3ec523
+    }
3ec523
+    va_end(list);
3ec523
+
3ec523
+    return ret;
3ec523
+}
3ec523
+
3ec523
 static int
3ec523
 fillAll(virDomainCapsPtr domCaps,
3ec523
         void *opaque ATTRIBUTE_UNUSED)
3ec523
@@ -49,6 +70,11 @@ fillAll(virDomainCapsPtr domCaps,
3ec523
     loader->device.supported = true;
3ec523
     SET_ALL_BITS(loader->type);
3ec523
     SET_ALL_BITS(loader->readonly);
3ec523
+    if (fillStringValues(&loader->values,
3ec523
+                         "/foo/bar",
3ec523
+                         "/tmp/my_path",
3ec523
+                         NULL) < 0)
3ec523
+        return -1;
3ec523
 
3ec523
     disk->device.supported = true;
3ec523
     SET_ALL_BITS(disk->diskDevice);
3ec523
@@ -66,13 +92,21 @@ fillAll(virDomainCapsPtr domCaps,
3ec523
 
3ec523
 #ifdef WITH_QEMU
3ec523
 # include "testutilsqemu.h"
3ec523
+
3ec523
+struct fillQemuCapsData {
3ec523
+    virQEMUCapsPtr qemuCaps;
3ec523
+    virQEMUDriverConfigPtr cfg;
3ec523
+};
3ec523
+
3ec523
 static int
3ec523
 fillQemuCaps(virDomainCapsPtr domCaps,
3ec523
              void *opaque)
3ec523
 {
3ec523
-    virQEMUCapsPtr qemuCaps = (virQEMUCapsPtr) opaque;
3ec523
+    struct fillQemuCapsData *data = (struct fillQemuCapsData *) opaque;
3ec523
+    virQEMUCapsPtr qemuCaps = data->qemuCaps;
3ec523
+    virQEMUDriverConfigPtr cfg = data->cfg;
3ec523
 
3ec523
-    if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps) < 0)
3ec523
+    if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, cfg) < 0)
3ec523
         return -1;
3ec523
 
3ec523
     /* The function above tries to query host's KVM & VFIO capabilities by
3ec523
@@ -97,7 +131,7 @@ buildVirDomainCaps(const char *emulatorbin,
3ec523
                    virDomainCapsFill fillFunc,
3ec523
                    void *opaque)
3ec523
 {
3ec523
-    virDomainCapsPtr domCaps;
3ec523
+    virDomainCapsPtr domCaps, ret = NULL;
3ec523
 
3ec523
     if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, type)))
3ec523
         goto cleanup;
3ec523
@@ -107,8 +141,9 @@ buildVirDomainCaps(const char *emulatorbin,
3ec523
         domCaps = NULL;
3ec523
     }
3ec523
 
3ec523
+    ret = domCaps;
3ec523
  cleanup:
3ec523
-    return domCaps;
3ec523
+    return ret;
3ec523
 }
3ec523
 
3ec523
 struct test_virDomainCapsFormatData {
3ec523
@@ -182,13 +217,16 @@ mymain(void)
3ec523
 
3ec523
 #ifdef WITH_QEMU
3ec523
 
3ec523
+    virQEMUDriverConfigPtr cfg = virQEMUDriverConfigNew(false);
3ec523
+
3ec523
 # define DO_TEST_QEMU(Filename, QemuCapsFile, Emulatorbin, Machine, Arch, Type, ...)    \
3ec523
     do {                                                                                \
3ec523
         const char *capsPath = abs_srcdir "/qemucapabilitiesdata/" QemuCapsFile ".caps";    \
3ec523
         virQEMUCapsPtr qemuCaps = qemuTestParseCapabilities(capsPath);                  \
3ec523
+        struct fillQemuCapsData fillData = {.qemuCaps = qemuCaps, .cfg = cfg};          \
3ec523
         struct test_virDomainCapsFormatData data = {.filename = Filename,               \
3ec523
             .emulatorbin = Emulatorbin, .machine = Machine, .arch = Arch,               \
3ec523
-            .type = Type, .fillFunc = fillQemuCaps, .opaque = qemuCaps};                \
3ec523
+            .type = Type, .fillFunc = fillQemuCaps, .opaque = &fillData};               \
3ec523
         if (!qemuCaps) {                                                                \
3ec523
             fprintf(stderr, "Unable to build qemu caps from %s\n", capsPath);           \
3ec523
             ret = -1;                                                                   \
3ec523
@@ -199,6 +237,7 @@ mymain(void)
3ec523
     DO_TEST_QEMU("qemu_1.6.50-1", "caps_1.6.50-1", "/usr/bin/qemu-system-x86_64",
3ec523
                  "pc-1.2",  VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_KVM);
3ec523
 
3ec523
+    virObjectUnref(cfg);
3ec523
 #endif /* WITH_QEMU */
3ec523
 
3ec523
     return ret;