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 46 #define PCMK__XML_PARSE_OPTS (XML_PARSE_NOBLANKS | XML_PARSE_RECOVER) 51 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
74 insert_prefix(
int options, GString *buffer,
int depth)
88 for (
int lpc = 0; lpc < spaces; lpc++) {
89 g_string_append_c(buffer,
' ');
94 set_parent_flag(xmlNode *xml,
long flag)
96 for(; xml; xml = xml->parent) {
99 if (nodepriv == NULL) {
110 if(xml && xml->doc && xml->doc->_private){
120 mark_xml_node_dirty(xmlNode *xml)
128 reset_xml_node_flags(xmlNode *xml)
130 xmlNode *cIter = NULL;
137 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
138 cIter = pcmk__xml_next(cIter)) {
139 reset_xml_node_flags(cIter);
147 xmlNode *cIter = NULL;
153 mark_xml_node_dirty(xml);
155 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
156 cIter = pcmk__xml_next(cIter)) {
165 xmlNode *
parent = a->parent;
170 mark_xml_node_dirty(
parent);
173 #define XML_DOC_PRIVATE_MAGIC 0x81726354UL 174 #define XML_NODE_PRIVATE_MAGIC 0x54637281UL 178 free_deleted_object(
void *
data)
183 free(deleted_obj->
path);
192 if (docpriv != NULL) {
196 docpriv->
user = NULL;
198 if (docpriv->
acls != NULL) {
200 docpriv->
acls = NULL;
204 g_list_free_full(docpriv->
deleted_objs, free_deleted_object);
212 free_private_data(xmlNode *node)
240 if (node->name == NULL || node->name[0] !=
' ') {
241 if (node->_private) {
242 if (node->type == XML_DOCUMENT_NODE) {
243 reset_xml_private_data(node->_private);
249 free(node->_private);
250 node->_private = NULL;
257 new_private_data(xmlNode *node)
259 switch (node->type) {
260 case XML_DOCUMENT_NODE: {
267 node->_private = docpriv;
270 case XML_ELEMENT_NODE:
271 case XML_ATTRIBUTE_NODE:
272 case XML_COMMENT_NODE: {
279 node->_private = nodepriv;
284 mark_xml_node_dirty(node);
290 case XML_CDATA_SECTION_NODE:
294 crm_trace(
"Ignoring %p %d", node, node->type);
304 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
307 if(acl_source == NULL) {
318 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
325 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
344 for (
const xmlNode *cIter = xml; cIter->prev; cIter = cIter->prev) {
357 marked_as_deleted(xmlAttrPtr a,
void *user_data)
370 accept_attr_deletions(xmlNode *xml)
379 for (xmlNodePtr cIter = pcmk__xml_first_child(xml); cIter != NULL;
380 cIter = pcmk__xml_next(cIter)) {
381 accept_attr_deletions(cIter);
398 if (needle->type == XML_COMMENT_NODE) {
402 const char *
id =
ID(needle);
403 const char *attr = (
id == NULL)? NULL :
XML_ATTR_ID;
405 return pcmk__xe_match(haystack, crm_element_name(needle), attr,
id);
422 docpriv = xml->doc->_private;
427 for(gIter = docpriv->
deleted_objs; gIter; gIter = gIter->next) {
454 crm_trace(
"Accepting changes to %p", xml);
455 docpriv = xml->doc->_private;
456 top = xmlDocGetRootElement(xml->doc);
458 reset_xml_private_data(xml->doc->_private);
466 accept_attr_deletions(top);
470 find_xml_node(
const xmlNode *root,
const char *search_path, gboolean must_find)
472 xmlNode *a_child = NULL;
473 const char *
name =
"NULL";
476 name = crm_element_name(root);
479 if (search_path == NULL) {
484 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
485 a_child = pcmk__xml_next(a_child)) {
486 if (strcmp((
const char *)a_child->name, search_path) == 0) {
493 crm_warn(
"Could not find %s in %s.", search_path,
name);
494 }
else if (root != NULL) {
497 crm_trace(
"Could not find %s in <NULL>.", search_path);
503 #define attr_matches(c, n, v) pcmk__str_eq(crm_element_value((c), (n)), \ 521 const char *attr_n,
const char *attr_v)
524 CRM_CHECK(attr_n == NULL || attr_v != NULL,
return NULL);
526 for (xmlNode *child = pcmk__xml_first_child(
parent); child != NULL;
527 child = pcmk__xml_next(child)) {
528 if (pcmk__str_eq(node_name, (
const char *) (child->name),
530 && ((attr_n == NULL) ||
attr_matches(child, attr_n, attr_v))) {
534 crm_trace(
"XML child node <%s%s%s%s%s> not found in %s",
535 (node_name? node_name :
"(any)"),
537 (attr_n? attr_n :
""),
539 (attr_n? attr_v :
""),
540 crm_element_name(
parent));
548 crm_warn(
"No node to copy properties from");
550 }
else if (
target == NULL) {
551 crm_err(
"No node to copy properties into");
554 for (xmlAttrPtr a = pcmk__xe_first_attr(src); a != NULL; a = a->next) {
555 const char *p_name = (
const char *) a->name;
556 const char *p_value = pcmk__xml_attr_value(a);
581 xmlNode *child = NULL;
583 for (xmlAttrPtr a = pcmk__xe_first_attr(
target); a != NULL; a = a->next) {
584 const char *p_name = (
const char *) a->name;
585 const char *p_value = pcmk__xml_attr_value(a);
589 for (child = pcmk__xml_first_child(
target); child != NULL;
590 child = pcmk__xml_next(child)) {
619 const char *old_value = NULL;
621 if (
target == NULL || value == NULL ||
name == NULL) {
627 if (old_value == NULL) {
631 }
else if (strstr(value,
name) != value) {
635 name_len = strlen(
name);
636 value_len = strlen(value);
637 if (value_len < (name_len + 2)
638 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
645 if (old_value != value) {
649 if (value[name_len + 1] !=
'+') {
650 const char *offset_s = value + (name_len + 2);
664 if (old_value == value) {
683 bool (*match)(xmlAttrPtr,
void *),
686 xmlAttrPtr next = NULL;
688 for (xmlAttrPtr a = pcmk__xe_first_attr(element); a != NULL; a = next) {
690 if ((match == NULL) || match(a, user_data)) {
692 crm_trace(
"ACLs prevent removal of attributes (%s and " 693 "possibly others) from %s element",
694 (
const char *) a->name, (
const char *) element->name);
720 xmlDocSetRootElement(doc, node);
721 xmlSetTreeDoc(node, doc);
729 xmlNode *child = NULL;
732 CRM_CHECK(src_node != NULL,
return NULL);
734 child = xmlDocCopyNode(src_node, doc, 1);
735 xmlAddChild(
parent, child);
752 xmlNode *node = NULL;
754 if (pcmk__str_empty(
name)) {
762 xmlDocSetRootElement(doc, node);
767 xmlAddChild(
parent, node);
779 xmlNodeSetContent(node, (
pcmkXmlStr) content);
787 const char *class_name,
const char *text)
791 if (class_name != NULL) {
815 free_xml_with_position(xmlNode * child,
int position)
819 xmlDoc *doc = child->doc;
824 top = xmlDocGetRootElement(doc);
827 if (doc != NULL && top == child) {
832 GString *xpath = NULL;
836 qb_log_from_external_source(__func__, __FILE__,
838 __LINE__, 0, (
const char *) xpath->str,
840 g_string_free(xpath, TRUE);
853 (
const char *) xpath->str, child, doc);
856 deleted_obj->
path = strdup((
const char *) xpath->str);
859 g_string_free(xpath, TRUE);
863 if (child->type == XML_COMMENT_NODE) {
873 docpriv = doc->_private;
887 free_xml_with_position(child, -1);
894 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
896 xmlDocSetRootElement(doc, copy);
897 xmlSetTreeDoc(copy, doc);
902 log_xmllib_err(
void *ctx,
const char *fmt, ...)
907 log_xmllib_err(
void *ctx, const
char *fmt, ...)
910 static struct qb_log_callsite *xml_error_cs = NULL;
912 if (xml_error_cs == NULL) {
913 xml_error_cs = qb_log_callsite_get(
918 if (xml_error_cs && xml_error_cs->targets) {
920 crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__,
"xml library error",
922 "XML Error: ", fmt, ap);
933 xmlDocPtr output = NULL;
934 xmlParserCtxtPtr ctxt = NULL;
935 xmlErrorPtr last_error = NULL;
938 crm_err(
"Can't parse NULL input");
943 ctxt = xmlNewParserCtxt();
946 xmlCtxtResetLastError(ctxt);
947 xmlSetGenericErrorFunc(ctxt, log_xmllib_err);
951 xml = xmlDocGetRootElement(output);
953 last_error = xmlCtxtGetLastError(ctxt);
954 if (last_error && last_error->code != XML_ERR_OK) {
960 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
961 last_error->domain, last_error->level, last_error->code, last_error->message);
963 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
966 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
967 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(
input),
974 int len = strlen(
input);
986 xmlFreeParserCtxt(ctxt);
993 size_t data_length = 0;
994 size_t read_chars = 0;
996 char *xml_buffer = NULL;
997 xmlNode *xml_obj = NULL;
1003 data_length += read_chars;
1006 if (data_length == 0) {
1007 crm_warn(
"No XML supplied on stdin");
1012 xml_buffer[data_length] =
'\0';
1021 decompress_file(
const char *filename)
1023 char *buffer = NULL;
1025 size_t length = 0, read_len = 0;
1026 BZFILE *bz_file = NULL;
1027 FILE *
input = fopen(filename,
"r");
1029 if (
input == NULL) {
1030 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
1034 bz_file = BZ2_bzReadOpen(&rc,
input, 0, 0, NULL, 0);
1036 crm_err(
"Could not prepare to read compressed %s: %s " 1038 BZ2_bzReadClose(&rc, bz_file);
1046 while (rc == BZ_OK) {
1050 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
1052 if (rc == BZ_OK || rc == BZ_STREAM_END) {
1057 buffer[length] =
'\0';
1059 if (rc != BZ_STREAM_END) {
1060 crm_err(
"Could not read compressed %s: %s " 1066 BZ2_bzReadClose(&rc, bz_file);
1080 xmlNode *iter = xml->children;
1083 xmlNode *next = iter->next;
1085 switch (iter->type) {
1091 case XML_ELEMENT_NODE:
1108 xmlNode *xml = NULL;
1109 xmlDocPtr output = NULL;
1110 bool uncompressed =
true;
1111 xmlParserCtxtPtr ctxt = NULL;
1112 xmlErrorPtr last_error = NULL;
1115 ctxt = xmlNewParserCtxt();
1118 xmlCtxtResetLastError(ctxt);
1119 xmlSetGenericErrorFunc(ctxt, log_xmllib_err);
1127 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL,
1130 }
else if (uncompressed) {
1134 char *
input = decompress_file(filename);
1141 if (output && (xml = xmlDocGetRootElement(output))) {
1145 last_error = xmlCtxtGetLastError(ctxt);
1146 if (last_error && last_error->code != XML_ERR_OK) {
1152 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
1153 last_error->domain, last_error->level, last_error->code, last_error->message);
1155 if (last_error && last_error->code != XML_ERR_OK) {
1156 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
1163 xmlFreeParserCtxt(ctxt);
1181 now_str ? now_str :
"Could not determine current time");
1194 for (c =
id; *c; ++c) {
1219 va_start(ap, format);
1220 len = vasprintf(&
id, format, ap);
1242 write_xml_stream(xmlNode *xml_node,
const char *filename, FILE *stream,
1243 bool compress,
unsigned int *nbytes)
1246 char *buffer = NULL;
1258 unsigned int in = 0;
1259 BZFILE *bz_file = NULL;
1262 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
1264 crm_warn(
"Not compressing %s: could not prepare file stream: %s " 1267 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
1269 crm_warn(
"Not compressing %s: could not compress data: %s " 1270 CRM_XS " bzerror=%d errno=%d",
1276 BZ2_bzWriteClose(&rc, bz_file, 0, &in, nbytes);
1278 crm_warn(
"Not compressing %s: could not write compressed data: %s " 1279 CRM_XS " bzerror=%d errno=%d",
1283 crm_trace(
"Compressed XML for %s from %u bytes to %u",
1284 filename, in, *nbytes);
1291 rc = fprintf(stream,
"%s", buffer);
1296 *nbytes = (
unsigned int) rc;
1303 if (fflush(stream) != 0) {
1305 crm_perror(LOG_ERR,
"flushing %s", filename);
1309 if (fsync(fileno(stream)) < 0 && errno != EROFS && errno != EINVAL) {
1311 crm_perror(LOG_ERR,
"synchronizing %s", filename);
1316 crm_trace(
"Saved %d bytes to %s as XML", *nbytes, filename);
1333 write_xml_fd(xmlNode * xml_node,
const char *filename,
int fd, gboolean compress)
1335 FILE *stream = NULL;
1336 unsigned int nbytes = 0;
1339 CRM_CHECK(xml_node && (fd > 0),
return -EINVAL);
1340 stream = fdopen(fd,
"w");
1341 if (stream == NULL) {
1344 rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
1348 return (
int) nbytes;
1363 FILE *stream = NULL;
1364 unsigned int nbytes = 0;
1367 CRM_CHECK(xml_node && filename,
return -EINVAL);
1368 stream = fopen(filename,
"w");
1369 if (stream == NULL) {
1372 rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
1376 return (
int) nbytes;
1381 replace_text(
char *text,
int start,
size_t *length,
const char *replace)
1383 size_t offset = strlen(replace) - 1;
1386 text = pcmk__realloc(text, *length);
1388 for (
size_t lpc = (*length) - 1; lpc > (start + offset); lpc--) {
1389 text[lpc] = text[lpc - offset];
1392 memcpy(text + start, replace, offset + 1);
1430 length = 1 + strlen(text);
1431 copy = strdup(text);
1433 for (
size_t index = 0; index < length; index++) {
1434 if(copy[index] & 0x80 && copy[index+1] & 0x80){
1438 switch (copy[index]) {
1442 copy = replace_text(copy, index, &length,
"<");
1445 copy = replace_text(copy, index, &length,
">");
1448 copy = replace_text(copy, index, &length,
""");
1451 copy = replace_text(copy, index, &length,
"'");
1454 copy = replace_text(copy, index, &length,
"&");
1458 copy = replace_text(copy, index, &length,
" ");
1461 copy = replace_text(copy, index, &length,
"\\n");
1464 copy = replace_text(copy, index, &length,
"\\r");
1468 if(copy[index] <
' ' || copy[index] >
'~') {
1471 copy = replace_text(copy, index, &length, replace);
1492 dump_xml_attr(
const xmlAttr *attr,
int options, GString *buffer)
1494 char *p_value = NULL;
1495 const char *p_name = NULL;
1499 if (attr == NULL || attr->children == NULL) {
1503 nodepriv = attr->_private;
1508 p_name = (
const char *) attr->name;
1510 pcmk__g_strcat(buffer,
" ", p_name,
"=\"", pcmk__s(p_value,
"<null>"),
"\"",
1518 log_xml_node_and_children(GString *buffer,
int log_level,
const char *file,
1519 const char *
function,
int line,
const char *prefix,
1520 const xmlNode *
data,
int depth,
int options)
1522 const char *
name = NULL;
1523 const char *hidden = NULL;
1525 xmlNode *child = NULL;
1530 || ((
data->type != XML_COMMENT_NODE)
1531 && (
data->type != XML_ELEMENT_NODE))) {
1537 g_string_truncate(buffer, 0);
1540 insert_prefix(options, buffer, depth);
1542 if (
data->type == XML_COMMENT_NODE) {
1550 for (xmlAttrPtr a = pcmk__xe_first_attr(
data); a != NULL;
1554 const char *p_name = (
const char *) a->name;
1555 const char *p_value = pcmk__xml_attr_value(a);
1556 char *p_copy = NULL;
1560 }
else if (pcmk_any_flags_set(options,
1566 }
else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
1567 p_copy = strdup(
"*****");
1574 pcmk__s(p_copy,
"<null>"),
"\"", NULL);
1579 g_string_append(buffer,
"/>");
1582 g_string_append_c(buffer,
'>');
1585 g_string_append(buffer,
"/>");
1590 (
const char *) buffer->str);
1593 if(
data->type == XML_COMMENT_NODE) {
1600 for (child = pcmk__xml_first_child(
data); child != NULL;
1601 child = pcmk__xml_next(child)) {
1603 log_xml_node_and_children(buffer, log_level, file,
function, line,
1604 prefix, child, depth + 1,
1611 g_string_truncate(buffer, 0);
1613 insert_prefix(options, buffer, depth);
1617 (
const char *) buffer->str);
1624 const char *prefix,
const xmlNode *
data,
int depth,
int options)
1629 GString *buffer = g_string_sized_new(1024);
1631 log_xml_node_and_children(buffer, log_level, file,
function, line, prefix,
1632 data, depth, options);
1634 g_string_free(buffer, TRUE);
1639 log_xml_changes(
int log_level,
const char *file,
const char *
function,
int line,
1640 const char *prefix,
const xmlNode *
data,
int depth,
int options)
1643 char *prefix_m = NULL;
1644 xmlNode *child = NULL;
1650 nodepriv =
data->_private;
1652 prefix_m = strdup(prefix);
1663 char *prefix_del = NULL;
1664 char *prefix_moved = NULL;
1665 const char *
flags = prefix;
1672 prefix_del = strdup(prefix);
1673 prefix_del[0] =
'-';
1674 prefix_del[1] =
'-';
1675 prefix_moved = strdup(prefix);
1676 prefix_moved[1] =
'~';
1679 flags = prefix_moved;
1687 for (xmlAttrPtr a = pcmk__xe_first_attr(
data); a != NULL; a = a->next) {
1688 const char *aname = (
const char*) a->name;
1690 nodepriv = a->_private;
1695 "%s %*s @%s=%s",
flags, spaces,
"", aname,
1708 flags = prefix_moved;
1714 "%s %*s @%s=%s",
flags, spaces,
"", aname,
1721 for (child = pcmk__xml_first_child(
data); child != NULL;
1722 child = pcmk__xml_next(child)) {
1723 log_xml_changes(log_level, file,
function, line, prefix, child,
1724 depth + 1, options);
1731 for (child = pcmk__xml_first_child(
data); child != NULL;
1732 child = pcmk__xml_next(child)) {
1733 log_xml_changes(log_level, file,
function, line, prefix, child,
1734 depth + 1, options);
1744 int line,
const char *prefix,
const xmlNode *
data,
int depth,
1747 xmlNode *a_child = NULL;
1749 char *prefix_m = NULL;
1755 if (prefix == NULL) {
1762 "No data to dump as XML");
1767 log_xml_changes(log_level, file,
function, line, prefix,
data, depth,
1776 prefix_m = strdup(prefix);
1783 prefix_m = strdup(prefix);
1792 for (a_child = pcmk__xml_first_child(
data); a_child != NULL;
1793 a_child = pcmk__xml_next(a_child)) {
1794 log_data_element(log_level, file,
function, line, prefix, a_child, depth + 1, options);
1813 dump_filtered_xml(
const xmlNode *
data,
int options, GString *buffer)
1817 for (
const xmlAttr *a = pcmk__xe_first_attr(
data); a != NULL; a = a->next) {
1819 dump_xml_attr(a, options, buffer);
1834 dump_xml_element(
const xmlNode *
data,
int options, GString *buffer,
int depth)
1836 const char *
name = NULL;
1848 insert_prefix(options, buffer, depth);
1852 dump_filtered_xml(
data, options, buffer);
1855 for (
const xmlAttr *a = pcmk__xe_first_attr(
data); a != NULL;
1858 dump_xml_attr(a, options, buffer);
1862 if (
data->children == NULL) {
1863 g_string_append(buffer,
"/>");
1866 g_string_append_c(buffer,
'>');
1870 g_string_append_c(buffer,
'\n');
1873 if (
data->children) {
1874 xmlNode *xChild = NULL;
1875 for(xChild =
data->children; xChild != NULL; xChild = xChild->next) {
1879 insert_prefix(options, buffer, depth);
1883 g_string_append_c(buffer,
'\n');
1898 dump_xml_text(
const xmlNode *
data,
int options, GString *buffer,
int depth)
1907 insert_prefix(options, buffer, depth);
1908 g_string_append(buffer, (
const gchar *)
data->content);
1911 g_string_append_c(buffer,
'\n');
1925 dump_xml_cdata(
const xmlNode *
data,
int options, GString *buffer,
int depth)
1934 insert_prefix(options, buffer, depth);
1939 g_string_append_c(buffer,
'\n');
1953 dump_xml_comment(
const xmlNode *
data,
int options, GString *buffer,
int depth)
1962 insert_prefix(options, buffer, depth);
1966 g_string_append_c(buffer,
'\n');
1970 #define PCMK__XMLDUMP_STATS 0 1999 #if (PCMK__XMLDUMP_STATS - 0) 2000 time_t next,
new = time(NULL);
2003 xmlOutputBuffer *xml_buffer;
2009 xml_buffer = xmlAllocOutputBuffer(NULL);
2022 xmlNodeDumpOutput(xml_buffer, doc,
data, 0,
2025 (void) xmlOutputBufferWrite(xml_buffer,
sizeof(
"\n") - 1,
"\n");
2026 if (xml_buffer->buffer != NULL) {
2027 g_string_append(buffer,
2028 (
const gchar *) xmlBufContent(xml_buffer->buffer));
2031 #if (PCMK__XMLDUMP_STATS - 0) 2033 if ((now + 1) < next) {
2035 crm_err(
"xmlNodeDumpOutput() -> %lld bytes took %ds",
2036 (
long long) buffer->len, next - now);
2041 (void) xmlOutputBufferClose(xml_buffer);
2045 switch(
data->type) {
2046 case XML_ELEMENT_NODE:
2048 dump_xml_element(
data, options, buffer, depth);
2053 dump_xml_text(
data, options, buffer, depth);
2056 case XML_COMMENT_NODE:
2057 dump_xml_comment(
data, options, buffer, depth);
2059 case XML_CDATA_SECTION_NODE:
2060 dump_xml_cdata(
data, options, buffer, depth);
2091 char *buffer = NULL;
2092 GString *g_buffer = g_string_sized_new(1024);
2098 if (g_buffer != NULL) {
2099 buffer = strdup((
const char *) g_buffer->str);
2100 g_string_free(g_buffer, TRUE);
2108 char *buffer = NULL;
2109 GString *g_buffer = g_string_sized_new(1024);
2113 if (g_buffer != NULL) {
2114 buffer = strdup((
const char *) g_buffer->str);
2115 g_string_free(g_buffer, TRUE);
2123 char *buffer = NULL;
2124 GString *g_buffer = g_string_sized_new(1024);
2128 if (g_buffer != NULL) {
2129 buffer = strdup((
const char *) g_buffer->str);
2130 g_string_free(g_buffer, TRUE);
2138 if (xml_root != NULL && xml_root->children != NULL) {
2167 if (filename == NULL) {
2175 crm_info(
"Saving %s to %s", desc, filename);
2190 for (xmlAttr *attr = pcmk__xe_first_attr(xml); attr; attr = attr->next) {
2210 mark_attr_deleted(xmlNode *new_xml,
const char *element,
const char *attr_name,
2211 const char *old_value)
2214 xmlAttr *attr = NULL;
2225 nodepriv = attr->_private;
2226 nodepriv->
flags = 0;
2231 crm_trace(
"XML attribute %s=%s was removed from %s",
2232 attr_name, old_value, element);
2240 mark_attr_changed(xmlNode *new_xml,
const char *element,
const char *attr_name,
2241 const char *old_value)
2245 crm_trace(
"XML attribute %s was changed from '%s' to '%s' in %s",
2246 attr_name, old_value, vcopy, element);
2268 mark_attr_moved(xmlNode *new_xml,
const char *element, xmlAttr *old_attr,
2269 xmlAttr *new_attr,
int p_old,
int p_new)
2273 crm_trace(
"XML attribute %s moved from position %d to %d in %s",
2274 old_attr->name, p_old, p_new, element);
2277 mark_xml_node_dirty(new_xml);
2282 nodepriv = (p_old > p_new)? old_attr->_private : new_attr->_private;
2294 xml_diff_old_attrs(xmlNode *old_xml, xmlNode *new_xml)
2296 xmlAttr *attr_iter = pcmk__xe_first_attr(old_xml);
2298 while (attr_iter != NULL) {
2299 xmlAttr *old_attr = attr_iter;
2300 xmlAttr *new_attr = xmlHasProp(new_xml, attr_iter->name);
2301 const char *
name = (
const char *) attr_iter->name;
2304 attr_iter = attr_iter->next;
2305 if (new_attr == NULL) {
2306 mark_attr_deleted(new_xml, (
const char *) old_xml->name,
name,
2320 if (strcmp(new_value, old_value) != 0) {
2321 mark_attr_changed(new_xml, (
const char *) old_xml->name,
name,
2324 }
else if ((old_pos != new_pos)
2326 mark_attr_moved(new_xml, (
const char *) old_xml->name,
2327 old_attr, new_attr, old_pos, new_pos);
2343 mark_created_attrs(xmlNode *new_xml)
2345 xmlAttr *attr_iter = pcmk__xe_first_attr(new_xml);
2347 while (attr_iter != NULL) {
2348 xmlAttr *new_attr = attr_iter;
2351 attr_iter = attr_iter->next;
2353 const char *attr_name = (
const char *) new_attr->name;
2355 crm_trace(
"Created new attribute %s=%s in %s",
2366 xmlUnsetProp(new_xml, new_attr->name);
2380 xml_diff_attrs(xmlNode *old_xml, xmlNode *new_xml)
2383 xml_diff_old_attrs(old_xml, new_xml);
2384 mark_created_attrs(new_xml);
2400 mark_child_deleted(xmlNode *old_child, xmlNode *new_parent)
2406 reset_xml_node_flags(candidate);
2412 free_xml_with_position(candidate,
2422 mark_child_moved(xmlNode *old_child, xmlNode *new_parent, xmlNode *new_child,
2423 int p_old,
int p_new)
2427 crm_trace(
"Child element %s with id='%s' moved from position %d to %d under %s",
2428 new_child->name, (
ID(new_child)?
ID(new_child) :
"<no id>"),
2429 p_old, p_new, new_parent->name);
2430 mark_xml_node_dirty(new_parent);
2433 if (p_old > p_new) {
2434 nodepriv = old_child->_private;
2436 nodepriv = new_child->_private;
2443 mark_xml_changes(xmlNode *old_xml, xmlNode *new_xml,
bool check_top)
2445 xmlNode *cIter = NULL;
2449 if (old_xml == NULL) {
2455 nodepriv = new_xml->_private;
2464 xml_diff_attrs(old_xml, new_xml);
2467 for (cIter = pcmk__xml_first_child(old_xml); cIter != NULL; ) {
2468 xmlNode *old_child = cIter;
2471 cIter = pcmk__xml_next(cIter);
2473 mark_xml_changes(old_child, new_child, TRUE);
2476 mark_child_deleted(old_child, new_xml);
2481 for (cIter = pcmk__xml_first_child(new_xml); cIter != NULL; ) {
2482 xmlNode *new_child = cIter;
2485 cIter = pcmk__xml_next(cIter);
2486 if(old_child == NULL) {
2488 nodepriv = new_child->_private;
2490 mark_xml_changes(old_child, new_child, TRUE);
2497 if(p_old != p_new) {
2498 mark_child_moved(old_child, new_xml, new_child, p_old, p_new);
2522 mark_xml_changes(old_xml, new_xml, FALSE);
2528 xmlNode *cIter = NULL;
2529 gboolean can_prune = TRUE;
2530 const char *
name = crm_element_name(xml_node);
2537 for (xmlAttrPtr a = pcmk__xe_first_attr(xml_node); a != NULL; a = a->next) {
2538 const char *p_name = (
const char *) a->name;
2546 cIter = pcmk__xml_first_child(xml_node);
2548 xmlNode *child = cIter;
2550 cIter = pcmk__xml_next(cIter);
2571 xmlNode *a_child = NULL;
2574 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
2576 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
2577 a_child = pcmk__xml_next(a_child)) {
2582 if (offset < search_offset) {
2585 }
else if (offset > search_offset) {
2594 if (a_child->type == XML_COMMENT_NODE
2595 && pcmk__str_eq((
const char *)a_child->content, (
const char *)search_comment->content,
pcmk__str_casei)) {
2621 CRM_CHECK(update->type == XML_COMMENT_NODE,
return);
2630 }
else if (!pcmk__str_eq((
const char *)
target->content, (
const char *)update->content,
pcmk__str_casei)) {
2631 xmlFree(
target->content);
2632 target->content = xmlStrdup(update->content);
2652 xmlNode *a_child = NULL;
2653 const char *object_name = NULL,
2654 *object_href = NULL,
2655 *object_href_val = NULL;
2657 #if XML_PARSER_DEBUG 2664 if (update->type == XML_COMMENT_NODE) {
2669 object_name = crm_element_name(update);
2670 object_href_val =
ID(update);
2671 if (object_href_val != NULL) {
2683 object_href, object_href_val);
2689 #if XML_PARSER_DEBUG 2690 crm_trace(
"Added <%s%s%s%s%s/>", pcmk__s(object_name,
"<null>"),
2691 object_href ?
" " :
"",
2692 object_href ? object_href :
"",
2693 object_href ?
"=" :
"",
2694 object_href ? object_href_val :
"");
2697 crm_trace(
"Found node <%s%s%s%s%s/> to update",
2698 pcmk__s(object_name,
"<null>"),
2699 object_href ?
" " :
"",
2700 object_href ? object_href :
"",
2701 object_href ?
"=" :
"",
2702 object_href ? object_href_val :
"");
2706 CRM_CHECK(pcmk__str_eq(crm_element_name(
target), crm_element_name(update),
2710 if (as_diff == FALSE) {
2716 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2718 const char *p_value = pcmk__xml_attr_value(a);
2721 xmlUnsetProp(
target, a->name);
2726 for (a_child = pcmk__xml_first_child(update); a_child != NULL;
2727 a_child = pcmk__xml_next(a_child)) {
2728 #if XML_PARSER_DEBUG 2729 crm_trace(
"Updating child <%s%s%s%s%s/>",
2730 pcmk__s(object_name,
"<null>"),
2731 object_href ?
" " :
"",
2732 object_href ? object_href :
"",
2733 object_href ?
"=" :
"",
2734 object_href ? object_href_val :
"");
2739 #if XML_PARSER_DEBUG 2740 crm_trace(
"Finished with <%s%s%s%s%s/>", pcmk__s(object_name,
"<null>"),
2741 object_href ?
" " :
"",
2742 object_href ? object_href :
"",
2743 object_href ?
"=" :
"",
2744 object_href ? object_href_val :
"");
2751 gboolean can_update = TRUE;
2752 xmlNode *child_of_child = NULL;
2755 CRM_CHECK(to_update != NULL,
return FALSE);
2757 if (!pcmk__str_eq(crm_element_name(to_update), crm_element_name(child),
pcmk__str_none)) {
2763 }
else if (can_update) {
2764 #if XML_PARSER_DEBUG 2770 for (child_of_child = pcmk__xml_first_child(child); child_of_child != NULL;
2771 child_of_child = pcmk__xml_next(child_of_child)) {
2784 const char *tag,
const char *field,
const char *value, gboolean search_matches)
2786 int match_found = 0;
2789 CRM_CHECK(children != NULL,
return FALSE);
2791 if (tag != NULL && !pcmk__str_eq(tag, crm_element_name(root),
pcmk__str_casei)) {
2796 if (*children == NULL) {
2803 if (search_matches || match_found == 0) {
2804 xmlNode *child = NULL;
2806 for (child = pcmk__xml_first_child(root); child != NULL;
2807 child = pcmk__xml_next(child)) {
2808 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
2818 gboolean can_delete = FALSE;
2819 xmlNode *child_of_child = NULL;
2821 const char *up_id = NULL;
2822 const char *child_id = NULL;
2823 const char *right_val = NULL;
2826 CRM_CHECK(update != NULL,
return FALSE);
2829 child_id =
ID(child);
2831 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
2834 if (!pcmk__str_eq(crm_element_name(update), crm_element_name(child),
pcmk__str_casei)) {
2837 if (can_delete && delete_only) {
2838 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2840 const char *p_name = (
const char *) a->name;
2841 const char *p_value = pcmk__xml_attr_value(a);
2850 if (can_delete &&
parent != NULL) {
2852 if (delete_only || update == NULL) {
2857 xmlDoc *doc = tmp->doc;
2858 xmlNode *old = NULL;
2861 old = xmlReplaceNode(child, tmp);
2869 xmlDocSetRootElement(doc, old);
2875 }
else if (can_delete) {
2880 child_of_child = pcmk__xml_first_child(child);
2881 while (child_of_child) {
2882 xmlNode *next = pcmk__xml_next(child_of_child);
2888 child_of_child = NULL;
2890 child_of_child = next;
2900 xmlNode *child = NULL;
2901 GSList *nvpairs = NULL;
2903 const char *
name = NULL;
2916 for (child = pcmk__xml_first_child(
input); child != NULL;
2917 child = pcmk__xml_next(child)) {
2932 xmlNode *match = NULL;
2934 for (match = pcmk__xe_first_child(
parent); match != NULL;
2935 match = pcmk__xe_next(match)) {
2958 xmlNode *match = pcmk__xe_next(sibling);
2959 const char *
name = crm_element_name(sibling);
2961 while (match != NULL) {
2962 if (!strcmp(crm_element_name(match),
name)) {
2965 match = pcmk__xe_next(match);
2973 static bool init =
true;
2982 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
2985 xmlDeregisterNodeDefault(free_private_data);
2986 xmlRegisterNodeDefault(new_private_data);
2999 #define XPATH_MAX 512 3004 const char *tag = NULL;
3005 const char *ref = NULL;
3011 }
else if (top == NULL) {
3015 tag = crm_element_name(
result);
3023 char *nodePath = (
char *)xmlGetNodePath(top);
3025 crm_err(
"No match for %s found in %s: Invalid configuration",
3026 xpath_string, pcmk__s(nodePath,
"unrecognizable path"));
3037 static const char *base = NULL;
3041 base = getenv(
"PCMK_schema_directory");
3043 if (pcmk__str_empty(base)) {
3057 crm_err(
"XML artefact family specified as %u not recognized", ns);
3077 crm_err(
"XML artefact family specified as %u not recognized", ns);
3088 const char *
name, *value;
3090 name = va_arg(pairs,
const char *);
3095 value = va_arg(pairs,
const char *);
3096 if (value != NULL) {
3106 va_start(pairs, node);
3113 int (*handler)(xmlNode *xml,
void *userdata),
3116 xmlNode *children = (xml? xml->children : NULL);
3120 for (xmlNode *node = children; node != NULL; node = node->next) {
3121 if (node->type == XML_ELEMENT_NODE &&
3123 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)
void pcmk__xml_log(int log_level, const char *file, const char *function, int line, const char *prefix, const xmlNode *data, int depth, int options)
char * crm_generate_uuid(void)
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)
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.
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,...)
#define pcmk__log_else(level, else_action)
void pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
xmlNode * stdin2xml(void)
#define XML_DOC_PRIVATE_MAGIC
#define CRM_LOG_ASSERT(expr)
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
unsigned int crm_trace_nonlog
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)
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)
#define PCMK__XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap)
Base for directing lib{xml2,xslt} log into standard libqb backend.
void log_data_element(int log_level, const char *file, const char *function, int line, const char *prefix, const xmlNode *data, int depth, int options)
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
#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)
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)
void xml_log_changes(uint8_t log_level, const char *function, xmlNode *xml)
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)
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Write XML to a file.
#define PCMK__BUFFER_SIZE
void copy_in_properties(xmlNode *target, xmlNode *src)
#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
#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
void pcmk__xml2text(xmlNodePtr data, int options, GString *buffer, int depth)
#define attr_matches(c, n, v)
void pcmk__xe_remove_matching_attrs(xmlNode *element, bool(*match)(xmlAttrPtr, void *), void *user_data)
const char * pcmk__epoch2str(const time_t *when)
#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)
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
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)