19 #include <libxml/relaxng.h> 20 #include <libxslt/xslt.h> 21 #include <libxslt/transform.h> 22 #include <libxslt/security.h> 23 #include <libxslt/xsltutils.h> 30 #define SCHEMA_ZERO { .v = { 0, 0 } } 32 #define schema_strdup_printf(prefix, version, suffix) \ 33 crm_strdup_printf(prefix "%u.%u" suffix, (version).v[0], (version).v[1]) 37 xmlRelaxNGValidCtxtPtr valid;
38 xmlRelaxNGParserCtxtPtr parser;
39 } relaxng_ctx_cache_t;
41 static GList *known_schemas = NULL;
42 static bool initialized =
false;
43 static bool silent_logging = FALSE;
45 static void G_GNUC_PRINTF(2, 3)
46 xml_log(
int priority, const
char *fmt, ...)
51 if (silent_logging == FALSE) {
59 xml_latest_schema_index(
void)
68 return g_list_length(known_schemas) - 3;
78 get_highest_schema(
void)
99 GList *entry = get_highest_schema();
113 #if defined(PCMK__UNIT_TESTING) 118 GList *x_0_entry = NULL;
120 static GList *x_0_entry = NULL;
125 if (x_0_entry != NULL) {
128 x_0_entry = get_highest_schema();
129 highest_schema = x_0_entry->data;
131 for (GList *iter = x_0_entry->prev; iter != NULL; iter = iter->prev) {
139 x_0_entry = iter->next;
146 if (iter->prev == NULL) {
147 x_0_entry = known_schemas->data;
158 return sscanf(filename,
"pacemaker-%hhu.%hhu.rng", &(
version->v[0]), &(
version->v[1])) == 2;
160 return sscanf(filename,
"pacemaker-%hhu.%hhu", &(
version->v[0]), &(
version->v[1])) == 2;
165 schema_filter(
const struct dirent *a)
170 if (strstr(a->d_name,
"pacemaker-") != a->d_name) {
176 }
else if (!version_from_filename(a->d_name, &
version)) {
190 for (
int i = 0; i < 2; ++i) {
191 if (a_version.
v[i] < b_version.
v[i]) {
193 }
else if (a_version.
v[i] > b_version.
v[i]) {
201 schema_cmp_directory(
const struct dirent **a,
const struct dirent **b)
206 if (!version_from_filename(a[0]->d_name, &a_version)
207 || !version_from_filename(b[0]->d_name, &b_version)) {
212 return schema_cmp(a_version, b_version);
224 const char *
name,
const char *transform,
225 const char *transform_enter,
bool transform_onleave)
247 if (transform_enter) {
251 known_schemas = g_list_prepend(known_schemas, schema);
285 bool transform_onleave = FALSE;
289 *transform_upgrade = NULL,
290 *transform_enter = NULL;
293 if (transform_expected) {
300 if (!transform_expected) {
303 }
else if (stat(xslt, &s) == 0) {
309 if (stat(xslt, &s) != 0) {
311 crm_debug(
"Upgrade-enter transform %s.xsl not found", xslt);
313 free(transform_enter);
314 transform_enter = strdup(
"upgrade-enter");
317 if (stat(xslt, &s) != 0) {
318 crm_debug(
"Upgrade-enter transform %s.xsl not found, either", xslt);
326 memcpy(strrchr(xslt,
'-') + 1,
"leave",
sizeof(
"leave") - 1);
327 transform_onleave = (stat(xslt, &s) == 0);
330 free(transform_enter);
331 transform_enter = NULL;
335 crm_err(
"Upgrade transform %s not found", xslt);
337 free(transform_upgrade);
338 transform_upgrade = NULL;
343 transform_upgrade, transform_enter, transform_onleave);
345 free(transform_upgrade);
346 free(transform_enter);
352 wrap_libxslt(
bool finalize)
354 static xsltSecurityPrefsPtr secprefs;
360 secprefs = xsltNewSecurityPrefs();
361 ret = xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_WRITE_FILE,
363 | xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_CREATE_DIRECTORY,
365 | xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_READ_NETWORK,
367 | xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_WRITE_NETWORK,
373 xsltFreeSecurityPrefs(secprefs);
379 xsltCleanupGlobals();
387 struct dirent **namelist = NULL;
389 max = scandir(dir, &namelist, schema_filter, schema_cmp_directory);
391 crm_warn(
"Could not load schemas from %s: %s", dir, strerror(errno));
395 for (lpc = 0; lpc < max; lpc++) {
396 bool transform_expected =
false;
399 if (!version_from_filename(namelist[lpc]->d_name, &
version)) {
401 crm_warn(
"Skipping schema '%s': could not parse version",
402 namelist[lpc]->d_name);
405 if ((lpc + 1) < max) {
408 if (version_from_filename(namelist[lpc+1]->d_name, &next_version)
409 && (
version.v[0] < next_version.
v[0])) {
410 transform_expected =
true;
419 for (lpc = 0; lpc < max; lpc++) {
427 schema_sort_GCompareFunc(gconstpointer a, gconstpointer b)
459 known_schemas = g_list_sort(known_schemas, schema_sort_GCompareFunc);
476 int schema_index = 0;
501 for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
505 crm_debug(
"Loaded schema %d: %s", schema_index, schema->
name);
507 crm_debug(
"Loaded schema %d: %s (upgrades with %s.xsl)",
516 validate_with_relaxng(xmlDocPtr doc, xmlRelaxNGValidityErrorFunc error_handler,
517 void *error_handler_context,
const char *relaxng_file,
518 relaxng_ctx_cache_t **cached_ctx)
522 relaxng_ctx_cache_t *ctx = NULL;
525 CRM_CHECK(relaxng_file != NULL,
return false);
527 if (cached_ctx && *cached_ctx) {
531 crm_debug(
"Creating RNG parser context");
534 ctx->parser = xmlRelaxNGNewParserCtxt(relaxng_file);
535 CRM_CHECK(ctx->parser != NULL,
goto cleanup);
538 xmlRelaxNGSetParserErrors(ctx->parser,
539 (xmlRelaxNGValidityErrorFunc) error_handler,
540 (xmlRelaxNGValidityWarningFunc) error_handler,
541 error_handler_context);
543 xmlRelaxNGSetParserErrors(ctx->parser,
544 (xmlRelaxNGValidityErrorFunc) fprintf,
545 (xmlRelaxNGValidityWarningFunc) fprintf,
549 ctx->rng = xmlRelaxNGParse(ctx->parser);
551 crm_err(
"Could not find/parse %s", relaxng_file);
554 ctx->valid = xmlRelaxNGNewValidCtxt(ctx->rng);
555 CRM_CHECK(ctx->valid != NULL,
goto cleanup);
558 xmlRelaxNGSetValidErrors(ctx->valid,
559 (xmlRelaxNGValidityErrorFunc) error_handler,
560 (xmlRelaxNGValidityWarningFunc) error_handler,
561 error_handler_context);
563 xmlRelaxNGSetValidErrors(ctx->valid,
564 (xmlRelaxNGValidityErrorFunc) fprintf,
565 (xmlRelaxNGValidityWarningFunc) fprintf,
570 rc = xmlRelaxNGValidateDoc(ctx->valid, doc);
575 crm_err(
"Internal libxml error during validation");
584 if (ctx->parser != NULL) {
585 xmlRelaxNGFreeParserCtxt(ctx->parser);
587 if (ctx->valid != NULL) {
588 xmlRelaxNGFreeValidCtxt(ctx->valid);
590 if (ctx->rng != NULL) {
591 xmlRelaxNGFree(ctx->rng);
600 free_schema(gpointer
data)
603 relaxng_ctx_cache_t *ctx = NULL;
610 ctx = (relaxng_ctx_cache_t *) schema->
cache;
615 if (ctx->parser != NULL) {
616 xmlRelaxNGFreeParserCtxt(ctx->parser);
619 if (ctx->valid != NULL) {
620 xmlRelaxNGFreeValidCtxt(ctx->valid);
623 if (ctx->rng != NULL) {
624 xmlRelaxNGFree(ctx->rng);
628 schema->
cache = NULL;
645 if (known_schemas != NULL) {
646 g_list_free_full(known_schemas, free_schema);
647 known_schemas = NULL;
669 for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
696 if (entry1 == NULL) {
697 return (entry2 == NULL)? 0 : -1;
699 }
else if (entry2 == NULL) {
712 xmlRelaxNGValidityErrorFunc error_handler,
713 void *error_handler_context)
717 relaxng_ctx_cache_t **cache = NULL;
719 if (schema == NULL) {
730 crm_trace(
"Validating with %s (type=%d)",
731 pcmk__s(file,
"missing schema"), schema->
validator);
734 cache = (relaxng_ctx_cache_t **) &(schema->
cache);
735 valid = validate_with_relaxng(xml->doc, error_handler, error_handler_context, file, cache);
749 bool rc, sl_backup = silent_logging;
750 silent_logging = TRUE;
751 rc = validate_with(xml, schema, (xmlRelaxNGValidityErrorFunc) xml_log, GUINT_TO_POINTER(LOG_ERR));
752 silent_logging = sl_backup;
758 xmlRelaxNGValidityErrorFunc error_handler,
759 void *error_handler_context)
764 CRM_CHECK((xml_blob != NULL) && (xml_blob->doc != NULL),
return false);
766 if (validation == NULL) {
772 if (validation == NULL) {
775 for (entry = known_schemas; entry != NULL; entry = entry->next) {
776 schema = entry->data;
777 if (validate_with(xml_blob, schema, NULL, NULL)) {
789 " set to an unknown schema such as '%s' (manually" 790 " edit to use a known schema)",
795 schema = entry->data;
796 return validate_with(xml_blob, schema, error_handler,
797 error_handler_context);
812 (xmlRelaxNGValidityErrorFunc) xml_log,
813 GUINT_TO_POINTER(LOG_ERR));
839 static void G_GNUC_PRINTF(2, 3)
840 cib_upgrade_err(
void *ctx, const
char *fmt, ...)
846 const char *fmt_iter = fmt;
847 uint8_t msg_log_level = LOG_WARNING;
848 const unsigned * log_level = (
const unsigned *) ctx;
852 } scan_state = escan_seennothing;
857 while (!found && *fmt_iter !=
'\0') {
859 switch (*fmt_iter++) {
861 if (scan_state == escan_seennothing) {
862 scan_state = escan_seenpercent;
863 }
else if (scan_state == escan_seenpercent) {
864 scan_state = escan_seennothing;
868 if (scan_state == escan_seenpercent) {
869 scan_state = escan_seennothing;
870 arg_cur = va_arg(aq,
char *);
871 if (arg_cur != NULL) {
872 switch (arg_cur[0]) {
874 if (!strncmp(arg_cur,
"WARNING: ",
875 sizeof(
"WARNING: ") - 1)) {
876 msg_log_level = LOG_WARNING;
879 memmove(arg_cur, arg_cur +
sizeof(
"WARNING: ") - 1,
880 strlen(arg_cur +
sizeof(
"WARNING: ") - 1) + 1);
885 if (!strncmp(arg_cur,
"INFO: ",
886 sizeof(
"INFO: ") - 1)) {
887 msg_log_level = LOG_INFO;
890 memmove(arg_cur, arg_cur +
sizeof(
"INFO: ") - 1,
891 strlen(arg_cur +
sizeof(
"INFO: ") - 1) + 1);
896 if (!strncmp(arg_cur,
"DEBUG: ",
897 sizeof(
"DEBUG: ") - 1)) {
898 msg_log_level = LOG_DEBUG;
901 memmove(arg_cur, arg_cur +
sizeof(
"DEBUG: ") - 1,
902 strlen(arg_cur +
sizeof(
"DEBUG: ") - 1) + 1);
910 case '#':
case '-':
case ' ':
case '+':
case '\'':
case 'I':
case '.':
911 case '0':
case '1':
case '2':
case '3':
case '4':
912 case '5':
case '6':
case '7':
case '8':
case '9':
929 if (scan_state == escan_seenpercent) {
930 (void) va_arg(aq,
void *);
931 scan_state = escan_seennothing;
935 scan_state = escan_seennothing;
940 if (log_level != NULL) {
943 if (*log_level + 4 >= msg_log_level) {
944 vfprintf(stderr, fmt, ap);
966 apply_transformation(
const xmlNode *xml,
const char *transform,
971 xmlDocPtr res = NULL;
972 xsltStylesheet *xslt = NULL;
979 xsltSetGenericErrorFunc(NULL, cib_upgrade_err);
984 xslt = xsltParseStylesheetFile((
pcmkXmlStr) xform);
990 res = xsltApplyStylesheet(xslt, xml->doc, NULL);
993 xsltSetGenericErrorFunc(NULL, NULL);
995 out = xmlDocGetRootElement(res);
999 xsltFreeStylesheet(xslt);
1024 apply_upgrade(
const xmlNode *original_xml,
int schema_index, gboolean to_logs)
1026 pcmk__schema_t *schema = g_list_nth_data(known_schemas, schema_index);
1029 bool transform_onleave =
false;
1030 char *transform_leave;
1031 const xmlNode *xml = original_xml;
1032 xmlNode *upgrade = NULL;
1033 xmlNode *
final = NULL;
1034 xmlRelaxNGValidityErrorFunc error_handler = NULL;
1036 pcmk__assert((schema != NULL) && (upgraded_schema != NULL));
1039 error_handler = (xmlRelaxNGValidityErrorFunc) xml_log;
1044 crm_debug(
"Upgrading schema from %s to %s: " 1045 "applying pre-upgrade XSL transform %s",
1047 upgrade = apply_transformation(xml, schema->
transform_enter, to_logs);
1048 if (upgrade == NULL) {
1049 crm_warn(
"Pre-upgrade XSL transform %s failed, " 1050 "will skip post-upgrade transform",
1052 transform_onleave = FALSE;
1059 crm_debug(
"Upgrading schema from %s to %s: " 1060 "applying upgrade XSL transform %s",
1062 final = apply_transformation(xml, schema->
transform, to_logs);
1063 if (upgrade != xml) {
1068 if ((
final != NULL) && transform_onleave) {
1074 memcpy(strrchr(transform_leave,
'-') + 1,
"leave",
sizeof(
"leave") - 1);
1075 crm_debug(
"Upgrading schema from %s to %s: " 1076 "applying post-upgrade XSL transform %s",
1077 schema->
name, upgraded_schema->
name, transform_leave);
1078 final = apply_transformation(upgrade, transform_leave, to_logs);
1079 if (
final == NULL) {
1080 crm_warn(
"Ignoring failure of post-upgrade XSL transform %s",
1086 free(transform_leave);
1089 if (
final == NULL) {
1097 if (!validate_with(
final, upgraded_schema, error_handler,
1098 GUINT_TO_POINTER(LOG_ERR))) {
1099 crm_err(
"Schema upgrade from %s to %s failed: " 1100 "XSL transform %s produced an invalid configuration",
1107 crm_info(
"Schema upgrade from %s to %s succeeded",
1108 schema->
name, upgraded_schema->
name);
1121 get_configured_schema(
const xmlNode *xml)
1126 if (schema_name == NULL) {
1150 int max_stable_schemas = xml_latest_schema_index();
1151 int max_schema_index = 0;
1153 GList *entry = NULL;
1156 xmlRelaxNGValidityErrorFunc error_handler =
1157 to_logs ? (xmlRelaxNGValidityErrorFunc) xml_log : NULL;
1159 CRM_CHECK((xml != NULL) && (*xml != NULL) && ((*xml)->doc != NULL),
1162 if (max_schema_name != NULL) {
1165 if (max_entry != NULL) {
1171 if ((max_schema_index < 1) || (max_schema_index > max_stable_schemas)) {
1172 max_schema_index = max_stable_schemas;
1175 entry = get_configured_schema(*xml);
1176 if (entry == NULL) {
1178 entry = known_schemas;
1180 original_schema = entry->data;
1181 if (original_schema->
schema_index >= max_schema_index) {
1186 for (; entry != NULL; entry = entry->next) {
1188 xmlNode *upgrade = NULL;
1194 if (!validate_with(*xml, current_schema, error_handler,
1195 GUINT_TO_POINTER(LOG_ERR))) {
1196 crm_debug(
"Schema %s does not validate", current_schema->
name);
1197 if (best_schema != NULL) {
1207 best_schema = current_schema;
1208 if (current_schema->
schema_index == max_schema_index) {
1212 if (!transform || (current_schema->
transform == NULL)
1213 || validate_with_silent(*xml, entry->next->data)) {
1221 upgrade = apply_upgrade(*xml, current_schema->
schema_index, to_logs);
1222 if (upgrade == NULL) {
1229 best_schema = current_schema;
1235 if (best_schema != NULL) {
1236 if ((original_schema == NULL)
1238 crm_info(
"%s the configuration schema to %s",
1239 (transform?
"Transformed" :
"Upgraded"),
1266 char *original_schema_name = NULL;
1269 const char *effective_original_name =
"the first";
1271 int orig_version = -1;
1273 GList *entry = NULL;
1280 if (entry != NULL) {
1283 effective_original_name = original_schema->
name;
1287 if (orig_version < x_0_schema->schema_index) {
1289 xmlNode *converted = NULL;
1290 const char *new_schema_name = NULL;
1300 schema = (entry == NULL)? NULL : entry->data;
1302 if ((schema == NULL)
1306 if ((orig_version == -1) || (schema == NULL)
1311 "%s schema) to at least %s because it " 1312 "does not validate with any schema from " 1314 pcmk__s(original_schema_name,
"no"),
1315 x_0_schema->
name, effective_original_name);
1317 fprintf(stderr,
"Cannot upgrade configuration (claiming " 1318 "%s schema) to at least %s because it " 1319 "does not validate with any schema from " 1320 "%s to the latest\n",
1321 pcmk__s(original_schema_name,
"no"),
1322 x_0_schema->
name, effective_original_name);
1328 "%s schema) to at least %s because it " 1329 "would not upgrade past %s",
1330 pcmk__s(original_schema_name,
"no"),
1332 pcmk__s(new_schema_name,
"unspecified version"));
1334 fprintf(stderr,
"Cannot upgrade configuration (claiming " 1335 "%s schema) to at least %s because it " 1336 "would not upgrade past %s\n",
1337 pcmk__s(original_schema_name,
"no"),
1339 pcmk__s(new_schema_name,
"unspecified version"));
1352 if (schema->
schema_index < xml_latest_schema_index()) {
1355 "internally upgraded to acceptable (but " 1356 "not most recent) %s",
1357 pcmk__s(original_schema_name,
"no"),
1360 }
else if (to_logs) {
1361 crm_info(
"Configuration with %s schema was internally " 1362 "upgraded to latest version %s",
1363 pcmk__s(original_schema_name,
"no"),
1373 pcmk__assert((entry != NULL) && (entry->data != NULL));
1375 none_schema = entry->data;
1376 if (!to_logs && (orig_version >= none_schema->
schema_index)) {
1377 fprintf(stderr,
"Schema validation of configuration is " 1380 " and will be removed in a future release)\n");
1384 free(original_schema_name);
1406 if (!version_from_filename(
name, &ver)) {
1410 for (GList *iter = g_list_nth(known_schemas, xml_latest_schema_index());
1411 iter != NULL; iter = iter->prev) {
1415 if (schema_cmp(ver, schema->
version) != -1) {
1420 lst = g_list_prepend(lst, s);
1424 lst = g_list_prepend(lst, xform);
1430 lst = g_list_prepend(lst, enter);
1433 int last_dash = strrchr(enter,
'-') - enter;
1436 lst = g_list_prepend(lst, leave);
1445 append_href(xmlNode *xml,
void *user_data)
1447 GList **list = user_data;
1453 *list = g_list_prepend(*list, href);
1457 external_refs_in_schema(GList **list,
const char *contents)
1462 const char *search =
"//*[local-name()='externalRef'] | //*[local-name()='include']";
1470 read_file_contents(
const char *file,
char **contents)
1488 add_schema_file_to_xml(xmlNode *
parent,
const char *file, GList **already_included)
1490 char *contents = NULL;
1492 xmlNode *file_node = NULL;
1493 GList *includes = NULL;
1497 if (g_list_find_custom(*already_included, file, (GCompareFunc) strcmp) != NULL) {
1510 rc = read_file_contents(
path, &contents);
1522 *already_included = g_list_prepend(*already_included,
path);
1524 xmlAddChild(file_node, xmlNewCDataBlock(
parent->doc, (
pcmkXmlStr) contents,
1530 external_refs_in_schema(&includes, contents);
1535 for (GList *iter = includes; iter != NULL; iter = iter->next) {
1536 add_schema_file_to_xml(
parent, iter->data, already_included);
1540 g_list_free_full(includes, free);
1563 add_schema_file_to_xml(schema_node,
name, already_included);
1565 if (schema_node->children == NULL) {
1581 if (pcmk__str_empty(dir)) {
1597 if ((schema == NULL) ||
1600 "deprecated and will be removed in a future release " 1601 "without the possibility of upgrades (manually edit " 1602 "to use a supported schema)", pcmk__s(schema,
""));
1622 return (schema != NULL)? schema->
name :
"unknown";
1634 for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
1653 if ((best != NULL) && (xml != NULL) && (rc ==
pcmk_rc_ok)) {
1658 if (schema_entry != NULL) {
1670 to_logs? (xmlRelaxNGValidityErrorFunc) xml_log : NULL,
1671 GUINT_TO_POINTER(LOG_ERR));
1672 return rc? TRUE : FALSE;
1676 dump_file(
const char *filename)
1684 fp = fopen(filename,
"r");
1686 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
1690 fprintf(stderr,
"%4d ", ++line);
1696 }
else if (ch ==
'\n') {
1697 fprintf(stderr,
"\n%4d ", ++line);
1711 xmlNode *xml = NULL;
1712 gboolean rc = FALSE;
1713 char *filename = NULL;
1717 umask(S_IWGRP | S_IWOTH | S_IROTH);
1718 fd = mkstemp(filename);
1721 dump_file(filename);
1723 doc = xmlReadFile(filename, NULL, 0);
1724 xml = xmlDocGetRootElement(doc);
1731 return rc? TRUE : FALSE;
1739 if (best_version != NULL) {
1748 *best_version = (schema == NULL)? -1 : schema->
schema_index;
char * pcmk__xml_artefact_root(enum pcmk__xml_artefact_ns ns)
int pcmk_update_configured_schema(xmlNode **xml)
#define CRM_CHECK(expr, failure_action)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
void crm_schema_init(void)
#define schema_strdup_printf(prefix, version, suffix)
bool pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidityErrorFunc error_handler, void *error_handler_context)
int pcmk_rc2legacy(int rc)
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
int pcmk__cmp_schemas_by_name(const char *schema1_name, const char *schema2_name)
const char * pcmk__highest_schema_name(void)
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
int pcmk__update_configured_schema(xmlNode **xml, bool to_logs)
Update XML from its configured schema to the latest major series.
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
bool pcmk__ends_with(const char *s, const char *match)
const char * pcmk__env_option(const char *option)
Deprecated Pacemaker XML API.
const char * pcmk__remote_schema_dir(void)
void pcmk__build_schema_xml_node(xmlNode *parent, const char *name, GList **already_included)
#define crm_warn(fmt, args...)
int get_schema_version(const char *name)
#define crm_debug(fmt, args...)
G_GNUC_INTERNAL void pcmk__xml_new_private_data(xmlNode *xml)
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.
#define PCMK__XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap)
Base for directing lib{xml2,xslt} log into standard libqb backend.
gboolean validate_xml_verbose(const xmlNode *xml_blob)
GList * pcmk__get_schema(const char *name)
void crm_schema_cleanup(void)
#define crm_trace(fmt, args...)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define crm_log_xml_debug(xml, text)
const char * get_schema_name(int version)
bool pcmk__configured_schema_validates(xmlNode *xml)
Wrappers for and extensions to libxml2.
enum pcmk__schema_validator validator
void free_xml(xmlNode *child)
int update_validation(xmlNode **xml, int *best, int max, gboolean transform, gboolean to_logs)
#define pcmk__str_copy(str)
#define PCMK_XA_VALIDATE_WITH
xmlNode * pcmk__xml_parse(const char *input)
#define PCMK__ENV_REMOTE_SCHEMA_DIRECTORY
const xmlChar * pcmkXmlStr
#define pcmk__assert(expr)
const char * pcmk__get_tmpdir(void)
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
unsigned int crm_log_level
int pcmk__file_contents(const char *filename, char **contents)
void pcmk__load_schemas_from_dir(const char *dir)
GList * pcmk__schema_files_later_than(const char *name)
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
#define crm_err(fmt, args...)
void pcmk__warn_if_schema_deprecated(const char *schema)
pcmk__schema_version_t version
void crm_foreach_xpath_result(xmlNode *xml, const char *xpath, void(*helper)(xmlNode *, void *), void *user_data)
Run a supplied function for each result of an xpath search.
int pcmk__update_schema(xmlNode **xml, const char *max_schema_name, bool transform, bool to_logs)
Update CIB XML to latest schema that validates it.
gboolean cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
int pcmk__xml_write_fd(const xmlNode *xml, const char *filename, int fd, bool compress, unsigned int *nbytes)
GList * pcmk__find_x_0_schema(void)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
char * pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns, const char *filespec)
#define pcmk__assert_alloc(nmemb, size)
void pcmk__sort_schemas(void)
#define PCMK__REMOTE_SCHEMA_DIR
#define crm_info(fmt, args...)
bool pcmk__ends_with_ext(const char *s, const char *match)
const char * xml_latest_schema(void)