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) 48 #define CHUNK_SIZE 1024 53 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
65 #define buffer_print(buffer, max, offset, fmt, args...) do { \ 68 rc = snprintf((buffer) + (offset), (max) - (offset), fmt, ##args); \ 70 if(buffer && rc < 0) { \ 71 crm_perror(LOG_ERR, "snprintf failed at offset %d", offset); \ 72 (buffer)[(offset)] = 0; \ 74 } else if(rc >= ((max) - (offset))) { \ 76 (max) = QB_MAX(CHUNK_SIZE, (max) * 2); \ 77 tmp = pcmk__realloc((buffer), (max)); \ 87 insert_prefix(
int options,
char **buffer,
int *offset,
int *max,
int depth)
90 size_t spaces = 2 * depth;
92 if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
94 (*buffer) = pcmk__realloc((*buffer), (*max));
96 memset((*buffer) + (*offset),
' ', spaces);
102 set_parent_flag(xmlNode *xml,
long flag)
105 for(; xml; xml = xml->parent) {
120 if(xml && xml->doc && xml->doc->_private){
130 mark_xml_node_dirty(xmlNode *xml)
138 reset_xml_node_flags(xmlNode *xml)
140 xmlNode *cIter = NULL;
147 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
148 cIter = pcmk__xml_next(cIter)) {
149 reset_xml_node_flags(cIter);
157 xmlNode *cIter = NULL;
163 mark_xml_node_dirty(xml);
165 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
166 cIter = pcmk__xml_next(cIter)) {
175 xmlNode *
parent = a->parent;
181 mark_xml_node_dirty(
parent);
184 #define XML_PRIVATE_MAGIC (long) 0x81726354 188 free_deleted_object(
void *
data)
193 free(deleted_obj->
path);
222 free_private_data(xmlNode *node)
231 if (node->type != XML_DOCUMENT_NODE || node->name == NULL
232 || node->name[0] !=
' ') {
233 reset_xml_private_data(node->_private);
234 free(node->_private);
240 new_private_data(xmlNode *node)
245 case XML_ELEMENT_NODE:
246 case XML_DOCUMENT_NODE:
247 case XML_ATTRIBUTE_NODE:
248 case XML_COMMENT_NODE:
257 case XML_CDATA_SECTION_NODE:
261 crm_trace(
"Ignoring %p %d", node, node->type);
270 mark_xml_node_dirty(node);
278 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
281 if(acl_source == NULL) {
292 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
299 return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
317 xmlNode *cIter = NULL;
319 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
332 marked_as_deleted(xmlAttrPtr a,
void *user_data)
345 accept_attr_deletions(xmlNode *xml)
354 for (xmlNodePtr cIter = pcmk__xml_first_child(xml); cIter != NULL;
355 cIter = pcmk__xml_next(cIter)) {
356 accept_attr_deletions(cIter);
373 if (needle->type == XML_COMMENT_NODE) {
377 const char *
id =
ID(needle);
378 const char *attr = (
id == NULL)? NULL :
XML_ATTR_ID;
380 return pcmk__xe_match(haystack, crm_element_name(needle), attr,
id);
397 doc = xml->doc->_private;
402 for(gIter = doc->
deleted_objs; gIter; gIter = gIter->next) {
429 crm_trace(
"Accepting changes to %p", xml);
430 doc = xml->doc->_private;
431 top = xmlDocGetRootElement(xml->doc);
433 reset_xml_private_data(xml->doc->_private);
441 accept_attr_deletions(top);
447 xmlNode *a_child = NULL;
448 const char *
name =
"NULL";
451 name = crm_element_name(root);
454 if (search_path == NULL) {
459 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
460 a_child = pcmk__xml_next(a_child)) {
461 if (strcmp((
const char *)a_child->name, search_path) == 0) {
468 crm_warn(
"Could not find %s in %s.", search_path,
name);
469 }
else if (root != NULL) {
472 crm_trace(
"Could not find %s in <NULL>.", search_path);
478 #define attr_matches(c, n, v) pcmk__str_eq(crm_element_value((c), (n)), \ 496 const char *attr_n,
const char *attr_v)
499 CRM_CHECK(attr_n == NULL || attr_v != NULL,
return NULL);
501 for (xmlNode *child = pcmk__xml_first_child(
parent); child != NULL;
502 child = pcmk__xml_next(child)) {
503 if (pcmk__str_eq(node_name, (
const char *) (child->name),
505 && ((attr_n == NULL) ||
attr_matches(child, attr_n, attr_v))) {
509 crm_trace(
"XML child node <%s%s%s%s%s> not found in %s",
510 (node_name? node_name :
"(any)"),
512 (attr_n? attr_n :
""),
514 (attr_n? attr_v :
""),
515 crm_element_name(
parent));
523 crm_warn(
"No node to copy properties from");
525 }
else if (
target == NULL) {
526 crm_err(
"No node to copy properties into");
529 for (xmlAttrPtr a = pcmk__xe_first_attr(src); a != NULL; a = a->next) {
530 const char *p_name = (
const char *) a->name;
531 const char *p_value = pcmk__xml_attr_value(a);
544 xmlNode *child = NULL;
546 for (xmlAttrPtr a = pcmk__xe_first_attr(
target); a != NULL; a = a->next) {
547 const char *p_name = (
const char *) a->name;
548 const char *p_value = pcmk__xml_attr_value(a);
552 for (child = pcmk__xml_first_child(
target); child != NULL;
553 child = pcmk__xml_next(child)) {
566 const char *old_value = NULL;
568 if (value == NULL ||
name == NULL) {
574 if (old_value == NULL) {
578 }
else if (strstr(value,
name) != value) {
582 name_len = strlen(
name);
583 value_len = strlen(value);
584 if (value_len < (name_len + 2)
585 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
592 if (old_value != value) {
596 if (value[name_len + 1] !=
'+') {
597 const char *offset_s = value + (name_len + 2);
611 if (old_value == value) {
630 bool (*match)(xmlAttrPtr,
void *),
633 xmlAttrPtr next = NULL;
635 for (xmlAttrPtr a = pcmk__xe_first_attr(element); a != NULL; a = next) {
637 if ((match == NULL) || match(a, user_data)) {
639 crm_trace(
"ACLs prevent removal of attributes (%s and " 640 "possibly others) from %s element",
641 (
const char *) a->name, (
const char *) element->name);
667 xmlDocSetRootElement(doc, node);
668 xmlSetTreeDoc(node, doc);
676 xmlNode *child = NULL;
679 CRM_CHECK(src_node != NULL,
return NULL);
681 child = xmlDocCopyNode(src_node, doc, 1);
682 xmlAddChild(
parent, child);
699 xmlNode *node = NULL;
701 if (pcmk__str_empty(
name)) {
709 xmlDocSetRootElement(doc, node);
714 xmlAddChild(
parent, node);
726 xmlNodeSetContent(node, (
pcmkXmlStr) content);
734 const char *class_name,
const char *text)
738 if (class_name != NULL) {
762 free_xml_with_position(xmlNode * child,
int position)
766 xmlDoc *doc = child->doc;
770 top = xmlDocGetRootElement(doc);
773 if (doc != NULL && top == child) {
792 sizeof(buffer)) > 0) {
795 crm_trace(
"Deleting %s %p from %p", buffer, child, doc);
798 deleted_obj->
path = strdup(buffer);
802 if (child->type == XML_COMMENT_NODE) {
826 free_xml_with_position(child, -1);
833 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
835 xmlDocSetRootElement(doc, copy);
836 xmlSetTreeDoc(copy, doc);
841 log_xmllib_err(
void *ctx,
const char *fmt, ...)
846 log_xmllib_err(
void *ctx, const
char *fmt, ...)
849 static struct qb_log_callsite *xml_error_cs = NULL;
851 if (xml_error_cs == NULL) {
852 xml_error_cs = qb_log_callsite_get(
857 if (xml_error_cs && xml_error_cs->targets) {
859 crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__,
"xml library error",
861 "XML Error: ", fmt, ap);
872 xmlDocPtr output = NULL;
873 xmlParserCtxtPtr ctxt = NULL;
874 xmlErrorPtr last_error = NULL;
877 crm_err(
"Can't parse NULL input");
882 ctxt = xmlNewParserCtxt();
885 xmlCtxtResetLastError(ctxt);
886 xmlSetGenericErrorFunc(ctxt, log_xmllib_err);
890 xml = xmlDocGetRootElement(output);
892 last_error = xmlCtxtGetLastError(ctxt);
893 if (last_error && last_error->code != XML_ERR_OK) {
899 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
900 last_error->domain, last_error->level, last_error->code, last_error->message);
902 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
905 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
906 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(
input),
913 int len = strlen(
input);
925 xmlFreeParserCtxt(ctxt);
932 size_t data_length = 0;
933 size_t read_chars = 0;
935 char *xml_buffer = NULL;
936 xmlNode *xml_obj = NULL;
942 data_length += read_chars;
945 if (data_length == 0) {
946 crm_warn(
"No XML supplied on stdin");
951 xml_buffer[data_length] =
'\0';
960 decompress_file(
const char *filename)
964 size_t length = 0, read_len = 0;
965 BZFILE *bz_file = NULL;
966 FILE *
input = fopen(filename,
"r");
969 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
973 bz_file = BZ2_bzReadOpen(&rc,
input, 0, 0, NULL, 0);
975 crm_err(
"Could not prepare to read compressed %s: %s " 977 BZ2_bzReadClose(&rc, bz_file);
985 while (rc == BZ_OK) {
989 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
991 if (rc == BZ_OK || rc == BZ_STREAM_END) {
996 buffer[length] =
'\0';
998 if (rc != BZ_STREAM_END) {
999 crm_err(
"Could not read compressed %s: %s " 1005 BZ2_bzReadClose(&rc, bz_file);
1019 xmlNode *iter = xml->children;
1022 xmlNode *next = iter->next;
1024 switch (iter->type) {
1030 case XML_ELEMENT_NODE:
1047 xmlNode *xml = NULL;
1048 xmlDocPtr output = NULL;
1049 bool uncompressed =
true;
1050 xmlParserCtxtPtr ctxt = NULL;
1051 xmlErrorPtr last_error = NULL;
1054 ctxt = xmlNewParserCtxt();
1057 xmlCtxtResetLastError(ctxt);
1058 xmlSetGenericErrorFunc(ctxt, log_xmllib_err);
1066 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL,
1069 }
else if (uncompressed) {
1073 char *
input = decompress_file(filename);
1080 if (output && (xml = xmlDocGetRootElement(output))) {
1084 last_error = xmlCtxtGetLastError(ctxt);
1085 if (last_error && last_error->code != XML_ERR_OK) {
1091 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
1092 last_error->domain, last_error->level, last_error->code, last_error->message);
1094 if (last_error && last_error->code != XML_ERR_OK) {
1095 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
1102 xmlFreeParserCtxt(ctxt);
1120 now_str ? now_str :
"Could not determine current time");
1133 for (c =
id; *c; ++c) {
1158 va_start(ap, format);
1159 len = vasprintf(&
id, format, ap);
1181 write_xml_stream(xmlNode *xml_node,
const char *filename, FILE *stream,
1182 bool compress,
unsigned int *nbytes)
1185 char *buffer = NULL;
1197 unsigned int in = 0;
1198 BZFILE *bz_file = NULL;
1201 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
1203 crm_warn(
"Not compressing %s: could not prepare file stream: %s " 1206 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
1208 crm_warn(
"Not compressing %s: could not compress data: %s " 1209 CRM_XS " bzerror=%d errno=%d",
1215 BZ2_bzWriteClose(&rc, bz_file, 0, &in, nbytes);
1217 crm_warn(
"Not compressing %s: could not write compressed data: %s " 1218 CRM_XS " bzerror=%d errno=%d",
1222 crm_trace(
"Compressed XML for %s from %u bytes to %u",
1223 filename, in, *nbytes);
1230 rc = fprintf(stream,
"%s", buffer);
1235 *nbytes = (
unsigned int) rc;
1242 if (fflush(stream) != 0) {
1244 crm_perror(LOG_ERR,
"flushing %s", filename);
1248 if (fsync(fileno(stream)) < 0 && errno != EROFS && errno != EINVAL) {
1250 crm_perror(LOG_ERR,
"synchronizing %s", filename);
1255 crm_trace(
"Saved %d bytes to %s as XML", *nbytes, filename);
1272 write_xml_fd(xmlNode * xml_node,
const char *filename,
int fd, gboolean compress)
1274 FILE *stream = NULL;
1275 unsigned int nbytes = 0;
1278 CRM_CHECK(xml_node && (fd > 0),
return -EINVAL);
1279 stream = fdopen(fd,
"w");
1280 if (stream == NULL) {
1283 rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
1287 return (
int) nbytes;
1302 FILE *stream = NULL;
1303 unsigned int nbytes = 0;
1306 CRM_CHECK(xml_node && filename,
return -EINVAL);
1307 stream = fopen(filename,
"w");
1308 if (stream == NULL) {
1311 rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
1315 return (
int) nbytes;
1320 replace_text(
char *text,
int start,
size_t *length,
const char *replace)
1322 size_t offset = strlen(replace) - 1;
1325 text = pcmk__realloc(text, *length);
1327 for (
size_t lpc = (*length) - 1; lpc > (start + offset); lpc--) {
1328 text[lpc] = text[lpc - offset];
1331 memcpy(text + start, replace, offset + 1);
1369 length = 1 + strlen(text);
1370 copy = strdup(text);
1372 for (
size_t index = 0; index < length; index++) {
1373 if(copy[index] & 0x80 && copy[index+1] & 0x80){
1377 switch (copy[index]) {
1381 copy = replace_text(copy, index, &length,
"<");
1384 copy = replace_text(copy, index, &length,
">");
1387 copy = replace_text(copy, index, &length,
""");
1390 copy = replace_text(copy, index, &length,
"'");
1393 copy = replace_text(copy, index, &length,
"&");
1397 copy = replace_text(copy, index, &length,
" ");
1400 copy = replace_text(copy, index, &length,
"\\n");
1403 copy = replace_text(copy, index, &length,
"\\r");
1407 if(copy[index] <
' ' || copy[index] >
'~') {
1410 copy = replace_text(copy, index, &length, replace);
1419 dump_xml_attr(xmlAttrPtr attr,
int options,
char **buffer,
int *offset,
int *max)
1421 char *p_value = NULL;
1422 const char *p_name = NULL;
1426 if (attr == NULL || attr->children == NULL) {
1435 p_name = (
const char *)attr->name;
1444 pcmk__xe_log(
int log_level,
const char *file,
const char *
function,
int line,
1445 const char *prefix, xmlNode *
data,
int depth,
int options)
1449 const char *
name = NULL;
1450 const char *hidden = NULL;
1452 xmlNode *child = NULL;
1461 char *buffer = NULL;
1463 insert_prefix(options, &buffer, &offset, &max, depth);
1465 if (
data->type == XML_COMMENT_NODE) {
1472 for (xmlAttrPtr a = pcmk__xe_first_attr(
data); a != NULL;
1476 const char *p_name = (
const char *) a->name;
1477 const char *p_value = pcmk__xml_attr_value(a);
1478 char *p_copy = NULL;
1482 }
else if (pcmk_any_flags_set(options,
1488 }
else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
1489 p_copy = strdup(
"*****");
1511 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
1515 if(
data->type == XML_COMMENT_NODE) {
1525 for (child = pcmk__xml_first_child(
data); child != NULL;
1526 child = pcmk__xml_next(child)) {
1527 pcmk__xe_log(log_level, file,
function, line, prefix, child,
1534 char *buffer = NULL;
1536 insert_prefix(options, &buffer, &offset, &max, depth);
1539 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
1546 log_xml_changes(
int log_level,
const char *file,
const char *
function,
int line,
1547 const char *prefix, xmlNode *
data,
int depth,
int options)
1550 char *prefix_m = NULL;
1551 xmlNode *child = NULL;
1559 prefix_m = strdup(prefix);
1569 char *spaces = calloc(80, 1);
1570 int s_count = 0, s_max = 80;
1571 char *prefix_del = NULL;
1572 char *prefix_moved = NULL;
1573 const char *
flags = prefix;
1575 insert_prefix(options, &spaces, &s_count, &s_max, depth);
1576 prefix_del = strdup(prefix);
1577 prefix_del[0] =
'-';
1578 prefix_del[1] =
'-';
1579 prefix_moved = strdup(prefix);
1580 prefix_moved[1] =
'~';
1583 flags = prefix_moved;
1591 for (xmlAttrPtr a = pcmk__xe_first_attr(
data); a != NULL; a = a->next) {
1592 const char *aname = (
const char*) a->name;
1599 "%s %s @%s=%s",
flags, spaces, aname, value);
1611 flags = prefix_moved;
1617 "%s %s @%s=%s",
flags, spaces, aname, value);
1624 for (child = pcmk__xml_first_child(
data); child != NULL;
1625 child = pcmk__xml_next(child)) {
1626 log_xml_changes(log_level, file,
function, line, prefix, child,
1627 depth + 1, options);
1634 for (child = pcmk__xml_first_child(
data); child != NULL;
1635 child = pcmk__xml_next(child)) {
1636 log_xml_changes(log_level, file,
function, line, prefix, child,
1637 depth + 1, options);
1647 const char *prefix, xmlNode *
data,
int depth,
int options)
1649 xmlNode *a_child = NULL;
1651 char *prefix_m = NULL;
1657 if (prefix == NULL) {
1664 "No data to dump as XML");
1669 log_xml_changes(log_level, file,
function, line, prefix,
data, depth,
1678 prefix_m = strdup(prefix);
1685 prefix_m = strdup(prefix);
1694 for (a_child = pcmk__xml_first_child(
data); a_child != NULL;
1695 a_child = pcmk__xml_next(a_child)) {
1696 log_data_element(log_level, file,
function, line, prefix, a_child, depth + 1, options);
1707 dump_filtered_xml(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max)
1709 for (xmlAttrPtr a = pcmk__xe_first_attr(
data); a != NULL; a = a->next) {
1711 dump_xml_attr(a, options, buffer, offset, max);
1717 dump_xml_element(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
1719 const char *
name = NULL;
1730 if (*buffer == NULL) {
1738 insert_prefix(options, buffer, offset, max, depth);
1742 dump_filtered_xml(
data, options, buffer, offset, max);
1745 for (xmlAttrPtr a = pcmk__xe_first_attr(
data); a != NULL; a = a->next) {
1746 dump_xml_attr(a, options, buffer, offset, max);
1750 if (
data->children == NULL) {
1761 if (
data->children) {
1762 xmlNode *xChild = NULL;
1763 for(xChild =
data->children; xChild != NULL; xChild = xChild->next) {
1767 insert_prefix(options, buffer, offset, max, depth);
1777 dump_xml_text(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
1788 if (*buffer == NULL) {
1793 insert_prefix(options, buffer, offset, max, depth);
1803 dump_xml_cdata(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
1814 if (*buffer == NULL) {
1819 insert_prefix(options, buffer, offset, max, depth);
1831 dump_xml_comment(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
1842 if (*buffer == NULL) {
1847 insert_prefix(options, buffer, offset, max, depth);
1858 #define PCMK__XMLDUMP_STATS 0 1873 int *max,
int depth)
1890 #if (PCMK__XMLDUMP_STATS - 0) 1891 time_t next,
new = time(NULL);
1894 xmlOutputBuffer *xml_buffer;
1900 xml_buffer = xmlAllocOutputBuffer(NULL);
1913 xmlNodeDumpOutput(xml_buffer, doc,
data, 0,
1916 (void) xmlOutputBufferWrite(xml_buffer,
sizeof(
"\n") - 1,
"\n");
1917 if (xml_buffer->buffer != NULL) {
1919 (
char *) xmlBufContent(xml_buffer->buffer));
1922 #if (PCMK__XMLDUMP_STATS - 0) 1924 if ((now + 1) < next) {
1926 crm_err(
"xmlNodeDump() -> %dbytes took %ds", *max, next - now);
1931 (void) xmlOutputBufferClose(xml_buffer);
1935 switch(
data->type) {
1936 case XML_ELEMENT_NODE:
1938 dump_xml_element(
data, options, buffer, offset, max, depth);
1943 dump_xml_text(
data, options, buffer, offset, max, depth);
1946 case XML_COMMENT_NODE:
1947 dump_xml_comment(
data, options, buffer, offset, max, depth);
1949 case XML_CDATA_SECTION_NODE:
1950 dump_xml_cdata(
data, options, buffer, offset, max, depth);
1997 char *buffer = NULL;
1998 int offset = 0, max = 0;
2002 &buffer, &offset, &max, 0);
2009 char *buffer = NULL;
2010 int offset = 0, max = 0;
2020 char *buffer = NULL;
2021 int offset = 0, max = 0;
2030 if (xml_root != NULL && xml_root->children != NULL) {
2060 if (filename == NULL) {
2068 crm_info(
"Saving %s to %s", desc, filename);
2083 for (xmlAttr *attr = pcmk__xe_first_attr(xml); attr; attr = attr->next) {
2098 mark_attr_deleted(xmlNode *new_xml,
const char *element,
const char *attr_name,
2099 const char *old_value)
2102 xmlAttr *attr = NULL;
2118 crm_trace(
"XML attribute %s=%s was removed from %s",
2119 attr_name, old_value, element);
2127 mark_attr_changed(xmlNode *new_xml,
const char *element,
const char *attr_name,
2128 const char *old_value)
2132 crm_trace(
"XML attribute %s was changed from '%s' to '%s' in %s",
2133 attr_name, old_value, vcopy, element);
2148 mark_attr_moved(xmlNode *new_xml,
const char *element, xmlAttr *old_attr,
2149 xmlAttr *new_attr,
int p_old,
int p_new)
2153 crm_trace(
"XML attribute %s moved from position %d to %d in %s",
2154 old_attr->name, p_old, p_new, element);
2157 mark_xml_node_dirty(new_xml);
2162 p = (p_old > p_new)? old_attr->_private : new_attr->_private;
2171 xml_diff_old_attrs(xmlNode *old_xml, xmlNode *new_xml)
2173 xmlAttr *attr_iter = pcmk__xe_first_attr(old_xml);
2175 while (attr_iter != NULL) {
2176 xmlAttr *old_attr = attr_iter;
2177 xmlAttr *new_attr = xmlHasProp(new_xml, attr_iter->name);
2178 const char *
name = (
const char *) attr_iter->name;
2181 attr_iter = attr_iter->next;
2182 if (new_attr == NULL) {
2183 mark_attr_deleted(new_xml, (
const char *) old_xml->name,
name,
2197 if (strcmp(new_value, old_value) != 0) {
2198 mark_attr_changed(new_xml, (
const char *) old_xml->name,
name,
2201 }
else if ((old_pos != new_pos)
2203 mark_attr_moved(new_xml, (
const char *) old_xml->name,
2204 old_attr, new_attr, old_pos, new_pos);
2215 mark_created_attrs(xmlNode *new_xml)
2217 xmlAttr *attr_iter = pcmk__xe_first_attr(new_xml);
2219 while (attr_iter != NULL) {
2220 xmlAttr *new_attr = attr_iter;
2223 attr_iter = attr_iter->next;
2225 const char *attr_name = (
const char *) new_attr->name;
2227 crm_trace(
"Created new attribute %s=%s in %s",
2238 xmlUnsetProp(new_xml, new_attr->name);
2249 xml_diff_attrs(xmlNode *old_xml, xmlNode *new_xml)
2252 xml_diff_old_attrs(old_xml, new_xml);
2253 mark_created_attrs(new_xml);
2266 mark_child_deleted(xmlNode *old_child, xmlNode *new_parent)
2272 reset_xml_node_flags(candidate);
2278 free_xml_with_position(candidate,
2288 mark_child_moved(xmlNode *old_child, xmlNode *new_parent, xmlNode *new_child,
2289 int p_old,
int p_new)
2293 crm_trace(
"Child element %s with id='%s' moved from position %d to %d under %s",
2294 new_child->name, (
ID(new_child)?
ID(new_child) :
"<no id>"),
2295 p_old, p_new, new_parent->name);
2296 mark_xml_node_dirty(new_parent);
2299 if (p_old > p_new) {
2300 p = old_child->_private;
2302 p = new_child->_private;
2309 mark_xml_changes(xmlNode *old_xml, xmlNode *new_xml,
bool check_top)
2311 xmlNode *cIter = NULL;
2315 if (old_xml == NULL) {
2321 p = new_xml->_private;
2330 xml_diff_attrs(old_xml, new_xml);
2333 for (cIter = pcmk__xml_first_child(old_xml); cIter != NULL; ) {
2334 xmlNode *old_child = cIter;
2337 cIter = pcmk__xml_next(cIter);
2339 mark_xml_changes(old_child, new_child, TRUE);
2342 mark_child_deleted(old_child, new_xml);
2347 for (cIter = pcmk__xml_first_child(new_xml); cIter != NULL; ) {
2348 xmlNode *new_child = cIter;
2351 cIter = pcmk__xml_next(cIter);
2352 if(old_child == NULL) {
2354 p = new_child->_private;
2356 mark_xml_changes(old_child, new_child, TRUE);
2363 if(p_old != p_new) {
2364 mark_child_moved(old_child, new_xml, new_child, p_old, p_new);
2388 mark_xml_changes(old_xml, new_xml, FALSE);
2394 xmlNode *cIter = NULL;
2395 gboolean can_prune = TRUE;
2396 const char *
name = crm_element_name(xml_node);
2403 for (xmlAttrPtr a = pcmk__xe_first_attr(xml_node); a != NULL; a = a->next) {
2404 const char *p_name = (
const char *) a->name;
2412 cIter = pcmk__xml_first_child(xml_node);
2414 xmlNode *child = cIter;
2416 cIter = pcmk__xml_next(cIter);
2437 xmlNode *a_child = NULL;
2440 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
2442 for (a_child = pcmk__xml_first_child(root); a_child != NULL;
2443 a_child = pcmk__xml_next(a_child)) {
2448 if (offset < search_offset) {
2451 }
else if (offset > search_offset) {
2460 if (a_child->type == XML_COMMENT_NODE
2461 && pcmk__str_eq((
const char *)a_child->content, (
const char *)search_comment->content,
pcmk__str_casei)) {
2487 CRM_CHECK(update->type == XML_COMMENT_NODE,
return);
2496 }
else if (!pcmk__str_eq((
const char *)
target->content, (
const char *)update->content,
pcmk__str_casei)) {
2497 xmlFree(
target->content);
2498 target->content = xmlStrdup(update->content);
2518 xmlNode *a_child = NULL;
2519 const char *object_name = NULL,
2520 *object_href = NULL,
2521 *object_href_val = NULL;
2523 #if XML_PARSER_DEBUG 2530 if (update->type == XML_COMMENT_NODE) {
2535 object_name = crm_element_name(update);
2536 object_href_val =
ID(update);
2537 if (object_href_val != NULL) {
2549 object_href, object_href_val);
2555 #if XML_PARSER_DEBUG 2557 object_href ?
" " :
"",
2558 object_href ? object_href :
"",
2559 object_href ?
"=" :
"",
2560 object_href ? object_href_val :
"");
2564 object_href ?
" " :
"",
2565 object_href ? object_href :
"",
2566 object_href ?
"=" :
"",
2567 object_href ? object_href_val :
"");
2571 CRM_CHECK(pcmk__str_eq(crm_element_name(
target), crm_element_name(update),
2575 if (as_diff == FALSE) {
2581 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2583 const char *p_value = pcmk__xml_attr_value(a);
2586 xmlUnsetProp(
target, a->name);
2591 for (a_child = pcmk__xml_first_child(update); a_child != NULL;
2592 a_child = pcmk__xml_next(a_child)) {
2593 #if XML_PARSER_DEBUG 2595 object_href ?
" " :
"",
2596 object_href ? object_href :
"",
2597 object_href ?
"=" :
"",
2598 object_href ? object_href_val :
"");
2603 #if XML_PARSER_DEBUG 2605 object_href ?
" " :
"",
2606 object_href ? object_href :
"",
2607 object_href ?
"=" :
"",
2608 object_href ? object_href_val :
"");
2615 gboolean can_update = TRUE;
2616 xmlNode *child_of_child = NULL;
2619 CRM_CHECK(to_update != NULL,
return FALSE);
2621 if (!pcmk__str_eq(crm_element_name(to_update), crm_element_name(child),
pcmk__str_none)) {
2627 }
else if (can_update) {
2628 #if XML_PARSER_DEBUG 2634 for (child_of_child = pcmk__xml_first_child(child); child_of_child != NULL;
2635 child_of_child = pcmk__xml_next(child_of_child)) {
2648 const char *tag,
const char *field,
const char *value, gboolean search_matches)
2650 int match_found = 0;
2653 CRM_CHECK(children != NULL,
return FALSE);
2655 if (tag != NULL && !pcmk__str_eq(tag, crm_element_name(root),
pcmk__str_casei)) {
2660 if (*children == NULL) {
2667 if (search_matches || match_found == 0) {
2668 xmlNode *child = NULL;
2670 for (child = pcmk__xml_first_child(root); child != NULL;
2671 child = pcmk__xml_next(child)) {
2672 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
2682 gboolean can_delete = FALSE;
2683 xmlNode *child_of_child = NULL;
2685 const char *up_id = NULL;
2686 const char *child_id = NULL;
2687 const char *right_val = NULL;
2690 CRM_CHECK(update != NULL,
return FALSE);
2693 child_id =
ID(child);
2695 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
2698 if (!pcmk__str_eq(crm_element_name(update), crm_element_name(child),
pcmk__str_casei)) {
2701 if (can_delete && delete_only) {
2702 for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
2704 const char *p_name = (
const char *) a->name;
2705 const char *p_value = pcmk__xml_attr_value(a);
2714 if (can_delete &&
parent != NULL) {
2716 if (delete_only || update == NULL) {
2721 xmlDoc *doc = tmp->doc;
2722 xmlNode *old = NULL;
2725 old = xmlReplaceNode(child, tmp);
2733 xmlDocSetRootElement(doc, old);
2739 }
else if (can_delete) {
2744 child_of_child = pcmk__xml_first_child(child);
2745 while (child_of_child) {
2746 xmlNode *next = pcmk__xml_next(child_of_child);
2752 child_of_child = NULL;
2754 child_of_child = next;
2764 xmlNode *child = NULL;
2765 GSList *nvpairs = NULL;
2767 const char *
name = NULL;
2780 for (child = pcmk__xml_first_child(
input); child != NULL;
2781 child = pcmk__xml_next(child)) {
2796 xmlNode *match = NULL;
2798 for (match = pcmk__xe_first_child(
parent); match != NULL;
2799 match = pcmk__xe_next(match)) {
2822 xmlNode *match = pcmk__xe_next(sibling);
2823 const char *
name = crm_element_name(sibling);
2825 while (match != NULL) {
2826 if (!strcmp(crm_element_name(match),
name)) {
2829 match = pcmk__xe_next(match);
2837 static bool init =
true;
2846 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
2849 xmlDeregisterNodeDefault(free_private_data);
2850 xmlRegisterNodeDefault(new_private_data);
2859 crm_info(
"Cleaning up memory from libxml2");
2864 #define XPATH_MAX 512 2869 const char *tag = NULL;
2870 const char *ref = NULL;
2876 }
else if (top == NULL) {
2880 tag = crm_element_name(
result);
2888 char *nodePath = (
char *)xmlGetNodePath(top);
2890 crm_err(
"No match for %s found in %s: Invalid configuration", xpath_string,
2908 static const char *base = NULL;
2912 base = getenv(
"PCMK_schema_directory");
2914 if (pcmk__str_empty(base)) {
2928 crm_err(
"XML artefact family specified as %u not recognized", ns);
2948 crm_err(
"XML artefact family specified as %u not recognized", ns);
2959 const char *
name, *value;
2961 name = va_arg(pairs,
const char *);
2966 value = va_arg(pairs,
const char *);
2967 if (value != NULL) {
2977 va_start(pairs, node);
#define CRM_CHECK(expr, failure_action)
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
void pcmk__xml2text(xmlNode *data, int options, char **buffer, int *offset, int *max, int depth)
const char * bz2_strerror(int rc)
char * crm_generate_uuid(void)
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
void log_data_element(int log_level, const char *file, const char *function, int line, const char *prefix, xmlNode *data, int depth, int options)
void pcmk__free_acls(GList *acls)
int pcmk_rc2legacy(int rc)
xmlNode * pcmk__xml_match(xmlNode *haystack, xmlNode *needle, bool exact)
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 int pcmk__element_xpath(const char *prefix, xmlNode *xml, char *buffer, int offset, size_t buffer_size)
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)
void crm_xml_init(void)
Initialize the CRM XML subsystem.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
#define buffer_print(buffer, max, offset, fmt, args...)
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__xe_log(int log_level, const char *file, const char *function, int line, const char *prefix, xmlNode *data, int depth, int options)
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 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.
GSList * pcmk_xml_attrs2nvpairs(xmlNode *xml)
Create a list of name/value pairs from an XML node's attributes.
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)
void pcmk__xml_update(xmlNode *parent, xmlNode *target, xmlNode *update, bool as_diff)
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)
int pcmk__xml_position(xmlNode *xml, enum xml_private_flags ignore_if_set)
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 free_xml(xmlNode *child)
#define crm_trace(fmt, args...)
#define XML_PRIVATE_MAGIC
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)
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.
void pcmk__buffer_add_char(char **buffer, int *offset, int *max, char c)
#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 char * pcmk__epoch2str(time_t *when)
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)
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)
xmlNode * pcmk__xe_match(xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
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
const char * pcmk__get_tmpdir(void)
#define XML_ACL_TAG_ROLE_REFv1
void pcmk__mark_xml_created(xmlNode *xml)
void pcmk__apply_acl(xmlNode *xml)
xmlNode * pcmk__xc_match(xmlNode *root, xmlNode *search_comment, bool exact)
xmlNode * find_xml_node(xmlNode *root, const char *search_path, gboolean must_find)
void xml_accept_changes(xmlNode *xml)
void crm_destroy_xml(gpointer data)
xmlNode destructor which can be used in glib collections
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)
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)
#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)
bool xml_tracking_changes(xmlNode *xml)
#define XML_ACL_TAG_ROLE_REF
#define attr_matches(c, n, v)
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
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)
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)
#define crm_info(fmt, args...)
bool pcmk__ends_with_ext(const char *s, const char *match)
gboolean can_prune_leaf(xmlNode *xml_node)
bool xml_document_dirty(xmlNode *xml)