Richard W.M. Jones
2014-Jan-17 09:39 UTC
[Libguestfs] [PATCH INCOMPLETE] launch: libvirt: Use C macros to simplify XML generation.
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
Reasonably Related Threads
- [PATCH v2 2/4] common/utils: Move libxml2 writer macros to a common header file.
- [PATCH v3 2/4] common/utils: Move libxml2 writer macros to a common header file.
- [PATCH v2 3/4] inspector: Use libxml writer macros.
- [PATCH] lib: Add direct support for the NBD (Network Block Device) protocol.
- [PATCH 2/2] Fix whitespace.