Add a helper method that can validate an XML document against an RNG schema --- include/libvirt/virterror.h | 1 + src/internal.h | 4 +++ src/libvirt_private.syms | 1 + src/util/virerror.c | 6 ++++ src/util/virxml.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ src/util/virxml.h | 5 +++ 6 files changed, 96 insertions(+) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 85dd74c..3d3d80a 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -304,6 +304,7 @@ typedef enum { VIR_ERR_STORAGE_VOL_EXIST = 90, /* the storage vol already exists */ VIR_ERR_CPU_INCOMPATIBLE = 91, /* given CPU is incompatible with host CPU*/ + VIR_ERR_XML_INVALID_SCHEMA = 92, /* XML document doens't validate against schema */ } virErrorNumber; /** diff --git a/src/internal.h b/src/internal.h index 30445c1..9855c49 100644 --- a/src/internal.h +++ b/src/internal.h @@ -234,11 +234,15 @@ # define VIR_WARNINGS_NO_CAST_ALIGN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wcast-align\"") +# define VIR_WARNINGS_NO_PRINTF \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wsuggest-attribute=format\"") # define VIR_WARNINGS_RESET \ _Pragma ("GCC diagnostic pop") # else # define VIR_WARNINGS_NO_CAST_ALIGN +# define VIR_WARNINGS_NO_PRINTF # define VIR_WARNINGS_RESET # endif diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7ceb54d..7a2c585 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2252,6 +2252,7 @@ virXMLParseHelper; virXMLPickShellSafeComment; virXMLPropString; virXMLSaveFile; +virXMLValidateAgainstSchema; virXPathBoolean; virXPathInt; virXPathLong; diff --git a/src/util/virerror.c b/src/util/virerror.c index 4aa6d04..f5d7f54 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -1285,6 +1285,12 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("the CPU is incompatible with host CPU: %s"); break; + case VIR_ERR_XML_INVALID_SCHEMA: + if (info == NULL) + errmsg = _("XML document failed to validate against schema"); + else + errmsg = _("XML document failed to validate against schema: %s"); + break; } return errmsg; } diff --git a/src/util/virxml.c b/src/util/virxml.c index 93f8590..489bad8 100644 --- a/src/util/virxml.c +++ b/src/util/virxml.c @@ -1082,3 +1082,82 @@ virXMLInjectNamespace(xmlNodePtr node, return 0; } + +static void catchRNGError(void *ctx, + const char *msg, + ...) +{ + virBufferPtr buf = ctx; + va_list args; + + va_start(args, msg); + VIR_WARNINGS_NO_PRINTF; + virBufferVasprintf(buf, msg, args); + VIR_WARNINGS_RESET; + va_end(args); +} + + +static void ignoreRNGError(void *ctx ATTRIBUTE_UNUSED, + const char *msg ATTRIBUTE_UNUSED, + ...) +{} + + +int +virXMLValidateAgainstSchema(const char *schemafile, + xmlDocPtr doc) +{ + xmlRelaxNGParserCtxtPtr rngParser = NULL; + xmlRelaxNGPtr rng = NULL; + xmlRelaxNGValidCtxtPtr rngValid = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + int ret = -1; + + if (!(rngParser = xmlRelaxNGNewParserCtxt(schemafile))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to create RNG parser for %s"), + schemafile); + goto cleanup; + } + + xmlRelaxNGSetParserErrors(rngParser, + catchRNGError, + ignoreRNGError, + &buf); + + if (!(rng = xmlRelaxNGParse(rngParser))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse RNG %s: %s"), + schemafile, virBufferCurrentContent(&buf)); + goto cleanup; + } + + if (!(rngValid = xmlRelaxNGNewValidCtxt(rng))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to create RNG validation context %s"), + schemafile); + goto cleanup; + } + + xmlRelaxNGSetValidErrors(rngValid, + catchRNGError, + ignoreRNGError, + &buf); + + if (xmlRelaxNGValidateDoc(rngValid, doc) != 0) { + virReportError(VIR_ERR_XML_INVALID_SCHEMA, + _("Unable to validate doc against %s\n%s"), + schemafile, virBufferCurrentContent(&buf)); + goto cleanup; + } + + ret = 0; + + cleanup: + virBufferFreeAndReset(&buf); + xmlRelaxNGFreeParserCtxt(rngParser); + xmlRelaxNGFreeValidCtxt(rngValid); + xmlRelaxNGFree(rng); + return ret; +} diff --git a/src/util/virxml.h b/src/util/virxml.h index 781b3bf..b94de74 100644 --- a/src/util/virxml.h +++ b/src/util/virxml.h @@ -28,6 +28,7 @@ # include <libxml/parser.h> # include <libxml/tree.h> # include <libxml/xpath.h> +# include <libxml/relaxng.h> int virXPathBoolean(const char *xpath, xmlXPathContextPtr ctxt); @@ -176,4 +177,8 @@ int virXMLInjectNamespace(xmlNodePtr node, const char *uri, const char *key); +int +virXMLValidateAgainstSchema(const char *schemafile, + xmlDocPtr xml); + #endif /* __VIR_XML_H__ */ -- 2.1.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list