In some places when generating XML output in C code we use some clever macros:
start_element ("memory") { attribute ("unit", "MiB"); string ("%d", g->memsize); } end_element (); This commit which is mostly refactoring moves the repeated definitions of these macros into a common header file. I also took this opportunity to change / clean up the macros: - The macros are now documented properly. - comment() and empty_element() macros are now available everywhere. - Error handling has been made generic. - Added do..while(0) around some of the macros to make them safe to use in all contexts. - Both string() and attribute() take a format string (previously there were string_format() and attribute_format() variants). The last point causes the most churn since we must change the callers to avoid format string security bugs. --- common/utils/Makefile.am | 1 + common/utils/libxml2-writer-macros.h | 143 +++++++++++++++++++++++ docs/C_SOURCE_FILES | 1 + lib/launch-libvirt.c | 169 +++++++++------------------ p2v/physical-xml.c | 99 +++++----------- 5 files changed, 225 insertions(+), 188 deletions(-) diff --git a/common/utils/Makefile.am b/common/utils/Makefile.am index 1fa98f992..4ff9efcbd 100644 --- a/common/utils/Makefile.am +++ b/common/utils/Makefile.am @@ -28,6 +28,7 @@ libutils_la_SOURCES = \ libxml2-cleanups.c \ libxml2-utils.c \ libxml2-utils.h \ + libxml2-writer-macros.h \ utils.c libutils_la_CPPFLAGS = \ -DGUESTFS_WARN_DEPRECATED=1 \ diff --git a/common/utils/libxml2-writer-macros.h b/common/utils/libxml2-writer-macros.h new file mode 100644 index 000000000..b5705645a --- /dev/null +++ b/common/utils/libxml2-writer-macros.h @@ -0,0 +1,143 @@ +/* libguestfs + * Copyright (C) 2009-2018 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * These macros make it easier to write XML. To use them correctly + * you must be aware of these assumptions: + * + * =over 4 + * + * =item * + * + * The C<xmlTextWriterPtr> is called C<xo>. It is used implicitly + * by all the macros. + * + * =item * + * + * On failure, a function called C<xml_error> is called which you must + * define (usually as a macro). You must use C<CLEANUP_*> macros in + * your functions if you want correct cleanup of local variables along + * the error path. + * + * =item * + * + * All the "bad" casting is hidden inside the macros. + * + * =back + */ + +#ifndef GUESTFS_LIBXML2_WRITER_MACROS_H_ +#define GUESTFS_LIBXML2_WRITER_MACROS_H_ + +#include <stdarg.h> + +/** + * To define an XML element use: + * + * start_element ("name") { + * ... + * } end_element (); + * + * which produces C<<< <name>...</name> >>> + */ +#define start_element(element) \ + if (xmlTextWriterStartElement (xo, BAD_CAST (element)) == -1) { \ + xml_error ("xmlTextWriterStartElement"); \ + } \ + do + +#define end_element() \ + while (0); \ + do { \ + if (xmlTextWriterEndElement (xo) == -1) { \ + xml_error ("xmlTextWriterEndElement"); \ + } \ + } while (0) + +/** + * To define an empty element: + * + * empty_element ("name"); + * + * which produces C<<< <name/> >>> + */ +#define empty_element(element) \ + do { start_element ((element)) {} end_element (); } while (0) + +/** + * To define an XML element with attributes, use: + * + * start_element ("name") { + * attribute ("foo", "bar"); + * attribute ("count", "%d", count); + * ... + * } end_element (); + * + * which produces C<<< <name foo="bar" count="123">...</name> >>> + */ +#define attribute(key,fs,...) \ + do { \ + if (xmlTextWriterWriteFormatAttribute (xo, BAD_CAST (key), \ + fs, ##__VA_ARGS__) == -1) { \ + xml_error ("xmlTextWriterWriteFormatAttribute"); \ + } \ + } while (0) + +/** + * C<attribute_ns (prefix, key, namespace_uri, value)> defines a + * namespaced attribute. + */ +#define attribute_ns(prefix,key,namespace_uri,value) \ + do { \ + if (xmlTextWriterWriteAttributeNS (xo, BAD_CAST (prefix), \ + BAD_CAST (key), \ + BAD_CAST (namespace_uri), \ + BAD_CAST (value)) == -1) { \ + xml_error ("xmlTextWriterWriteAttribute"); \ + } \ + } while (0) + +/** + * To define a verbatim string, use: + * + * string ("hello"); + * + * or: + * + * string ("%s, world", greeting); + */ +#define string(fs,...) \ + do { \ + if (xmlTextWriterWriteFormatString (xo, fs, ##__VA_ARGS__) == -1) { \ + xml_error ("xmlTextWriterWriteFormatString"); \ + } \ + } while (0) + +/** + * To define a comment in the XML, use: + * + * comment ("number of items = %d", nr_items); + */ +#define comment(fs,...) \ + do { \ + if (xmlTextWriterWriteFormatComment (xo, fs, ##__VA_ARGS__) == -1) { \ + xml_error ("xmlTextWriterWriteFormatComment"); \ + } \ + } while (0) + +#endif /* GUESTFS_LIBXML2_WRITER_MACROS_H_ */ diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES index 1c262973c..7f1c60b30 100644 --- a/docs/C_SOURCE_FILES +++ b/docs/C_SOURCE_FILES @@ -62,6 +62,7 @@ common/utils/cleanups.h common/utils/gnulib-cleanups.c common/utils/guestfs-utils.h common/utils/libxml2-cleanups.c +common/utils/libxml2-writer-macros.h common/utils/utils.c common/visit/visit.c common/visit/visit.h diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c index 1a074fd6c..7b4b9f752 100644 --- a/lib/launch-libvirt.c +++ b/lib/launch-libvirt.c @@ -52,6 +52,16 @@ #include "guestfs-internal.h" #include "guestfs_protocol.h" +#include "libxml2-writer-macros.h" + +/* This macro is used by the macros in "libxml2-writer-macros.h" + * when an error occurs. + */ +#define xml_error(fn) \ + perrorf (g, _("%s:%d: error constructing libvirt XML near call to \"%s\""), \ + __FILE__, __LINE__, (fn)); \ + return -1; + /* Fixes for Mac OS X */ #ifndef SOCK_CLOEXEC # define SOCK_CLOEXEC O_CLOEXEC @@ -909,79 +919,6 @@ 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); \ - do { \ - if (xmlTextWriterEndElement (xo) == -1) { \ - xml_error ("xmlTextWriterEndElement"); \ - return -1; \ - } \ - } while (0) - -/* 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; \ - } - -/* key=value, but value is a printf-style format string. */ -#define attribute_format(key,fs,...) \ - if (xmlTextWriterWriteFormatAttribute (xo, BAD_CAST (key), \ - fs, ##__VA_ARGS__) == -1) { \ - xml_error ("xmlTextWriterWriteFormatAttribute"); \ - 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; \ - } - -/* A string, eg. within an element. */ -#define string(str) \ - if (xmlTextWriterWriteString (xo, BAD_CAST (str)) == -1) { \ - xml_error ("xmlTextWriterWriteString"); \ - return -1; \ - } - -/* A string, using printf-style formatting. */ -#define string_format(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)); - static xmlChar * construct_libvirt_xml (guestfs_h *g, const struct libvirt_xml_params *params) { @@ -1040,7 +977,7 @@ construct_libvirt_xml_domain (guestfs_h *g, xmlTextWriterPtr xo) { start_element ("domain") { - attribute ("type", params->data->is_kvm ? "kvm" : "qemu"); + attribute ("type", "%s", params->data->is_kvm ? "kvm" : "qemu"); attribute_ns ("xmlns", "qemu", NULL, "http://libvirt.org/schemas/domain/qemu/1.0"); @@ -1070,7 +1007,7 @@ construct_libvirt_xml_name (guestfs_h *g, xmlTextWriterPtr xo) { start_element ("name") { - string (params->data->name); + string ("%s", params->data->name); } end_element (); return 0; @@ -1086,12 +1023,12 @@ construct_libvirt_xml_cpu (guestfs_h *g, start_element ("memory") { attribute ("unit", "MiB"); - string_format ("%d", g->memsize); + string ("%d", g->memsize); } end_element (); start_element ("currentMemory") { attribute ("unit", "MiB"); - string_format ("%d", g->memsize); + string ("%d", g->memsize); } end_element (); cpu_model = guestfs_int_get_cpu_model (params->data->is_kvm); @@ -1105,14 +1042,14 @@ construct_libvirt_xml_cpu (guestfs_h *g, } else { start_element ("model") { - string (cpu_model); + string ("%s", cpu_model); } end_element (); } } end_element (); } start_element ("vcpu") { - string_format ("%d", g->smp); + string ("%d", g->smp); } end_element (); start_element ("clock") { @@ -1162,7 +1099,7 @@ construct_libvirt_xml_boot (guestfs_h *g, start_element ("os") { start_element ("type") { #ifdef MACHINE_TYPE - attribute ("machine", MACHINE_TYPE); + attribute ("machine", "%s", MACHINE_TYPE); #endif string ("hvm"); } end_element (); @@ -1171,12 +1108,12 @@ construct_libvirt_xml_boot (guestfs_h *g, start_element ("loader") { attribute ("readonly", "yes"); attribute ("type", "pflash"); - string (params->data->uefi_code); + string ("%s", params->data->uefi_code); } end_element (); if (params->data->uefi_vars) { start_element ("nvram") { - string (params->data->uefi_vars); + string ("%s", params->data->uefi_vars); } end_element (); } } @@ -1192,15 +1129,15 @@ construct_libvirt_xml_boot (guestfs_h *g, #endif start_element ("kernel") { - string (params->kernel); + string ("%s", params->kernel); } end_element (); start_element ("initrd") { - string (params->initrd); + string ("%s", params->initrd); } end_element (); start_element ("cmdline") { - string (cmdline); + string ("%s", cmdline); } end_element (); #if defined(__i386__) || defined(__x86_64__) @@ -1252,10 +1189,10 @@ construct_libvirt_xml_seclabel (guestfs_h *g, attribute ("model", "selinux"); attribute ("relabel", "yes"); start_element ("label") { - string (params->data->selinux_label); + string ("%s", params->data->selinux_label); } end_element (); start_element ("imagelabel") { - string (params->data->selinux_imagelabel); + string ("%s", params->data->selinux_imagelabel); } end_element (); } end_element (); } @@ -1292,7 +1229,7 @@ construct_libvirt_xml_devices (guestfs_h *g, */ if (is_custom_hv (g)) { start_element ("emulator") { - string (g->hv); + string ("%s", g->hv); } end_element (); } #if defined(__arm__) @@ -1301,7 +1238,7 @@ construct_libvirt_xml_devices (guestfs_h *g, */ else { start_element ("emulator") { - string (QEMU); + string ("%s", QEMU); } end_element (); } #endif @@ -1345,7 +1282,7 @@ construct_libvirt_xml_devices (guestfs_h *g, attribute ("type", "unix"); start_element ("source") { attribute ("mode", "connect"); - attribute ("path", params->data->console_path); + attribute ("path", "%s", params->data->console_path); } end_element (); start_element ("target") { attribute ("port", "0"); @@ -1359,7 +1296,7 @@ construct_libvirt_xml_devices (guestfs_h *g, attribute ("type", "unix"); start_element ("source") { attribute ("mode", "connect"); - attribute ("path", params->data->console_path); + attribute ("path", "%s", params->data->console_path); } end_element (); start_element ("target") { attribute ("type", "sclp"); @@ -1373,7 +1310,7 @@ construct_libvirt_xml_devices (guestfs_h *g, attribute ("type", "unix"); start_element ("source") { attribute ("mode", "connect"); - attribute ("path", params->data->guestfsd_path); + attribute ("path", "%s", params->data->guestfsd_path); } end_element (); start_element ("target") { attribute ("type", "virtio"); @@ -1386,7 +1323,7 @@ construct_libvirt_xml_devices (guestfs_h *g, start_element ("interface") { attribute ("type", "bridge"); start_element ("source") { - attribute ("bridge", params->data->network_bridge); + attribute ("bridge", "%s", params->data->network_bridge); } end_element (); start_element ("model") { attribute ("type", "virtio"); @@ -1440,7 +1377,7 @@ construct_libvirt_xml_disk (guestfs_h *g, attribute ("type", "file"); start_element ("source") { - attribute ("file", drv->overlay); + attribute ("file", "%s", drv->overlay); if (construct_libvirt_xml_disk_source_seclabel (g, data, xo) == -1) return -1; } end_element (); @@ -1480,7 +1417,7 @@ construct_libvirt_xml_disk (guestfs_h *g, attribute ("type", "file"); start_element ("source") { - attribute ("file", path); + attribute ("file", "%s", path); if (construct_libvirt_xml_disk_source_seclabel (g, data, xo) == -1) return -1; } end_element (); @@ -1489,7 +1426,7 @@ construct_libvirt_xml_disk (guestfs_h *g, attribute ("type", "block"); start_element ("source") { - attribute ("dev", drv->src.u.path); + attribute ("dev", "%s", drv->src.u.path); if (construct_libvirt_xml_disk_source_seclabel (g, data, xo) == -1) return -1; } end_element (); @@ -1521,9 +1458,9 @@ construct_libvirt_xml_disk (guestfs_h *g, attribute ("type", "network"); start_element ("source") { - attribute ("protocol", protocol_str); + attribute ("protocol", "%s", protocol_str); if (STRNEQ (drv->src.u.exportname, "")) - attribute ("name", drv->src.u.exportname); + attribute ("name", "%s", drv->src.u.exportname); if (construct_libvirt_xml_disk_source_hosts (g, xo, &drv->src) == -1) return -1; @@ -1533,14 +1470,14 @@ construct_libvirt_xml_disk (guestfs_h *g, if (drv->src.username != NULL) { start_element ("auth") { - attribute ("username", drv->src.username); + attribute ("username", "%s", drv->src.username); r = find_secret (g, data, drv, &type, &uuid); if (r == -1) return -1; if (r == 1) { start_element ("secret") { - attribute ("type", type); - attribute ("uuid", uuid); + attribute ("type", "%s", type); + attribute ("uuid", "%s", uuid); } end_element (); } } end_element (); @@ -1576,7 +1513,7 @@ construct_libvirt_xml_disk (guestfs_h *g, if (drv->disk_label) { start_element ("serial") { - string (drv->disk_label); + string ("%s", drv->disk_label); } end_element (); } @@ -1597,7 +1534,7 @@ construct_libvirt_xml_disk_target (guestfs_h *g, xmlTextWriterPtr xo, guestfs_int_drive_name (drv_index, &drive_name[2]); start_element ("target") { - attribute ("dev", drive_name); + attribute ("dev", "%s", drive_name); attribute ("bus", "scsi"); } end_element (); @@ -1642,8 +1579,8 @@ construct_libvirt_xml_disk_driver_qemu (guestfs_h *g, start_element ("driver") { attribute ("name", "qemu"); - attribute ("type", format); - attribute ("cache", cachemode); + attribute ("type", "%s", format); + attribute ("cache", "%s", cachemode); if (discard_unmap) attribute ("discard", "unmap"); if (copyonread) @@ -1679,7 +1616,7 @@ construct_libvirt_xml_disk_address (guestfs_h *g, xmlTextWriterPtr xo, * virtio-scsi driver, this is the ".id" field). This is a number * in the range 0-255. */ - attribute_format ("target", "%zu", drv_index); + attribute ("target", "%zu", drv_index); /* libvirt "unit" == qemu "lun". This is the SCSI logical unit * number, which is a number in the range 0..16383. @@ -1702,9 +1639,9 @@ construct_libvirt_xml_disk_source_hosts (guestfs_h *g, switch (src->servers[i].transport) { case drive_transport_none: case drive_transport_tcp: { - attribute ("name", src->servers[i].u.hostname); + attribute ("name", "%s", src->servers[i].u.hostname); if (src->servers[i].port > 0) - attribute_format ("port", "%d", src->servers[i].port); + attribute ("port", "%d", src->servers[i].port); break; } @@ -1722,7 +1659,7 @@ construct_libvirt_xml_disk_source_hosts (guestfs_h *g, } attribute ("transport", "unix"); - attribute ("socket", abs_socket); + attribute ("socket", "%s", abs_socket); break; } } @@ -1758,11 +1695,11 @@ construct_libvirt_xml_appliance (guestfs_h *g, attribute ("device", "disk"); start_element ("source") { - attribute ("file", params->appliance_overlay); + attribute ("file", "%s", params->appliance_overlay); } end_element (); start_element ("target") { - attribute ("dev", ¶ms->appliance_dev[5]); + attribute ("dev", "%s", ¶ms->appliance_dev[5]); attribute ("bus", "scsi"); } end_element (); @@ -1798,18 +1735,18 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, start_element ("qemu:env") { attribute ("name", "TMPDIR"); - attribute ("value", tmpdir); + attribute ("value", "%s", tmpdir); } end_element (); /* The qemu command line arguments requested by the caller. */ for (hp = g->hv_params; hp; hp = hp->next) { start_element ("qemu:arg") { - attribute ("value", hp->hv_param); + attribute ("value", "%s", hp->hv_param); } end_element (); if (hp->hv_value) { start_element ("qemu:arg") { - attribute ("value", hp->hv_value); + attribute ("value", "%s", hp->hv_value); } end_element (); } } @@ -1828,8 +1765,8 @@ construct_libvirt_xml_secret (guestfs_h *g, attribute ("ephemeral", "yes"); attribute ("private", "yes"); start_element ("description") { - string_format ("guestfs secret associated with %s %s", - data->name, drv->src.u.path); + string ("guestfs secret associated with %s %s", + data->name, drv->src.u.path); } end_element (); } end_element (); diff --git a/p2v/physical-xml.c b/p2v/physical-xml.c index f65a514d5..6ac8cc991 100644 --- a/p2v/physical-xml.c +++ b/p2v/physical-xml.c @@ -39,65 +39,20 @@ #include "getprogname.h" +#include "libxml2-writer-macros.h" + #include "p2v.h" +/* This macro is used by the macros in "libxml2-writer-macros.h" + * when an error occurs. + */ +#define xml_error(fn) \ + error (EXIT_FAILURE, errno, \ + "%s:%d: error constructing XML near call to \"%s\"", \ + __FILE__, __LINE__, (fn)); + static const char *map_interface_to_network (struct config *, const char *interface); -/* Macros "inspired" by lib/launch-libvirt.c */ -/* <element */ -#define start_element(element) \ - if (xmlTextWriterStartElement (xo, BAD_CAST (element)) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterStartElement"); \ - do - -/* finish current </element> */ -#define end_element() \ - while (0); \ - do { \ - if (xmlTextWriterEndElement (xo) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterEndElement"); \ - } while (0) - -/* <element/> */ -#define empty_element(element) \ - do { start_element(element) {} end_element (); } while (0) - -/* key=value attribute of the current element. */ -#define attribute(key,value) \ - do { \ - if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key), BAD_CAST (value)) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteAttribute"); \ - } while (0) - -/* key=value, but value is a printf-style format string. */ -#define attribute_format(key,fs,...) \ - do { \ - if (xmlTextWriterWriteFormatAttribute (xo, BAD_CAST (key), \ - fs, ##__VA_ARGS__) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatAttribute"); \ - } while (0) - -/* A string, eg. within an element. */ -#define string(str) \ - do { \ - if (xmlTextWriterWriteString (xo, BAD_CAST (str)) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteString"); \ - } while (0) - -/* A string, using printf-style formatting. */ -#define string_format(fs,...) \ - do { \ - if (xmlTextWriterWriteFormatString (xo, fs, ##__VA_ARGS__) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatString"); \ - } while (0) - -/* An XML comment. */ -#define comment(fs,...) \ - do { \ - if (xmlTextWriterWriteFormatComment (xo, fs, ##__VA_ARGS__) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatComment"); \ - } while (0) - /** * Write the libvirt XML for this physical machine. * @@ -143,21 +98,21 @@ generate_physical_xml (struct config *config, struct data_conn *data_conns, attribute ("type", "physical"); start_element ("name") { - string (config->guestname); + string ("%s", config->guestname); } end_element (); start_element ("memory") { attribute ("unit", "KiB"); - string_format ("%" PRIu64, memkb); + string ("%" PRIu64, memkb); } end_element (); start_element ("currentMemory") { attribute ("unit", "KiB"); - string_format ("%" PRIu64, memkb); + string ("%" PRIu64, memkb); } end_element (); start_element ("vcpu") { - string_format ("%d", config->vcpus); + string ("%d", config->vcpus); } end_element (); if (config->cpu.vendor || config->cpu.model || @@ -167,23 +122,23 @@ generate_physical_xml (struct config *config, struct data_conn *data_conns, attribute ("match", "minimum"); if (config->cpu.vendor) { start_element ("vendor") { - string (config->cpu.vendor); + string ("%s", config->cpu.vendor); } end_element (); } if (config->cpu.model) { start_element ("model") { attribute ("fallback", "allow"); - string (config->cpu.model); + string ("%s", config->cpu.model); } end_element (); } if (config->cpu.sockets || config->cpu.cores || config->cpu.threads) { start_element ("topology") { if (config->cpu.sockets) - attribute_format ("sockets", "%u", config->cpu.sockets); + attribute ("sockets", "%u", config->cpu.sockets); if (config->cpu.cores) - attribute_format ("cores", "%u", config->cpu.cores); + attribute ("cores", "%u", config->cpu.cores); if (config->cpu.threads) - attribute_format ("threads", "%u", config->cpu.threads); + attribute ("threads", "%u", config->cpu.threads); } end_element (); } } end_element (); @@ -200,7 +155,7 @@ generate_physical_xml (struct config *config, struct data_conn *data_conns, else { attribute ("offset", "variable"); attribute ("basis", "utc"); - attribute_format ("adjustment", "%d", config->rtc.offset); + attribute ("adjustment", "%d", config->rtc.offset); } } end_element (); break; @@ -214,7 +169,7 @@ generate_physical_xml (struct config *config, struct data_conn *data_conns, start_element ("os") { start_element ("type") { - attribute ("arch", host_cpu); + attribute ("arch", "%s", host_cpu); string ("hvm"); } end_element (); } end_element (); @@ -252,11 +207,11 @@ generate_physical_xml (struct config *config, struct data_conn *data_conns, attribute ("protocol", "nbd"); start_element ("host") { attribute ("name", "localhost"); - attribute_format ("port", "%d", data_conns[i].nbd_remote_port); + attribute ("port", "%d", data_conns[i].nbd_remote_port); } end_element (); } end_element (); start_element ("target") { - attribute ("dev", target_dev); + attribute ("dev", "%s", target_dev); /* XXX Need to set bus to "ide" or "scsi" here. */ } end_element (); } end_element (); @@ -272,7 +227,7 @@ generate_physical_xml (struct config *config, struct data_conn *data_conns, attribute ("type", "raw"); } end_element (); start_element ("target") { - attribute ("dev", config->removable[i]); + attribute ("dev", "%s", config->removable[i]); } end_element (); } end_element (); } @@ -300,14 +255,14 @@ generate_physical_xml (struct config *config, struct data_conn *data_conns, start_element ("interface") { attribute ("type", "network"); start_element ("source") { - attribute ("network", target_network); + attribute ("network", "%s", target_network); } end_element (); start_element ("target") { - attribute ("dev", config->interfaces[i]); + attribute ("dev", "%s", config->interfaces[i]); } end_element (); if (mac) { start_element ("mac") { - attribute ("address", mac); + attribute ("address", "%s", mac); } end_element (); } } end_element (); -- 2.19.0.rc0 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs