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
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;
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list