[libvirt] [PATCH 2/2] Detailed XML errors
Richard W.M. Jones
rjones at redhat.com
Wed Jul 30 16:12:53 UTC 2008
This implements the XML errors using thread-local storage to
store the connection.
Rich.
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
-------------- next part --------------
Index: src/domain_conf.c
===================================================================
RCS file: /data/cvs/libvirt/src/domain_conf.c,v
retrieving revision 1.10
diff -u -r1.10 domain_conf.c
--- src/domain_conf.c 28 Jul 2008 14:06:54 -0000 1.10
+++ src/domain_conf.c 30 Jul 2008 16:07:07 -0000
@@ -38,6 +38,7 @@
#include "util.h"
#include "buf.h"
#include "c-ctype.h"
+#include "threads.h"
VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
"qemu",
@@ -1838,32 +1839,66 @@
return NULL;
}
+/* Called from SAX on parsing errors in the XML. */
+THREAD_LOCAL(xml_conn)
+
+static void
+catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
+{
+ xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+ if (ctxt &&
+ ctxt->lastError.level == XML_ERR_FATAL &&
+ ctxt->lastError.message != NULL) {
+ virDomainReportError (THREAD_LOCAL_GET (xml_conn), VIR_ERR_XML_DETAIL,
+ ctxt->lastError.message, ctxt->lastError.line);
+ }
+}
virDomainDefPtr virDomainDefParseString(virConnectPtr conn,
virCapsPtr caps,
const char *xmlStr)
{
- xmlDocPtr xml;
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr xml = NULL;
xmlNodePtr root;
virDomainDefPtr def = NULL;
- if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "domain.xml", NULL,
- XML_PARSE_NOENT | XML_PARSE_NONET |
- XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
- virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);
- return NULL;
+ THREAD_LOCAL_INIT (xml_conn);
+ THREAD_LOCAL_SET (xml_conn, conn);
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+
+ /* It'd be nice to do this, but seems ->userData field is used
+ * by something else.
+ */
+ /*pctxt->userData = conn;*/
+
+ xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "domain.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xml) {
+ /* virDomainReportError has already been called by the
+ * callback function (hopefully).
+ */
+ goto cleanup;
}
if ((root = xmlDocGetRootElement(xml)) == NULL) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
"%s", _("missing root element"));
- xmlFreeDoc(xml);
- return NULL;
+ goto cleanup;
}
def = virDomainDefParseNode(conn, caps, xml, root);
- xmlFreeDoc(xml);
+cleanup:
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc (xml);
return def;
}
@@ -1871,27 +1906,46 @@
virCapsPtr caps,
const char *filename)
{
- xmlDocPtr xml;
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr xml = NULL;
xmlNodePtr root;
virDomainDefPtr def = NULL;
- if (!(xml = xmlReadFile(filename, NULL,
- XML_PARSE_NOENT | XML_PARSE_NONET |
- XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
- virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);
- return NULL;
+ THREAD_LOCAL_INIT (xml_conn);
+ THREAD_LOCAL_SET (xml_conn, conn);
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+
+ /* It'd be nice to do this, but seems ->userData field is used
+ * by something else.
+ */
+ /*pctxt->userData = conn;*/
+
+ xml = xmlCtxtReadFile (pctxt, filename, NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xml) {
+ /* virDomainReportError has already been called by the
+ * callback function (hopefully).
+ */
+ goto cleanup;
}
if ((root = xmlDocGetRootElement(xml)) == NULL) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
"%s", _("missing root element"));
- xmlFreeDoc(xml);
- return NULL;
+ goto cleanup;
}
def = virDomainDefParseNode(conn, caps, xml, root);
- xmlFreeDoc(xml);
+cleanup:
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc (xml);
return def;
}
Index: src/network_conf.c
===================================================================
RCS file: /data/cvs/libvirt/src/network_conf.c,v
retrieving revision 1.3
diff -u -r1.3 network_conf.c
--- src/network_conf.c 25 Jul 2008 14:27:25 -0000 1.3
+++ src/network_conf.c 30 Jul 2008 16:07:07 -0000
@@ -39,6 +39,7 @@
#include "uuid.h"
#include "util.h"
#include "buf.h"
+#include "threads.h"
VIR_ENUM_DECL(virNetworkForward)
@@ -348,57 +349,111 @@
return NULL;
}
+/* Called from SAX on parsing errors in the XML. */
+THREAD_LOCAL (xml_conn)
+
+static void
+catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
+{
+ xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+ if (ctxt &&
+ ctxt->lastError.level == XML_ERR_FATAL &&
+ ctxt->lastError.message != NULL) {
+ virNetworkReportError (THREAD_LOCAL_GET (xml_conn), VIR_ERR_XML_DETAIL,
+ ctxt->lastError.message, ctxt->lastError.line);
+ }
+}
+
virNetworkDefPtr virNetworkDefParseString(virConnectPtr conn,
const char *xmlStr)
{
- xmlDocPtr xml;
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr xml = NULL;
xmlNodePtr root;
- virNetworkDefPtr def;
+ virNetworkDefPtr def = NULL;
- if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "network.xml", NULL,
- XML_PARSE_NOENT | XML_PARSE_NONET |
- XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
- virNetworkReportError(conn, VIR_ERR_XML_ERROR, NULL);
- return NULL;
+ THREAD_LOCAL_INIT (xml_conn);
+ THREAD_LOCAL_SET (xml_conn, conn);
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+
+ /* It'd be nice to do this, but seems ->userData field is used
+ * by something else.
+ */
+ /*pctxt->userData = conn;*/
+
+ xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "network.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xml) {
+ /* virNetworkReportError has already been called by the
+ * callback function (hopefully).
+ */
+ goto cleanup;
}
if ((root = xmlDocGetRootElement(xml)) == NULL) {
virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
"%s", _("missing root element"));
- xmlFreeDoc(xml);
- return NULL;
+ goto cleanup;
}
def = virNetworkDefParseNode(conn, xml, root);
- xmlFreeDoc(xml);
+cleanup:
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc (xml);
return def;
}
virNetworkDefPtr virNetworkDefParseFile(virConnectPtr conn,
const char *filename)
{
- xmlDocPtr xml;
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr xml = NULL;
xmlNodePtr root;
- virNetworkDefPtr def;
+ virNetworkDefPtr def = NULL;
- if (!(xml = xmlReadFile(filename, NULL,
- XML_PARSE_NOENT | XML_PARSE_NONET |
- XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
- virNetworkReportError(conn, VIR_ERR_XML_ERROR, NULL);
- return NULL;
+ THREAD_LOCAL_INIT (xml_conn);
+ THREAD_LOCAL_SET (xml_conn, conn);
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+
+ /* It'd be nice to do this, but seems ->userData field is used
+ * by something else.
+ */
+ /*pctxt->userData = conn;*/
+
+ xml = xmlCtxtReadFile (pctxt, filename, NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xml) {
+ /* virNetworkReportError has already been called by the
+ * callback function (hopefully).
+ */
+ goto cleanup;
}
if ((root = xmlDocGetRootElement(xml)) == NULL) {
virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
"%s", _("missing root element"));
- xmlFreeDoc(xml);
- return NULL;
+ goto cleanup;
}
def = virNetworkDefParseNode(conn, xml, root);
- xmlFreeDoc(xml);
+cleanup:
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc (xml);
return def;
}
Index: src/storage_conf.c
===================================================================
RCS file: /data/cvs/libvirt/src/storage_conf.c,v
retrieving revision 1.10
diff -u -r1.10 storage_conf.c
--- src/storage_conf.c 25 Jul 2008 14:27:25 -0000 1.10
+++ src/storage_conf.c 30 Jul 2008 16:07:08 -0000
@@ -46,6 +46,7 @@
#include "buf.h"
#include "util.h"
#include "memory.h"
+#include "threads.h"
#define virStorageLog(msg...) fprintf(stderr, msg)
@@ -361,22 +362,55 @@
return NULL;
}
+/* Called from SAX on parsing errors in the XML. */
+THREAD_LOCAL (xml_conn)
+
+static void
+catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
+{
+ xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+ if (ctxt &&
+ ctxt->lastError.level == XML_ERR_FATAL &&
+ ctxt->lastError.message != NULL) {
+ virStorageReportError (THREAD_LOCAL_GET (xml_conn), VIR_ERR_XML_DETAIL,
+ ctxt->lastError.message, ctxt->lastError.line);
+ }
+}
+
virStoragePoolDefPtr
virStoragePoolDefParse(virConnectPtr conn,
const char *xmlStr,
const char *filename) {
virStoragePoolDefPtr ret = NULL;
+ xmlParserCtxtPtr pctxt;
xmlDocPtr xml = NULL;
xmlNodePtr node = NULL;
xmlXPathContextPtr ctxt = NULL;
- if (!(xml = xmlReadDoc(BAD_CAST xmlStr,
- filename ? filename : "storage.xml",
- NULL,
- XML_PARSE_NOENT | XML_PARSE_NONET |
- XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
- virStorageReportError(conn, VIR_ERR_XML_ERROR,
- "%s", _("malformed xml document"));
+ THREAD_LOCAL_INIT (xml_conn);
+ THREAD_LOCAL_SET (xml_conn, conn);
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+
+ /* It'd be nice to do this, but seems ->userData field is used
+ * by something else.
+ */
+ /*pctxt->userData = conn;*/
+
+ xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr,
+ filename ? filename : "storage.xml",
+ NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xml) {
+ /* virStorageReportError has already been called by the
+ * callback function (hopefully).
+ */
goto cleanup;
}
@@ -396,12 +430,14 @@
ret = virStoragePoolDefParseDoc(conn, ctxt, node);
+ xmlFreeParserCtxt (pctxt);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
return ret;
cleanup:
+ xmlFreeParserCtxt (pctxt);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
return NULL;
@@ -725,15 +761,33 @@
const char *xmlStr,
const char *filename) {
virStorageVolDefPtr ret = NULL;
+ xmlParserCtxtPtr pctxt;
xmlDocPtr xml = NULL;
xmlNodePtr node = NULL;
xmlXPathContextPtr ctxt = NULL;
- if (!(xml = xmlReadDoc(BAD_CAST xmlStr, filename ? filename : "storage.xml", NULL,
- XML_PARSE_NOENT | XML_PARSE_NONET |
- XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
- virStorageReportError(conn, VIR_ERR_XML_ERROR,
- "%s", _("malformed xml document"));
+ THREAD_LOCAL_INIT (xml_conn);
+ THREAD_LOCAL_SET (xml_conn, conn);
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+
+ /* It'd be nice to do this, but seems ->userData field is used
+ * by something else.
+ */
+ /*pctxt->userData = conn;*/
+
+ xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr,
+ filename ? filename : "storage.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xml) {
+ /* virStorageReportError has already been called by the
+ * callback function (hopefully).
+ */
goto cleanup;
}
@@ -753,12 +807,14 @@
ret = virStorageVolDefParseDoc(conn, pool, ctxt, node);
+ xmlFreeParserCtxt (pctxt);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
return ret;
cleanup:
+ xmlFreeParserCtxt (pctxt);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
return NULL;
More information about the libvir-list
mailing list