Richard W.M. Jones
2018-Oct-04 12:03 UTC
[Libguestfs] [PATCH v2 0/4] common/utils: Move libxml2 writer macros to a common header file.
v1 was here: https://www.redhat.com/archives/libguestfs/2018-October/msg00047.html However it was broken in a few ways. First of all the documentation was broken because "/**" enhanced comments were not permitted on macros. This is fixed in the new 1/4 patch. Secondly we didn't use single_element() everywhere possible, which is fixed in the new 4/4 patch. Lastly I've enhanced the documentation so it's clear what precise XML is generated. Rich.
Richard W.M. Jones
2018-Oct-04 12:03 UTC
[Libguestfs] [PATCH v2 1/4] docs: Allow enhanced comments for macros (ie. #define).
---
docs/make-internal-documentation.pl | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/docs/make-internal-documentation.pl
b/docs/make-internal-documentation.pl
index a6673c48f..e08adad70 100755
--- a/docs/make-internal-documentation.pl
+++ b/docs/make-internal-documentation.pl
@@ -245,13 +245,19 @@ foreach $dir (@dirs) {
}
}
else {
- # First line tells us if this is a struct
- # or function.
+ # First line tells us if this is a struct,
+ # define or function.
if (/^struct ([\w_]+) \{$/) {
$thing = "Structure";
$name = $1;
$end = "};";
}
+ elsif (/^#define ([\w_]+)/) {
+ $thing = "Definition";
+ $name = $1;
+ $found_end = 1;
+ last;
+ }
else {
$thing = "Function";
$end = "{";
@@ -276,6 +282,10 @@ foreach $dir (@dirs) {
push @defn, "};"
}
+ if ($thing eq "Definition") {
+ @defn = ( "#define $name" )
+ }
+
# Print the definition, followed by the comment.
print OUTPUT "=head4 $thing
C<$input:$name>\n\n";
print OUTPUT " ", join ("\n ", @defn),
"\n";
--
2.19.0.rc0
Richard W.M. Jones
2018-Oct-04 12:03 UTC
[Libguestfs] [PATCH v2 2/4] common/utils: Move libxml2 writer macros to a common header file.
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
Richard W.M. Jones
2018-Oct-04 12:03 UTC
[Libguestfs] [PATCH v2 3/4] inspector: Use libxml writer macros.
Change virt-inspector so it uses the common set of macros. I also
added:
- single_element():
creates <foo>bar</foo> which is used extensively by
virt-inspector
- base64():
used by virt-inspector for the icon
---
common/utils/libxml2-writer-macros.h | 26 ++
inspector/inspector.c | 524 ++++++++++++---------------
2 files changed, 258 insertions(+), 292 deletions(-)
diff --git a/common/utils/libxml2-writer-macros.h
b/common/utils/libxml2-writer-macros.h
index b5705645a..13cd22ecd 100644
--- a/common/utils/libxml2-writer-macros.h
+++ b/common/utils/libxml2-writer-macros.h
@@ -79,6 +79,20 @@
#define empty_element(element) \
do { start_element ((element)) {} end_element (); } while (0)
+/**
+ * To define a single element with no attributes containing some text:
+ *
+ * single_element ("name", "%s", text);
+ *
+ * which produces C<<< <name>text</name> >>>
+ */
+#define single_element(element,fs,...) \
+ do { \
+ start_element ((element)) { \
+ string ((fs), ##__VA_ARGS__); \
+ } end_element (); \
+ } while (0)
+
/**
* To define an XML element with attributes, use:
*
@@ -128,6 +142,18 @@
} \
} while (0)
+/**
+ * To write a string encoded as base64:
+ *
+ * base64 (data, size);
+ */
+#define base64(data, size) \
+ do { \
+ if (xmlTextWriterWriteBase64 (xo, (data), 0, (size)) == -1) { \
+ xml_error ("xmlTextWriterWriteBase64");
\
+ } \
+ } while (0)
+
/**
* To define a comment in the XML, use:
*
diff --git a/inspector/inspector.c b/inspector/inspector.c
index 9be8f5110..cc5b49545 100644
--- a/inspector/inspector.c
+++ b/inspector/inspector.c
@@ -43,6 +43,7 @@
#include "structs-cleanups.h"
#include "options.h"
#include "display-options.h"
+#include "libxml2-writer-macros.h"
/* Currently open libguestfs handle. */
guestfs_h *g;
@@ -69,6 +70,14 @@ static void output_drive_mappings (xmlTextWriterPtr xo, char
*root);
static void output_applications (xmlTextWriterPtr xo, char *root);
static void do_xpath (const char *query);
+/* 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 void __attribute__((noreturn))
usage (int status)
{
@@ -307,11 +316,6 @@ main (int argc, char *argv[])
exit (EXIT_SUCCESS);
}
-#define XMLERROR(code,e) do { \
- if ((e) == (code)) \
- error (EXIT_FAILURE, errno, _("XML write error at
\"%s\""), #e); \
- } while (0)
-
static void
output (char **roots)
{
@@ -327,12 +331,17 @@ output (char **roots)
_("xmlNewTextWriter: failed to create libxml2 writer"));
/* Pretty-print the output. */
- XMLERROR (-1, xmlTextWriterSetIndent (xo, 1));
- XMLERROR (-1, xmlTextWriterSetIndentString (xo, BAD_CAST " "));
+ if (xmlTextWriterSetIndent (xo, 1) == -1 ||
+ xmlTextWriterSetIndentString (xo, BAD_CAST " ") == -1)
+ error (EXIT_FAILURE, errno, "could not set XML indent");
+
+ if (xmlTextWriterStartDocument (xo, NULL, NULL, NULL) == -1)
+ error (EXIT_FAILURE, errno, "xmlTextWriterStartDocument");
- XMLERROR (-1, xmlTextWriterStartDocument (xo, NULL, NULL, NULL));
output_roots (xo, roots);
- XMLERROR (-1, xmlTextWriterEndDocument (xo));
+
+ if (xmlTextWriterEndDocument (xo) == -1)
+ error (EXIT_FAILURE, errno, "xmlTextWriterEndDocument");
}
static void
@@ -340,10 +349,10 @@ output_roots (xmlTextWriterPtr xo, char **roots)
{
size_t i;
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"operatingsystems"));
- for (i = 0; roots[i] != NULL; ++i)
- output_root (xo, roots[i]);
- XMLERROR (-1, xmlTextWriterEndElement (xo));
+ start_element ("operatingsystems") {
+ for (i = 0; roots[i] != NULL; ++i)
+ output_root (xo, roots[i]);
+ } end_element ();
}
static void
@@ -351,152 +360,129 @@ output_root (xmlTextWriterPtr xo, char *root)
{
char *str;
int i;
- char buf[32];
char *canonical_root;
size_t size;
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"operatingsystem"));
-
- canonical_root = guestfs_canonical_device_name (g, root);
- if (canonical_root == NULL)
- exit (EXIT_FAILURE);
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "root", BAD_CAST
canonical_root));
- free (canonical_root);
-
- str = guestfs_inspect_get_type (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "name", BAD_CAST
str));
- free (str);
-
- str = guestfs_inspect_get_arch (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "arch", BAD_CAST
str));
- free (str);
-
- str = guestfs_inspect_get_distro (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "distro", BAD_CAST
str));
- free (str);
-
- str = guestfs_inspect_get_product_name (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "product_name",
BAD_CAST str));
- free (str);
-
- str = guestfs_inspect_get_product_variant (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "product_variant",
BAD_CAST str));
- free (str);
-
- i = guestfs_inspect_get_major_version (g, root);
- snprintf (buf, sizeof buf, "%d", i);
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "major_version",
BAD_CAST buf));
- i = guestfs_inspect_get_minor_version (g, root);
- snprintf (buf, sizeof buf, "%d", i);
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "minor_version",
BAD_CAST buf));
-
- str = guestfs_inspect_get_package_format (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "package_format",
BAD_CAST str));
- free (str);
-
- str = guestfs_inspect_get_package_management (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "package_management",
- BAD_CAST str));
- free (str);
-
- /* inspect-get-windows-systemroot will fail with non-windows guests,
- * or if the systemroot could not be determined for a windows guest.
- * Disable error output around this call.
- */
- guestfs_push_error_handler (g, NULL, NULL);
- str = guestfs_inspect_get_windows_systemroot (g, root);
- if (str)
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST
"windows_systemroot",
- BAD_CAST str));
- free (str);
- str = guestfs_inspect_get_windows_current_control_set (g, root);
- if (str)
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST
"windows_current_control_set",
- BAD_CAST str));
- free (str);
- guestfs_pop_error_handler (g);
-
- str = guestfs_inspect_get_hostname (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "hostname",
- BAD_CAST str));
- free (str);
-
- str = guestfs_inspect_get_osinfo (g, root);
- if (!str) exit (EXIT_FAILURE);
- if (STRNEQ (str, "unknown"))
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "osinfo",
BAD_CAST str));
- free (str);
-
- output_mountpoints (xo, root);
-
- output_filesystems (xo, root);
-
- output_drive_mappings (xo, root);
-
- /* We need to mount everything up in order to read out the list of
- * applications and the icon, ie. everything below this point.
- */
- if (inspect_apps || inspect_icon) {
- inspect_mount_root (g, root);
-
- if (inspect_apps)
- output_applications (xo, root);
-
- if (inspect_icon) {
- /* Don't return favicon. RHEL 7 and Fedora have crappy 16x16
- * favicons in the base distro.
- */
- str = guestfs_inspect_get_icon (g, root, &size,
- GUESTFS_INSPECT_GET_ICON_FAVICON, 0,
- -1);
- if (!str) exit (EXIT_FAILURE);
- if (size > 0) {
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"icon"));
- XMLERROR (-1, xmlTextWriterWriteBase64 (xo, str, 0, size));
- XMLERROR (-1, xmlTextWriterEndElement (xo));
+ start_element ("operatingsystem") {
+ canonical_root = guestfs_canonical_device_name (g, root);
+ if (canonical_root == NULL)
+ exit (EXIT_FAILURE);
+ single_element ("root", "%s", canonical_root);
+ free (canonical_root);
+
+ str = guestfs_inspect_get_type (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("name", "%s", str);
+ free (str);
+
+ str = guestfs_inspect_get_arch (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("arch", "%s", str);
+ free (str);
+
+ str = guestfs_inspect_get_distro (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("distro", "%s", str);
+ free (str);
+
+ str = guestfs_inspect_get_product_name (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("product_name", "%s", str);
+ free (str);
+
+ str = guestfs_inspect_get_product_variant (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("product_variant", "%s", str);
+ free (str);
+
+ i = guestfs_inspect_get_major_version (g, root);
+ single_element ("major_version", "%d", i);
+ i = guestfs_inspect_get_minor_version (g, root);
+ single_element ("minor_version", "%d", i);
+
+ str = guestfs_inspect_get_package_format (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("package_format", "%s", str);
+ free (str);
+
+ str = guestfs_inspect_get_package_management (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("package_management", "%s", str);
+ free (str);
+
+ /* inspect-get-windows-systemroot will fail with non-windows guests,
+ * or if the systemroot could not be determined for a windows guest.
+ * Disable error output around this call.
+ */
+ guestfs_push_error_handler (g, NULL, NULL);
+ str = guestfs_inspect_get_windows_systemroot (g, root);
+ if (str)
+ single_element ("windows_systemroot", "%s", str);
+ free (str);
+ str = guestfs_inspect_get_windows_current_control_set (g, root);
+ if (str)
+ single_element ("windows_current_control_set", "%s",
str);
+ free (str);
+ guestfs_pop_error_handler (g);
+
+ str = guestfs_inspect_get_hostname (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("hostname", "%s", str);
+ free (str);
+
+ str = guestfs_inspect_get_osinfo (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ single_element ("osinfo", "%s", str);
+ free (str);
+
+ output_mountpoints (xo, root);
+
+ output_filesystems (xo, root);
+
+ output_drive_mappings (xo, root);
+
+ /* We need to mount everything up in order to read out the list of
+ * applications and the icon, ie. everything below this point.
+ */
+ if (inspect_apps || inspect_icon) {
+ inspect_mount_root (g, root);
+
+ if (inspect_apps)
+ output_applications (xo, root);
+
+ if (inspect_icon) {
+ /* Don't return favicon. RHEL 7 and Fedora have crappy 16x16
+ * favicons in the base distro.
+ */
+ str = guestfs_inspect_get_icon (g, root, &size,
+ GUESTFS_INSPECT_GET_ICON_FAVICON, 0,
+ -1);
+ if (!str) exit (EXIT_FAILURE);
+ if (size > 0) {
+ start_element ("icon") {
+ base64 (str, size);
+ } end_element ();
+ }
+ /* Note we must free (str) even if size == 0, because that indicates
+ * there was no icon.
+ */
+ free (str);
}
- /* Note we must free (str) even if size == 0, because that indicates
- * there was no icon.
- */
- free (str);
+
+ /* Unmount (see inspect_mount_root above). */
+ if (guestfs_umount_all (g) == -1)
+ exit (EXIT_FAILURE);
}
-
- /* Unmount (see inspect_mount_root above). */
- if (guestfs_umount_all (g) == -1)
- exit (EXIT_FAILURE);
- }
-
- XMLERROR (-1, xmlTextWriterEndElement (xo));
+ } end_element (); /* operatingsystem */
}
static int
@@ -548,23 +534,19 @@ output_mountpoints (xmlTextWriterPtr xo, char *root)
2 * sizeof (char *),
compare_keys_len);
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"mountpoints"));
+ start_element ("mountpoints") {
+ for (i = 0; mountpoints[i] != NULL; i += 2) {
+ CLEANUP_FREE char *p + guestfs_canonical_device_name (g,
mountpoints[i+1]);
+ if (!p)
+ exit (EXIT_FAILURE);
- for (i = 0; mountpoints[i] != NULL; i += 2) {
- CLEANUP_FREE char *p = guestfs_canonical_device_name (g, mountpoints[i+1]);
- if (!p)
- exit (EXIT_FAILURE);
-
- XMLERROR (-1,
- xmlTextWriterStartElement (xo, BAD_CAST "mountpoint"));
- XMLERROR (-1,
- xmlTextWriterWriteAttribute (xo, BAD_CAST "dev",
BAD_CAST p));
- XMLERROR (-1,
- xmlTextWriterWriteString (xo, BAD_CAST mountpoints[i]));
- XMLERROR (-1, xmlTextWriterEndElement (xo));
- }
-
- XMLERROR (-1, xmlTextWriterEndElement (xo));
+ start_element ("mountpoint") {
+ attribute ("dev", "%s", p);
+ string ("%s", mountpoints[i]);
+ } end_element ();
+ }
+ } end_element ();
}
static void
@@ -582,47 +564,37 @@ output_filesystems (xmlTextWriterPtr xo, char *root)
qsort (filesystems, guestfs_int_count_strings (filesystems), sizeof (char *),
compare_keys);
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"filesystems"));
-
- for (i = 0; filesystems[i] != NULL; ++i) {
- str = guestfs_canonical_device_name (g, filesystems[i]);
- if (!str)
- exit (EXIT_FAILURE);
-
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"filesystem"));
- XMLERROR (-1,
- xmlTextWriterWriteAttribute (xo, BAD_CAST "dev",
BAD_CAST str));
- free (str);
-
- guestfs_push_error_handler (g, NULL, NULL);
-
- str = guestfs_vfs_type (g, filesystems[i]);
- if (str && str[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "type",
- BAD_CAST str));
- free (str);
-
- str = guestfs_vfs_label (g, filesystems[i]);
- if (str && str[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "label",
- BAD_CAST str));
- free (str);
-
- str = guestfs_vfs_uuid (g, filesystems[i]);
- if (str && str[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "uuid",
- BAD_CAST str));
- free (str);
-
- guestfs_pop_error_handler (g);
-
- XMLERROR (-1, xmlTextWriterEndElement (xo));
- }
-
- XMLERROR (-1, xmlTextWriterEndElement (xo));
+ start_element ("filesystems") {
+ for (i = 0; filesystems[i] != NULL; ++i) {
+ str = guestfs_canonical_device_name (g, filesystems[i]);
+ if (!str)
+ exit (EXIT_FAILURE);
+
+ start_element ("filesystem") {
+ attribute ("dev", "%s", str);
+ free (str);
+
+ guestfs_push_error_handler (g, NULL, NULL);
+
+ str = guestfs_vfs_type (g, filesystems[i]);
+ if (str && str[0])
+ single_element ("type", "%s", str);
+ free (str);
+
+ str = guestfs_vfs_label (g, filesystems[i]);
+ if (str && str[0])
+ single_element ("label", "%s", str);
+ free (str);
+
+ str = guestfs_vfs_uuid (g, filesystems[i]);
+ if (str && str[0])
+ single_element ("uuid", "%s", str);
+ free (str);
+
+ guestfs_pop_error_handler (g);
+ } end_element ();
+ }
+ } end_element ();
}
static void
@@ -646,26 +618,20 @@ output_drive_mappings (xmlTextWriterPtr xo, char *root)
guestfs_int_count_strings (drive_mappings) / 2, 2 * sizeof (char *),
compare_keys_nocase);
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"drive_mappings"));
-
- for (i = 0; drive_mappings[i] != NULL; i += 2) {
- str = guestfs_canonical_device_name (g, drive_mappings[i+1]);
- if (!str)
- exit (EXIT_FAILURE);
-
- XMLERROR (-1,
- xmlTextWriterStartElement (xo, BAD_CAST
"drive_mapping"));
- XMLERROR (-1,
- xmlTextWriterWriteAttribute (xo, BAD_CAST "name",
- BAD_CAST drive_mappings[i]));
- XMLERROR (-1,
- xmlTextWriterWriteString (xo, BAD_CAST str));
- XMLERROR (-1, xmlTextWriterEndElement (xo));
-
- free (str);
- }
-
- XMLERROR (-1, xmlTextWriterEndElement (xo));
+ start_element ("drive_mappings") {
+ for (i = 0; drive_mappings[i] != NULL; i += 2) {
+ str = guestfs_canonical_device_name (g, drive_mappings[i+1]);
+ if (!str)
+ exit (EXIT_FAILURE);
+
+ start_element ("drive_mapping") {
+ attribute ("name", "%s", drive_mappings[i]);
+ string ("%s", str);
+ } end_element ();
+
+ free (str);
+ }
+ } end_element ();
}
static void
@@ -681,71 +647,45 @@ output_applications (xmlTextWriterPtr xo, char *root)
if (apps == NULL)
exit (EXIT_FAILURE);
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"applications"));
+ start_element ("applications") {
+ for (i = 0; i < apps->len; ++i) {
+ start_element ("application") {
+ assert (apps->val[i].app2_name &&
apps->val[i].app2_name[0]);
+ single_element ("name", "%s",
apps->val[i].app2_name);
- for (i = 0; i < apps->len; ++i) {
- XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST
"application"));
+ if (apps->val[i].app2_display_name &&
+ apps->val[i].app2_display_name[0])
+ single_element ("display_name", "%s",
+ apps->val[i].app2_display_name);
- assert (apps->val[i].app2_name && apps->val[i].app2_name[0]);
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "name",
- BAD_CAST apps->val[i].app2_name));
+ if (apps->val[i].app2_epoch != 0)
+ single_element ("epoch", "%d",
apps->val[i].app2_epoch);
- if (apps->val[i].app2_display_name &&
apps->val[i].app2_display_name[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "display_name",
- BAD_CAST apps->val[i].app2_display_name));
-
- if (apps->val[i].app2_epoch != 0) {
- char buf[32];
-
- snprintf (buf, sizeof buf, "%d", apps->val[i].app2_epoch);
-
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "epoch", BAD_CAST buf));
+ if (apps->val[i].app2_version &&
apps->val[i].app2_version[0])
+ single_element ("version", "%s",
apps->val[i].app2_version);
+ if (apps->val[i].app2_release &&
apps->val[i].app2_release[0])
+ single_element ("release", "%s",
apps->val[i].app2_release);
+ if (apps->val[i].app2_arch && apps->val[i].app2_arch[0])
+ single_element ("arch", "%s",
apps->val[i].app2_arch);
+ if (apps->val[i].app2_install_path &&
+ apps->val[i].app2_install_path[0])
+ single_element ("install_path", "%s",
+ apps->val[i].app2_install_path);
+ if (apps->val[i].app2_publisher &&
apps->val[i].app2_publisher[0])
+ single_element ("publisher", "%s",
apps->val[i].app2_publisher);
+ if (apps->val[i].app2_url && apps->val[i].app2_url[0])
+ single_element ("url", "%s",
apps->val[i].app2_url);
+ if (apps->val[i].app2_source_package &&
+ apps->val[i].app2_source_package[0])
+ single_element ("source_package", "%s",
+ apps->val[i].app2_source_package);
+ if (apps->val[i].app2_summary &&
apps->val[i].app2_summary[0])
+ single_element ("summary", "%s",
apps->val[i].app2_summary);
+ if (apps->val[i].app2_description &&
apps->val[i].app2_description[0])
+ single_element ("description", "%s",
apps->val[i].app2_description);
+ } end_element ();
}
-
- if (apps->val[i].app2_version &&
apps->val[i].app2_version[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "version",
- BAD_CAST apps->val[i].app2_version));
- if (apps->val[i].app2_release &&
apps->val[i].app2_release[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "release",
- BAD_CAST apps->val[i].app2_release));
- if (apps->val[i].app2_arch && apps->val[i].app2_arch[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "arch",
- BAD_CAST apps->val[i].app2_arch));
- if (apps->val[i].app2_install_path &&
apps->val[i].app2_install_path[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "install_path",
- BAD_CAST apps->val[i].app2_install_path));
- if (apps->val[i].app2_publisher &&
apps->val[i].app2_publisher[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "publisher",
- BAD_CAST apps->val[i].app2_publisher));
- if (apps->val[i].app2_url && apps->val[i].app2_url[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "url",
- BAD_CAST apps->val[i].app2_url));
- if (apps->val[i].app2_source_package &&
apps->val[i].app2_source_package[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "source_package",
- BAD_CAST apps->val[i].app2_source_package));
- if (apps->val[i].app2_summary &&
apps->val[i].app2_summary[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "summary",
- BAD_CAST apps->val[i].app2_summary));
- if (apps->val[i].app2_description &&
apps->val[i].app2_description[0])
- XMLERROR (-1,
- xmlTextWriterWriteElement (xo, BAD_CAST "description",
- BAD_CAST apps->val[i].app2_description));
-
- XMLERROR (-1, xmlTextWriterEndElement (xo));
- }
-
- XMLERROR (-1, xmlTextWriterEndElement (xo));
+ } end_element ();
}
/* Run an XPath query on XML on stdin, print results to stdout. */
--
2.19.0.rc0
Richard W.M. Jones
2018-Oct-04 12:03 UTC
[Libguestfs] [PATCH v2 4/4] lib, p2v: Use single_element() macro where possible.
After the previous commit, wherever we had:
start_element ("foo") {
string ("bar");
} end_element ();
this can now be replaced by:
single_element ("foo", "bar");
---
lib/launch-libvirt.c | 81 ++++++++++++--------------------------------
p2v/physical-xml.c | 15 +++-----
2 files changed, 25 insertions(+), 71 deletions(-)
diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
index 7b4b9f752..f6ef6bcad 100644
--- a/lib/launch-libvirt.c
+++ b/lib/launch-libvirt.c
@@ -1006,10 +1006,7 @@ construct_libvirt_xml_name (guestfs_h *g,
const struct libvirt_xml_params *params,
xmlTextWriterPtr xo)
{
- start_element ("name") {
- string ("%s", params->data->name);
- } end_element ();
-
+ single_element ("name", "%s", params->data->name);
return 0;
}
@@ -1040,17 +1037,12 @@ construct_libvirt_xml_cpu (guestfs_h *g,
attribute ("fallback", "allow");
} end_element ();
}
- else {
- start_element ("model") {
- string ("%s", cpu_model);
- } end_element ();
- }
+ else
+ single_element ("model", "%s", cpu_model);
} end_element ();
}
- start_element ("vcpu") {
- string ("%d", g->smp);
- } end_element ();
+ single_element ("vcpu", "%d", g->smp);
start_element ("clock") {
attribute ("offset", "utc");
@@ -1111,11 +1103,8 @@ construct_libvirt_xml_boot (guestfs_h *g,
string ("%s", params->data->uefi_code);
} end_element ();
- if (params->data->uefi_vars) {
- start_element ("nvram") {
- string ("%s", params->data->uefi_vars);
- } end_element ();
- }
+ if (params->data->uefi_vars)
+ single_element ("nvram", "%s",
params->data->uefi_vars);
}
#ifdef __powerpc64__
@@ -1128,17 +1117,9 @@ construct_libvirt_xml_boot (guestfs_h *g,
}
#endif
- start_element ("kernel") {
- string ("%s", params->kernel);
- } end_element ();
-
- start_element ("initrd") {
- string ("%s", params->initrd);
- } end_element ();
-
- start_element ("cmdline") {
- string ("%s", cmdline);
- } end_element ();
+ single_element ("kernel", "%s", params->kernel);
+ single_element ("initrd", "%s", params->initrd);
+ single_element ("cmdline", "%s", cmdline);
#if defined(__i386__) || defined(__x86_64__)
if (g->verbose) {
@@ -1167,9 +1148,7 @@ construct_libvirt_xml_seclabel (guestfs_h *g,
attribute ("type", "static");
attribute ("model", "dac");
attribute ("relabel", "no");
- start_element ("label") {
- string ("0:0");
- } end_element ();
+ single_element ("label", "0:0");
} end_element ();
}
@@ -1188,12 +1167,8 @@ construct_libvirt_xml_seclabel (guestfs_h *g,
attribute ("type", "static");
attribute ("model", "selinux");
attribute ("relabel", "yes");
- start_element ("label") {
- string ("%s", params->data->selinux_label);
- } end_element ();
- start_element ("imagelabel") {
- string ("%s", params->data->selinux_imagelabel);
- } end_element ();
+ single_element ("label", "%s",
params->data->selinux_label);
+ single_element ("imagelabel", "%s",
params->data->selinux_imagelabel);
} end_element ();
}
@@ -1206,10 +1181,7 @@ construct_libvirt_xml_lifecycle (guestfs_h *g,
const struct libvirt_xml_params *params,
xmlTextWriterPtr xo)
{
- start_element ("on_reboot") {
- string ("destroy");
- } end_element ();
-
+ single_element ("on_reboot", "destroy");
return 0;
}
@@ -1227,20 +1199,14 @@ construct_libvirt_xml_devices (guestfs_h *g,
/* Path to hypervisor. Only write this if the user has changed the
* default, otherwise allow libvirt to choose the best one.
*/
- if (is_custom_hv (g)) {
- start_element ("emulator") {
- string ("%s", g->hv);
- } end_element ();
- }
+ if (is_custom_hv (g))
+ single_element ("emulator", "%s", g->hv);
#if defined(__arm__)
/* Hopefully temporary hack to make ARM work (otherwise libvirt
* chooses to run /usr/bin/qemu-kvm).
*/
- else {
- start_element ("emulator") {
- string ("%s", QEMU);
- } end_element ();
- }
+ else
+ single_element ("emulator", "%s", QEMU);
#endif
/* Add a random number generator (backend for virtio-rng). This
@@ -1511,11 +1477,8 @@ construct_libvirt_xml_disk (guestfs_h *g,
return -1;
}
- if (drv->disk_label) {
- start_element ("serial") {
- string ("%s", drv->disk_label);
- } end_element ();
- }
+ if (drv->disk_label)
+ single_element ("serial", "%s", drv->disk_label);
if (construct_libvirt_xml_disk_address (g, xo, drv_index) == -1)
return -1;
@@ -1764,10 +1727,8 @@ construct_libvirt_xml_secret (guestfs_h *g,
start_element ("secret") {
attribute ("ephemeral", "yes");
attribute ("private", "yes");
- start_element ("description") {
- string ("guestfs secret associated with %s %s",
- data->name, drv->src.u.path);
- } end_element ();
+ single_element ("description", "guestfs secret associated
with %s %s",
+ data->name, drv->src.u.path);
} end_element ();
return 0;
diff --git a/p2v/physical-xml.c b/p2v/physical-xml.c
index 6ac8cc991..ffcb9e24e 100644
--- a/p2v/physical-xml.c
+++ b/p2v/physical-xml.c
@@ -97,9 +97,7 @@ generate_physical_xml (struct config *config, struct data_conn
*data_conns,
start_element ("domain") {
attribute ("type", "physical");
- start_element ("name") {
- string ("%s", config->guestname);
- } end_element ();
+ single_element ("name", "%s", config->guestname);
start_element ("memory") {
attribute ("unit", "KiB");
@@ -111,20 +109,15 @@ generate_physical_xml (struct config *config, struct
data_conn *data_conns,
string ("%" PRIu64, memkb);
} end_element ();
- start_element ("vcpu") {
- string ("%d", config->vcpus);
- } end_element ();
+ single_element ("vcpu", "%d", config->vcpus);
if (config->cpu.vendor || config->cpu.model ||
config->cpu.sockets || config->cpu.cores ||
config->cpu.threads) {
/* https://libvirt.org/formatdomain.html#elementsCPU */
start_element ("cpu") {
attribute ("match", "minimum");
- if (config->cpu.vendor) {
- start_element ("vendor") {
- string ("%s", config->cpu.vendor);
- } end_element ();
- }
+ if (config->cpu.vendor)
+ single_element ("vendor", "%s",
config->cpu.vendor);
if (config->cpu.model) {
start_element ("model") {
attribute ("fallback", "allow");
--
2.19.0.rc0
Pino Toscano
2018-Nov-02 14:15 UTC
Re: [Libguestfs] [PATCH v2 2/4] common/utils: Move libxml2 writer macros to a common header file.
On Thursday, 4 October 2018 14:03:48 CET Richard W.M. Jones wrote:> 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).I'd still keep these variants, as there is no need for a format string in case there is already the final string to be used. -- Pino Toscano
Pino Toscano
2018-Nov-02 14:24 UTC
Re: [Libguestfs] [PATCH v2 3/4] inspector: Use libxml writer macros.
On Thursday, 4 October 2018 14:03:49 CET Richard W.M. Jones wrote:> Change virt-inspector so it uses the common set of macros. I also > added: > > - single_element(): > > creates <foo>bar</foo> which is used extensively by virt-inspectorAs mentioned in patch #2, having two variants single_elements (for string) and single_element_format (for format string) is better IMHO. -- Pino Toscano
Seemingly Similar Threads
- [PATCH 2/2] Fix whitespace.
- [PATCH INCOMPLETE] launch: libvirt: Use C macros to simplify XML generation.
- Re: [PATCH] inspector: Fix virt-inspector on *BSD guests (RHBZ#1144138).
- [PATCH] inspector: Fix virt-inspector on *BSD guests (RHBZ#1144138).
- Re: [PATCH] inspector: Fix virt-inspector on *BSD guests (RHBZ#1144138).