13 #include <sys/types.h>    21 #include <libxml/parser.h>    22 #include <libxml/tree.h>    23 #include <libxml/xmlIO.h>      33 #ifndef XML_PARSER_DEBUG    34 #define XML_PARSER_DEBUG 0    47 #define PCMK__XML_PARSE_OPTS    (XML_PARSE_NOBLANKS | XML_PARSE_RECOVER)    49 #define CHUNK_SIZE 1024    54     if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
    66 #define buffer_print(buffer, max, offset, fmt, args...) do {            \    69             rc = snprintf((buffer) + (offset), (max) - (offset), fmt, ##args); \    71         if(buffer && rc < 0) {                                          \    72             crm_perror(LOG_ERR, "snprintf failed at offset %d", offset); \    73             (buffer)[(offset)] = 0;                                     \    75         } else if(rc >= ((max) - (offset))) {                           \    77             (max) = QB_MAX(CHUNK_SIZE, (max) * 2);                      \    78             tmp = pcmk__realloc((buffer), (max));                       \    88 insert_prefix(
int options, 
char **buffer, 
int *offset, 
int *max, 
int depth)
    91         size_t spaces = 2 * depth;
    93         if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
    95             (*buffer) = pcmk__realloc((*buffer), (*max));
    97         memset((*buffer) + (*offset), 
' ', spaces);
   103 set_parent_flag(xmlNode *xml, 
long flag) 
   106     for(; xml; xml = xml->parent) {
   121     if(xml && xml->doc && xml->doc->_private){
   131 mark_xml_node_dirty(xmlNode *xml)
   139 reset_xml_node_flags(xmlNode *xml)
   141     xmlNode *cIter = NULL;
   148     for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
   149          cIter = pcmk__xml_next(cIter)) {
   150         reset_xml_node_flags(cIter);
   158     xmlNode *cIter = NULL;
   164             mark_xml_node_dirty(xml);
   166         for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
   167              cIter = pcmk__xml_next(cIter)) {
   176     xmlNode *parent = a->parent;
   182     mark_xml_node_dirty(parent);
   185 #define XML_PRIVATE_MAGIC (long) 0x81726354   189 free_deleted_object(
void *
data)
   194         free(deleted_obj->
path);
   223 free_private_data(xmlNode *node)
   232     if (node->type != XML_DOCUMENT_NODE || node->name == NULL
   233             || node->name[0] != 
' ') {
   234         reset_xml_private_data(node->_private);
   235         free(node->_private);
   241 new_private_data(xmlNode *node)
   246         case XML_ELEMENT_NODE:
   247         case XML_DOCUMENT_NODE:
   248         case XML_ATTRIBUTE_NODE:
   249         case XML_COMMENT_NODE:
   258         case XML_CDATA_SECTION_NODE:
   262             crm_trace(
"Ignoring %p %d", node, node->type);
   271         mark_xml_node_dirty(node);
   279     crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
   282         if(acl_source == NULL) {
   293     return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
   300     return (xml != NULL) && (xml->doc != NULL) && (xml->doc->_private != NULL)
   318     xmlNode *cIter = NULL;
   320     for(cIter = xml; cIter->prev; cIter = cIter->prev) {
   333 accept_attr_deletions(xmlNode *xml)
   335     xmlNode *cIter = NULL;
   336     xmlAttr *pIter = NULL;
   340     pIter = pcmk__first_xml_attr(xml);
   342     while (pIter != NULL) {
   343         const xmlChar *
name = pIter->name;
   356     for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
   357          cIter = pcmk__xml_next(cIter)) {
   358         accept_attr_deletions(cIter);
   375     if (needle->type == XML_COMMENT_NODE) {
   379         const char *
id = 
ID(needle);
   380         const char *attr = (
id == NULL)? NULL : 
XML_ATTR_ID;
   382         return pcmk__xe_match(haystack, crm_element_name(needle), attr, 
id);
   399     doc = xml->doc->_private;
   404     for(gIter = doc->
deleted_objs; gIter; gIter = gIter->next) {
   431     crm_trace(
"Accepting changes to %p", xml);
   432     doc = xml->doc->_private;
   433     top = xmlDocGetRootElement(xml->doc);
   435     reset_xml_private_data(xml->doc->_private);
   443     accept_attr_deletions(top);
   449     xmlNode *a_child = NULL;
   450     const char *
name = 
"NULL";
   453         name = crm_element_name(root);
   456     if (search_path == NULL) {
   461     for (a_child = pcmk__xml_first_child(root); a_child != NULL;
   462          a_child = pcmk__xml_next(a_child)) {
   463         if (strcmp((
const char *)a_child->name, search_path) == 0) {
   470         crm_warn(
"Could not find %s in %s.", search_path, 
name);
   471     } 
else if (root != NULL) {
   474         crm_trace(
"Could not find %s in <NULL>.", search_path);
   480 #define attr_matches(c, n, v) pcmk__str_eq(crm_element_value((c), (n)), \   498                const char *attr_n, 
const char *attr_v)
   501     CRM_CHECK(attr_n == NULL || attr_v != NULL, 
return NULL);
   503     for (xmlNode *child = pcmk__xml_first_child(parent); child != NULL;
   504          child = pcmk__xml_next(child)) {
   505         if (pcmk__str_eq(node_name, (
const char *) (child->name),
   507             && ((attr_n == NULL) || 
attr_matches(child, attr_n, attr_v))) {
   511     crm_trace(
"XML child node <%s%s%s%s%s> not found in %s",
   512               (node_name? node_name : 
"(any)"),
   514               (attr_n? attr_n : 
""),
   516               (attr_n? attr_v : 
""),
   517               crm_element_name(parent));
   525         crm_warn(
"No node to copy properties from");
   527     } 
else if (
target == NULL) {
   528         crm_err(
"No node to copy properties into");
   531         xmlAttrPtr pIter = NULL;
   533         for (pIter = pcmk__first_xml_attr(src); pIter != NULL; pIter = pIter->next) {
   534             const char *p_name = (
const char *)pIter->name;
   535             const char *p_value = pcmk__xml_attr_value(pIter);
   548     xmlNode *child = NULL;
   549     xmlAttrPtr pIter = NULL;
   551     for (pIter = pcmk__first_xml_attr(
target); pIter != NULL; pIter = pIter->next) {
   552         const char *p_name = (
const char *)pIter->name;
   553         const char *p_value = pcmk__xml_attr_value(pIter);
   557     for (child = pcmk__xml_first_child(
target); child != NULL;
   558          child = pcmk__xml_next(child)) {
   571     const char *old_value = NULL;
   573     if (value == NULL || 
name == NULL) {
   579     if (old_value == NULL) {
   583     } 
else if (strstr(value, 
name) != value) {
   587     name_len = strlen(
name);
   588     value_len = strlen(value);
   589     if (value_len < (name_len + 2)
   590         || value[name_len] != 
'+' || (value[name_len + 1] != 
'+' && value[name_len + 1] != 
'=')) {
   597     if (old_value != value) {
   601     if (value[name_len + 1] != 
'+') {
   602         const char *offset_s = value + (name_len + 2);
   616     if (old_value == value) {
   634         xmlDocSetRootElement(doc, node);
   635         xmlSetTreeDoc(node, doc);
   643     xmlNode *child = NULL;
   646     CRM_CHECK(src_node != NULL, 
return NULL);
   648     child = xmlDocCopyNode(src_node, doc, 1);
   649     xmlAddChild(parent, child);
   666     xmlNode *node = NULL;
   668     if (pcmk__str_empty(
name)) {
   673     if (parent == NULL) {
   676         xmlDocSetRootElement(doc, node);
   681         xmlAddChild(parent, node);
   693         xmlNodeSetContent(node, (
pcmkXmlStr) content);
   701                       const char *class_name, 
const char *text)
   705     if (class_name != NULL) {
   729 free_xml_with_position(xmlNode * child, 
int position)
   733         xmlDoc *doc = child->doc;
   737             top = xmlDocGetRootElement(doc);
   740         if (doc != NULL && top == child) {
   759                                         sizeof(buffer)) > 0) {
   762                     crm_trace(
"Deleting %s %p from %p", buffer, child, doc);
   765                     deleted_obj->
path = strdup(buffer);
   769                     if (child->type == XML_COMMENT_NODE) {
   792     free_xml_with_position(child, -1);
   799     xmlNode *copy = xmlDocCopyNode(src, doc, 1);
   801     xmlDocSetRootElement(doc, copy);
   802     xmlSetTreeDoc(copy, doc);
   807 log_xmllib_err(
void *ctx, 
const char *fmt, ...)
   812 log_xmllib_err(
void *ctx, const 
char *fmt, ...)
   815     static struct qb_log_callsite *xml_error_cs = NULL;
   817     if (xml_error_cs == NULL) {
   818         xml_error_cs = qb_log_callsite_get(
   823     if (xml_error_cs && xml_error_cs->targets) {
   825                            crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, 
"xml library error",
   827                            "XML Error: ", fmt, ap);
   838     xmlDocPtr output = NULL;
   839     xmlParserCtxtPtr ctxt = NULL;
   840     xmlErrorPtr last_error = NULL;
   843         crm_err(
"Can't parse NULL input");
   848     ctxt = xmlNewParserCtxt();
   851     xmlCtxtResetLastError(ctxt);
   852     xmlSetGenericErrorFunc(ctxt, log_xmllib_err);
   853     output = xmlCtxtReadDoc(ctxt, (
pcmkXmlStr) input, NULL, NULL,
   856         xml = xmlDocGetRootElement(output);
   858     last_error = xmlCtxtGetLastError(ctxt);
   859     if (last_error && last_error->code != XML_ERR_OK) {
   865         crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
   866                  last_error->domain, last_error->level, last_error->code, last_error->message);
   868         if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
   871         } 
else if (last_error->code != XML_ERR_DOCUMENT_END) {
   872             crm_err(
"Couldn't%s parse %d chars: %s", xml ? 
" fully" : 
"", (
int)strlen(input),
   879             int len = strlen(input);
   883                 crm_warn(
"Parse error[+%.3d]: %.80s", lpc, input+lpc);
   891     xmlFreeParserCtxt(ctxt);
   898     size_t data_length = 0;
   899     size_t read_chars = 0;
   901     char *xml_buffer = NULL;
   902     xmlNode *xml_obj = NULL;
   908         data_length += read_chars;
   911     if (data_length == 0) {
   912         crm_warn(
"No XML supplied on stdin");
   917     xml_buffer[data_length] = 
'\0';
   926 decompress_file(
const char *filename)
   932     size_t length = 0, read_len = 0;
   934     BZFILE *bz_file = NULL;
   935     FILE *input = fopen(filename, 
"r");
   938         crm_perror(LOG_ERR, 
"Could not open %s for reading", filename);
   942     bz_file = BZ2_bzReadOpen(&
rc, input, 0, 0, NULL, 0);
   944         crm_err(
"Could not prepare to read compressed %s: %s "   946         BZ2_bzReadClose(&
rc, bz_file);
   953     while (
rc == BZ_OK) {
   957         crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, 
rc);
   959         if (
rc == BZ_OK || 
rc == BZ_STREAM_END) {
   964     buffer[length] = 
'\0';
   966     if (
rc != BZ_STREAM_END) {
   967         crm_err(
"Could not read compressed %s: %s "   973     BZ2_bzReadClose(&
rc, bz_file);
   977     crm_err(
"Could not read compressed %s: not built with bzlib support",
   992     xmlNode *iter = xml->children;
   995         xmlNode *next = iter->next;
   997         switch (iter->type) {
  1003             case XML_ELEMENT_NODE:
  1020     xmlNode *xml = NULL;
  1021     xmlDocPtr output = NULL;
  1022     gboolean uncompressed = TRUE;
  1023     xmlParserCtxtPtr ctxt = NULL;
  1024     xmlErrorPtr last_error = NULL;
  1027     ctxt = xmlNewParserCtxt();
  1030     xmlCtxtResetLastError(ctxt);
  1031     xmlSetGenericErrorFunc(ctxt, log_xmllib_err);
  1037     if (filename == NULL) {
  1039         output = xmlCtxtReadFd(ctxt, STDIN_FILENO, 
"unknown.xml", NULL,
  1042     } 
else if (uncompressed) {
  1046         char *input = decompress_file(filename);
  1048         output = xmlCtxtReadDoc(ctxt, (
pcmkXmlStr) input, NULL, NULL,
  1053     if (output && (xml = xmlDocGetRootElement(output))) {
  1057     last_error = xmlCtxtGetLastError(ctxt);
  1058     if (last_error && last_error->code != XML_ERR_OK) {
  1064         crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
  1065                 last_error->domain, last_error->level, last_error->code, last_error->message);
  1067         if (last_error && last_error->code != XML_ERR_OK) {
  1068             crm_err(
"Couldn't%s parse %s", xml ? 
" fully" : 
"", filename);
  1075     xmlFreeParserCtxt(ctxt);
  1093                        now_str ? now_str : 
"Could not determine current time");
  1106     for (c = 
id; *c; ++c) {
  1131     va_start(ap, format);
  1132     len = vasprintf(&
id, format, ap);
  1154 write_xml_stream(xmlNode *xml_node, 
const char *filename, FILE *stream,
  1155                  bool compress, 
unsigned int *nbytes)
  1158     char *buffer = NULL;
  1171         unsigned int in = 0;
  1172         BZFILE *bz_file = NULL;
  1175         bz_file = BZ2_bzWriteOpen(&
rc, stream, 5, 0, 30);
  1177             crm_warn(
"Not compressing %s: could not prepare file stream: %s "  1180             BZ2_bzWrite(&
rc, bz_file, buffer, strlen(buffer));
  1182                 crm_warn(
"Not compressing %s: could not compress data: %s "  1183                          CRM_XS " bzerror=%d errno=%d",
  1189             BZ2_bzWriteClose(&
rc, bz_file, 0, &in, nbytes);
  1191                 crm_warn(
"Not compressing %s: could not write compressed data: %s "  1192                          CRM_XS " bzerror=%d errno=%d",
  1196                 crm_trace(
"Compressed XML for %s from %u bytes to %u",
  1197                           filename, in, *nbytes);
  1202         crm_warn(
"Not compressing %s: not built with bzlib support", filename);
  1207         rc = fprintf(stream, 
"%s", buffer);
  1212             *nbytes = (
unsigned int) 
rc;
  1219     if (fflush(stream) != 0) {
  1221         crm_perror(LOG_ERR, 
"flushing %s", filename);
  1225     if (fsync(fileno(stream)) < 0 && errno != EROFS  && errno != EINVAL) {
  1227         crm_perror(LOG_ERR, 
"synchronizing %s", filename);
  1232     crm_trace(
"Saved %d bytes to %s as XML", *nbytes, filename);
  1249 write_xml_fd(xmlNode * xml_node, 
const char *filename, 
int fd, gboolean compress)
  1251     FILE *stream = NULL;
  1252     unsigned int nbytes = 0;
  1255     CRM_CHECK(xml_node && (fd > 0), 
return -EINVAL);
  1256     stream = fdopen(fd, 
"w");
  1257     if (stream == NULL) {
  1260     rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
  1264     return (
int) nbytes;
  1279     FILE *stream = NULL;
  1280     unsigned int nbytes = 0;
  1283     CRM_CHECK(xml_node && filename, 
return -EINVAL);
  1284     stream = fopen(filename, 
"w");
  1285     if (stream == NULL) {
  1288     rc = write_xml_stream(xml_node, filename, stream, compress, &nbytes);
  1292     return (
int) nbytes;
  1297 replace_text(
char *text, 
int start, 
int *length, 
const char *replace)
  1300     int offset = strlen(replace) - 1;   
  1303     text = pcmk__realloc(text, *length);
  1305     for (lpc = (*length) - 1; lpc > (start + offset); lpc--) {
  1306         text[lpc] = text[lpc - offset];
  1309     memcpy(text + start, replace, offset + 1);
  1318     int length = 1 + strlen(text);
  1319     char *copy = strdup(text);
  1336     for (index = 0; index < length; index++) {
  1337         switch (copy[index]) {
  1341                 copy = replace_text(copy, index, &length, 
"<");
  1345                 copy = replace_text(copy, index, &length, 
">");
  1349                 copy = replace_text(copy, index, &length, 
""");
  1353                 copy = replace_text(copy, index, &length, 
"'");
  1357                 copy = replace_text(copy, index, &length, 
"&");
  1362                 copy = replace_text(copy, index, &length, 
"    ");
  1367                 copy = replace_text(copy, index, &length, 
"\\n");
  1371                 copy = replace_text(copy, index, &length, 
"\\r");
  1381                 if(copy[index] < 
' ' || copy[index] > 
'~') {
  1385                     copy = replace_text(copy, index, &length, replace);
  1399 dump_xml_attr(xmlAttrPtr attr, 
int options, 
char **buffer, 
int *offset, 
int *max)
  1401     char *p_value = NULL;
  1402     const char *p_name = NULL;
  1406     if (attr == NULL || attr->children == NULL) {
  1415     p_name = (
const char *)attr->name;
  1417     buffer_print(*buffer, *max, *offset, 
" %s=\"%s\"", p_name, p_value);
  1423 pcmk__xe_log(
int log_level, 
const char *file, 
const char *
function, 
int line,
  1424              const char *prefix, xmlNode *
data, 
int depth, 
int options)
  1428     const char *
name = NULL;
  1429     const char *hidden = NULL;
  1431     xmlNode *child = NULL;
  1432     xmlAttrPtr pIter = NULL;
  1441         char *buffer = NULL;
  1443         insert_prefix(options, &buffer, &offset, &max, depth);
  1445         if (
data->type == XML_COMMENT_NODE) {
  1452             for (pIter = pcmk__first_xml_attr(
data); pIter != NULL; pIter = pIter->next) {
  1454                 const char *p_name = (
const char *)pIter->name;
  1455                 const char *p_value = pcmk__xml_attr_value(pIter);
  1456                 char *p_copy = NULL;
  1460                 } 
else if (pcmk_any_flags_set(options,
  1466                 } 
else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
  1467                     p_copy = strdup(
"*****");
  1473                 buffer_print(buffer, max, offset, 
" %s=\"%s\"", p_name, p_copy);
  1488         do_crm_log_alias(log_level, file, 
function, line, 
"%s %s", prefix, buffer);
  1492     if(
data->type == XML_COMMENT_NODE) {
  1502         for (child = pcmk__xml_first_child(
data); child != NULL;
  1503              child = pcmk__xml_next(child)) {
  1504             pcmk__xe_log(log_level, file, 
function, line, prefix, child,
  1511         char *buffer = NULL;
  1513         insert_prefix(options, &buffer, &offset, &max, depth);
  1516         do_crm_log_alias(log_level, file, 
function, line, 
"%s %s", prefix, buffer);
  1523 log_xml_changes(
int log_level, 
const char *file, 
const char *
function, 
int line,
  1524                 const char *prefix, xmlNode *
data, 
int depth, 
int options)
  1527     char *prefix_m = NULL;
  1528     xmlNode *child = NULL;
  1529     xmlAttrPtr pIter = NULL;
  1537     prefix_m = strdup(prefix);
  1547         char *spaces = calloc(80, 1);
  1548         int s_count = 0, s_max = 80;
  1549         char *prefix_del = NULL;
  1550         char *prefix_moved = NULL;
  1551         const char *
flags = prefix;
  1553         insert_prefix(options, &spaces, &s_count, &s_max, depth);
  1554         prefix_del = strdup(prefix);
  1555         prefix_del[0] = 
'-';
  1556         prefix_del[1] = 
'-';
  1557         prefix_moved = strdup(prefix);
  1558         prefix_moved[1] = 
'~';
  1561             flags = prefix_moved;
  1569         for (pIter = pcmk__first_xml_attr(
data); pIter != NULL; pIter = pIter->next) {
  1570             const char *aname = (
const char*)pIter->name;
  1572             p = pIter->_private;
  1577                                  "%s %s @%s=%s", 
flags, spaces, aname, value);
  1589                     flags = prefix_moved;
  1595                                  "%s %s @%s=%s", 
flags, spaces, aname, value);
  1602         for (child = pcmk__xml_first_child(
data); child != NULL;
  1603              child = pcmk__xml_next(child)) {
  1604             log_xml_changes(log_level, file, 
function, line, prefix, child,
  1605                             depth + 1, options);
  1612         for (child = pcmk__xml_first_child(
data); child != NULL;
  1613              child = pcmk__xml_next(child)) {
  1614             log_xml_changes(log_level, file, 
function, line, prefix, child,
  1615                             depth + 1, options);
  1625                  const char *prefix, xmlNode * 
data, 
int depth, 
int options)
  1627     xmlNode *a_child = NULL;
  1629     char *prefix_m = NULL;
  1635     if (prefix == NULL) {
  1642                          "No data to dump as XML");
  1647         log_xml_changes(log_level, file, 
function, line, prefix, 
data, depth,
  1656             prefix_m = strdup(prefix);
  1663             prefix_m = strdup(prefix);
  1672         for (a_child = pcmk__xml_first_child(
data); a_child != NULL;
  1673              a_child = pcmk__xml_next(a_child)) {
  1674             log_data_element(log_level, file, 
function, line, prefix, a_child, depth + 1, options);
  1685 dump_filtered_xml(xmlNode * 
data, 
int options, 
char **buffer, 
int *offset, 
int *max)
  1687     xmlAttrPtr xIter = NULL;
  1689     for (xIter = pcmk__first_xml_attr(
data); xIter != NULL; xIter = xIter->next) {
  1691             dump_xml_attr(xIter, options, buffer, offset, max);
  1697 dump_xml_element(xmlNode * 
data, 
int options, 
char **buffer, 
int *offset, 
int *max, 
int depth)
  1699     const char *
name = NULL;
  1710     if (*buffer == NULL) {
  1718     insert_prefix(options, buffer, offset, max, depth);
  1722         dump_filtered_xml(
data, options, buffer, offset, max);
  1725         xmlAttrPtr xIter = NULL;
  1727         for (xIter = pcmk__first_xml_attr(
data); xIter != NULL; xIter = xIter->next) {
  1728             dump_xml_attr(xIter, options, buffer, offset, max);
  1732     if (
data->children == NULL) {
  1743     if (
data->children) {
  1744         xmlNode *xChild = NULL;
  1745         for(xChild = 
data->children; xChild != NULL; xChild = xChild->next) {
  1749         insert_prefix(options, buffer, offset, max, depth);
  1759 dump_xml_text(xmlNode * 
data, 
int options, 
char **buffer, 
int *offset, 
int *max, 
int depth)
  1770     if (*buffer == NULL) {
  1775     insert_prefix(options, buffer, offset, max, depth);
  1785 dump_xml_cdata(xmlNode * 
data, 
int options, 
char **buffer, 
int *offset, 
int *max, 
int depth)
  1796     if (*buffer == NULL) {
  1801     insert_prefix(options, buffer, offset, max, depth);
  1813 dump_xml_comment(xmlNode * 
data, 
int options, 
char **buffer, 
int *offset, 
int *max, 
int depth)
  1824     if (*buffer == NULL) {
  1829     insert_prefix(options, buffer, offset, max, depth);
  1840 #define PCMK__XMLDUMP_STATS 0  1855                int *max, 
int depth)
  1872 #if (PCMK__XMLDUMP_STATS - 0)  1873         time_t next, 
new = time(NULL);
  1876         xmlOutputBuffer *xml_buffer;
  1882         xml_buffer = xmlAllocOutputBuffer(NULL);
  1895         xmlNodeDumpOutput(xml_buffer, doc, 
data, 0,
  1898         (void) xmlOutputBufferWrite(xml_buffer, 
sizeof(
"\n") - 1, 
"\n");
  1899         if (xml_buffer->buffer != NULL) {
  1901                          (
char *) xmlBufContent(xml_buffer->buffer));
  1904 #if (PCMK__XMLDUMP_STATS - 0)  1906         if ((now + 1) < next) {
  1908             crm_err(
"xmlNodeDump() -> %dbytes took %ds", *max, next - now);
  1913         (void) xmlOutputBufferClose(xml_buffer);
  1917     switch(
data->type) {
  1918         case XML_ELEMENT_NODE:
  1920             dump_xml_element(
data, options, buffer, offset, max, depth);
  1925                 dump_xml_text(
data, options, buffer, offset, max, depth);
  1928         case XML_COMMENT_NODE:
  1929             dump_xml_comment(
data, options, buffer, offset, max, depth);
  1931         case XML_CDATA_SECTION_NODE:
  1932             dump_xml_cdata(
data, options, buffer, offset, max, depth);
  1979     char *buffer = NULL;
  1980     int offset = 0, max = 0;
  1984                    &buffer, &offset, &max, 0);
  1991     char *buffer = NULL;
  1992     int offset = 0, max = 0;
  2002     char *buffer = NULL;
  2003     int offset = 0, max = 0;
  2012     if (xml_root != NULL && xml_root->children != NULL) {
  2042     if (filename == NULL) {
  2050     crm_info(
"Saving %s to %s", desc, filename);
  2065     for (xmlAttr *attr = pcmk__first_xml_attr(xml); attr; attr = attr->next) {
  2080 mark_attr_deleted(xmlNode *new_xml, 
const char *element, 
const char *attr_name,
  2081                   const char *old_value)
  2084     xmlAttr *attr = NULL;
  2100     crm_trace(
"XML attribute %s=%s was removed from %s",
  2101               attr_name, old_value, element);
  2109 mark_attr_changed(xmlNode *new_xml, 
const char *element, 
const char *attr_name,
  2110                   const char *old_value)
  2114     crm_trace(
"XML attribute %s was changed from '%s' to '%s' in %s",
  2115               attr_name, old_value, vcopy, element);
  2130 mark_attr_moved(xmlNode *new_xml, 
const char *element, xmlAttr *old_attr,
  2131                 xmlAttr *new_attr, 
int p_old, 
int p_new)
  2135     crm_trace(
"XML attribute %s moved from position %d to %d in %s",
  2136               old_attr->name, p_old, p_new, element);
  2139     mark_xml_node_dirty(new_xml);
  2144     p = (p_old > p_new)? old_attr->_private : new_attr->_private;
  2153 xml_diff_old_attrs(xmlNode *old_xml, xmlNode *new_xml)
  2155     xmlAttr *attr_iter = pcmk__first_xml_attr(old_xml);
  2157     while (attr_iter != NULL) {
  2158         xmlAttr *old_attr = attr_iter;
  2159         xmlAttr *new_attr = xmlHasProp(new_xml, attr_iter->name);
  2160         const char *
name = (
const char *) attr_iter->name;
  2163         attr_iter = attr_iter->next;
  2164         if (new_attr == NULL) {
  2165             mark_attr_deleted(new_xml, (
const char *) old_xml->name, 
name,
  2177             if (strcmp(new_value, old_value) != 0) {
  2178                 mark_attr_changed(new_xml, (
const char *) old_xml->name, 
name,
  2181             } 
else if ((old_pos != new_pos)
  2183                 mark_attr_moved(new_xml, (
const char *) old_xml->name,
  2184                                 old_attr, new_attr, old_pos, new_pos);
  2195 mark_created_attrs(xmlNode *new_xml)
  2197     xmlAttr *attr_iter = pcmk__first_xml_attr(new_xml);
  2199     while (attr_iter != NULL) {
  2200         xmlAttr *new_attr = attr_iter;
  2203         attr_iter = attr_iter->next;
  2205             const char *attr_name = (
const char *) new_attr->name;
  2207             crm_trace(
"Created new attribute %s=%s in %s",
  2218                 xmlUnsetProp(new_xml, new_attr->name);
  2229 xml_diff_attrs(xmlNode *old_xml, xmlNode *new_xml)
  2232     xml_diff_old_attrs(old_xml, new_xml);
  2233     mark_created_attrs(new_xml);
  2246 mark_child_deleted(xmlNode *old_child, xmlNode *new_parent)
  2252     reset_xml_node_flags(candidate);
  2258     free_xml_with_position(candidate,
  2267 mark_child_moved(xmlNode *old_child, xmlNode *new_parent, xmlNode *new_child,
  2268                  int p_old, 
int p_new)
  2272     crm_trace(
"Child element %s with id='%s' moved from position %d to %d under %s",
  2273               new_child->name, (
ID(new_child)? 
ID(new_child) : 
"<no id>"),
  2274               p_old, p_new, new_parent->name);
  2275     mark_xml_node_dirty(new_parent);
  2278     if (p_old > p_new) {
  2279         p = old_child->_private;
  2281         p = new_child->_private;
  2288 mark_xml_changes(xmlNode *old_xml, xmlNode *new_xml, 
bool check_top)
  2290     xmlNode *cIter = NULL;
  2294     if (old_xml == NULL) {
  2300     p = new_xml->_private;
  2309     xml_diff_attrs(old_xml, new_xml);
  2312     for (cIter = pcmk__xml_first_child(old_xml); cIter != NULL; ) {
  2313         xmlNode *old_child = cIter;
  2316         cIter = pcmk__xml_next(cIter);
  2318             mark_xml_changes(old_child, new_child, TRUE);
  2321             mark_child_deleted(old_child, new_xml);
  2326     for (cIter = pcmk__xml_first_child(new_xml); cIter != NULL; ) {
  2327         xmlNode *new_child = cIter;
  2330         cIter = pcmk__xml_next(cIter);
  2331         if(old_child == NULL) {
  2333             p = new_child->_private;
  2335             mark_xml_changes(old_child, new_child, TRUE);
  2342             if(p_old != p_new) {
  2343                 mark_child_moved(old_child, new_xml, new_child, p_old, p_new);
  2367     mark_xml_changes(old_xml, new_xml, FALSE);
  2373     xmlNode *cIter = NULL;
  2374     xmlAttrPtr pIter = NULL;
  2375     gboolean can_prune = TRUE;
  2376     const char *
name = crm_element_name(xml_node);
  2383     for (pIter = pcmk__first_xml_attr(xml_node); pIter != NULL; pIter = pIter->next) {
  2384         const char *p_name = (
const char *)pIter->name;
  2392     cIter = pcmk__xml_first_child(xml_node);
  2394         xmlNode *child = cIter;
  2396         cIter = pcmk__xml_next(cIter);
  2417     xmlNode *a_child = NULL;
  2420     CRM_CHECK(search_comment->type == XML_COMMENT_NODE, 
return NULL);
  2422     for (a_child = pcmk__xml_first_child(root); a_child != NULL;
  2423          a_child = pcmk__xml_next(a_child)) {
  2428             if (offset < search_offset) {
  2431             } 
else if (offset > search_offset) {
  2440         if (a_child->type == XML_COMMENT_NODE
  2441             && pcmk__str_eq((
const char *)a_child->content, (
const char *)search_comment->content, 
pcmk__str_casei)) {
  2467     CRM_CHECK(update->type == XML_COMMENT_NODE, 
return);
  2476     } 
else if (!pcmk__str_eq((
const char *)
target->content, (
const char *)update->content, 
pcmk__str_casei)) {
  2477         xmlFree(
target->content);
  2478         target->content = xmlStrdup(update->content);
  2498     xmlNode *a_child = NULL;
  2499     const char *object_name = NULL,
  2500                *object_href = NULL,
  2501                *object_href_val = NULL;
  2503 #if XML_PARSER_DEBUG  2510     if (update->type == XML_COMMENT_NODE) {
  2515     object_name = crm_element_name(update);
  2516     object_href_val = 
ID(update);
  2517     if (object_href_val != NULL) {
  2529                                 object_href, object_href_val);
  2535 #if XML_PARSER_DEBUG  2537                   object_href ? 
" " : 
"",
  2538                   object_href ? object_href : 
"",
  2539                   object_href ? 
"=" : 
"",
  2540                   object_href ? object_href_val : 
"");
  2544                   object_href ? 
" " : 
"",
  2545                   object_href ? object_href : 
"",
  2546                   object_href ? 
"=" : 
"",
  2547                   object_href ? object_href_val : 
"");
  2551     CRM_CHECK(pcmk__str_eq(crm_element_name(
target), crm_element_name(update),
  2555     if (as_diff == FALSE) {
  2561         xmlAttrPtr pIter = NULL;
  2563         for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
  2564             const char *p_name = (
const char *)pIter->name;
  2565             const char *p_value = pcmk__xml_attr_value(pIter);
  2573     for (a_child = pcmk__xml_first_child(update); a_child != NULL;
  2574          a_child = pcmk__xml_next(a_child)) {
  2575 #if XML_PARSER_DEBUG  2577                   object_href ? 
" " : 
"",
  2578                   object_href ? object_href : 
"",
  2579                   object_href ? 
"=" : 
"",
  2580                   object_href ? object_href_val : 
"");
  2585 #if XML_PARSER_DEBUG  2587               object_href ? 
" " : 
"",
  2588               object_href ? object_href : 
"",
  2589               object_href ? 
"=" : 
"",
  2590               object_href ? object_href_val : 
"");
  2597     gboolean can_update = TRUE;
  2598     xmlNode *child_of_child = NULL;
  2601     CRM_CHECK(to_update != NULL, 
return FALSE);
  2603     if (!pcmk__str_eq(crm_element_name(to_update), crm_element_name(child), 
pcmk__str_casei)) {
  2609     } 
else if (can_update) {
  2610 #if XML_PARSER_DEBUG  2616     for (child_of_child = pcmk__xml_first_child(child); child_of_child != NULL;
  2617          child_of_child = pcmk__xml_next(child_of_child)) {
  2630                   const char *tag, 
const char *field, 
const char *value, gboolean search_matches)
  2632     int match_found = 0;
  2635     CRM_CHECK(children != NULL, 
return FALSE);
  2637     if (tag != NULL && !pcmk__str_eq(tag, crm_element_name(root), 
pcmk__str_casei)) {
  2642         if (*children == NULL) {
  2649     if (search_matches || match_found == 0) {
  2650         xmlNode *child = NULL;
  2652         for (child = pcmk__xml_first_child(root); child != NULL;
  2653              child = pcmk__xml_next(child)) {
  2654             match_found += 
find_xml_children(children, child, tag, field, value, search_matches);
  2664     gboolean can_delete = FALSE;
  2665     xmlNode *child_of_child = NULL;
  2667     const char *up_id = NULL;
  2668     const char *child_id = NULL;
  2669     const char *right_val = NULL;
  2672     CRM_CHECK(update != NULL, 
return FALSE);
  2675     child_id = 
ID(child);
  2677     if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
  2680     if (!pcmk__str_eq(crm_element_name(update), crm_element_name(child), 
pcmk__str_casei)) {
  2683     if (can_delete && delete_only) {
  2684         xmlAttrPtr pIter = NULL;
  2686         for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
  2687             const char *p_name = (
const char *)pIter->name;
  2688             const char *p_value = pcmk__xml_attr_value(pIter);
  2697     if (can_delete && parent != NULL) {
  2699         if (delete_only || update == NULL) {
  2704             xmlDoc *doc = tmp->doc;
  2705             xmlNode *old = NULL;
  2708             old = xmlReplaceNode(child, tmp);
  2716             xmlDocSetRootElement(doc, old);
  2722     } 
else if (can_delete) {
  2727     child_of_child = pcmk__xml_first_child(child);
  2728     while (child_of_child) {
  2729         xmlNode *next = pcmk__xml_next(child_of_child);
  2735             child_of_child = NULL;
  2737             child_of_child = next;
  2747     xmlNode *child = NULL;
  2748     GSList *nvpairs = NULL;
  2749     xmlNode *result = NULL;
  2750     const char *
name = NULL;
  2754     name = crm_element_name(input);
  2763     for (child = pcmk__xml_first_child(input); child != NULL;
  2764          child = pcmk__xml_next(child)) {
  2779     xmlNode *match = NULL;
  2781     for (match = pcmk__xe_first_child(parent); match != NULL;
  2782          match = pcmk__xe_next(match)) {
  2805     xmlNode *match = pcmk__xe_next(sibling);
  2806     const char *
name = crm_element_name(sibling);
  2808     while (match != NULL) {
  2809         if (!strcmp(crm_element_name(match), 
name)) {
  2812         match = pcmk__xe_next(match);
  2820     static bool init = TRUE;
  2829         xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
  2832         xmlDeregisterNodeDefault(free_private_data);
  2833         xmlRegisterNodeDefault(new_private_data);
  2842     crm_info(
"Cleaning up memory from libxml2");
  2847 #define XPATH_MAX 512  2852     const char *tag = NULL;
  2853     const char *ref = NULL;
  2854     xmlNode *result = input;
  2856     if (result == NULL) {
  2859     } 
else if (top == NULL) {
  2863     tag = crm_element_name(result);
  2870         if (result == NULL) {
  2871             char *nodePath = (
char *)xmlGetNodePath(top);
  2873             crm_err(
"No match for %s found in %s: Invalid configuration", xpath_string,
  2891     static const char *base = NULL;
  2895         base = getenv(
"PCMK_schema_directory");
  2897     if (pcmk__str_empty(base)) {
  2911             crm_err(
"XML artefact family specified as %u not recognized", ns);
  2931             crm_err(
"XML artefact family specified as %u not recognized", ns);
  2940 xmlNode *
find_entity(xmlNode *parent, 
const char *node_name, 
const char *
id);
 
#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)
 
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)
 
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__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)
 
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)
 
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
 
#define crm_warn(fmt, args...)
 
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
 
#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)
 
#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)
 
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)
 
#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)
 
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
 
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)