[libvirt] [PATCH] domaincaps: Expose UEFI binary path, if it exists

Cole Robinson crobinso at redhat.com
Tue Sep 16 23:52:54 UTC 2014


Check to see if the UEFI binary mentioned in qemu.conf actually
exists, and if so expose it in domcapabilities like

<loader ...>
  <value>/path/to/ovmf</value>
</loader>

We introduce some generic domcaps infrastructure for handling
a dynamic list of string values, it may be of use for future bits.
---
 docs/formatdomaincaps.html.in                  |  6 ++++
 docs/schemas/domaincaps.rng                    | 17 ++++++---
 src/conf/domain_capabilities.c                 | 23 ++++++++++++
 src/conf/domain_capabilities.h                 |  8 +++++
 src/qemu/qemu_driver.c                         | 24 +++++++++++++
 tests/domaincapsschemadata/domaincaps-full.xml |  1 +
 tests/domaincapstest.c                         | 49 +++++++++++++++++++++-----
 7 files changed, 115 insertions(+), 13 deletions(-)

diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in
index 34d746d..6959dfe 100644
--- a/docs/formatdomaincaps.html.in
+++ b/docs/formatdomaincaps.html.in
@@ -105,6 +105,7 @@
   ...
   <os supported='yes'>
     <loader supported='yes'>
+      <value>/usr/share/OVMF/OVMF_CODE.fd</value>
       <enum name='type'>
         <value>rom</value>
         <value>pflash</value>
@@ -122,6 +123,11 @@
     <p>For the <code>loader</code> element, the following can occur:</p>
 
     <dl>
+      <dt>value</dt>
+      <dd>List of known loader paths. Currently this is only used
+      to advertise known locations of OVMF binaries for qemu. Binaries
+      will only be listed if they actually exist on disk.</dd>
+
       <dt>type</dt>
       <dd>Whether loader is a typical BIOS (<code>rom</code>) or
       an UEFI binary (<code>pflash</code>). This refers to
diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng
index ad8d966..dfdb9b9 100644
--- a/docs/schemas/domaincaps.rng
+++ b/docs/schemas/domaincaps.rng
@@ -46,6 +46,9 @@
 
   <define name='loader'>
     <element name='loader'>
+      <optional>
+        <ref name='value'/>
+      </optional>
       <ref name='supported'/>
       <ref name='enum'/>
     </element>
@@ -85,6 +88,14 @@
     </element>
   </define>
 
+  <define name='value'>
+    <zeroOrMore>
+      <element name='value'>
+        <text/>
+      </element>
+    </zeroOrMore>
+  </define>
+
   <define name='supported'>
     <attribute name='supported'>
       <choice>
@@ -100,11 +111,7 @@
         <attribute name='name'>
           <text/>
         </attribute>
-        <zeroOrMore>
-          <element name='value'>
-            <text/>
-          </element>
-        </zeroOrMore>
+        <ref name='value'/>
       </element>
     </zeroOrMore>
   </define>
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index 5a3c8e7..44e422a 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -46,6 +46,15 @@ static int virDomainCapsOnceInit(void)
 
 VIR_ONCE_GLOBAL_INIT(virDomainCaps)
 
+static void
+virDomainCapsValuesFree(virDomainCapsValuesPtr values)
+{
+    size_t i;
+
+    for (i = 0; i < values->nvalues; i++) {
+        VIR_FREE(values->values[i]);
+    }
+}
 
 static void
 virDomainCapsDispose(void *obj)
@@ -54,6 +63,8 @@ virDomainCapsDispose(void *obj)
 
     VIR_FREE(caps->path);
     VIR_FREE(caps->machine);
+
+    virDomainCapsValuesFree(&caps->os.loader.values);
 }
 
 
@@ -156,6 +167,17 @@ virDomainCapsEnumFormat(virBufferPtr buf,
     return ret;
 }
 
+static void
+virDomainCapsValuesFormat(virBufferPtr buf,
+                          virDomainCapsValuesPtr values)
+{
+    size_t i;
+
+    for (i = 0; i < values->nvalues; i++) {
+        virBufferAsprintf(buf, "<value>%s</value>\n", values->values[i]);
+    }
+}
+
 #define FORMAT_PROLOGUE(item)                                       \
     do {                                                            \
         virBufferAsprintf(buf, "<" #item " supported='%s'%s\n",     \
@@ -185,6 +207,7 @@ virDomainCapsLoaderFormat(virBufferPtr buf,
 {
     FORMAT_PROLOGUE(loader);
 
+    virDomainCapsValuesFormat(buf, &loader->values);
     ENUM_PROCESS(loader, type, virDomainLoaderTypeToString);
     ENUM_PROCESS(loader, readonly, virTristateBoolTypeToString);
 
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
index 768646b..3d5aaa3 100644
--- a/src/conf/domain_capabilities.h
+++ b/src/conf/domain_capabilities.h
@@ -37,6 +37,13 @@ struct _virDomainCapsEnum {
     unsigned int values; /* Bitmask of values supported in the corresponding enum */
 };
 
+typedef struct _virDomainCapsValues virDomainCapsValues;
+typedef virDomainCapsValues *virDomainCapsValuesPtr;
+struct _virDomainCapsValues {
+    char **values; /* raw string values */
+    size_t nvalues; /* number of strings */
+};
+
 typedef struct _virDomainCapsDevice virDomainCapsDevice;
 typedef virDomainCapsDevice *virDomainCapsDevicePtr;
 struct _virDomainCapsDevice {
@@ -47,6 +54,7 @@ typedef struct _virDomainCapsLoader virDomainCapsLoader;
 typedef virDomainCapsLoader *virDomainCapsLoaderPtr;
 struct _virDomainCapsLoader {
     virDomainCapsDevice device;
+    virDomainCapsValues values;
     virDomainCapsEnum type;     /* Info about virDomainLoader */
     virDomainCapsEnum readonly; /* Info about readonly:virTristateBool */
 };
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6008aeb..4dd9d14 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17282,6 +17282,8 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn,
     int virttype; /* virDomainVirtType */
     virDomainCapsPtr domCaps = NULL;
     int arch = virArchFromHost(); /* virArch */
+    virQEMUDriverConfigPtr cfg = NULL;
+    size_t i;
 
     virCheckFlags(0, ret);
 
@@ -17356,8 +17358,30 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn,
 
     virQEMUCapsFillDomainCaps(domCaps, qemuCaps);
 
+    cfg = virQEMUDriverGetConfig(driver);
+    for (i = 0; i < cfg->nloader; i++) {
+        char *filename = cfg->loader[i];
+
+        if (access(filename, F_OK) == 0) {
+            if (VIR_REALLOC_N(domCaps->os.loader.values.values,
+                              domCaps->os.loader.values.nvalues + 1) < 0) {
+                goto cleanup;
+            }
+            domCaps->os.loader.values.nvalues++;
+
+            if (VIR_STRDUP(domCaps->os.loader.values.values[
+                           domCaps->os.loader.values.nvalues - 1],
+                           filename) < 0) {
+                goto cleanup;
+            }
+        } else {
+            VIR_DEBUG("loader filename=%s doesn't exist", filename);
+        }
+    }
+
     ret = virDomainCapsFormat(domCaps);
  cleanup:
+    virObjectUnref(cfg);
     virObjectUnref(domCaps);
     virObjectUnref(qemuCaps);
     return ret;
diff --git a/tests/domaincapsschemadata/domaincaps-full.xml b/tests/domaincapsschemadata/domaincaps-full.xml
index 9722772..e7f41d7 100644
--- a/tests/domaincapsschemadata/domaincaps-full.xml
+++ b/tests/domaincapsschemadata/domaincaps-full.xml
@@ -6,6 +6,7 @@
   <vcpu max='255'/>
   <os supported='yes'>
     <loader supported='yes'>
+      <value>/foo/test</value>
       <enum name='type'>
         <value>rom</value>
         <value>pflash</value>
diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
index f240643..ddc4d02 100644
--- a/tests/domaincapstest.c
+++ b/tests/domaincapstest.c
@@ -28,16 +28,37 @@
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 
-typedef void (*virDomainCapsFill)(virDomainCapsPtr domCaps,
-                                  void *opaque);
+typedef int (*virDomainCapsFill)(virDomainCapsPtr domCaps,
+                                 void *opaque);
 
 #define SET_ALL_BITS(x) \
     memset(&(x.values), 0xff, sizeof(x.values))
 
-static void
+static int
+fillValues(virDomainCapsValuesPtr values)
+{
+    int ret = -1;
+
+    if (VIR_ALLOC_N(values->values, 1) < 0) {
+        goto cleanup;
+    }
+    values->nvalues = 1;
+
+    if (VIR_STRDUP(values->values[0], "/foo/test") < 0) {
+        goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    return ret;
+}
+
+static int
 fillAll(virDomainCapsPtr domCaps,
         void *opaque ATTRIBUTE_UNUSED)
 {
+    int ret = -1;
+
     virDomainCapsOSPtr os = &domCaps->os;
     virDomainCapsLoaderPtr loader = &os->loader;
     virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
@@ -49,6 +70,9 @@ fillAll(virDomainCapsPtr domCaps,
     loader->device.supported = true;
     SET_ALL_BITS(loader->type);
     SET_ALL_BITS(loader->readonly);
+    if (fillValues(&loader->values) < 0) {
+        goto cleanup;
+    }
 
     disk->device.supported = true;
     SET_ALL_BITS(disk->diskDevice);
@@ -60,12 +84,16 @@ fillAll(virDomainCapsPtr domCaps,
     SET_ALL_BITS(hostdev->subsysType);
     SET_ALL_BITS(hostdev->capsType);
     SET_ALL_BITS(hostdev->pciBackend);
+
+    ret = 0;
+ cleanup:
+    return ret;
 }
 
 
 #ifdef WITH_QEMU
 # include "testutilsqemu.h"
-static void
+static int
 fillQemuCaps(virDomainCapsPtr domCaps,
              void *opaque)
 {
@@ -82,6 +110,8 @@ fillQemuCaps(virDomainCapsPtr domCaps,
                              VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
                              VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM,
                              VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO);
+
+    return 0;
 }
 #endif /* WITH_QEMU */
 
@@ -94,16 +124,19 @@ buildVirDomainCaps(const char *emulatorbin,
                    virDomainCapsFill fillFunc,
                    void *opaque)
 {
-    virDomainCapsPtr domCaps;
+    virDomainCapsPtr domCaps, ret = NULL;
 
     if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, type)))
         goto cleanup;
 
-    if (fillFunc)
-        fillFunc(domCaps, opaque);
+    if (fillFunc && fillFunc(domCaps, opaque) < 0) {
+        virObjectUnref(domCaps);
+        goto cleanup;
+    }
 
+    ret = domCaps;
  cleanup:
-    return domCaps;
+    return ret;
 }
 
 struct test_virDomainCapsFormatData {
-- 
2.1.0




More information about the libvir-list mailing list