pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xpath.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <crm_internal.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 /*
24  * From xpath2.c
25  *
26  * All the elements returned by an XPath query are pointers to
27  * elements from the tree *except* namespace nodes where the XPath
28  * semantic is different from the implementation in libxml2 tree.
29  * As a result when a returned node set is freed when
30  * xmlXPathFreeObject() is called, that routine must check the
31  * element type. But node from the returned set may have been removed
32  * by xmlNodeSetContent() resulting in access to freed data.
33  *
34  * This can be exercised by running
35  * valgrind xpath2 test3.xml '//discarded' discarded
36  *
37  * There is 2 ways around it:
38  * - make a copy of the pointers to the nodes from the result set
39  * then call xmlXPathFreeObject() and then modify the nodes
40  * or
41  * - remove the references from the node set, if they are not
42  namespace nodes, before calling xmlXPathFreeObject().
43  */
44 void
45 freeXpathObject(xmlXPathObjectPtr xpathObj)
46 {
47  int lpc, max = numXpathResults(xpathObj);
48 
49  if (xpathObj == NULL) {
50  return;
51  }
52 
53  for (lpc = 0; lpc < max; lpc++) {
54  if (xpathObj->nodesetval->nodeTab[lpc] && xpathObj->nodesetval->nodeTab[lpc]->type != XML_NAMESPACE_DECL) {
55  xpathObj->nodesetval->nodeTab[lpc] = NULL;
56  }
57  }
58 
59  /* _Now_ it's safe to free it */
60  xmlXPathFreeObject(xpathObj);
61 }
62 
63 xmlNode *
64 getXpathResult(xmlXPathObjectPtr xpathObj, int index)
65 {
66  xmlNode *match = NULL;
67  int max = numXpathResults(xpathObj);
68 
69  CRM_CHECK(index >= 0, return NULL);
70  CRM_CHECK(xpathObj != NULL, return NULL);
71 
72  if (index >= max) {
73  crm_err("Requested index %d of only %d items", index, max);
74  return NULL;
75 
76  } else if(xpathObj->nodesetval->nodeTab[index] == NULL) {
77  /* Previously requested */
78  return NULL;
79  }
80 
81  match = xpathObj->nodesetval->nodeTab[index];
82  CRM_CHECK(match != NULL, return NULL);
83 
84  if (xpathObj->nodesetval->nodeTab[index]->type != XML_NAMESPACE_DECL) {
85  /* See the comment for freeXpathObject() */
86  xpathObj->nodesetval->nodeTab[index] = NULL;
87  }
88 
89  if (match->type == XML_DOCUMENT_NODE) {
90  /* Will happen if section = '/' */
91  match = match->children;
92 
93  } else if (match->type != XML_ELEMENT_NODE
94  && match->parent && match->parent->type == XML_ELEMENT_NODE) {
95  /* Return the parent instead */
96  match = match->parent;
97 
98  } else if (match->type != XML_ELEMENT_NODE) {
99  /* We only support searching nodes */
100  crm_err("We only support %d not %d", XML_ELEMENT_NODE, match->type);
101  match = NULL;
102  }
103  return match;
104 }
105 
106 void
107 dedupXpathResults(xmlXPathObjectPtr xpathObj)
108 {
109  int lpc, max = numXpathResults(xpathObj);
110 
111  if (xpathObj == NULL) {
112  return;
113  }
114 
115  for (lpc = 0; lpc < max; lpc++) {
116  xmlNode *xml = NULL;
117  gboolean dedup = FALSE;
118 
119  if (xpathObj->nodesetval->nodeTab[lpc] == NULL) {
120  continue;
121  }
122 
123  xml = xpathObj->nodesetval->nodeTab[lpc]->parent;
124 
125  for (; xml; xml = xml->parent) {
126  int lpc2 = 0;
127 
128  for (lpc2 = 0; lpc2 < max; lpc2++) {
129  if (xpathObj->nodesetval->nodeTab[lpc2] == xml) {
130  xpathObj->nodesetval->nodeTab[lpc] = NULL;
131  dedup = TRUE;
132  break;
133  }
134  }
135 
136  if (dedup) {
137  break;
138  }
139  }
140  }
141 }
142 
143 /* the caller needs to check if the result contains a xmlDocPtr or xmlNodePtr */
144 xmlXPathObjectPtr
145 xpath_search(xmlNode * xml_top, const char *path)
146 {
147  xmlDocPtr doc = NULL;
148  xmlXPathObjectPtr xpathObj = NULL;
149  xmlXPathContextPtr xpathCtx = NULL;
150  const xmlChar *xpathExpr = (pcmkXmlStr) path;
151 
152  CRM_CHECK(path != NULL, return NULL);
153  CRM_CHECK(xml_top != NULL, return NULL);
154  CRM_CHECK(strlen(path) > 0, return NULL);
155 
156  doc = getDocPtr(xml_top);
157 
158  xpathCtx = xmlXPathNewContext(doc);
159  CRM_ASSERT(xpathCtx != NULL);
160 
161  xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
162  xmlXPathFreeContext(xpathCtx);
163  return xpathObj;
164 }
165 
178 void
179 crm_foreach_xpath_result(xmlNode *xml, const char *xpath,
180  void (*helper)(xmlNode*, void*), void *user_data)
181 {
182  xmlXPathObjectPtr xpathObj = xpath_search(xml, xpath);
183  int nresults = numXpathResults(xpathObj);
184  int i;
185 
186  for (i = 0; i < nresults; i++) {
187  xmlNode *result = getXpathResult(xpathObj, i);
188 
189  CRM_LOG_ASSERT(result != NULL);
190  if (result) {
191  (*helper)(result, user_data);
192  }
193  }
194  freeXpathObject(xpathObj);
195 }
196 
197 xmlNode *
198 get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level)
199 {
200  xmlNode *result = NULL;
201  char *xpath_full = NULL;
202  char *xpath_prefix = NULL;
203 
204  if (xml_obj == NULL || xpath == NULL) {
205  return NULL;
206  }
207 
208  xpath_prefix = (char *)xmlGetNodePath(xml_obj);
209 
210  xpath_full = crm_strdup_printf("%s%s", xpath_prefix, xpath);
211 
212  result = get_xpath_object(xpath_full, xml_obj, error_level);
213 
214  free(xpath_prefix);
215  free(xpath_full);
216  return result;
217 }
218 
219 xmlNode *
220 get_xpath_object(const char *xpath, xmlNode * xml_obj, int error_level)
221 {
222  int max;
223  xmlNode *result = NULL;
224  xmlXPathObjectPtr xpathObj = NULL;
225  char *nodePath = NULL;
226  char *matchNodePath = NULL;
227 
228  if (xpath == NULL) {
229  return xml_obj; /* or return NULL? */
230  }
231 
232  xpathObj = xpath_search(xml_obj, xpath);
233  nodePath = (char *)xmlGetNodePath(xml_obj);
234  max = numXpathResults(xpathObj);
235 
236  if (max < 1) {
237  do_crm_log(error_level, "No match for %s in %s", xpath, crm_str(nodePath));
238  crm_log_xml_explicit(xml_obj, "Unexpected Input");
239 
240  } else if (max > 1) {
241  int lpc = 0;
242 
243  do_crm_log(error_level, "Too many matches for %s in %s", xpath, crm_str(nodePath));
244 
245  for (lpc = 0; lpc < max; lpc++) {
246  xmlNode *match = getXpathResult(xpathObj, lpc);
247 
248  CRM_LOG_ASSERT(match != NULL);
249  if(match != NULL) {
250  matchNodePath = (char *)xmlGetNodePath(match);
251  do_crm_log(error_level, "%s[%d] = %s", xpath, lpc, crm_str(matchNodePath));
252  free(matchNodePath);
253  }
254  }
255  crm_log_xml_explicit(xml_obj, "Bad Input");
256 
257  } else {
258  result = getXpathResult(xpathObj, 0);
259  }
260 
261  freeXpathObject(xpathObj);
262  free(nodePath);
263 
264  return result;
265 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:156
xmlNode * get_xpath_object_relative(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:198
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:142
void dedupXpathResults(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:107
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:220
xmlDoc * getDocPtr(xmlNode *node)
Definition: xml.c:1852
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:121
#define crm_log_xml_explicit(xml, text)
Definition: logging.h:256
const xmlChar * pcmkXmlStr
Definition: xml.h:51
#define crm_err(fmt, args...)
Definition: logging.h:240
#define CRM_ASSERT(expr)
Definition: results.h:42
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:145
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:64
#define crm_str(x)
Definition: logging.h:266
void crm_foreach_xpath_result(xmlNode *xml, const char *xpath, void(*helper)(xmlNode *, void *), void *user_data)
Run a supplied function for each result of an xpath search.
Definition: xpath.c:179
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:45
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__