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 (XML_PARSE_NOBLANKS | XML_PARSE_RECOVER) 50 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
63 set_parent_flag(xmlNode *xml,
long flag)
65 for(; xml; xml = xml->parent) {
68 if (nodepriv == NULL) {
79 if(xml && xml->doc && xml->doc->_private){
89 mark_xml_node_dirty(xmlNode *xml)
97 reset_xml_node_flags(xmlNode *xml)
99 xmlNode *cIter = NULL;
106 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
107 cIter = pcmk__xml_next(cIter)) {
108 reset_xml_node_flags(cIter);
116 xmlNode *cIter = NULL;
122 mark_xml_node_dirty(xml);
124 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
125 cIter = pcmk__xml_next(cIter)) {
134 xmlNode *
parent = a->parent;
139 mark_xml_node_dirty(
parent);
142 #define XML_DOC_PRIVATE_MAGIC 0x81726354UL 143 #define XML_NODE_PRIVATE_MAGIC 0x54637281UL 147 free_deleted_object(
void *
data)
152 free(deleted_obj->
path);
161 if (docpriv != NULL) {
165 docpriv->
user = NULL;
167 if (docpriv->
acls != NULL) {
169 docpriv->
acls = NULL;
173 g_list_free_full(docpriv->
deleted_objs, free_deleted_object);
181 free_private_data(xmlNode *node)
209 if (node->name == NULL || node->name[0] !=
' ') {
210 if (node->_private) {
211 if (node->type == XML_DOCUMENT_NODE) {
212 reset_xml_private_data(node->_private);
218 free(node->_private);
219 node->_private = NULL;
226 new_private_data(xmlNode *node)
228 switch (node->type) {
229 case XML_DOCUMENT_NODE: {
236 node->_private = docpriv;
239 case XML_ELEMENT_NODE:
240 case XML_ATTRIBUTE_NODE:
241 case XML_COMMENT_NODE: {
248 node->_private = nodepriv;
253 mark_xml_node_dirty(node);
259 case XML_CDATA_SECTION_NODE:
263 crm_trace(
"Ignoring %p %d", node, node->type);
273 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
276 if(acl_source == NULL) {
287 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
294 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
313 for (
const xmlNode *cIter = xml; cIter->prev; cIter = cIter->prev) {
326 marked_as_deleted(xmlAttrPtr a,
void *user_data)
339 accept_attr_deletions(xmlNode *xml)
348 for (xmlNodePtr cIter = pcmk__xml_first_child(xml); cIter != NULL;
349 cIter = pcmk__xml_next(cIter)) {
350 accept_attr_deletions(cIter);
367 if (needle->type == XML_COMMENT_NODE) {
371 const char *
id =
ID(needle);
372 const char *attr = (
id == NULL)? NULL :
XML_ATTR_ID;
374 return pcmk__xe_match(haystack, crm_element_name(needle), attr,
id);
388 crm_trace(
"Accepting changes to %p", xml);
389 docpriv = xml->doc->_private;
390 top = xmlDocGetRootElement(xml->doc);
392 reset_xml_private_data(xml->doc->_private);
400 accept_attr_deletions(top);
404 find_xml_node(
const xmlNode *root,
const char *search_path, gboolean must_find)
406 xmlNode *a_child = NULL;
407 const char *
name =
"NULL";
410 name = crm_element_name(root);
413 if (search_path == NULL) {
418 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
419 a_child = pcmk__xml_next(a_child)) {
420 if (strcmp((
const char *)a_child->name, search_path) == 0) {
427 crm_warn(
"Could not find %s in %s.", search_path,
name);
428 }
else if (root != NULL) {
431 crm_trace(
"Could not find %s in <NULL>.", search_path);
437 #define attr_matches(c, n, v) pcmk__str_eq(crm_element_value((c), (n)), \ 455 const char *attr_n,
const char *attr_v)
458 CRM_CHECK(attr_v == NULL || attr_n != NULL,
return NULL);
460 for (xmlNode *child = pcmk__xml_first_child(
parent); child != NULL;
461 child = pcmk__xml_next(child)) {
462 if (pcmk__str_eq(node_name, (
const char *) (child->name),
464 && ((attr_n == NULL) ||
465 (attr_v == NULL && xmlHasProp(child, (
pcmkXmlStr) attr_n)) ||
466 (attr_v != NULL &&
attr_matches(child, attr_n, attr_v)))) {
470 crm_trace(
"XML child node <%s%s%s%s%s> not found in %s",
471 (node_name? node_name :
"(any)"),
473 (attr_n? attr_n :
""),
475 (attr_n? attr_v :
""),
476 crm_element_name(
parent));
484 crm_warn(
"No node to copy properties from");
486 }
else if (
target == NULL) {
487 crm_err(
"No node to copy properties into");
490 for (xmlAttrPtr a = pcmk__xe_first_attr(src); a != NULL; a = a->next) {
491 const char *p_name = (
const char *) a->name;
492 const char *p_value = pcmk__xml_attr_value(a);
517 xmlNode *child = NULL;
519 for (xmlAttrPtr a = pcmk__xe_first_attr(
target); a != NULL; a = a->next) {
520 const char *p_name = (
const char *) a->name;
521 const char *p_value = pcmk__xml_attr_value(a);
525 for (child = pcmk__xml_first_child(
target); child != NULL;
526 child = pcmk__xml_next(child)) {
555 const char *old_value = NULL;
557 if (
target == NULL || value == NULL ||
name == NULL) {
563 if (old_value == NULL) {
567 }
else if (strstr(value,
name) != value) {
571 name_len = strlen(
name);
572 value_len = strlen(value);
573 if (value_len < (name_len + 2)
574 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
581 if (old_value != value) {
585 if (value[name_len + 1] !=
'+') {
586 const char *offset_s = value + (name_len + 2);
600 if (old_value == value) {
619 bool (*match)(xmlAttrPtr,
void *),
622 xmlAttrPtr next = NULL;
624 for (xmlAttrPtr a = pcmk__xe_first_attr(element); a != NULL; a = next) {
626 if ((match == NULL) || match(a, user_data)) {
628 crm_trace(
"ACLs prevent removal of attributes (%s and " 629 "possibly others) from %s element",
630 (
const char *) a->name, (
const char *) element->name);
656 xmlDocSetRootElement(doc, node);
657 xmlSetTreeDoc(node, doc);
665 xmlNode *child = NULL;
668 CRM_CHECK(src_node != NULL,
return NULL);
670 child = xmlDocCopyNode(src_node, doc, 1);
671 xmlAddChild(
parent, child);
680 xmlNode *node = NULL;
682 if (pcmk__str_empty(
name)) {
690 xmlDocSetRootElement(doc, node);
695 xmlAddChild(
parent, node);
707 xmlNodeSetContent(node, (
pcmkXmlStr) content);
715 const char *class_name,
const char *text)
719 if (class_name != NULL) {
743 free_xml_with_position(xmlNode * child,
int position)
747 xmlDoc *doc = child->doc;
752 top = xmlDocGetRootElement(doc);
755 if (doc != NULL && top == child) {
760 GString *xpath = NULL;
764 qb_log_from_external_source(__func__, __FILE__,
766 __LINE__, 0, (
const char *) xpath->str,
768 g_string_free(xpath, TRUE);
781 (
const char *) xpath->str, child, doc);
784 deleted_obj->
path = strdup((
const char *) xpath->str);
787 g_string_free(xpath, TRUE);
791 if (child->type == XML_COMMENT_NODE) {
801 docpriv = doc->_private;
815 free_xml_with_position(child, -1);
822 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
825 xmlDocSetRootElement(doc, copy);
826 xmlSetTreeDoc(copy, doc);
834 xmlDocPtr output = NULL;
835 xmlParserCtxtPtr ctxt = NULL;
836 xmlErrorPtr last_error = NULL;
839 crm_err(
"Can't parse NULL input");
844 ctxt = xmlNewParserCtxt();
847 xmlCtxtResetLastError(ctxt);
852 xml = xmlDocGetRootElement(output);
854 last_error = xmlCtxtGetLastError(ctxt);
855 if (last_error && last_error->code != XML_ERR_OK) {
861 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
862 last_error->domain, last_error->level, last_error->code, last_error->message);
864 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
867 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
868 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(
input),
875 int len = strlen(
input);
887 xmlFreeParserCtxt(ctxt);
894 size_t data_length = 0;
895 size_t read_chars = 0;
897 char *xml_buffer = NULL;
898 xmlNode *xml_obj = NULL;
904 data_length += read_chars;
907 if (data_length == 0) {
908 crm_warn(
"No XML supplied on stdin");
913 xml_buffer[data_length] =
'\0';
922 decompress_file(
const char *filename)
926 size_t length = 0, read_len = 0;
927 BZFILE *bz_file = NULL;
928 FILE *
input = fopen(filename,
"r");
931 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
935 bz_file = BZ2_bzReadOpen(&rc,
input, 0, 0, NULL, 0);
937 crm_err(
"Could not prepare to read compressed %s: %s " 939 BZ2_bzReadClose(&rc, bz_file);
947 while (rc == BZ_OK) {
951 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
953 if (rc == BZ_OK || rc == BZ_STREAM_END) {
958 buffer[length] =
'\0';
960 if (rc != BZ_STREAM_END) {
961 crm_err(
"Could not read compressed %s: %s " 967 BZ2_bzReadClose(&rc, bz_file);
981 xmlNode *iter = xml->children;
984 xmlNode *next = iter->next;
986 switch (iter->type) {
992 case XML_ELEMENT_NODE:
1009 xmlNode *xml = NULL;
1010 xmlDocPtr output = NULL;
1011 bool uncompressed =
true;
1012 xmlParserCtxtPtr ctxt = NULL;
1013 xmlErrorPtr last_error = NULL;
1016 ctxt = xmlNewParserCtxt();
1019 xmlCtxtResetLastError(ctxt);
1028 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL,
1031 }
else if (uncompressed) {
1035 char *
input = decompress_file(filename);
1042 if (output && (xml = xmlDocGetRootElement(output))) {
1046 last_error = xmlCtxtGetLastError(ctxt);
1047 if (last_error && last_error->code != XML_ERR_OK) {
1053 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
1054 last_error->domain, last_error->level, last_error->code, last_error->message);
1056 if (last_error && last_error->code != XML_ERR_OK) {
1057 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
1064 xmlFreeParserCtxt(ctxt);
1080 const char *
result = NULL;
1083 pcmk__s(now_s,
"Could not determine current time"));
1098 for (c =
id; *c; ++c) {
1123 va_start(ap, format);
1124 len = vasprintf(&
id, format, ap);
1146 write_xml_stream(xmlNode *xml_node,
const char *filename, FILE *stream,
1147 bool compress,
unsigned int *nbytes)
1150 char *buffer = NULL;
1162 unsigned int in = 0;
1163 BZFILE *bz_file = NULL;
1166 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
1168 crm_warn(
"Not compressing %s: could not prepare file stream: %s " 1171 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
1173 crm_warn(
"Not compressing %s: could not compress data: %s " 1174 CRM_XS " bzerror=%d errno=%d",
1180 BZ2_bzWriteClose(&rc, bz_file, 0, &in, nbytes);
1182 crm_warn(
"Not compressing %s: could not write compressed data: %s " 1183 CRM_XS " bzerror=%d errno=%d",
1187 crm_trace(
"Compressed XML for %s from %u bytes to %u",
1188 filename, in, *nbytes);
1195 rc = fprintf(stream,
"%s", buffer);
1200 *nbytes = (
unsigned int) rc;
1207 if (fflush(stream) != 0) {
1209 crm_perror(LOG_ERR,
"flushing %s", filename);
1213 if (fsync(fileno(stream)) < 0 && errno != EROFS && errno != EINVAL) {
1215 crm_perror(LOG_ERR,
"synchronizing %s", filename);
1220 crm_trace(
"Saved %d bytes to %s as XML", *nbytes, filename);
1237 write_xml_fd(xmlNode * xml_node,
const char *filename,
int fd, gboolean compress)
1239 FILE *stream = NULL;
1240 unsigned int nbytes = 0;
1243 CRM_CHECK(xml_node && (fd > 0),
return -EINVAL);
1244 stream = fdopen(fd,
"w");
1245 if (stream == NULL) {
1248 rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
1252 return (
int) nbytes;
1267 FILE *stream = NULL;
1268 unsigned int nbytes = 0;
1271 CRM_CHECK(xml_node && filename,
return -EINVAL);
1272 stream = fopen(filename,
"w");
1273 if (stream == NULL) {
1276 rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
1280 return (
int) nbytes;
1285 replace_text(
char *text,
int start,
size_t *length,
const char *replace)
1287 size_t offset = strlen(replace) - 1;
1290 text = pcmk__realloc(text, *length);
1292 for (
size_t lpc = (*length) - 1; lpc > (start + offset); lpc--) {
1293 text[lpc] = text[lpc - offset];
1296 memcpy(text + start, replace, offset + 1);
1334 length = 1 + strlen(text);
1335 copy = strdup(text);
1337 for (
size_t index = 0; index < length; index++) {
1338 if(copy[index] & 0x80 && copy[index+1] & 0x80){
1342 switch (copy[index]) {
1346 copy = replace_text(copy, index, &length,
"<");
1349 copy = replace_text(copy, index, &length,
">");
1352 copy = replace_text(copy, index, &length,
""");
1355 copy = replace_text(copy, index, &length,
"'");
1358 copy = replace_text(copy, index, &length,
"&");
1362 copy = replace_text(copy, index, &length,
" ");
1365 copy = replace_text(copy, index, &length,
"\\n");
1368 copy = replace_text(copy, index, &length,
"\\r");
1372 if(copy[index] <
' ' || copy[index] >
'~') {
1375 copy = replace_text(copy, index, &length, replace);
1391 dump_xml_attr(
const xmlAttr *attr, GString *buffer)
1393 char *p_value = NULL;
1394 const char *p_name = NULL;
1397 if (attr == NULL || attr->children == NULL) {
1401 nodepriv = attr->_private;
1406 p_name = (
const char *) attr->name;
1408 pcmk__g_strcat(buffer,
" ", p_name,
"=\"", pcmk__s(p_value,
"<null>"),
"\"",
1424 dump_xml_element(
const xmlNode *
data, uint32_t options, GString *buffer,
1427 const char *
name = crm_element_name(
data);
1430 int spaces = pretty? (2 * depth) : 0;
1434 for (
int lpc = 0; lpc < spaces; lpc++) {
1435 g_string_append_c(buffer,
' ');
1440 for (
const xmlAttr *attr = pcmk__xe_first_attr(
data); attr != NULL;
1441 attr = attr->next) {
1444 dump_xml_attr(attr, buffer);
1448 if (
data->children == NULL) {
1449 g_string_append(buffer,
"/>");
1452 g_string_append_c(buffer,
'>');
1456 g_string_append_c(buffer,
'\n');
1459 if (
data->children) {
1460 xmlNode *xChild = NULL;
1461 for(xChild =
data->children; xChild != NULL; xChild = xChild->next) {
1465 for (
int lpc = 0; lpc < spaces; lpc++) {
1466 g_string_append_c(buffer,
' ');
1472 g_string_append_c(buffer,
'\n');
1487 dump_xml_text(
const xmlNode *
data, uint32_t options, GString *buffer,
1494 int spaces = pretty? (2 * depth) : 0;
1496 for (
int lpc = 0; lpc < spaces; lpc++) {
1497 g_string_append_c(buffer,
' ');
1500 g_string_append(buffer, (
const gchar *)
data->content);
1503 g_string_append_c(buffer,
'\n');
1517 dump_xml_cdata(
const xmlNode *
data, uint32_t options, GString *buffer,
1521 int spaces = pretty? (2 * depth) : 0;
1523 for (
int lpc = 0; lpc < spaces; lpc++) {
1524 g_string_append_c(buffer,
' ');
1531 g_string_append_c(buffer,
'\n');
1545 dump_xml_comment(
const xmlNode *
data, uint32_t options, GString *buffer,
1549 int spaces = pretty? (2 * depth) : 0;
1551 for (
int lpc = 0; lpc < spaces; lpc++) {
1552 g_string_append_c(buffer,
' ');
1558 g_string_append_c(buffer,
'\n');
1562 #define PCMK__XMLDUMP_STATS 0 1592 #if (PCMK__XMLDUMP_STATS - 0) 1593 time_t next,
new = time(NULL);
1596 xmlOutputBuffer *xml_buffer;
1602 xml_buffer = xmlAllocOutputBuffer(NULL);
1615 xmlNodeDumpOutput(xml_buffer, doc,
data, 0,
1618 (void) xmlOutputBufferWrite(xml_buffer,
sizeof(
"\n") - 1,
"\n");
1619 if (xml_buffer->buffer != NULL) {
1620 g_string_append(buffer,
1621 (
const gchar *) xmlBufContent(xml_buffer->buffer));
1624 #if (PCMK__XMLDUMP_STATS - 0) 1626 if ((now + 1) < next) {
1628 crm_err(
"xmlNodeDumpOutput() -> %lld bytes took %ds",
1629 (
long long) buffer->len, next - now);
1634 (void) xmlOutputBufferClose(xml_buffer);
1638 switch(
data->type) {
1639 case XML_ELEMENT_NODE:
1641 dump_xml_element(
data, options, buffer, depth);
1650 dump_xml_text(
data, options, buffer, depth);
1653 case XML_COMMENT_NODE:
1654 dump_xml_comment(
data, options, buffer, depth);
1656 case XML_CDATA_SECTION_NODE:
1657 dump_xml_cdata(
data, options, buffer, depth);
1688 char *buffer = NULL;
1689 GString *g_buffer = g_string_sized_new(1024);
1695 g_string_free(g_buffer, TRUE);
1702 char *buffer = NULL;
1703 GString *g_buffer = g_string_sized_new(1024);
1708 g_string_free(g_buffer, TRUE);
1715 char *buffer = NULL;
1716 GString *g_buffer = g_string_sized_new(1024);
1721 g_string_free(g_buffer, TRUE);
1728 if (xml_root != NULL && xml_root->children != NULL) {
1757 if (filename == NULL) {
1765 crm_info(
"Saving %s to %s", desc, filename);
1780 for (xmlAttr *attr = pcmk__xe_first_attr(xml); attr; attr = attr->next) {
1800 mark_attr_deleted(xmlNode *new_xml,
const char *element,
const char *attr_name,
1801 const char *old_value)
1804 xmlAttr *attr = NULL;
1815 nodepriv = attr->_private;
1816 nodepriv->
flags = 0;
1821 crm_trace(
"XML attribute %s=%s was removed from %s",
1822 attr_name, old_value, element);
1830 mark_attr_changed(xmlNode *new_xml,
const char *element,
const char *attr_name,
1831 const char *old_value)
1835 crm_trace(
"XML attribute %s was changed from '%s' to '%s' in %s",
1836 attr_name, old_value, vcopy, element);
1858 mark_attr_moved(xmlNode *new_xml,
const char *element, xmlAttr *old_attr,
1859 xmlAttr *new_attr,
int p_old,
int p_new)
1863 crm_trace(
"XML attribute %s moved from position %d to %d in %s",
1864 old_attr->name, p_old, p_new, element);
1867 mark_xml_node_dirty(new_xml);
1872 nodepriv = (p_old > p_new)? old_attr->_private : new_attr->_private;
1884 xml_diff_old_attrs(xmlNode *old_xml, xmlNode *new_xml)
1886 xmlAttr *attr_iter = pcmk__xe_first_attr(old_xml);
1888 while (attr_iter != NULL) {
1889 xmlAttr *old_attr = attr_iter;
1890 xmlAttr *new_attr = xmlHasProp(new_xml, attr_iter->name);
1891 const char *
name = (
const char *) attr_iter->name;
1894 attr_iter = attr_iter->next;
1895 if (new_attr == NULL) {
1896 mark_attr_deleted(new_xml, (
const char *) old_xml->name,
name,
1910 if (strcmp(new_value, old_value) != 0) {
1911 mark_attr_changed(new_xml, (
const char *) old_xml->name,
name,
1914 }
else if ((old_pos != new_pos)
1916 mark_attr_moved(new_xml, (
const char *) old_xml->name,
1917 old_attr, new_attr, old_pos, new_pos);
1933 mark_created_attrs(xmlNode *new_xml)
1935 xmlAttr *attr_iter = pcmk__xe_first_attr(new_xml);
1937 while (attr_iter != NULL) {
1938 xmlAttr *new_attr = attr_iter;
1941 attr_iter = attr_iter->next;
1943 const char *attr_name = (
const char *) new_attr->name;
1945 crm_trace(
"Created new attribute %s=%s in %s",
1956 xmlUnsetProp(new_xml, new_attr->name);
1970 xml_diff_attrs(xmlNode *old_xml, xmlNode *new_xml)
1973 xml_diff_old_attrs(old_xml, new_xml);
1974 mark_created_attrs(new_xml);
1990 mark_child_deleted(xmlNode *old_child, xmlNode *new_parent)
1996 reset_xml_node_flags(candidate);
2002 free_xml_with_position(candidate,
2012 mark_child_moved(xmlNode *old_child, xmlNode *new_parent, xmlNode *new_child,
2013 int p_old,
int p_new)
2017 crm_trace(
"Child element %s with id='%s' moved from position %d to %d under %s",
2018 new_child->name, (
ID(new_child)?
ID(new_child) :
"<no id>"),
2019 p_old, p_new, new_parent->name);
2020 mark_xml_node_dirty(new_parent);
2023 if (p_old > p_new) {
2024 nodepriv = old_child->_private;
2026 nodepriv = new_child->_private;
2033 mark_xml_changes(xmlNode *old_xml, xmlNode *new_xml,
bool check_top)
2035 xmlNode *cIter = NULL;
2039 if (old_xml == NULL) {
2045 nodepriv = new_xml->_private;
2054 xml_diff_attrs(old_xml, new_xml);
2057 for (cIter = pcmk__xml_first_child(old_xml); cIter != NULL; ) {
2058 xmlNode *old_child = cIter;
2061 cIter = pcmk__xml_next(cIter);
2063 mark_xml_changes(old_child, new_child, TRUE);
2066 mark_child_deleted(old_child, new_xml);
2071 for (cIter = pcmk__xml_first_child(new_xml); cIter != NULL; ) {
2072 xmlNode *new_child = cIter;
2075 cIter = pcmk__xml_next(cIter);
2076 if(old_child == NULL) {
2078 nodepriv = new_child->_private;
2080 mark_xml_changes(old_child, new_child, TRUE);
2087 if(p_old != p_new) {
2088 mark_child_moved(old_child, new_xml, new_child, p_old, p_new);
2113 mark_xml_changes(old_xml, new_xml, FALSE);
2119 xmlNode *cIter = NULL;
2120 gboolean can_prune = TRUE;
2121 const char *
name = crm_element_name(xml_node);
2128 for (xmlAttrPtr a = pcmk__xe_first_attr(xml_node); a != NULL; a = a->next) {
2129 const char *p_name = (
const char *) a->name;
2137 cIter = pcmk__xml_first_child(xml_node);
2139 xmlNode *child = cIter;
2141 cIter = pcmk__xml_next(cIter);
2162 xmlNode *a_child = NULL;
2165 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
2167 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
2168 a_child = pcmk__xml_next(a_child)) {
2173 if (offset < search_offset) {
2176 }
else if (offset > search_offset) {
2185 if (a_child->type == XML_COMMENT_NODE
2186 && pcmk__str_eq((
const char *)a_child->content, (
const char *)search_comment->content,
pcmk__str_casei)) {
2212 CRM_CHECK(update->type == XML_COMMENT_NODE,
return);
2221 }
else if (!pcmk__str_eq((
const char *)
target->content, (
const char *)update->content,
pcmk__str_casei)) {
2222 xmlFree(
target->content);
2223 target->content = xmlStrdup(update->content);
2243 xmlNode *a_child = NULL;
2244 const char *object_name = NULL,
2245 *object_href = NULL,
2246 *object_href_val = NULL;
2248 #if XML_PARSER_DEBUG 2255 if (update->type == XML_COMMENT_NODE) {
2260 object_name = crm_element_name(update);
2261 object_href_val =
ID(update);
2262 if (object_href_val != NULL) {
2274 object_href, object_href_val);
2280 #if XML_PARSER_DEBUG 2281 crm_trace(
"Added <%s%s%s%s%s/>", pcmk__s(object_name,
"<null>"),
2282 object_href ?
" " :
"",
2283 object_href ? object_href :
"",
2284 object_href ?
"=" :
"",
2285 object_href ? object_href_val :
"");
2288 crm_trace(
"Found node <%s%s%s%s%s/> to update",
2289 pcmk__s(object_name,
"<null>"),
2290 object_href ?
" " :
"",
2291 object_href ? object_href :
"",
2292 object_href ?
"=" :
"",
2293 object_href ? object_href_val :
"");
2297 CRM_CHECK(pcmk__str_eq(crm_element_name(
target), crm_element_name(update),
2301 if (as_diff == FALSE) {
2307 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2309 const char *p_value = pcmk__xml_attr_value(a);
2312 xmlUnsetProp(
target, a->name);
2317 for (a_child = pcmk__xml_first_child(update); a_child != NULL;
2318 a_child = pcmk__xml_next(a_child)) {
2319 #if XML_PARSER_DEBUG 2320 crm_trace(
"Updating child <%s%s%s%s%s/>",
2321 pcmk__s(object_name,
"<null>"),
2322 object_href ?
" " :
"",
2323 object_href ? object_href :
"",
2324 object_href ?
"=" :
"",
2325 object_href ? object_href_val :
"");
2330 #if XML_PARSER_DEBUG 2331 crm_trace(
"Finished with <%s%s%s%s%s/>", pcmk__s(object_name,
"<null>"),
2332 object_href ?
" " :
"",
2333 object_href ? object_href :
"",
2334 object_href ?
"=" :
"",
2335 object_href ? object_href_val :
"");
2342 gboolean can_update = TRUE;
2343 xmlNode *child_of_child = NULL;
2346 CRM_CHECK(to_update != NULL,
return FALSE);
2348 if (!pcmk__str_eq(crm_element_name(to_update), crm_element_name(child),
pcmk__str_none)) {
2354 }
else if (can_update) {
2355 #if XML_PARSER_DEBUG 2361 for (child_of_child = pcmk__xml_first_child(child); child_of_child != NULL;
2362 child_of_child = pcmk__xml_next(child_of_child)) {
2375 const char *tag,
const char *field,
const char *value, gboolean search_matches)
2377 int match_found = 0;
2380 CRM_CHECK(children != NULL,
return FALSE);
2382 if (tag != NULL && !pcmk__str_eq(tag, crm_element_name(root),
pcmk__str_casei)) {
2387 if (*children == NULL) {
2394 if (search_matches || match_found == 0) {
2395 xmlNode *child = NULL;
2397 for (child = pcmk__xml_first_child(root); child != NULL;
2398 child = pcmk__xml_next(child)) {
2399 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
2409 gboolean can_delete = FALSE;
2410 xmlNode *child_of_child = NULL;
2412 const char *up_id = NULL;
2413 const char *child_id = NULL;
2414 const char *right_val = NULL;
2417 CRM_CHECK(update != NULL,
return FALSE);
2420 child_id =
ID(child);
2422 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
2425 if (!pcmk__str_eq(crm_element_name(update), crm_element_name(child),
pcmk__str_casei)) {
2428 if (can_delete && delete_only) {
2429 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2431 const char *p_name = (
const char *) a->name;
2432 const char *p_value = pcmk__xml_attr_value(a);
2441 if (can_delete &&
parent != NULL) {
2443 if (delete_only || update == NULL) {
2448 xmlDoc *doc = tmp->doc;
2449 xmlNode *old = NULL;
2452 old = xmlReplaceNode(child, tmp);
2460 xmlDocSetRootElement(doc, old);
2466 }
else if (can_delete) {
2471 child_of_child = pcmk__xml_first_child(child);
2472 while (child_of_child) {
2473 xmlNode *next = pcmk__xml_next(child_of_child);
2479 child_of_child = NULL;
2481 child_of_child = next;
2491 xmlNode *child = NULL;
2492 GSList *nvpairs = NULL;
2494 const char *
name = NULL;
2507 for (child = pcmk__xml_first_child(
input); child != NULL;
2508 child = pcmk__xml_next(child)) {
2523 xmlNode *match = NULL;
2525 for (match = pcmk__xe_first_child(
parent); match != NULL;
2526 match = pcmk__xe_next(match)) {
2549 xmlNode *match = pcmk__xe_next(sibling);
2550 const char *
name = crm_element_name(sibling);
2552 while (match != NULL) {
2553 if (!strcmp(crm_element_name(match),
name)) {
2556 match = pcmk__xe_next(match);
2564 static bool init =
true;
2573 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
2576 xmlDeregisterNodeDefault(free_private_data);
2577 xmlRegisterNodeDefault(new_private_data);
2590 #define XPATH_MAX 512 2595 const char *tag = NULL;
2596 const char *ref = NULL;
2602 }
else if (top == NULL) {
2606 tag = crm_element_name(
result);
2615 char *nodePath = (
char *)xmlGetNodePath(top);
2617 crm_err(
"No match for %s found in %s: Invalid configuration",
2618 xpath_string, pcmk__s(nodePath,
"unrecognizable path"));
2629 static const char *base = NULL;
2633 base = getenv(
"PCMK_schema_directory");
2635 if (pcmk__str_empty(base)) {
2649 crm_err(
"XML artefact family specified as %u not recognized", ns);
2669 crm_err(
"XML artefact family specified as %u not recognized", ns);
2680 const char *
name, *value;
2682 name = va_arg(pairs,
const char *);
2687 value = va_arg(pairs,
const char *);
2688 if (value != NULL) {
2698 va_start(pairs, node);
2705 int (*handler)(xmlNode *xml,
void *userdata),
2708 xmlNode *children = (xml? xml->children : NULL);
2712 for (xmlNode *node = children; node != NULL; node = node->next) {
2713 if (node->type == XML_ELEMENT_NODE &&
2715 int rc = handler(node, userdata);
#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
const char * bz2_strerror(int rc)
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__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.
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.
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
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)
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Include indentation and newlines.
Deprecated Pacemaker XML API.
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)
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
Include full XML subtree (with any text), using libxml serialization.
#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 save_xml_to_file(xmlNode *xml, const char *desc, const char *filename)
void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag)
void pcmk__xml2text(xmlNodePtr data, uint32_t options, GString *buffer, int depth)
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)
void crm_xml_cleanup(void)
xmlNode * add_node_copy(xmlNode *parent, xmlNode *src_node)
xmlDoc * getDocPtr(xmlNode *node)
char * dump_xml_formatted(xmlNode *an_xml_node)
void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
xmlNode * string2xml(const char *input)
const xmlChar * pcmkXmlStr
char * dump_xml_formatted_with_text(xmlNode *an_xml_node)
G_GNUC_INTERNAL bool pcmk__xa_filterable(const char *name)
char * dump_xml_unformatted(xmlNode *an_xml_node)
const char * pcmk__get_tmpdir(void)
void copy_in_properties(xmlNode *target, const xmlNode *src)
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Write XML to a file.
#define PCMK__BUFFER_SIZE
#define crm_log_xml_err(xml, text)
pcmk__action_result_t result
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
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)
#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 pcmk_nvpairs2xml_attrs(GSList *list, xmlNode *xml)
Add XML attributes based on a list of name/value pairs.
void pcmk__mark_xml_attr_dirty(xmlAttr *a)
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)
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)
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)