13 #include <sys/types.h> 21 #include <libxml/parser.h> 22 #include <libxml/tree.h> 23 #include <libxml/xmlIO.h> 32 #ifndef XML_PARSER_DEBUG 33 #define XML_PARSER_DEBUG 0 45 #define PCMK__XML_PARSE_OPTS_WITHOUT_RECOVER (XML_PARSE_NOBLANKS) 46 #define PCMK__XML_PARSE_OPTS_WITH_RECOVER (XML_PARSE_NOBLANKS | XML_PARSE_RECOVER) 51 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
64 set_parent_flag(xmlNode *xml,
long flag)
66 for(; xml; xml = xml->parent) {
69 if (nodepriv == NULL) {
80 if(xml && xml->doc && xml->doc->_private){
98 reset_xml_node_flags(xmlNode *xml)
100 xmlNode *cIter = NULL;
107 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
108 cIter = pcmk__xml_next(cIter)) {
109 reset_xml_node_flags(cIter);
117 xmlNode *cIter = NULL;
121 nodepriv = xml->_private;
128 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
129 cIter = pcmk__xml_next(cIter)) {
135 #define XML_DOC_PRIVATE_MAGIC 0x81726354UL 136 #define XML_NODE_PRIVATE_MAGIC 0x54637281UL 140 free_deleted_object(
void *
data)
145 free(deleted_obj->
path);
154 if (docpriv != NULL) {
158 docpriv->
user = NULL;
160 if (docpriv->
acls != NULL) {
162 docpriv->
acls = NULL;
166 g_list_free_full(docpriv->
deleted_objs, free_deleted_object);
174 free_private_data(xmlNode *node)
202 if (node->name == NULL || node->name[0] !=
' ') {
203 if (node->_private) {
204 if (node->type == XML_DOCUMENT_NODE) {
205 reset_xml_private_data(node->_private);
211 free(node->_private);
212 node->_private = NULL;
219 new_private_data(xmlNode *node)
221 switch (node->type) {
222 case XML_DOCUMENT_NODE: {
229 node->_private = docpriv;
232 case XML_ELEMENT_NODE:
233 case XML_ATTRIBUTE_NODE:
234 case XML_COMMENT_NODE: {
241 node->_private = nodepriv;
252 case XML_CDATA_SECTION_NODE:
256 crm_trace(
"Ignoring %p %d", node, node->type);
266 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
269 if(acl_source == NULL) {
280 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
287 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
306 for (
const xmlNode *cIter = xml; cIter->prev; cIter = cIter->prev) {
319 accept_attr_deletions(xmlNode *xml)
328 for (xmlNodePtr cIter = pcmk__xml_first_child(xml); cIter != NULL;
329 cIter = pcmk__xml_next(cIter)) {
330 accept_attr_deletions(cIter);
347 if (needle->type == XML_COMMENT_NODE) {
351 const char *
id =
ID(needle);
352 const char *attr = (
id == NULL)? NULL :
XML_ATTR_ID;
354 return pcmk__xe_match(haystack, (
const char *) needle->name, attr,
id);
368 crm_trace(
"Accepting changes to %p", xml);
369 docpriv = xml->doc->_private;
370 top = xmlDocGetRootElement(xml->doc);
372 reset_xml_private_data(xml->doc->_private);
380 accept_attr_deletions(top);
384 find_xml_node(
const xmlNode *root,
const char *search_path, gboolean must_find)
386 xmlNode *a_child = NULL;
387 const char *
name = (root == NULL)?
"<NULL>" : (
const char *) root->name;
389 if (search_path == NULL) {
394 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
395 a_child = pcmk__xml_next(a_child)) {
396 if (strcmp((
const char *)a_child->name, search_path) == 0) {
402 crm_warn(
"Could not find %s in %s.", search_path,
name);
403 }
else if (root != NULL) {
406 crm_trace(
"Could not find %s in <NULL>.", search_path);
412 #define attr_matches(c, n, v) pcmk__str_eq(crm_element_value((c), (n)), \ 430 const char *attr_n,
const char *attr_v)
433 CRM_CHECK(attr_v == NULL || attr_n != NULL,
return NULL);
435 for (xmlNode *child = pcmk__xml_first_child(
parent); child != NULL;
436 child = pcmk__xml_next(child)) {
437 if (pcmk__str_eq(node_name, (
const char *) (child->name),
439 && ((attr_n == NULL) ||
440 (attr_v == NULL && xmlHasProp(child, (
pcmkXmlStr) attr_n)) ||
441 (attr_v != NULL &&
attr_matches(child, attr_n, attr_v)))) {
445 crm_trace(
"XML child node <%s%s%s%s%s> not found in %s",
446 (node_name? node_name :
"(any)"),
448 (attr_n? attr_n :
""),
450 (attr_n? attr_v :
""),
451 (
const char *)
parent->name);
459 crm_warn(
"No node to copy properties from");
461 }
else if (
target == NULL) {
462 crm_err(
"No node to copy properties into");
465 for (xmlAttrPtr a = pcmk__xe_first_attr(src); a != NULL; a = a->next) {
466 const char *p_name = (
const char *) a->name;
467 const char *p_value = pcmk__xml_attr_value(a);
492 xmlNode *child = NULL;
494 for (xmlAttrPtr a = pcmk__xe_first_attr(
target); a != NULL; a = a->next) {
495 const char *p_name = (
const char *) a->name;
496 const char *p_value = pcmk__xml_attr_value(a);
500 for (child = pcmk__xml_first_child(
target); child != NULL;
501 child = pcmk__xml_next(child)) {
530 const char *old_value = NULL;
532 if (
target == NULL || value == NULL ||
name == NULL) {
538 if (old_value == NULL) {
542 }
else if (strstr(value,
name) != value) {
546 name_len = strlen(
name);
547 value_len = strlen(value);
548 if (value_len < (name_len + 2)
549 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
556 if (old_value != value) {
560 if (value[name_len + 1] !=
'+') {
561 const char *offset_s = value + (name_len + 2);
575 if (old_value == value) {
594 bool (*match)(xmlAttrPtr,
void *),
597 xmlAttrPtr next = NULL;
599 for (xmlAttrPtr a = pcmk__xe_first_attr(element); a != NULL; a = next) {
601 if ((match == NULL) || match(a, user_data)) {
603 crm_trace(
"ACLs prevent removal of attributes (%s and " 604 "possibly others) from %s element",
605 (
const char *) a->name, (
const char *) element->name);
624 xmlNode *child = NULL;
628 child = xmlDocCopyNode(src_node,
parent->doc, 1);
632 xmlAddChild(
parent, child);
641 xmlNode *node = NULL;
643 if (pcmk__str_empty(
name)) {
659 xmlDocSetRootElement(doc, node);
677 xmlNodeSetContent(node, (
pcmkXmlStr) content);
685 const char *class_name,
const char *text)
689 if (class_name != NULL) {
713 free_xml_with_position(xmlNode * child,
int position)
717 xmlDoc *doc = child->doc;
722 top = xmlDocGetRootElement(doc);
725 if (doc != NULL && top == child) {
730 GString *xpath = NULL;
734 qb_log_from_external_source(__func__, __FILE__,
736 __LINE__, 0, (
const char *) xpath->str,
738 g_string_free(xpath, TRUE);
751 (
const char *) xpath->str, child, doc);
754 deleted_obj->
path = strdup((
const char *) xpath->str);
757 g_string_free(xpath, TRUE);
761 if (child->type == XML_COMMENT_NODE) {
771 docpriv = doc->_private;
785 free_xml_with_position(child, -1);
792 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
795 xmlDocSetRootElement(doc, copy);
803 xmlDocPtr output = NULL;
804 xmlParserCtxtPtr ctxt = NULL;
805 const xmlError *last_error = NULL;
808 crm_err(
"Can't parse NULL input");
813 ctxt = xmlNewParserCtxt();
816 xmlCtxtResetLastError(ctxt);
821 if (output == NULL) {
825 crm_warn(
"Successfully recovered from XML errors " 826 "(note: a future release will treat this as a fatal failure)");
831 xml = xmlDocGetRootElement(output);
833 last_error = xmlCtxtGetLastError(ctxt);
834 if (last_error && last_error->code != XML_ERR_OK) {
840 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
841 last_error->domain, last_error->level, last_error->code, last_error->message);
843 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
846 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
847 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(
input),
854 int len = strlen(
input);
866 xmlFreeParserCtxt(ctxt);
873 size_t data_length = 0;
874 size_t read_chars = 0;
876 char *xml_buffer = NULL;
877 xmlNode *xml_obj = NULL;
883 data_length += read_chars;
886 if (data_length == 0) {
887 crm_warn(
"No XML supplied on stdin");
892 xml_buffer[data_length] =
'\0';
901 decompress_file(
const char *filename)
905 size_t length = 0, read_len = 0;
906 BZFILE *bz_file = NULL;
907 FILE *
input = fopen(filename,
"r");
910 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
914 bz_file = BZ2_bzReadOpen(&rc,
input, 0, 0, NULL, 0);
918 crm_err(
"Could not prepare to read compressed %s: %s " 920 BZ2_bzReadClose(&rc, bz_file);
928 while (rc == BZ_OK) {
932 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
934 if (rc == BZ_OK || rc == BZ_STREAM_END) {
939 buffer[length] =
'\0';
950 BZ2_bzReadClose(&rc, bz_file);
964 xmlNode *iter = xml->children;
967 xmlNode *next = iter->next;
969 switch (iter->type) {
975 case XML_ELEMENT_NODE:
993 xmlDocPtr output = NULL;
994 bool uncompressed =
true;
995 xmlParserCtxtPtr ctxt = NULL;
996 const xmlError *last_error = NULL;
999 ctxt = xmlNewParserCtxt();
1002 xmlCtxtResetLastError(ctxt);
1011 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL,
1014 if (output == NULL) {
1015 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL,
1018 crm_warn(
"Successfully recovered from XML errors " 1019 "(note: a future release will treat this as a fatal failure)");
1023 }
else if (uncompressed) {
1024 output = xmlCtxtReadFile(ctxt, filename, NULL,
1027 if (output == NULL) {
1028 output = xmlCtxtReadFile(ctxt, filename, NULL,
1031 crm_warn(
"Successfully recovered from XML errors " 1032 "(note: a future release will treat this as a fatal failure)");
1037 char *
input = decompress_file(filename);
1042 if (output == NULL) {
1046 crm_warn(
"Successfully recovered from XML errors " 1047 "(note: a future release will treat this as a fatal failure)");
1054 if (output && (xml = xmlDocGetRootElement(output))) {
1058 last_error = xmlCtxtGetLastError(ctxt);
1059 if (last_error && last_error->code != XML_ERR_OK) {
1065 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
1066 last_error->domain, last_error->level, last_error->code, last_error->message);
1068 if (last_error && last_error->code != XML_ERR_OK) {
1069 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
1076 xmlFreeParserCtxt(ctxt);
1092 const char *
result = NULL;
1095 pcmk__s(now_s,
"Could not determine current time"));
1110 for (c =
id; *c; ++c) {
1135 va_start(ap, format);
1136 len = vasprintf(&
id, format, ap);
1158 write_xml_stream(
const xmlNode *xml,
const char *filename, FILE *stream,
1159 bool compress,
unsigned int *nbytes)
1162 char *buffer = NULL;
1174 unsigned int in = 0;
1175 BZFILE *bz_file = NULL;
1178 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
1182 crm_warn(
"Not compressing %s: could not prepare file stream: %s " 1185 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
1189 crm_warn(
"Not compressing %s: could not compress data: %s " 1190 CRM_XS " rc=%d errno=%d",
1196 BZ2_bzWriteClose(&rc, bz_file, 0, &in, nbytes);
1200 crm_warn(
"Not compressing %s: could not write compressed data: %s " 1201 CRM_XS " rc=%d errno=%d",
1205 crm_trace(
"Compressed XML for %s from %u bytes to %u",
1206 filename, in, *nbytes);
1213 rc = fprintf(stream,
"%s", buffer);
1218 *nbytes = (
unsigned int) rc;
1225 if (fflush(stream) != 0) {
1227 crm_perror(LOG_ERR,
"flushing %s", filename);
1231 if (fsync(fileno(stream)) < 0 && errno != EROFS && errno != EINVAL) {
1233 crm_perror(LOG_ERR,
"synchronizing %s", filename);
1238 crm_trace(
"Saved %d bytes to %s as XML", *nbytes, filename);
1258 FILE *stream = NULL;
1259 unsigned int nbytes = 0;
1262 CRM_CHECK((xml != NULL) && (fd > 0),
return -EINVAL);
1263 stream = fdopen(fd,
"w");
1264 if (stream == NULL) {
1267 rc = write_xml_stream(xml, filename, stream, compress, &nbytes);
1271 return (
int) nbytes;
1286 FILE *stream = NULL;
1287 unsigned int nbytes = 0;
1290 CRM_CHECK((xml != NULL) && (filename != NULL),
return -EINVAL);
1291 stream = fopen(filename,
"w");
1292 if (stream == NULL) {
1295 rc = write_xml_stream(xml, filename, stream, compress, &nbytes);
1299 return (
int) nbytes;
1304 replace_text(
char *text,
int start,
size_t *length,
const char *replace)
1306 size_t offset = strlen(replace) - 1;
1309 text = pcmk__realloc(text, *length);
1311 for (
size_t lpc = (*length) - 1; lpc > (start + offset); lpc--) {
1312 text[lpc] = text[lpc - offset];
1315 memcpy(text + start, replace, offset + 1);
1353 length = 1 + strlen(text);
1354 copy = strdup(text);
1356 for (
size_t index = 0; index < length; index++) {
1357 if(copy[index] & 0x80 && copy[index+1] & 0x80){
1361 switch (copy[index]) {
1365 copy = replace_text(copy, index, &length,
"<");
1368 copy = replace_text(copy, index, &length,
">");
1371 copy = replace_text(copy, index, &length,
""");
1374 copy = replace_text(copy, index, &length,
"'");
1377 copy = replace_text(copy, index, &length,
"&");
1381 copy = replace_text(copy, index, &length,
" ");
1384 copy = replace_text(copy, index, &length,
"\\n");
1387 copy = replace_text(copy, index, &length,
"\\r");
1391 if(copy[index] <
' ' || copy[index] >
'~') {
1394 copy = replace_text(copy, index, &length, replace);
1412 dump_xml_element(
const xmlNode *
data, uint32_t options, GString *buffer,
1417 int spaces = pretty? (2 * depth) : 0;
1419 for (
int lpc = 0; lpc < spaces; lpc++) {
1420 g_string_append_c(buffer,
' ');
1425 for (
const xmlAttr *attr = pcmk__xe_first_attr(
data); attr != NULL;
1426 attr = attr->next) {
1433 if (
data->children == NULL) {
1434 g_string_append(buffer,
"/>");
1437 g_string_append_c(buffer,
'>');
1441 g_string_append_c(buffer,
'\n');
1444 if (
data->children) {
1445 for (
const xmlNode *child =
data->children; child != NULL;
1446 child = child->next) {
1450 for (
int lpc = 0; lpc < spaces; lpc++) {
1451 g_string_append_c(buffer,
' ');
1457 g_string_append_c(buffer,
'\n');
1472 dump_xml_text(
const xmlNode *
data, uint32_t options, GString *buffer,
1479 int spaces = pretty? (2 * depth) : 0;
1481 for (
int lpc = 0; lpc < spaces; lpc++) {
1482 g_string_append_c(buffer,
' ');
1485 g_string_append(buffer, (
const gchar *)
data->content);
1488 g_string_append_c(buffer,
'\n');
1502 dump_xml_cdata(
const xmlNode *
data, uint32_t options, GString *buffer,
1506 int spaces = pretty? (2 * depth) : 0;
1508 for (
int lpc = 0; lpc < spaces; lpc++) {
1509 g_string_append_c(buffer,
' ');
1516 g_string_append_c(buffer,
'\n');
1530 dump_xml_comment(
const xmlNode *
data, uint32_t options, GString *buffer,
1534 int spaces = pretty? (2 * depth) : 0;
1536 for (
int lpc = 0; lpc < spaces; lpc++) {
1537 g_string_append_c(buffer,
' ');
1543 g_string_append_c(buffer,
'\n');
1556 xml_element_type2str(xmlElementType
type)
1558 static const char *
const element_type_names[] = {
1559 [XML_ELEMENT_NODE] =
"element",
1560 [XML_ATTRIBUTE_NODE] =
"attribute",
1561 [XML_TEXT_NODE] =
"text",
1562 [XML_CDATA_SECTION_NODE] =
"CDATA section",
1563 [XML_ENTITY_REF_NODE] =
"entity reference",
1564 [XML_ENTITY_NODE] =
"entity",
1565 [XML_PI_NODE] =
"PI",
1566 [XML_COMMENT_NODE] =
"comment",
1567 [XML_DOCUMENT_NODE] =
"document",
1568 [XML_DOCUMENT_TYPE_NODE] =
"document type",
1569 [XML_DOCUMENT_FRAG_NODE] =
"document fragment",
1570 [XML_NOTATION_NODE] =
"notation",
1571 [XML_HTML_DOCUMENT_NODE] =
"HTML document",
1572 [XML_DTD_NODE] =
"DTD",
1573 [XML_ELEMENT_DECL] =
"element declaration",
1574 [XML_ATTRIBUTE_DECL] =
"attribute declaration",
1575 [XML_ENTITY_DECL] =
"entity declaration",
1576 [XML_NAMESPACE_DECL] =
"namespace declaration",
1577 [XML_XINCLUDE_START] =
"XInclude start",
1578 [XML_XINCLUDE_END] =
"XInclude end",
1582 return "unrecognized type";
1584 return element_type_names[
type];
1608 switch(
data->type) {
1609 case XML_ELEMENT_NODE:
1611 dump_xml_element(
data, options, buffer, depth);
1615 dump_xml_text(
data, options, buffer, depth);
1618 case XML_COMMENT_NODE:
1619 dump_xml_comment(
data, options, buffer, depth);
1621 case XML_CDATA_SECTION_NODE:
1622 dump_xml_cdata(
data, options, buffer, depth);
1625 crm_warn(
"Cannot convert XML %s node to text " CRM_XS " type=%d",
1626 xml_element_type2str(
data->type),
data->type);
1638 char *buffer = NULL;
1639 GString *g_buffer = g_string_sized_new(1024);
1644 g_string_free(g_buffer, TRUE);
1651 char *buffer = NULL;
1652 GString *g_buffer = g_string_sized_new(1024);
1657 g_string_free(g_buffer, TRUE);
1664 char *buffer = NULL;
1665 GString *g_buffer = g_string_sized_new(1024);
1670 g_string_free(g_buffer, TRUE);
1679 xmlOutputBuffer *fd_out = xmlOutputBufferCreateFd(fd, NULL);
1683 success = xmlOutputBufferWrite(fd_out,
sizeof(
"\n") - 1,
"\n") != -1;
1685 success = xmlOutputBufferClose(fd_out) != -1 && success;
1722 if (filename == NULL) {
1730 crm_info(
"Saving %s to %s", desc, filename);
1745 for (xmlAttr *attr = pcmk__xe_first_attr(xml); attr; attr = attr->next) {
1765 mark_attr_deleted(xmlNode *new_xml,
const char *element,
const char *attr_name,
1766 const char *old_value)
1769 xmlAttr *attr = NULL;
1780 nodepriv = attr->_private;
1781 nodepriv->
flags = 0;
1786 crm_trace(
"XML attribute %s=%s was removed from %s",
1787 attr_name, old_value, element);
1795 mark_attr_changed(xmlNode *new_xml,
const char *element,
const char *attr_name,
1796 const char *old_value)
1800 crm_trace(
"XML attribute %s was changed from '%s' to '%s' in %s",
1801 attr_name, old_value, vcopy, element);
1823 mark_attr_moved(xmlNode *new_xml,
const char *element, xmlAttr *old_attr,
1824 xmlAttr *new_attr,
int p_old,
int p_new)
1828 crm_trace(
"XML attribute %s moved from position %d to %d in %s",
1829 old_attr->name, p_old, p_new, element);
1837 nodepriv = (p_old > p_new)? old_attr->_private : new_attr->_private;
1849 xml_diff_old_attrs(xmlNode *old_xml, xmlNode *new_xml)
1851 xmlAttr *attr_iter = pcmk__xe_first_attr(old_xml);
1853 while (attr_iter != NULL) {
1854 const char *
name = (
const char *) attr_iter->name;
1855 xmlAttr *old_attr = attr_iter;
1856 xmlAttr *new_attr = xmlHasProp(new_xml, attr_iter->name);
1857 const char *old_value = pcmk__xml_attr_value(attr_iter);
1859 attr_iter = attr_iter->next;
1860 if (new_attr == NULL) {
1861 mark_attr_deleted(new_xml, (
const char *) old_xml->name,
name,
1875 if (strcmp(new_value, old_value) != 0) {
1876 mark_attr_changed(new_xml, (
const char *) old_xml->name,
name,
1879 }
else if ((old_pos != new_pos)
1881 mark_attr_moved(new_xml, (
const char *) old_xml->name,
1882 old_attr, new_attr, old_pos, new_pos);
1898 mark_created_attrs(xmlNode *new_xml)
1900 xmlAttr *attr_iter = pcmk__xe_first_attr(new_xml);
1902 while (attr_iter != NULL) {
1903 xmlAttr *new_attr = attr_iter;
1906 attr_iter = attr_iter->next;
1908 const char *attr_name = (
const char *) new_attr->name;
1910 crm_trace(
"Created new attribute %s=%s in %s",
1911 attr_name, pcmk__xml_attr_value(new_attr),
1921 xmlUnsetProp(new_xml, new_attr->name);
1935 xml_diff_attrs(xmlNode *old_xml, xmlNode *new_xml)
1938 xml_diff_old_attrs(old_xml, new_xml);
1939 mark_created_attrs(new_xml);
1955 mark_child_deleted(xmlNode *old_child, xmlNode *new_parent)
1961 reset_xml_node_flags(candidate);
1967 free_xml_with_position(candidate,
1977 mark_child_moved(xmlNode *old_child, xmlNode *new_parent, xmlNode *new_child,
1978 int p_old,
int p_new)
1982 crm_trace(
"Child element %s with id='%s' moved from position %d to %d under %s",
1983 new_child->name, (
ID(new_child)?
ID(new_child) :
"<no id>"),
1984 p_old, p_new, new_parent->name);
1988 if (p_old > p_new) {
1989 nodepriv = old_child->_private;
1991 nodepriv = new_child->_private;
1998 mark_xml_changes(xmlNode *old_xml, xmlNode *new_xml,
bool check_top)
2000 xmlNode *cIter = NULL;
2004 if (old_xml == NULL) {
2010 nodepriv = new_xml->_private;
2019 xml_diff_attrs(old_xml, new_xml);
2022 for (cIter = pcmk__xml_first_child(old_xml); cIter != NULL; ) {
2023 xmlNode *old_child = cIter;
2026 cIter = pcmk__xml_next(cIter);
2028 mark_xml_changes(old_child, new_child, TRUE);
2031 mark_child_deleted(old_child, new_xml);
2036 for (cIter = pcmk__xml_first_child(new_xml); cIter != NULL; ) {
2037 xmlNode *new_child = cIter;
2040 cIter = pcmk__xml_next(cIter);
2041 if(old_child == NULL) {
2043 nodepriv = new_child->_private;
2045 mark_xml_changes(old_child, new_child, TRUE);
2052 if(p_old != p_new) {
2053 mark_child_moved(old_child, new_xml, new_child, p_old, p_new);
2070 CRM_CHECK((old_xml != NULL) && (new_xml != NULL)
2071 && pcmk__xe_is(old_xml, (
const char *) new_xml->name)
2079 mark_xml_changes(old_xml, new_xml, FALSE);
2085 xmlNode *cIter = NULL;
2086 gboolean can_prune = TRUE;
2088 CRM_CHECK(xml_node != NULL,
return FALSE);
2097 for (xmlAttrPtr a = pcmk__xe_first_attr(xml_node); a != NULL; a = a->next) {
2098 const char *p_name = (
const char *) a->name;
2106 cIter = pcmk__xml_first_child(xml_node);
2108 xmlNode *child = cIter;
2110 cIter = pcmk__xml_next(cIter);
2131 xmlNode *a_child = NULL;
2134 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
2136 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
2137 a_child = pcmk__xml_next(a_child)) {
2142 if (offset < search_offset) {
2145 }
else if (offset > search_offset) {
2154 if (a_child->type == XML_COMMENT_NODE
2155 && pcmk__str_eq((
const char *)a_child->content, (
const char *)search_comment->content,
pcmk__str_casei)) {
2181 CRM_CHECK(update->type == XML_COMMENT_NODE,
return);
2190 }
else if (!pcmk__str_eq((
const char *)
target->content, (
const char *)update->content,
pcmk__str_casei)) {
2191 xmlFree(
target->content);
2192 target->content = xmlStrdup(update->content);
2212 xmlNode *a_child = NULL;
2213 const char *object_name = NULL,
2214 *object_href = NULL,
2215 *object_href_val = NULL;
2217 #if XML_PARSER_DEBUG 2224 if (update->type == XML_COMMENT_NODE) {
2229 object_name = (
const char *) update->name;
2230 object_href_val =
ID(update);
2231 if (object_href_val != NULL) {
2243 object_href, object_href_val);
2249 #if XML_PARSER_DEBUG 2250 crm_trace(
"Added <%s%s%s%s%s/>", pcmk__s(object_name,
"<null>"),
2251 object_href ?
" " :
"",
2252 object_href ? object_href :
"",
2253 object_href ?
"=" :
"",
2254 object_href ? object_href_val :
"");
2257 crm_trace(
"Found node <%s%s%s%s%s/> to update",
2258 pcmk__s(object_name,
"<null>"),
2259 object_href ?
" " :
"",
2260 object_href ? object_href :
"",
2261 object_href ?
"=" :
"",
2262 object_href ? object_href_val :
"");
2268 if (as_diff == FALSE) {
2274 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2276 const char *p_value = pcmk__xml_attr_value(a);
2279 xmlUnsetProp(
target, a->name);
2284 for (a_child = pcmk__xml_first_child(update); a_child != NULL;
2285 a_child = pcmk__xml_next(a_child)) {
2286 #if XML_PARSER_DEBUG 2287 crm_trace(
"Updating child <%s%s%s%s%s/>",
2288 pcmk__s(object_name,
"<null>"),
2289 object_href ?
" " :
"",
2290 object_href ? object_href :
"",
2291 object_href ?
"=" :
"",
2292 object_href ? object_href_val :
"");
2297 #if XML_PARSER_DEBUG 2298 crm_trace(
"Finished with <%s%s%s%s%s/>", pcmk__s(object_name,
"<null>"),
2299 object_href ?
" " :
"",
2300 object_href ? object_href :
"",
2301 object_href ?
"=" :
"",
2302 object_href ? object_href_val :
"");
2309 gboolean can_update = TRUE;
2310 xmlNode *child_of_child = NULL;
2313 CRM_CHECK(to_update != NULL,
return FALSE);
2315 if (!pcmk__xe_is(to_update, (
const char *) child->name)) {
2321 }
else if (can_update) {
2322 #if XML_PARSER_DEBUG 2328 for (child_of_child = pcmk__xml_first_child(child); child_of_child != NULL;
2329 child_of_child = pcmk__xml_next(child_of_child)) {
2342 const char *tag,
const char *field,
const char *value, gboolean search_matches)
2344 int match_found = 0;
2347 CRM_CHECK(children != NULL,
return FALSE);
2349 if ((tag != NULL) && !pcmk__xe_is(root, tag)) {
2354 if (*children == NULL) {
2361 if (search_matches || match_found == 0) {
2362 xmlNode *child = NULL;
2364 for (child = pcmk__xml_first_child(root); child != NULL;
2365 child = pcmk__xml_next(child)) {
2366 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
2376 gboolean can_delete = FALSE;
2377 xmlNode *child_of_child = NULL;
2379 const char *up_id = NULL;
2380 const char *child_id = NULL;
2381 const char *right_val = NULL;
2384 CRM_CHECK(update != NULL,
return FALSE);
2387 child_id =
ID(child);
2389 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
2392 if (!pcmk__xe_is(update, (
const char *) child->name)) {
2395 if (can_delete && delete_only) {
2396 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2398 const char *p_name = (
const char *) a->name;
2399 const char *p_value = pcmk__xml_attr_value(a);
2408 if (can_delete &&
parent != NULL) {
2410 if (delete_only || update == NULL) {
2414 xmlNode *old = child;
2415 xmlNode *
new = xmlCopyNode(update, 1);
2420 reset_xml_node_flags(
new);
2422 old = xmlReplaceNode(old,
new);
2433 }
else if (can_delete) {
2438 child_of_child = pcmk__xml_first_child(child);
2439 while (child_of_child) {
2440 xmlNode *next = pcmk__xml_next(child_of_child);
2446 child_of_child = NULL;
2448 child_of_child = next;
2458 xmlNode *child = NULL;
2459 GSList *nvpairs = NULL;
2470 for (child = pcmk__xml_first_child(
input); child != NULL;
2471 child = pcmk__xml_next(child)) {
2486 xmlNode *match = NULL;
2488 for (match = pcmk__xe_first_child(
parent); match != NULL;
2489 match = pcmk__xe_next(match)) {
2512 xmlNode *match = pcmk__xe_next(sibling);
2514 while (match != NULL) {
2515 if (pcmk__xe_is(match, (
const char *) sibling->name)) {
2518 match = pcmk__xe_next(match);
2526 static bool init =
true;
2535 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
2538 xmlDeregisterNodeDefault(free_private_data);
2539 xmlRegisterNodeDefault(new_private_data);
2552 #define XPATH_MAX 512 2557 const char *ref = NULL;
2563 }
else if (top == NULL) {
2574 char *nodePath = (
char *)xmlGetNodePath(top);
2576 crm_err(
"No match for %s found in %s: Invalid configuration",
2577 xpath_string, pcmk__s(nodePath,
"unrecognizable path"));
2588 static const char *base = NULL;
2594 if (pcmk__str_empty(base)) {
2608 crm_err(
"XML artefact family specified as %u not recognized", ns);
2628 crm_err(
"XML artefact family specified as %u not recognized", ns);
2639 const char *
name, *value;
2641 name = va_arg(pairs,
const char *);
2646 value = va_arg(pairs,
const char *);
2647 if (value != NULL) {
2657 va_start(pairs, node);
2664 int (*handler)(xmlNode *xml,
void *userdata),
2667 xmlNode *children = (xml? xml->children : NULL);
2671 for (xmlNode *node = children; node != NULL; node = node->next) {
2672 if (node->type == XML_ELEMENT_NODE &&
2674 int rc = handler(node, userdata);
2713 xmlDocSetRootElement(doc, node);
2729 if (xml_root != NULL && xml_root->children != NULL) {
#define CRM_CHECK(expr, failure_action)
int pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name, int(*handler)(xmlNode *xml, void *userdata), void *userdata)
bool pcmk__tracking_xml_changes(xmlNode *xml, bool lazy)
void xml_calculate_significant_changes(xmlNode *old_xml, xmlNode *new_xml)
GSList * pcmk_sort_nvpairs(GSList *list)
Sort a list of name/value pairs.
void crm_schema_init(void)
#define PCMK__XML_PARSE_OPTS_WITHOUT_RECOVER
char * crm_generate_uuid(void)
#define pcmk__if_tracing(if_action, else_action)
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
void pcmk__free_acls(GList *acls)
int pcmk_rc2legacy(int rc)
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
G_GNUC_INTERNAL void pcmk__mark_xml_attr_dirty(xmlAttr *a)
G_GNUC_INTERNAL void pcmk__log_xmllib_err(void *ctx, const char *fmt,...) G_GNUC_PRINTF(2
void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
char * dump_xml_unformatted(const xmlNode *xml)
Exclude certain XML attributes (for calculating digests)
void crm_xml_sanitize_id(char *id)
Sanitize a string so it is usable as an XML ID.
int char2score(const char *score)
Get the integer value of a score string.
void fix_plus_plus_recursive(xmlNode *target)
Parse integer assignment statements on this node and all its child nodes.
void crm_xml_init(void)
Initialize the CRM XML subsystem.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
void crm_schema_cleanup(void)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
void pcmk_free_xml_subtree(xmlNode *xml)
void pcmk__xe_set_props(xmlNodePtr node,...)
void pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
xmlNode * stdin2xml(void)
#define XML_DOC_PRIVATE_MAGIC
#define CRM_LOG_ASSERT(expr)
enum crm_ais_msg_types type
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
char * dump_xml_formatted(const xmlNode *xml)
const char * pcmk__env_option(const char *option)
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Include indentation and newlines.
Deprecated Pacemaker XML API.
G_GNUC_INTERNAL bool pcmk__marked_as_deleted(xmlAttrPtr a, void *user_data)
xmlNode * filename2xml(const char *filename)
int find_xml_children(xmlNode **children, xmlNode *root, const char *tag, const char *field, const char *value, gboolean search_matches)
void expand_plus_plus(xmlNode *target, const char *name, const char *value)
Update current XML attribute value per parsed integer assignment statement.
void pcmk__xml_update(xmlNode *parent, xmlNode *target, xmlNode *update, bool as_diff)
#define PCMK__ENV_SCHEMA_DIRECTORY
int pcmk__xml_position(const xmlNode *xml, enum xml_private_flags ignore_if_set)
xmlNode * pcmk__xml_match(const xmlNode *haystack, const xmlNode *needle, bool exact)
char * pcmk__xml_artefact_root(enum pcmk__xml_artefact_ns ns)
#define crm_warn(fmt, args...)
void pcmk__xe_set_propv(xmlNodePtr node, va_list pairs)
void pcmk__strip_xml_text(xmlNode *xml)
xmlNode * copy_xml(xmlNode *src)
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
void free_xml(xmlNode *child)
#define crm_trace(fmt, args...)
#define XML_NODE_PRIVATE_MAGIC
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
void pcmk__mark_xml_node_dirty(xmlNode *xml)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
#define crm_log_xml_debug(xml, text)
xmlNode * pcmk__xe_match(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag)
void pcmk__str_update(char **str, const char *value)
Wrappers for and extensions to libxml2.
#define crm_log_xml_warn(xml, text)
void crm_xml_set_id(xmlNode *xml, const char *format,...)
Set the ID of an XML element using a format.
#define XML_TAG_RESOURCE_REF
char * pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns, const char *filespec)
int pcmk__xml2fd(int fd, xmlNode *cur)
void crm_xml_cleanup(void)
xmlNode * add_node_copy(xmlNode *parent, xmlNode *src_node)
xmlDoc * getDocPtr(xmlNode *node)
void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
xmlNode * string2xml(const char *input)
const xmlChar * pcmkXmlStr
G_GNUC_INTERNAL bool pcmk__xa_filterable(const char *name)
const char * pcmk__get_tmpdir(void)
void copy_in_properties(xmlNode *target, const xmlNode *src)
int pcmk__bzlib2rc(int bz2)
Map a bz2 return code to the most similar Pacemaker return code.
#define PCMK__BUFFER_SIZE
#define crm_log_xml_err(xml, text)
void pcmk__xml2text(const xmlNode *data, uint32_t options, GString *buffer, int depth)
pcmk__action_result_t result
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
int write_xml_fd(const xmlNode *xml, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
gboolean xml_has_children(const xmlNode *xml_root)
#define crm_err(fmt, args...)
#define CRM_SCHEMA_DIRECTORY
char * pcmk__epoch2str(const time_t *source, uint32_t flags)
#define XML_CIB_ATTR_WRITTEN
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
G_GNUC_INTERNAL void pcmk__dump_xml_attr(const xmlAttr *attr, GString *buffer)
#define XML_ACL_TAG_ROLE_REFv1
void pcmk__mark_xml_created(xmlNode *xml)
void pcmk__apply_acl(xmlNode *xml)
void xml_accept_changes(xmlNode *xml)
void crm_destroy_xml(gpointer data)
void save_xml_to_file(const xmlNode *xml, const char *desc, const char *filename)
void pcmk_nvpairs2xml_attrs(GSList *list, xmlNode *xml)
Add XML attributes based on a list of name/value pairs.
int write_xml_file(const xmlNode *xml, const char *filename, gboolean compress)
Write XML to a file.
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
char * crm_xml_escape(const char *text)
Replace special characters with their XML escape sequences.
xmlNode * pcmk_create_html_node(xmlNode *parent, const char *element_name, const char *id, const char *class_name, const char *text)
gboolean update_xml_child(xmlNode *child, xmlNode *to_update)
GString * pcmk__element_xpath(const xmlNode *xml)
#define XML_CIB_TAG_OBJ_REF
xmlNode * pcmk_create_xml_text_node(xmlNode *parent, const char *name, const char *content)
xmlNode * sorted_xml(xmlNode *input, xmlNode *parent, gboolean recursive)
#define crm_log_xml_trace(xml, text)
xmlNode * find_xml_node(const xmlNode *root, const char *search_path, gboolean must_find)
bool xml_tracking_changes(xmlNode *xml)
#define XML_ACL_TAG_ROLE_REF
#define attr_matches(c, n, v)
char * dump_xml_formatted_with_text(const xmlNode *xml)
void pcmk__xe_remove_matching_attrs(xmlNode *element, bool(*match)(xmlAttrPtr, void *), void *user_data)
#define pcmk__set_xml_flags(xml_priv, flags_to_set)
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
#define pcmk__clear_xml_flags(xml_priv, flags_to_clear)
gboolean replace_xml_child(xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only)
#define PCMK__XML_PARSE_OPTS_WITH_RECOVER
void pcmk__xc_update(xmlNode *parent, xmlNode *target, xmlNode *update)
void xml_remove_prop(xmlNode *obj, const char *name)
const char * pcmk__xe_add_last_written(xmlNode *xe)
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
GSList * pcmk_xml_attrs2nvpairs(const xmlNode *xml)
Create a list of name/value pairs from an XML node's attributes.
#define crm_info(fmt, args...)
xmlNode * pcmk__xc_match(const xmlNode *root, const xmlNode *search_comment, bool exact)
bool pcmk__ends_with_ext(const char *s, const char *match)
gboolean can_prune_leaf(xmlNode *xml_node)
bool xml_document_dirty(xmlNode *xml)