/* * xml.c: XML based interfaces for the libvir library * * Copyright (C) 2005, 2007-2009 Red Hat, Inc. * * See COPYING.LIB for the License of this software * * Daniel Veillard */ #include #include #include #include #include #include #include /* for isnan() */ #include "virterror_internal.h" #include "xml.h" #include "buf.h" #include "util.h" #include "memory.h" #define VIR_FROM_THIS VIR_FROM_XML #define virXMLError(conn, code, fmt...) \ virReportErrorHelper(conn, VIR_FROM_XML, code, __FILE__, \ __FUNCTION__, __LINE__, fmt) /************************************************************************ * * * Wrappers around libxml2 XPath specific functions * * * ************************************************************************/ /** * virXPathString: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * * Convenience function to evaluate an XPath string * * Returns a new string which must be deallocated by the caller or NULL * if the evaluation failed. */ char * virXPathString(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt) { xmlXPathObjectPtr obj; xmlNodePtr relnode; char *ret; if ((ctxt == NULL) || (xpath == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathString()")); return (NULL); } relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) || (obj->stringval[0] == 0)) { xmlXPathFreeObject(obj); return (NULL); } ret = strdup((char *) obj->stringval); xmlXPathFreeObject(obj); if (ret == NULL) { virReportOOMError(conn); } return (ret); } /** * virXPathStringLimit: * @xpath: the XPath string to evaluate * @maxlen: maximum length permittred string * @ctxt: an XPath context * * Wrapper for virXPathString, which validates the length of the returned * string. * * Returns a new string which must be deallocated by the caller or NULL if * the evaluation failed. */ char * virXPathStringLimit(virConnectPtr conn, const char *xpath, size_t maxlen, xmlXPathContextPtr ctxt) { char *tmp = virXPathString(conn, xpath, ctxt); if (tmp != NULL && strlen(tmp) >= maxlen) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, _("\'%s\' value longer than %Zd bytes in virXPathStringLimit()"), xpath, maxlen); return NULL; } return tmp; } /** * virXPathNumber: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @value: the returned double value * * Convenience function to evaluate an XPath number * * Returns 0 in case of success in which case @value is set, * or -1 if the evaluation failed. */ int virXPathNumber(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, double *value) { xmlXPathObjectPtr obj; xmlNodePtr relnode; if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathNumber()")); return (-1); } relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj == NULL) || (obj->type != XPATH_NUMBER) || (isnan(obj->floatval))) { xmlXPathFreeObject(obj); return (-1); } *value = obj->floatval; xmlXPathFreeObject(obj); return (0); } static int virXPathLongBase(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, int base, long *value) { xmlXPathObjectPtr obj; xmlNodePtr relnode; int ret = 0; if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathLong()")); return (-1); } relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj != NULL) && (obj->type == XPATH_STRING) && (obj->stringval != NULL) && (obj->stringval[0] != 0)) { char *conv = NULL; long val; val = strtol((const char *) obj->stringval, &conv, base); if (conv == (const char *) obj->stringval) { ret = -2; } else { *value = val; } } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) && (!(isnan(obj->floatval)))) { *value = (long) obj->floatval; if (*value != obj->floatval) { ret = -2; } } else { ret = -1; } xmlXPathFreeObject(obj); return (ret); } /** * virXPathLong: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @value: the returned long value * * Convenience function to evaluate an XPath number * * Returns 0 in case of success in which case @value is set, * or -1 if the XPath evaluation failed or -2 if the * value doesn't have a long format. */ int virXPathLong(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, long *value) { return virXPathLongBase(conn, xpath, ctxt, 10, value); } /** * virXPathLongHex: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @value: the returned long value * * Convenience function to evaluate an XPath number * according to a base of 16 * * Returns 0 in case of success in which case @value is set, * or -1 if the XPath evaluation failed or -2 if the * value doesn't have a long format. */ int virXPathLongHex(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, long *value) { return virXPathLongBase(conn, xpath, ctxt, 16, value); } static int virXPathULongBase(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, int base, unsigned long *value) { xmlXPathObjectPtr obj; xmlNodePtr relnode; int ret = 0; if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathULong()")); return (-1); } relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj != NULL) && (obj->type == XPATH_STRING) && (obj->stringval != NULL) && (obj->stringval[0] != 0)) { char *conv = NULL; long val; val = strtoul((const char *) obj->stringval, &conv, base); if (conv == (const char *) obj->stringval) { ret = -2; } else { *value = val; } } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) && (!(isnan(obj->floatval)))) { *value = (unsigned long) obj->floatval; if (*value != obj->floatval) { ret = -2; } } else { ret = -1; } xmlXPathFreeObject(obj); return (ret); } /** * virXPathULong: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @value: the returned long value * * Convenience function to evaluate an XPath number * * Returns 0 in case of success in which case @value is set, * or -1 if the XPath evaluation failed or -2 if the * value doesn't have a long format. */ int virXPathULong(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, unsigned long *value) { return virXPathULongBase(conn, xpath, ctxt, 10, value); } /** * virXPathUHex: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @value: the returned long value * * Convenience function to evaluate an XPath number * according to base of 16 * * Returns 0 in case of success in which case @value is set, * or -1 if the XPath evaluation failed or -2 if the * value doesn't have a long format. */ int virXPathULongHex(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, unsigned long *value) { return virXPathULongBase(conn, xpath, ctxt, 16, value); } /** * virXPathULongLong: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @value: the returned long long value * * Convenience function to evaluate an XPath number * * Returns 0 in case of success in which case @value is set, * or -1 if the XPath evaluation failed or -2 if the * value doesn't have a long format. */ int virXPathULongLong(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, unsigned long long *value) { xmlXPathObjectPtr obj; xmlNodePtr relnode; int ret = 0; if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathULong()")); return (-1); } relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj != NULL) && (obj->type == XPATH_STRING) && (obj->stringval != NULL) && (obj->stringval[0] != 0)) { char *conv = NULL; unsigned long long val; val = strtoull((const char *) obj->stringval, &conv, 10); if (conv == (const char *) obj->stringval) { ret = -2; } else { *value = val; } } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) && (!(isnan(obj->floatval)))) { *value = (unsigned long long) obj->floatval; if (*value != obj->floatval) { ret = -2; } } else { ret = -1; } xmlXPathFreeObject(obj); return (ret); } char * virXMLPropString(xmlNodePtr node, const char *name) { return (char *)xmlGetProp(node, BAD_CAST name); } /** * virXPathBoolean: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * * Convenience function to evaluate an XPath boolean * * Returns 0 if false, 1 if true, or -1 if the evaluation failed. */ int virXPathBoolean(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt) { xmlXPathObjectPtr obj; xmlNodePtr relnode; int ret; if ((ctxt == NULL) || (xpath == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathBoolean()")); return (-1); } relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) || (obj->boolval < 0) || (obj->boolval > 1)) { xmlXPathFreeObject(obj); return (-1); } ret = obj->boolval; xmlXPathFreeObject(obj); return (ret); } /** * virXPathNode: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * * Convenience function to evaluate an XPath node set and returning * only one node, the first one in the set if any * * Returns a pointer to the node or NULL if the evaluation failed. */ xmlNodePtr virXPathNode(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt) { xmlXPathObjectPtr obj; xmlNodePtr relnode; xmlNodePtr ret; if ((ctxt == NULL) || (xpath == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathNode()")); return (NULL); } relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj == NULL) || (obj->type != XPATH_NODESET) || (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) || (obj->nodesetval->nodeTab == NULL)) { xmlXPathFreeObject(obj); return (NULL); } ret = obj->nodesetval->nodeTab[0]; xmlXPathFreeObject(obj); return (ret); } /** * virXPathNodeSet: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @list: the returned list of nodes (or NULL if only count matters) * * Convenience function to evaluate an XPath node set * * Returns the number of nodes found in which case @list is set (and * must be freed) or -1 if the evaluation failed. */ int virXPathNodeSet(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, xmlNodePtr **list) { xmlXPathObjectPtr obj; xmlNodePtr relnode; int ret; if ((ctxt == NULL) || (xpath == NULL)) { virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid parameter to virXPathNodeSet()")); return (-1); } if (list != NULL) *list = NULL; relnode = ctxt->node; obj = xmlXPathEval(BAD_CAST xpath, ctxt); ctxt->node = relnode; if ((obj == NULL) || (obj->type != XPATH_NODESET) || (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) { xmlXPathFreeObject(obj); return (-1); } ret = obj->nodesetval->nodeNr; if (list != NULL && ret) { if (VIR_ALLOC_N(*list, ret) < 0) { virReportOOMError(conn); ret = -1; } else { memcpy(*list, obj->nodesetval->nodeTab, ret * sizeof(xmlNodePtr)); } } xmlXPathFreeObject(obj); return (ret); }