root/include/crm/common/xml_internal.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. pcmk__xml_first_child
  2. pcmk__xml_next
  3. pcmk__xe_first_child
  4. pcmk__xe_next

   1 /*
   2  * Copyright 2017-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #ifndef PCMK__XML_INTERNAL__H
  11 #  define PCMK__XML_INTERNAL__H
  12 
  13 /*
  14  * Internal-only wrappers for and extensions to libxml2 (libxslt)
  15  */
  16 
  17 #  include <stdlib.h>
  18 #  include <stdio.h>
  19 #  include <string.h>
  20 
  21 #  include <crm/crm.h>  /* transitively imports qblog.h */
  22 
  23 
  24 /*!
  25  * \brief Base for directing lib{xml2,xslt} log into standard libqb backend
  26  *
  27  * This macro implements the core of what can be needed for directing
  28  * libxml2 or libxslt error messaging into standard, preconfigured
  29  * libqb-backed log stream.
  30  *
  31  * It's a bit unfortunate that libxml2 (and more sparsely, also libxslt)
  32  * emits a single message by chunks (location is emitted separatedly from
  33  * the message itself), so we have to take the effort to combine these
  34  * chunks back to single message.  Whether to do this or not is driven
  35  * with \p dechunk toggle.
  36  *
  37  * The form of a macro was chosen for implicit deriving of __FILE__, etc.
  38  * and also because static dechunking buffer should be differentiated per
  39  * library (here we assume different functions referring to this macro
  40  * will not ever be using both at once), preferably also per-library
  41  * context of use to avoid clashes altogether.
  42  *
  43  * Note that we cannot use qb_logt, because callsite data have to be known
  44  * at the moment of compilation, which it is not always the case -- xml_log
  45  * (and unfortunately there's no clear explanation of the fail to compile).
  46  *
  47  * Also note that there's no explicit guard against said libraries producing
  48  * never-newline-terminated chunks (which would just keep consuming memory),
  49  * as it's quite improbable.  Termination of the program in between the
  50  * same-message chunks will raise a flag with valgrind and the likes, though.
  51  *
  52  * And lastly, regarding how dechunking combines with other non-message
  53  * parameters -- for \p priority, most important running specification
  54  * wins (possibly elevated to LOG_ERR in case of nonconformance with the
  55  * newline-termination "protocol"), \p dechunk is expected to always be
  56  * on once it was at the start, and the rest (\p postemit and \p prefix)
  57  * are picked directly from the last chunk entry finalizing the message
  58  * (also reasonable to always have it the same with all related entries).
  59  *
  60  * \param[in] priority Syslog priority for the message to be logged
  61  * \param[in] dechunk  Whether to dechunk new-line terminated message
  62  * \param[in] postemit Code to be executed once message is sent out
  63  * \param[in] prefix   How to prefix the message or NULL for raw passing
  64  * \param[in] fmt      Format string as with printf-like functions
  65  * \param[in] ap       Variable argument list to supplement \p fmt format string
  66  */
  67 #define PCMK__XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap)        \
  68 do {                                                                            \
  69     if (!(dechunk) && (prefix) == NULL) {  /* quick pass */                     \
  70         qb_log_from_external_source_va(__func__, __FILE__, (fmt),               \
  71                                        (priority), __LINE__, 0, (ap));          \
  72         (void) (postemit);                                                      \
  73     } else {                                                                    \
  74         int CXLB_len = 0;                                                       \
  75         char *CXLB_buf = NULL;                                                  \
  76         static int CXLB_buffer_len = 0;                                         \
  77         static char *CXLB_buffer = NULL;                                        \
  78         static uint8_t CXLB_priority = 0;                                       \
  79                                                                                 \
  80         CXLB_len = vasprintf(&CXLB_buf, (fmt), (ap));                           \
  81                                                                                 \
  82         if (CXLB_len <= 0 || CXLB_buf[CXLB_len - 1] == '\n' || !(dechunk)) {    \
  83             if (CXLB_len < 0) {                                                 \
  84                 CXLB_buf = (char *) "LOG CORRUPTION HAZARD"; /*we don't modify*/\
  85                 CXLB_priority = QB_MIN(CXLB_priority, LOG_ERR);                 \
  86             } else if (CXLB_len > 0 /* && (dechunk) */                          \
  87                        && CXLB_buf[CXLB_len - 1] == '\n') {                     \
  88                 CXLB_buf[CXLB_len - 1] = '\0';                                  \
  89             }                                                                   \
  90             if (CXLB_buffer) {                                                  \
  91                 qb_log_from_external_source(__func__, __FILE__, "%s%s%s",       \
  92                                             CXLB_priority, __LINE__, 0,         \
  93                                             (prefix) != NULL ? (prefix) : "",   \
  94                                             CXLB_buffer, CXLB_buf);             \
  95                 free(CXLB_buffer);                                              \
  96             } else {                                                            \
  97                 qb_log_from_external_source(__func__, __FILE__, "%s%s",         \
  98                                             (priority), __LINE__, 0,            \
  99                                             (prefix) != NULL ? (prefix) : "",   \
 100                                             CXLB_buf);                          \
 101             }                                                                   \
 102             if (CXLB_len < 0) {                                                 \
 103                 CXLB_buf = NULL;  /* restore temporary override */              \
 104             }                                                                   \
 105             CXLB_buffer = NULL;                                                 \
 106             CXLB_buffer_len = 0;                                                \
 107             (void) (postemit);                                                  \
 108                                                                                 \
 109         } else if (CXLB_buffer == NULL) {                                       \
 110             CXLB_buffer_len = CXLB_len;                                         \
 111             CXLB_buffer = CXLB_buf;                                             \
 112             CXLB_buf = NULL;                                                    \
 113             CXLB_priority = (priority);  /* remember as a running severest */   \
 114                                                                                 \
 115         } else {                                                                \
 116             CXLB_buffer = realloc(CXLB_buffer, 1 + CXLB_buffer_len + CXLB_len); \
 117             memcpy(CXLB_buffer + CXLB_buffer_len, CXLB_buf, CXLB_len);          \
 118             CXLB_buffer_len += CXLB_len;                                        \
 119             CXLB_buffer[CXLB_buffer_len] = '\0';                                \
 120             CXLB_priority = QB_MIN(CXLB_priority, (priority));  /* severest? */ \
 121         }                                                                       \
 122         free(CXLB_buf);                                                         \
 123     }                                                                           \
 124 } while (0)
 125 
 126 enum pcmk__xml_artefact_ns {
 127     pcmk__xml_artefact_ns_legacy_rng = 1,
 128     pcmk__xml_artefact_ns_legacy_xslt,
 129     pcmk__xml_artefact_ns_base_rng,
 130     pcmk__xml_artefact_ns_base_xslt,
 131 };
 132 
 133 void pcmk__strip_xml_text(xmlNode *xml);
 134 const char *pcmk__xe_add_last_written(xmlNode *xe);
 135 
 136 xmlNode *pcmk__xe_match(xmlNode *parent, const char *node_name,
 137                         const char *attr_n, const char *attr_v);
 138 
 139 /*!
 140  * \internal
 141  * \brief Get the root directory to scan XML artefacts of given kind for
 142  *
 143  * \param[in] ns governs the hierarchy nesting against the inherent root dir
 144  *
 145  * \return root directory to scan XML artefacts of given kind for
 146  */
 147 char *
 148 pcmk__xml_artefact_root(enum pcmk__xml_artefact_ns ns);
 149 
 150 /*!
 151  * \internal
 152  * \brief Get the fully unwrapped path to particular XML artifact (RNG/XSLT)
 153  *
 154  * \param[in] ns       denotes path forming details (parent dir, suffix)
 155  * \param[in] filespec symbolic file specification to be combined with
 156  *                     #artefact_ns to form the final path
 157  * \return unwrapped path to particular XML artifact (RNG/XSLT)
 158  */
 159 char *pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns,
 160                               const char *filespec);
 161 
 162 /*!
 163  * \internal
 164  * \brief Return first non-text child node of an XML node
 165  *
 166  * \param[in] parent  XML node to check
 167  *
 168  * \return First non-text child node of \p parent (or NULL if none)
 169  */
 170 static inline xmlNode *
 171 pcmk__xml_first_child(const xmlNode *parent)
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173     xmlNode *child = (parent? parent->children : NULL);
 174 
 175     while (child && (child->type == XML_TEXT_NODE)) {
 176         child = child->next;
 177     }
 178     return child;
 179 }
 180 
 181 /*!
 182  * \internal
 183  * \brief Return next non-text sibling node of an XML node
 184  *
 185  * \param[in] child  XML node to check
 186  *
 187  * \return Next non-text sibling of \p child (or NULL if none)
 188  */
 189 static inline xmlNode *
 190 pcmk__xml_next(const xmlNode *child)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192     xmlNode *next = (child? child->next : NULL);
 193 
 194     while (next && (next->type == XML_TEXT_NODE)) {
 195         next = next->next;
 196     }
 197     return next;
 198 }
 199 
 200 /*!
 201  * \internal
 202  * \brief Return first non-text child element of an XML node
 203  *
 204  * \param[in] parent  XML node to check
 205  *
 206  * \return First child element of \p parent (or NULL if none)
 207  */
 208 static inline xmlNode *
 209 pcmk__xe_first_child(const xmlNode *parent)
     /* [previous][next][first][last][top][bottom][index][help] */
 210 {
 211     xmlNode *child = (parent? parent->children : NULL);
 212 
 213     while (child && (child->type != XML_ELEMENT_NODE)) {
 214         child = child->next;
 215     }
 216     return child;
 217 }
 218 
 219 /*!
 220  * \internal
 221  * \brief Return next non-text sibling element of an XML element
 222  *
 223  * \param[in] child  XML element to check
 224  *
 225  * \return Next sibling element of \p child (or NULL if none)
 226  */
 227 static inline xmlNode *
 228 pcmk__xe_next(const xmlNode *child)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230     xmlNode *next = child? child->next : NULL;
 231 
 232     while (next && (next->type != XML_ELEMENT_NODE)) {
 233         next = next->next;
 234     }
 235     return next;
 236 }
 237 
 238 #endif // PCMK__XML_INTERNAL__H

/* [previous][next][first][last][top][bottom][index][help] */