From 6d06b0d89bfeec8c9e04d99bf7b9fc430ed25d37 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 18 Nov 2014 14:50:05 +0000 Subject: [PATCH] Add virXMLValidateAgainstSchema helper method 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 85dd74cbbe..3d3d80a1d7 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 30445c1267..9855c49912 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 7ceb54dcf3..7a2c585ef2 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 4aa6d04088..f5d7f54fd8 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 93f8590cde..489bad8d5e 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 781b3bf8f6..b94de74a5e 100644 --- a/src/util/virxml.h +++ b/src/util/virxml.h @@ -28,6 +28,7 @@ # include # include # include +# include 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__ */