[Libguestfs] [PATCH INCOMPLETE] launch: libvirt: Use C macros to simplify XML generation.

Richard W.M. Jones rjones at redhat.com
Fri Jan 17 09:39:19 UTC 2014


This commit implements some hairy C macros to simplify
XML generation.

Given the target XML:

  <cpu mode="host-passthrough">
    <model fallback="allow"/>
  </cpu>

The old code would have looked like this:

   XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "cpu"));
   XMLERROR (-1,
            xmlTextWriterWriteAttribute (xo, BAD_CAST "mode",
                                         BAD_CAST "host-passthrough"));
   XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "model"));
   XMLERROR (-1,
            xmlTextWriterWriteAttribute (xo, BAD_CAST "fallback",
                                         BAD_CAST "allow"));
   XMLERROR (-1, xmlTextWriterEndElement (xo));
   XMLERROR (-1, xmlTextWriterEndElement (xo));

The new code looks like this:

   start_element ("cpu") {
     attribute ("mode", "host-passthrough");
     start_element ("model") {
       attribute ("fallback", "allow");
     } end_element ();
   } end_element ();
---
 src/launch-libvirt.c | 157 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 96 insertions(+), 61 deletions(-)

diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index f28b288..b2af881 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -801,6 +801,59 @@ static int construct_libvirt_xml_disk_source_hosts (guestfs_h *g, xmlTextWriterP
 static int construct_libvirt_xml_disk_source_seclabel (guestfs_h *g, const struct backend_libvirt_data *data, xmlTextWriterPtr xo);
 static int construct_libvirt_xml_appliance (guestfs_h *g, const struct libvirt_xml_params *params, xmlTextWriterPtr xo);
 
+/* These macros make it easier to write XML, but they also make a lot
+ * of assumptions:
+ *
+ * - The xmlTextWriterPtr is called 'xo'.  It is used implicitly.
+ *
+ * - The guestfs handle is called 'g'.  It is used implicitly for errors.
+ *
+ * - It is safe to 'return -1' on failure.  This is OK provided you
+ *   always use CLEANUP_* macros.
+ *
+ * - All the "bad" casting is hidden inside the macros.
+ */
+
+/* <element */
+#define start_element(element)                                        \
+  if (xmlTextWriterStartElement (xo, BAD_CAST (element)) == -1) {     \
+    xml_error ("xmlTextWriterStartElement");                          \
+    return -1;                                                        \
+  }                                                                   \
+  do
+
+/* finish current </element> */
+#define end_element()                                                 \
+  while (0);                                                          \
+  if (xmlTextWriterEndElement (xo) == -1) {                           \
+    xml_error ("xmlTextWriterEndElement");                            \
+    return -1;                                                        \
+  }
+
+/* key=value attribute of the current element. */
+#define attribute(key,value)                                            \
+  if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key), BAD_CAST (value)) == -1) { \
+    xml_error ("xmlTextWriterWriteAttribute"); \
+    return -1;                                 \
+  }
+
+/* attribute with namespace. */
+#define attribute_ns(prefix,key,namespace_uri,value)                    \
+  if (xmlTextWriterWriteAttributeNS (xo, BAD_CAST (prefix),             \
+                                     BAD_CAST (key), BAD_CAST (namespace_uri), \
+                                     BAD_CAST (value)) == -1) {         \
+    xml_error ("xmlTextWriterWriteAttribute");                          \
+    return -1;                                                          \
+  }
+
+#define write_format_string(fs,...)                                     \
+  if (xmlTextWriterWriteFormatString (xo, fs, ##__VA_ARGS__) == -1) {   \
+    xml_error ("xmlTextWriterWriteFormatString");                       \
+    return -1;                                                          \
+  }
+
+#define xml_error(fn) perrorf (g, _("%s:%d: error constructing libvirt XML near call to \"%s\""), __FILE__, __LINE__, fn);
+
 /* Note this macro is rather specialized: It assumes that any local
  * variables are protected by CLEANUP_* macros, so that simply
  * returning will not cause any memory leaks.
@@ -848,33 +901,27 @@ construct_libvirt_xml_domain (guestfs_h *g,
   XMLERROR (-1, xmlTextWriterSetIndentString (xo, BAD_CAST "  "));
   XMLERROR (-1, xmlTextWriterStartDocument (xo, NULL, NULL, NULL));
 
-  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "domain"));
-  XMLERROR (-1,
-            xmlTextWriterWriteAttribute (xo, BAD_CAST "type",
-                         params->is_kvm ? BAD_CAST "kvm" : BAD_CAST "qemu"));
-  XMLERROR (-1,
-            xmlTextWriterWriteAttributeNS (xo,
-                                           BAD_CAST "xmlns",
-                                           BAD_CAST "qemu",
-                                           NULL,
-                                           BAD_CAST "http://libvirt.org/schemas/domain/qemu/1.0"));
+  start_element ("domain") {
+    attribute ("type", params->is_kvm ? "kvm" : "qemu");
+    attribute_ns ("xmlns", "qemu", NULL,
+                  "http://libvirt.org/schemas/domain/qemu/1.0");
 
-  if (construct_libvirt_xml_name (g, params, xo) == -1)
-    return -1;
-  if (construct_libvirt_xml_cpu (g, params, xo) == -1)
-    return -1;
-  if (construct_libvirt_xml_boot (g, params, xo) == -1)
-    return -1;
-  if (construct_libvirt_xml_seclabel (g, params, xo) == -1)
-    return -1;
-  if (construct_libvirt_xml_lifecycle (g, params, xo) == -1)
-    return -1;
-  if (construct_libvirt_xml_devices (g, params, xo) == -1)
-    return -1;
-  if (construct_libvirt_xml_qemu_cmdline (g, params, xo) == -1)
-    return -1;
+    if (construct_libvirt_xml_name (g, params, xo) == -1)
+      return -1;
+    if (construct_libvirt_xml_cpu (g, params, xo) == -1)
+      return -1;
+    if (construct_libvirt_xml_boot (g, params, xo) == -1)
+      return -1;
+    if (construct_libvirt_xml_seclabel (g, params, xo) == -1)
+      return -1;
+    if (construct_libvirt_xml_lifecycle (g, params, xo) == -1)
+      return -1;
+    if (construct_libvirt_xml_devices (g, params, xo) == -1)
+      return -1;
+    if (construct_libvirt_xml_qemu_cmdline (g, params, xo) == -1)
+      return -1;
 
-  XMLERROR (-1, xmlTextWriterEndElement (xo));
+  } end_element ();
 
   return 0;
 }
@@ -897,17 +944,15 @@ construct_libvirt_xml_cpu (guestfs_h *g,
                            const struct libvirt_xml_params *params,
                            xmlTextWriterPtr xo)
 {
-  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "memory"));
-  XMLERROR (-1,
-            xmlTextWriterWriteAttribute (xo, BAD_CAST "unit", BAD_CAST "MiB"));
-  XMLERROR (-1, xmlTextWriterWriteFormatString (xo, "%d", g->memsize));
-  XMLERROR (-1, xmlTextWriterEndElement (xo));
+  start_element ("memory") {
+    attribute ("unit", "MiB");
+    write_format_string ("%d", g->memsize);
+  } end_element ();
 
-  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "currentMemory"));
-  XMLERROR (-1,
-            xmlTextWriterWriteAttribute (xo, BAD_CAST "unit", BAD_CAST "MiB"));
-  XMLERROR (-1, xmlTextWriterWriteFormatString (xo, "%d", g->memsize));
-  XMLERROR (-1, xmlTextWriterEndElement (xo));
+  start_element ("currentMemory") {
+    attribute ("unit", "MiB");
+    write_format_string ("%d", g->memsize);
+  } end_element ();
 
 #ifndef __arm__
   /* It is faster to pass the CPU host model to the appliance,
@@ -916,36 +961,26 @@ construct_libvirt_xml_cpu (guestfs_h *g,
    * fairly pointless anyway.
    */
   if (params->is_kvm) {
-    XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "cpu"));
-    XMLERROR (-1,
-	      xmlTextWriterWriteAttribute (xo, BAD_CAST "mode",
-					   BAD_CAST "host-passthrough"));
-    XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "model"));
-    XMLERROR (-1,
-	      xmlTextWriterWriteAttribute (xo, BAD_CAST "fallback",
-					   BAD_CAST "allow"));
-    XMLERROR (-1, xmlTextWriterEndElement (xo));
-    XMLERROR (-1, xmlTextWriterEndElement (xo));
+    start_element ("cpu") {
+      attribute ("mode", "host-passthrough");
+      start_element ("model") {
+        attribute ("fallback", "allow");
+      } end_element ();
+    } end_element ();
   }
 #endif
 
-  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "vcpu"));
-  XMLERROR (-1, xmlTextWriterWriteFormatString (xo, "%d", g->smp));
-  XMLERROR (-1, xmlTextWriterEndElement (xo));
+  start_element ("vcpu") {
+    write_format_string ("%d", g->smp);
+  } end_element ();
 
-  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "clock"));
-  XMLERROR (-1,
-            xmlTextWriterWriteAttribute (xo, BAD_CAST "offset",
-                                         BAD_CAST "utc"));
-  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "timer"));
-  XMLERROR (-1,
-            xmlTextWriterWriteAttribute (xo, BAD_CAST "name",
-                                         BAD_CAST "kvmclock"));
-  XMLERROR (-1,
-            xmlTextWriterWriteAttribute (xo, BAD_CAST "present",
-                                         BAD_CAST "yes"));
-  XMLERROR (-1, xmlTextWriterEndElement (xo));
-  XMLERROR (-1, xmlTextWriterEndElement (xo));
+  start_element ("clock") {
+    attribute ("offset", "utc");
+    start_element ("timer") {
+      attribute ("name", "kvmclock");
+      attribute ("present", "yes");
+    } end_element ();
+  } end_element ();
 
   return 0;
 }
-- 
1.8.4.2




More information about the Libguestfs mailing list