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