Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/lib/common/schemas.c b/lib/common/schemas.c
index 9222acba09..fc895daa2a 100644
--- a/lib/common/schemas.c
+++ b/lib/common/schemas.c
@@ -1,958 +1,963 @@
/*
* Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <libxml/relaxng.h>
#if HAVE_LIBXSLT
# include <libxslt/xslt.h>
# include <libxslt/transform.h>
# include <libxslt/xsltutils.h>
#endif
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/xml_internal.h> /* CRM_XML_LOG_BASE */
typedef struct {
unsigned char v[2];
} schema_version_t;
#define SCHEMA_ZERO { .v = { 0, 0 } }
#define schema_scanf(s, prefix, version, suffix) \
sscanf((s), prefix "%hhu.%hhu" suffix, &((version).v[0]), &((version).v[1]))
#define schema_strdup_printf(prefix, version, suffix) \
crm_strdup_printf(prefix "%u.%u" suffix, (version).v[0], (version).v[1])
typedef struct {
xmlRelaxNGPtr rng;
xmlRelaxNGValidCtxtPtr valid;
xmlRelaxNGParserCtxtPtr parser;
} relaxng_ctx_cache_t;
enum schema_validator_e {
schema_validator_none,
schema_validator_rng
};
struct schema_s {
char *name;
char *location;
char *transform;
void *cache;
enum schema_validator_e validator;
int after_transform;
schema_version_t version;
};
static struct schema_s *known_schemas = NULL;
static int xml_schema_max = 0;
static void
xml_log(int priority, const char *fmt, ...)
G_GNUC_PRINTF(2, 3);
static void
xml_log(int priority, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
/* XXX should not this enable dechunking as well? */
CRM_XML_LOG_BASE(priority, FALSE, 0, NULL, fmt, ap);
va_end(ap);
}
static int
xml_latest_schema_index(void)
{
return xml_schema_max - 3; // index from 0, ignore "pacemaker-next"/"none"
}
static int
xml_minimum_schema_index(void)
{
static int best = 0;
if (best == 0) {
int lpc = 0;
best = xml_latest_schema_index();
for (lpc = best; lpc > 0; lpc--) {
if (known_schemas[lpc].version.v[0]
< known_schemas[best].version.v[0]) {
return best;
} else {
best = lpc;
}
}
best = xml_latest_schema_index();
}
return best;
}
const char *
xml_latest_schema(void)
{
return get_schema_name(xml_latest_schema_index());
}
static const char *
get_schema_root(void)
{
static const char *base = NULL;
if (base == NULL) {
base = getenv("PCMK_schema_directory");
}
if (base == NULL || strlen(base) == 0) {
base = CRM_SCHEMA_DIRECTORY;
}
return base;
}
static char *
get_schema_path(const char *name, const char *file)
{
const char *base = get_schema_root();
if (file) {
return crm_strdup_printf("%s/%s", base, file);
}
return crm_strdup_printf("%s/%s.rng", base, name);
}
static inline bool
version_from_filename(const char *filename, schema_version_t *version)
{
int rc = schema_scanf(filename, "pacemaker-", *version, ".rng");
return (rc == 2);
}
static int
schema_filter(const struct dirent *a)
{
int rc = 0;
schema_version_t version = SCHEMA_ZERO;
if (strstr(a->d_name, "pacemaker-") != a->d_name) {
/* crm_trace("%s - wrong prefix", a->d_name); */
} else if (!crm_ends_with_ext(a->d_name, ".rng")) {
/* crm_trace("%s - wrong suffix", a->d_name); */
} else if (!version_from_filename(a->d_name, &version)) {
/* crm_trace("%s - wrong format", a->d_name); */
} else {
/* crm_debug("%s - candidate", a->d_name); */
rc = 1;
}
return rc;
}
static int
schema_sort(const struct dirent **a, const struct dirent **b)
{
schema_version_t a_version = SCHEMA_ZERO;
schema_version_t b_version = SCHEMA_ZERO;
if (!version_from_filename(a[0]->d_name, &a_version)
|| !version_from_filename(b[0]->d_name, &b_version)) {
// Shouldn't be possible, but makes static analysis happy
return 0;
}
for (int i = 0; i < 2; ++i) {
if (a_version.v[i] < b_version.v[i]) {
return -1;
} else if (a_version.v[i] > b_version.v[i]) {
return 1;
}
}
return 0;
}
static void
add_schema(enum schema_validator_e validator, const schema_version_t *version,
const char *name, const char *location, const char *transform,
int after_transform)
{
int last = xml_schema_max;
bool have_version = FALSE;
xml_schema_max++;
known_schemas = realloc_safe(known_schemas,
xml_schema_max * sizeof(struct schema_s));
CRM_ASSERT(known_schemas != NULL);
memset(known_schemas+last, 0, sizeof(struct schema_s));
known_schemas[last].validator = validator;
known_schemas[last].after_transform = after_transform;
for (int i = 0; i < 2; ++i) {
known_schemas[last].version.v[i] = version->v[i];
if (version->v[i]) {
have_version = TRUE;
}
}
if (have_version) {
known_schemas[last].name = schema_strdup_printf("pacemaker-", *version, "");
known_schemas[last].location = crm_strdup_printf("%s.rng",
known_schemas[last].name);
} else {
CRM_ASSERT(name);
CRM_ASSERT(location);
schema_scanf(name, "%*[^-]-", known_schemas[last].version, "");
known_schemas[last].name = strdup(name);
known_schemas[last].location = strdup(location);
}
if (transform) {
known_schemas[last].transform = strdup(transform);
}
if (after_transform == 0) {
after_transform = xml_schema_max; /* upgrade is a one-way */
}
known_schemas[last].after_transform = after_transform;
if (known_schemas[last].after_transform < 0) {
crm_debug("Added supported schema %d: %s (%s)",
last, known_schemas[last].name, known_schemas[last].location);
} else if (known_schemas[last].transform) {
crm_debug("Added supported schema %d: %s (%s upgrades to %d with %s)",
last, known_schemas[last].name, known_schemas[last].location,
known_schemas[last].after_transform,
known_schemas[last].transform);
} else {
crm_debug("Added supported schema %d: %s (%s upgrades to %d)",
last, known_schemas[last].name, known_schemas[last].location,
known_schemas[last].after_transform);
}
}
/*!
* \internal
* \brief Load pacemaker schemas into cache
*/
void
crm_schema_init(void)
{
int lpc, max;
const char *base = get_schema_root();
struct dirent **namelist = NULL;
const schema_version_t zero = SCHEMA_ZERO;
max = scandir(base, &namelist, schema_filter, schema_sort);
if (max < 0) {
crm_notice("scandir(%s) failed: %s (%d)", base, strerror(errno), errno);
} else {
for (lpc = 0; lpc < max; lpc++) {
int next = 0;
schema_version_t version = SCHEMA_ZERO;
char *transform = NULL;
if (!version_from_filename(namelist[lpc]->d_name, &version)) {
// Shouldn't be possible, but makes static analysis happy
crm_err("Skipping schema '%s': could not parse version",
namelist[lpc]->d_name);
continue;
}
if ((lpc + 1) < max) {
schema_version_t next_version = SCHEMA_ZERO;
if (version_from_filename(namelist[lpc+1]->d_name, &next_version)
&& (version.v[0] < next_version.v[0])) {
struct stat s;
char *xslt = NULL;
transform = schema_strdup_printf("upgrade-", version, ".xsl");
xslt = get_schema_path(NULL, transform);
if (stat(xslt, &s) != 0) {
crm_err("Transform %s not found", xslt);
free(xslt);
add_schema(schema_validator_rng, &version, NULL, NULL,
NULL, -1);
break;
} else {
free(xslt);
}
}
} else {
next = -1;
}
add_schema(schema_validator_rng, &version, NULL, NULL, transform,
next);
free(transform);
}
for (lpc = 0; lpc < max; lpc++) {
free(namelist[lpc]);
}
free(namelist);
}
add_schema(schema_validator_rng, &zero, "pacemaker-next",
"pacemaker-next.rng", NULL, -1);
add_schema(schema_validator_none, &zero, "none",
"N/A", NULL, -1);
}
#if 0
static void
relaxng_invalid_stderr(void *userData, xmlErrorPtr error)
{
/*
Structure xmlError
struct _xmlError {
int domain : What part of the library raised this er
int code : The error code, e.g. an xmlParserError
char * message : human-readable informative error messag
xmlErrorLevel level : how consequent is the error
char * file : the filename
int line : the line number if available
char * str1 : extra string information
char * str2 : extra string information
char * str3 : extra string information
int int1 : extra number information
int int2 : column number of the error or 0 if N/A
void * ctxt : the parser context if available
void * node : the node in the tree
}
*/
crm_err("Structured error: line=%d, level=%d %s", error->line, error->level, error->message);
}
#endif
static gboolean
validate_with_relaxng(xmlDocPtr doc, gboolean to_logs, const char *relaxng_file,
relaxng_ctx_cache_t **cached_ctx)
{
int rc = 0;
gboolean valid = TRUE;
relaxng_ctx_cache_t *ctx = NULL;
CRM_CHECK(doc != NULL, return FALSE);
CRM_CHECK(relaxng_file != NULL, return FALSE);
if (cached_ctx && *cached_ctx) {
ctx = *cached_ctx;
} else {
crm_info("Creating RNG parser context");
ctx = calloc(1, sizeof(relaxng_ctx_cache_t));
xmlLoadExtDtdDefaultValue = 1;
ctx->parser = xmlRelaxNGNewParserCtxt(relaxng_file);
CRM_CHECK(ctx->parser != NULL, goto cleanup);
if (to_logs) {
xmlRelaxNGSetParserErrors(ctx->parser,
(xmlRelaxNGValidityErrorFunc) xml_log,
(xmlRelaxNGValidityWarningFunc) xml_log,
GUINT_TO_POINTER(LOG_ERR));
} else {
xmlRelaxNGSetParserErrors(ctx->parser,
(xmlRelaxNGValidityErrorFunc) fprintf,
(xmlRelaxNGValidityWarningFunc) fprintf,
stderr);
}
ctx->rng = xmlRelaxNGParse(ctx->parser);
CRM_CHECK(ctx->rng != NULL,
crm_err("Could not find/parse %s", relaxng_file);
goto cleanup);
ctx->valid = xmlRelaxNGNewValidCtxt(ctx->rng);
CRM_CHECK(ctx->valid != NULL, goto cleanup);
if (to_logs) {
xmlRelaxNGSetValidErrors(ctx->valid,
(xmlRelaxNGValidityErrorFunc) xml_log,
(xmlRelaxNGValidityWarningFunc) xml_log,
GUINT_TO_POINTER(LOG_ERR));
} else {
xmlRelaxNGSetValidErrors(ctx->valid,
(xmlRelaxNGValidityErrorFunc) fprintf,
(xmlRelaxNGValidityWarningFunc) fprintf,
stderr);
}
}
/* xmlRelaxNGSetValidStructuredErrors( */
/* valid, relaxng_invalid_stderr, valid); */
xmlLineNumbersDefault(1);
rc = xmlRelaxNGValidateDoc(ctx->valid, doc);
if (rc > 0) {
valid = FALSE;
} else if (rc < 0) {
crm_err("Internal libxml error during validation");
}
cleanup:
if (cached_ctx) {
*cached_ctx = ctx;
} else {
if (ctx->parser != NULL) {
xmlRelaxNGFreeParserCtxt(ctx->parser);
}
if (ctx->valid != NULL) {
xmlRelaxNGFreeValidCtxt(ctx->valid);
}
if (ctx->rng != NULL) {
xmlRelaxNGFree(ctx->rng);
}
free(ctx);
}
return valid;
}
/*!
* \internal
* \brief Clean up global memory associated with XML schemas
*/
void
crm_schema_cleanup(void)
{
int lpc;
relaxng_ctx_cache_t *ctx = NULL;
for (lpc = 0; lpc < xml_schema_max; lpc++) {
switch (known_schemas[lpc].validator) {
case schema_validator_none: // not cached
break;
case schema_validator_rng: // cached
ctx = (relaxng_ctx_cache_t *) known_schemas[lpc].cache;
if (ctx == NULL) {
break;
}
if (ctx->parser != NULL) {
xmlRelaxNGFreeParserCtxt(ctx->parser);
}
if (ctx->valid != NULL) {
xmlRelaxNGFreeValidCtxt(ctx->valid);
}
if (ctx->rng != NULL) {
xmlRelaxNGFree(ctx->rng);
}
free(ctx);
known_schemas[lpc].cache = NULL;
break;
}
free(known_schemas[lpc].name);
free(known_schemas[lpc].location);
free(known_schemas[lpc].transform);
}
free(known_schemas);
known_schemas = NULL;
+
+ xsltCleanupGlobals(); /* XXX proper, explicit reshaking regarding
+ init/fini routines is pending (pair
+ of facade functions to express the
+ intentions in a clean way) */
}
static gboolean
validate_with(xmlNode *xml, int method, gboolean to_logs)
{
xmlDocPtr doc = NULL;
gboolean valid = FALSE;
char *file = NULL;
if (method < 0) {
return FALSE;
}
if (known_schemas[method].validator == schema_validator_none) {
return TRUE;
}
CRM_CHECK(xml != NULL, return FALSE);
doc = getDocPtr(xml);
file = get_schema_path(known_schemas[method].name,
known_schemas[method].location);
crm_trace("Validating with: %s (type=%d)",
crm_str(file), known_schemas[method].validator);
switch (known_schemas[method].validator) {
case schema_validator_rng:
valid =
validate_with_relaxng(doc, to_logs, file,
(relaxng_ctx_cache_t **) & (known_schemas[method].cache));
break;
default:
crm_err("Unknown validator type: %d",
known_schemas[method].validator);
break;
}
free(file);
return valid;
}
static void
dump_file(const char *filename)
{
FILE *fp = NULL;
int ch, line = 0;
CRM_CHECK(filename != NULL, return);
fp = fopen(filename, "r");
if (fp == NULL) {
crm_perror(LOG_ERR, "Could not open %s for reading", filename);
return;
}
fprintf(stderr, "%4d ", ++line);
do {
ch = getc(fp);
if (ch == EOF) {
putc('\n', stderr);
break;
} else if (ch == '\n') {
fprintf(stderr, "\n%4d ", ++line);
} else {
putc(ch, stderr);
}
} while (1);
fclose(fp);
}
gboolean
validate_xml_verbose(xmlNode *xml_blob)
{
int fd = 0;
xmlDoc *doc = NULL;
xmlNode *xml = NULL;
gboolean rc = FALSE;
char *filename = NULL;
filename = crm_strdup_printf("%s/cib-invalid.XXXXXX", crm_get_tmpdir());
umask(S_IWGRP | S_IWOTH | S_IROTH);
fd = mkstemp(filename);
write_xml_fd(xml_blob, filename, fd, FALSE);
dump_file(filename);
doc = xmlParseFile(filename);
xml = xmlDocGetRootElement(doc);
rc = validate_xml(xml, NULL, FALSE);
free_xml(xml);
unlink(filename);
free(filename);
return rc;
}
gboolean
validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
{
int version = 0;
if (validation == NULL) {
validation = crm_element_value(xml_blob, XML_ATTR_VALIDATION);
}
if (validation == NULL) {
int lpc = 0;
bool valid = FALSE;
for (lpc = 0; lpc < xml_schema_max; lpc++) {
if (validate_with(xml_blob, lpc, FALSE)) {
valid = TRUE;
crm_xml_add(xml_blob, XML_ATTR_VALIDATION,
known_schemas[lpc].name);
crm_info("XML validated against %s", known_schemas[lpc].name);
if(known_schemas[lpc].after_transform == 0) {
break;
}
}
}
return valid;
}
version = get_schema_version(validation);
if (strcmp(validation, "none") == 0) {
return TRUE;
} else if (version < xml_schema_max) {
return validate_with(xml_blob, version, to_logs);
}
crm_err("Unknown validator: %s", validation);
return FALSE;
}
#if HAVE_LIBXSLT
static void
cib_upgrade_err(void *ctx, const char *fmt, ...)
G_GNUC_PRINTF(2, 3);
static void
cib_upgrade_err(void *ctx, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
CRM_XML_LOG_BASE(LOG_WARNING, TRUE, 0, "CIB upgrade: ", fmt, ap);
va_end(ap);
}
/* Denotes temporary emergency fix for "xmldiff'ing not text-node-ready";
proper fix is most likely to teach __xml_diff_object and friends to
deal with XML_TEXT_NODE (and more?), i.e., those nodes currently
missing "_private" field (implicitly as NULL) which clashes with
unchecked accesses (e.g. in __xml_offset) -- the outcome may be that
those unexpected XML nodes will simply be ignored for the purpose of
diff'ing, or it may be made more robust, or per the user's preference
(which then may be exposed as crm_diff switch).
Said XML_TEXT_NODE may appear unexpectedly due to how upgrade-2.10.xsl
is arranged.
The emergency fix is simple: reparse XSLT output with blank-ignoring
parser. */
#ifndef PCMK_SCHEMAS_EMERGENCY_XSLT
#define PCMK_SCHEMAS_EMERGENCY_XSLT 1
#endif
static xmlNode *
apply_transformation(xmlNode *xml, const char *transform, gboolean to_logs)
{
char *xform = NULL;
xmlNode *out = NULL;
xmlDocPtr res = NULL;
xmlDocPtr doc = NULL;
xsltStylesheet *xslt = NULL;
#if PCMK_SCHEMAS_EMERGENCY_XSLT != 0
xmlChar *emergency_result;
int emergency_txt_len;
int emergency_res;
#endif
CRM_CHECK(xml != NULL, return FALSE);
doc = getDocPtr(xml);
xform = get_schema_path(NULL, transform);
xmlLoadExtDtdDefaultValue = 1;
xmlSubstituteEntitiesDefault(1);
/* for capturing, e.g., what's emitted via <xsl:message> */
if (to_logs) {
xsltSetGenericErrorFunc(NULL, cib_upgrade_err);
} else {
xsltSetGenericErrorFunc((void *) stderr, (xmlGenericErrorFunc) fprintf);
}
xslt = xsltParseStylesheetFile((const xmlChar *)xform);
CRM_CHECK(xslt != NULL, goto cleanup);
res = xsltApplyStylesheet(xslt, doc, NULL);
CRM_CHECK(res != NULL, goto cleanup);
xsltSetGenericErrorFunc(NULL, NULL); /* restore default one */
#if PCMK_SCHEMAS_EMERGENCY_XSLT != 0
emergency_res = xsltSaveResultToString(&emergency_result,
&emergency_txt_len, res, xslt);
xmlFreeDoc(res);
CRM_CHECK(emergency_res == 0, goto cleanup);
out = string2xml((const char *) emergency_result);
free(emergency_result);
#else
out = xmlDocGetRootElement(res);
#endif
cleanup:
if (xslt) {
xsltFreeStylesheet(xslt);
}
free(xform);
return out;
}
#endif
const char *
get_schema_name(int version)
{
if (version < 0 || version >= xml_schema_max) {
return "unknown";
}
return known_schemas[version].name;
}
int
get_schema_version(const char *name)
{
int lpc = 0;
if (name == NULL) {
name = "none";
}
for (; lpc < xml_schema_max; lpc++) {
if (safe_str_eq(name, known_schemas[lpc].name)) {
return lpc;
}
}
return -1;
}
/* set which validation to use */
int
update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
gboolean to_logs)
{
xmlNode *xml = NULL;
char *value = NULL;
int max_stable_schemas = xml_latest_schema_index();
int lpc = 0, match = -1, rc = pcmk_ok;
int next = -1; /* -1 denotes "inactive" value */
CRM_CHECK(best != NULL, return -EINVAL);
*best = 0;
CRM_CHECK(xml_blob != NULL, return -EINVAL);
CRM_CHECK(*xml_blob != NULL, return -EINVAL);
xml = *xml_blob;
value = crm_element_value_copy(xml, XML_ATTR_VALIDATION);
if (value != NULL) {
match = get_schema_version(value);
lpc = match;
if (lpc >= 0 && transform == FALSE) {
*best = lpc++;
} else if (lpc < 0) {
crm_debug("Unknown validation schema");
lpc = 0;
}
}
if (match >= max_stable_schemas) {
/* nothing to do */
free(value);
*best = match;
return pcmk_ok;
}
while (lpc <= max_stable_schemas) {
crm_debug("Testing '%s' validation (%d of %d)",
known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>",
lpc, max_stable_schemas);
if (validate_with(xml, lpc, to_logs) == FALSE) {
if (next != -1) {
crm_info("Configuration not valid for schema: %s",
known_schemas[lpc].name);
next = -1;
} else {
crm_trace("%s validation failed",
known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>");
}
if (*best) {
/* we've satisfied the validation, no need to check further */
break;
}
rc = -pcmk_err_schema_validation;
} else {
if (next != -1) {
crm_debug("Configuration valid for schema: %s",
known_schemas[next].name);
next = -1;
}
rc = pcmk_ok;
}
if (rc == pcmk_ok) {
*best = lpc;
}
if (rc == pcmk_ok && transform) {
xmlNode *upgrade = NULL;
next = known_schemas[lpc].after_transform;
if (next <= lpc) {
/* There is no next version, or next would regress */
crm_trace("Stopping at %s", known_schemas[lpc].name);
break;
} else if (max > 0 && (lpc == max || next > max)) {
crm_trace("Upgrade limit reached at %s (lpc=%d, next=%d, max=%d)",
known_schemas[lpc].name, lpc, next, max);
break;
} else if (known_schemas[lpc].transform == NULL) {
crm_debug("%s-style configuration is also valid for %s",
known_schemas[lpc].name, known_schemas[next].name);
lpc = next;
} else {
crm_debug("Upgrading %s-style configuration to %s with %s",
known_schemas[lpc].name, known_schemas[next].name,
known_schemas[lpc].transform ? known_schemas[lpc].transform : "no-op");
#if HAVE_LIBXSLT
upgrade = apply_transformation(xml, known_schemas[lpc].transform, to_logs);
#endif
if (upgrade == NULL) {
crm_err("Transformation %s failed",
known_schemas[lpc].transform);
rc = -pcmk_err_transform_failed;
} else if (validate_with(upgrade, next, to_logs)) {
crm_info("Transformation %s successful",
known_schemas[lpc].transform);
lpc = next;
*best = next;
free_xml(xml);
xml = upgrade;
rc = pcmk_ok;
} else {
crm_err("Transformation %s did not produce a valid configuration",
known_schemas[lpc].transform);
crm_log_xml_info(upgrade, "transform:bad");
free_xml(upgrade);
rc = -pcmk_err_schema_validation;
}
next = -1;
}
}
if (transform == FALSE || rc != pcmk_ok) {
/* we need some progress! */
lpc++;
}
}
if (*best > match && *best) {
crm_info("%s the configuration from %s to %s",
transform?"Transformed":"Upgraded",
value ? value : "<none>", known_schemas[*best].name);
crm_xml_add(xml, XML_ATTR_VALIDATION, known_schemas[*best].name);
}
*xml_blob = xml;
free(value);
return rc;
}
gboolean
cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
{
gboolean rc = TRUE;
const char *value = crm_element_value(*xml, XML_ATTR_VALIDATION);
char *const orig_value = strdup(value == NULL ? "(none)" : value);
int version = get_schema_version(value);
int orig_version = version;
int min_version = xml_minimum_schema_index();
if (version < min_version) {
xmlNode *converted = NULL;
converted = copy_xml(*xml);
update_validation(&converted, &version, 0, TRUE, to_logs);
value = crm_element_value(converted, XML_ATTR_VALIDATION);
if (version < min_version) {
if (version < orig_version || orig_version == -1) {
if (to_logs) {
crm_config_err("Your current configuration %s could not"
" validate with any schema in range [%s, %s],"
" cannot upgrade to %s.",
orig_value,
get_schema_name(orig_version),
xml_latest_schema(),
get_schema_name(min_version));
} else {
fprintf(stderr, "Your current configuration %s could not"
" validate with any schema in range [%s, %s],"
" cannot upgrade to %s.\n",
orig_value,
get_schema_name(orig_version),
xml_latest_schema(),
get_schema_name(min_version));
}
} else if (to_logs) {
crm_config_err("Your current configuration could only be upgraded to %s... "
"the minimum requirement is %s.", crm_str(value),
get_schema_name(min_version));
} else {
fprintf(stderr, "Your current configuration could only be upgraded to %s... "
"the minimum requirement is %s.\n",
crm_str(value), get_schema_name(min_version));
}
free_xml(converted);
converted = NULL;
rc = FALSE;
} else {
free_xml(*xml);
*xml = converted;
if (version < xml_latest_schema_index()) {
crm_config_warn("Your configuration was internally updated to %s... "
"which is acceptable but not the most recent",
get_schema_name(version));
} else if (to_logs) {
crm_info("Your configuration was internally updated to the latest version (%s)",
get_schema_name(version));
}
}
} else if (version >= get_schema_version("none")) {
if (to_logs) {
crm_config_warn("Configuration validation is currently disabled."
" It is highly encouraged and prevents many common cluster issues.");
} else {
fprintf(stderr, "Configuration validation is currently disabled."
" It is highly encouraged and prevents many common cluster issues.\n");
}
}
if (best_version) {
*best_version = version;
}
free(orig_value);
return rc;
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 25, 3:39 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952054
Default Alt Text
(29 KB)

Event Timeline