pacemaker  2.0.4-2deceaa
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 2004-2019 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <stdio.h>
12 #include <string.h>
13 
14 /*
15  * From xpath2.c
16  *
17  * All the elements returned by an XPath query are pointers to
18  * elements from the tree *except* namespace nodes where the XPath
19  * semantic is different from the implementation in libxml2 tree.
20  * As a result when a returned node set is freed when
21  * xmlXPathFreeObject() is called, that routine must check the
22  * element type. But node from the returned set may have been removed
23  * by xmlNodeSetContent() resulting in access to freed data.
24  *
25  * This can be exercised by running
26  * valgrind xpath2 test3.xml '//discarded' discarded
27  *
28  * There is 2 ways around it:
29  * - make a copy of the pointers to the nodes from the result set
30  * then call xmlXPathFreeObject() and then modify the nodes
31  * or
32  * - remove the references from the node set, if they are not
33  namespace nodes, before calling xmlXPathFreeObject().
34  */
35 void
36 freeXpathObject(xmlXPathObjectPtr xpathObj)
37 {
38  int lpc, max = numXpathResults(xpathObj);
39 
40  if (xpathObj == NULL) {
41  return;
42  }
43 
44  for (lpc = 0; lpc < max; lpc++) {
45  if (xpathObj->nodesetval->nodeTab[lpc] && xpathObj->nodesetval->nodeTab[lpc]->type != XML_NAMESPACE_DECL) {
46  xpathObj->nodesetval->nodeTab[lpc] = NULL;
47  }
48  }
49 
50  /* _Now_ it's safe to free it */
51  xmlXPathFreeObject(xpathObj);
52 }
53 
54 xmlNode *
55 getXpathResult(xmlXPathObjectPtr xpathObj, int index)
56 {
57  xmlNode *match = NULL;
58  int max = numXpathResults(xpathObj);
59 
60  CRM_CHECK(index >= 0, return NULL);
61  CRM_CHECK(xpathObj != NULL, return NULL);
62 
63  if (index >= max) {
64  crm_err("Requested index %d of only %d items", index, max);
65  return NULL;
66 
67  } else if(xpathObj->nodesetval->nodeTab[index] == NULL) {
68  /* Previously requested */
69  return NULL;
70  }
71 
72  match = xpathObj->nodesetval->nodeTab[index];
73  CRM_CHECK(match != NULL, return NULL);
74 
75  if (xpathObj->nodesetval->nodeTab[index]->type != XML_NAMESPACE_DECL) {
76  /* See the comment for freeXpathObject() */
77  xpathObj->nodesetval->nodeTab[index] = NULL;
78  }
79 
80  if (match->type == XML_DOCUMENT_NODE) {
81  /* Will happen if section = '/' */
82  match = match->children;
83 
84  } else if (match->type != XML_ELEMENT_NODE
85  && match->parent && match->parent->type == XML_ELEMENT_NODE) {
86  /* Return the parent instead */
87  match = match->parent;
88 
89  } else if (match->type != XML_ELEMENT_NODE) {
90  /* We only support searching nodes */
91  crm_err("We only support %d not %d", XML_ELEMENT_NODE, match->type);
92  match = NULL;
93  }
94  return match;
95 }
96 
97 void
98 dedupXpathResults(xmlXPathObjectPtr xpathObj)
99 {
100  int lpc, max = numXpathResults(xpathObj);
101 
102  if (xpathObj == NULL) {
103  return;
104  }
105 
106  for (lpc = 0; lpc < max; lpc++) {
107  xmlNode *xml = NULL;
108  gboolean dedup = FALSE;
109 
110  if (xpathObj->nodesetval->nodeTab[lpc] == NULL) {
111  continue;
112  }
113 
114  xml = xpathObj->nodesetval->nodeTab[lpc]->parent;
115 
116  for (; xml; xml = xml->parent) {
117  int lpc2 = 0;
118 
119  for (lpc2 = 0; lpc2 < max; lpc2++) {
120  if (xpathObj->nodesetval->nodeTab[lpc2] == xml) {
121  xpathObj->nodesetval->nodeTab[lpc] = NULL;
122  dedup = TRUE;
123  break;
124  }
125  }
126 
127  if (dedup) {
128  break;
129  }
130  }
131  }
132 }
133 
134 /* the caller needs to check if the result contains a xmlDocPtr or xmlNodePtr */
135 xmlXPathObjectPtr
136 xpath_search(xmlNode * xml_top, const char *path)
137 {
138  xmlDocPtr doc = NULL;
139  xmlXPathObjectPtr xpathObj = NULL;
140  xmlXPathContextPtr xpathCtx = NULL;
141  const xmlChar *xpathExpr = (pcmkXmlStr) path;
142 
143  CRM_CHECK(path != NULL, return NULL);
144  CRM_CHECK(xml_top != NULL, return NULL);
145  CRM_CHECK(strlen(path) > 0, return NULL);
146 
147  doc = getDocPtr(xml_top);
148 
149  xpathCtx = xmlXPathNewContext(doc);
150  CRM_ASSERT(xpathCtx != NULL);
151 
152  xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
153  xmlXPathFreeContext(xpathCtx);
154  return xpathObj;
155 }
156 
169 void
170 crm_foreach_xpath_result(xmlNode *xml, const char *xpath,
171  void (*helper)(xmlNode*, void*), void *user_data)
172 {
173  xmlXPathObjectPtr xpathObj = xpath_search(xml, xpath);
174  int nresults = numXpathResults(xpathObj);
175  int i;
176 
177  for (i = 0; i < nresults; i++) {
178  xmlNode *result = getXpathResult(xpathObj, i);
179 
180  CRM_LOG_ASSERT(result != NULL);
181  if (result) {
182  (*helper)(result, user_data);
183  }
184  }
185  freeXpathObject(xpathObj);
186 }
187 
188 xmlNode *
189 get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level)
190 {
191  xmlNode *result = NULL;
192  char *xpath_full = NULL;
193  char *xpath_prefix = NULL;
194 
195  if (xml_obj == NULL || xpath == NULL) {
196  return NULL;
197  }
198 
199  xpath_prefix = (char *)xmlGetNodePath(xml_obj);
200 
201  xpath_full = crm_strdup_printf("%s%s", xpath_prefix, xpath);
202 
203  result = get_xpath_object(xpath_full, xml_obj, error_level);
204 
205  free(xpath_prefix);
206  free(xpath_full);
207  return result;
208 }
209 
210 xmlNode *
211 get_xpath_object(const char *xpath, xmlNode * xml_obj, int error_level)
212 {
213  int max;
214  xmlNode *result = NULL;
215  xmlXPathObjectPtr xpathObj = NULL;
216  char *nodePath = NULL;
217  char *matchNodePath = NULL;
218 
219  if (xpath == NULL) {
220  return xml_obj; /* or return NULL? */
221  }
222 
223  xpathObj = xpath_search(xml_obj, xpath);
224  nodePath = (char *)xmlGetNodePath(xml_obj);
225  max = numXpathResults(xpathObj);
226 
227  if (max < 1) {
228  if (error_level < LOG_NEVER) {
229  do_crm_log(error_level, "No match for %s in %s",
230  xpath, crm_str(nodePath));
231  crm_log_xml_explicit(xml_obj, "Unexpected Input");
232  }
233 
234  } else if (max > 1) {
235  if (error_level < LOG_NEVER) {
236  int lpc = 0;
237 
238  do_crm_log(error_level, "Too many matches for %s in %s",
239  xpath, crm_str(nodePath));
240 
241  for (lpc = 0; lpc < max; lpc++) {
242  xmlNode *match = getXpathResult(xpathObj, lpc);
243 
244  CRM_LOG_ASSERT(match != NULL);
245  if (match != NULL) {
246  matchNodePath = (char *) xmlGetNodePath(match);
247  do_crm_log(error_level, "%s[%d] = %s",
248  xpath, lpc, crm_str(matchNodePath));
249  free(matchNodePath);
250  }
251  }
252  crm_log_xml_explicit(xml_obj, "Bad Input");
253  }
254 
255  } else {
256  result = getXpathResult(xpathObj, 0);
257  }
258 
259  freeXpathObject(xpathObj);
260  free(nodePath);
261 
262  return result;
263 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
xmlNode * get_xpath_object_relative(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
void dedupXpathResults(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:98
#define LOG_NEVER
Definition: logging.h:46
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:211
xmlDoc * getDocPtr(xmlNode *node)
Definition: xml.c:1938
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:150
#define crm_log_xml_explicit(xml, text)
Definition: logging.h:379
const xmlChar * pcmkXmlStr
Definition: xml.h:51
#define crm_err(fmt, args...)
Definition: logging.h:363
#define CRM_ASSERT(expr)
Definition: results.h:42
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:136
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:55
#define crm_str(x)
Definition: logging.h:389
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:170
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:36
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__