|
rpm-build |
3ee90c |
/*
|
|
rpm-build |
3ee90c |
* Copyright 2004-2019 the Pacemaker project contributors
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* The version control history for this file may have further details.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* This source code is licensed under the GNU Lesser General Public License
|
|
rpm-build |
3ee90c |
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#include <crm_internal.h>
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#include <stdio.h>
|
|
rpm-build |
3ee90c |
#include <string.h>
|
|
rpm-build |
3ee90c |
#include <dirent.h>
|
|
rpm-build |
3ee90c |
#include <errno.h>
|
|
rpm-build |
3ee90c |
#include <sys/stat.h>
|
|
rpm-build |
3ee90c |
#include <stdarg.h>
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#include <libxml/relaxng.h>
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#if HAVE_LIBXSLT
|
|
rpm-build |
3ee90c |
# include <libxslt/xslt.h>
|
|
rpm-build |
3ee90c |
# include <libxslt/transform.h>
|
|
rpm-build |
3ee90c |
# include <libxslt/security.h>
|
|
rpm-build |
3ee90c |
# include <libxslt/xsltutils.h>
|
|
rpm-build |
3ee90c |
#endif
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#include <crm/msg_xml.h>
|
|
rpm-build |
3ee90c |
#include <crm/common/xml.h>
|
|
rpm-build |
3ee90c |
#include <crm/common/xml_internal.h> /* CRM_XML_LOG_BASE */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
typedef struct {
|
|
rpm-build |
3ee90c |
unsigned char v[2];
|
|
rpm-build |
3ee90c |
} schema_version_t;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#define SCHEMA_ZERO { .v = { 0, 0 } }
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#define schema_scanf(s, prefix, version, suffix) \
|
|
rpm-build |
3ee90c |
sscanf((s), prefix "%hhu.%hhu" suffix, &((version).v[0]), &((version).v[1]))
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#define schema_strdup_printf(prefix, version, suffix) \
|
|
rpm-build |
3ee90c |
crm_strdup_printf(prefix "%u.%u" suffix, (version).v[0], (version).v[1])
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
typedef struct {
|
|
rpm-build |
3ee90c |
xmlRelaxNGPtr rng;
|
|
rpm-build |
3ee90c |
xmlRelaxNGValidCtxtPtr valid;
|
|
rpm-build |
3ee90c |
xmlRelaxNGParserCtxtPtr parser;
|
|
rpm-build |
3ee90c |
} relaxng_ctx_cache_t;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
enum schema_validator_e {
|
|
rpm-build |
3ee90c |
schema_validator_none,
|
|
rpm-build |
3ee90c |
schema_validator_rng
|
|
rpm-build |
3ee90c |
};
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
struct schema_s {
|
|
rpm-build |
3ee90c |
char *name;
|
|
rpm-build |
3ee90c |
char *transform;
|
|
rpm-build |
3ee90c |
void *cache;
|
|
rpm-build |
3ee90c |
enum schema_validator_e validator;
|
|
rpm-build |
3ee90c |
int after_transform;
|
|
rpm-build |
3ee90c |
schema_version_t version;
|
|
rpm-build |
3ee90c |
char *transform_enter;
|
|
rpm-build |
3ee90c |
bool transform_onleave;
|
|
rpm-build |
3ee90c |
};
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static struct schema_s *known_schemas = NULL;
|
|
rpm-build |
3ee90c |
static int xml_schema_max = 0;
|
|
rpm-build |
3ee90c |
static bool silent_logging = FALSE;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static void
|
|
rpm-build |
3ee90c |
xml_log(int priority, const char *fmt, ...)
|
|
rpm-build |
3ee90c |
G_GNUC_PRINTF(2, 3);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static void
|
|
rpm-build |
3ee90c |
xml_log(int priority, const char *fmt, ...)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
va_list ap;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
va_start(ap, fmt);
|
|
rpm-build |
3ee90c |
if (silent_logging == FALSE) {
|
|
rpm-build |
3ee90c |
/* XXX should not this enable dechunking as well? */
|
|
rpm-build |
3ee90c |
CRM_XML_LOG_BASE(priority, FALSE, 0, NULL, fmt, ap);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
va_end(ap);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static int
|
|
rpm-build |
3ee90c |
xml_latest_schema_index(void)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
return xml_schema_max - 3; // index from 0, ignore "pacemaker-next"/"none"
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static int
|
|
rpm-build |
3ee90c |
xml_minimum_schema_index(void)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
static int best = 0;
|
|
rpm-build |
3ee90c |
if (best == 0) {
|
|
rpm-build |
3ee90c |
int lpc = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
best = xml_latest_schema_index();
|
|
rpm-build |
3ee90c |
for (lpc = best; lpc > 0; lpc--) {
|
|
rpm-build |
3ee90c |
if (known_schemas[lpc].version.v[0]
|
|
rpm-build |
3ee90c |
< known_schemas[best].version.v[0]) {
|
|
rpm-build |
3ee90c |
return best;
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
best = lpc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
best = xml_latest_schema_index();
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
return best;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
const char *
|
|
rpm-build |
3ee90c |
xml_latest_schema(void)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
return get_schema_name(xml_latest_schema_index());
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static inline bool
|
|
rpm-build |
3ee90c |
version_from_filename(const char *filename, schema_version_t *version)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int rc = schema_scanf(filename, "pacemaker-", *version, ".rng");
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return (rc == 2);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static int
|
|
rpm-build |
3ee90c |
schema_filter(const struct dirent *a)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int rc = 0;
|
|
rpm-build |
3ee90c |
schema_version_t version = SCHEMA_ZERO;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (strstr(a->d_name, "pacemaker-") != a->d_name) {
|
|
rpm-build |
3ee90c |
/* crm_trace("%s - wrong prefix", a->d_name); */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (!crm_ends_with_ext(a->d_name, ".rng")) {
|
|
rpm-build |
3ee90c |
/* crm_trace("%s - wrong suffix", a->d_name); */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (!version_from_filename(a->d_name, &version)) {
|
|
rpm-build |
3ee90c |
/* crm_trace("%s - wrong format", a->d_name); */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
/* crm_debug("%s - candidate", a->d_name); */
|
|
rpm-build |
3ee90c |
rc = 1;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return rc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static int
|
|
rpm-build |
3ee90c |
schema_sort(const struct dirent **a, const struct dirent **b)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
schema_version_t a_version = SCHEMA_ZERO;
|
|
rpm-build |
3ee90c |
schema_version_t b_version = SCHEMA_ZERO;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (!version_from_filename(a[0]->d_name, &a_version)
|
|
rpm-build |
3ee90c |
|| !version_from_filename(b[0]->d_name, &b_version)) {
|
|
rpm-build |
3ee90c |
// Shouldn't be possible, but makes static analysis happy
|
|
rpm-build |
3ee90c |
return 0;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (int i = 0; i < 2; ++i) {
|
|
rpm-build |
3ee90c |
if (a_version.v[i] < b_version.v[i]) {
|
|
rpm-build |
3ee90c |
return -1;
|
|
rpm-build |
3ee90c |
} else if (a_version.v[i] > b_version.v[i]) {
|
|
rpm-build |
3ee90c |
return 1;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
return 0;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/*!
|
|
rpm-build |
3ee90c |
* \internal
|
|
rpm-build |
3ee90c |
* \brief Add given schema + auxiliary data to internal bookkeeping.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* \note When providing \p version, should not be called directly but
|
|
rpm-build |
3ee90c |
* through \c add_schema_by_version.
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
static void
|
|
rpm-build |
3ee90c |
add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
rpm-build |
3ee90c |
const char *name, const char *transform,
|
|
rpm-build |
3ee90c |
const char *transform_enter, bool transform_onleave,
|
|
rpm-build |
3ee90c |
int after_transform)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int last = xml_schema_max;
|
|
rpm-build |
3ee90c |
bool have_version = FALSE;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xml_schema_max++;
|
|
rpm-build |
3ee90c |
known_schemas = realloc_safe(known_schemas,
|
|
rpm-build |
3ee90c |
xml_schema_max * sizeof(struct schema_s));
|
|
rpm-build |
3ee90c |
CRM_ASSERT(known_schemas != NULL);
|
|
rpm-build |
3ee90c |
memset(known_schemas+last, 0, sizeof(struct schema_s));
|
|
rpm-build |
3ee90c |
known_schemas[last].validator = validator;
|
|
rpm-build |
3ee90c |
known_schemas[last].after_transform = after_transform;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (int i = 0; i < 2; ++i) {
|
|
rpm-build |
3ee90c |
known_schemas[last].version.v[i] = version->v[i];
|
|
rpm-build |
3ee90c |
if (version->v[i]) {
|
|
rpm-build |
3ee90c |
have_version = TRUE;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (have_version) {
|
|
rpm-build |
3ee90c |
known_schemas[last].name = schema_strdup_printf("pacemaker-", *version, "");
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
CRM_ASSERT(name);
|
|
rpm-build |
3ee90c |
schema_scanf(name, "%*[^-]-", known_schemas[last].version, "");
|
|
rpm-build |
3ee90c |
known_schemas[last].name = strdup(name);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (transform) {
|
|
rpm-build |
3ee90c |
known_schemas[last].transform = strdup(transform);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (transform_enter) {
|
|
rpm-build |
3ee90c |
known_schemas[last].transform_enter = strdup(transform_enter);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
known_schemas[last].transform_onleave = transform_onleave;
|
|
rpm-build |
3ee90c |
if (after_transform == 0) {
|
|
rpm-build |
3ee90c |
after_transform = xml_schema_max; /* upgrade is a one-way */
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
known_schemas[last].after_transform = after_transform;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (known_schemas[last].after_transform < 0) {
|
|
rpm-build |
3ee90c |
crm_debug("Added supported schema %d: %s",
|
|
rpm-build |
3ee90c |
last, known_schemas[last].name);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (known_schemas[last].transform) {
|
|
rpm-build |
3ee90c |
crm_debug("Added supported schema %d: %s (upgrades to %d with %s.xsl)",
|
|
rpm-build |
3ee90c |
last, known_schemas[last].name,
|
|
rpm-build |
3ee90c |
known_schemas[last].after_transform,
|
|
rpm-build |
3ee90c |
known_schemas[last].transform);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
crm_debug("Added supported schema %d: %s (upgrades to %d)",
|
|
rpm-build |
3ee90c |
last, known_schemas[last].name,
|
|
rpm-build |
3ee90c |
known_schemas[last].after_transform);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/*!
|
|
rpm-build |
3ee90c |
* \internal
|
|
rpm-build |
3ee90c |
* \brief Add version-specified schema + auxiliary data to internal bookkeeping.
|
|
rpm-build |
3ee90c |
* \return \c -ENOENT when no upgrade schema associated, \c pcmk_ok otherwise.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* \note There's no reliance on the particular order of schemas entering here.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* \par A bit of theory
|
|
rpm-build |
3ee90c |
* We track 3 XSLT stylesheets that differ per usage:
|
|
rpm-build |
3ee90c |
* - "upgrade":
|
|
rpm-build |
3ee90c |
* . sparsely spread over the sequence of all available schemas,
|
|
rpm-build |
3ee90c |
* as they are only relevant when major version of the schema
|
|
rpm-build |
3ee90c |
* is getting bumped -- in that case, it MUST be set
|
|
rpm-build |
3ee90c |
* . name convention: upgrade-X.Y.xsl
|
|
rpm-build |
3ee90c |
* - "upgrade-enter":
|
|
rpm-build |
3ee90c |
* . may only accompany "upgrade" occurrence, but doesn't need to
|
|
rpm-build |
3ee90c |
* be present anytime such one is, i.e., it MAY not be set when
|
|
rpm-build |
3ee90c |
* "upgrade" is
|
|
rpm-build |
3ee90c |
* . name convention: upgrade-X.Y-enter.xsl,
|
|
rpm-build |
3ee90c |
* when not present: upgrade-enter.xsl
|
|
rpm-build |
3ee90c |
* - "upgrade-leave":
|
|
rpm-build |
3ee90c |
* . like "upgrade-enter", but SHOULD be present whenever
|
|
rpm-build |
3ee90c |
* "upgrade-enter" is (and vice versa, but that's only
|
|
rpm-build |
3ee90c |
* to prevent confusion based on observing the files,
|
|
rpm-build |
3ee90c |
* it would get ignored regardless)
|
|
rpm-build |
3ee90c |
* . name convention: (see "upgrade-enter")
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
static int
|
|
rpm-build |
3ee90c |
add_schema_by_version(const schema_version_t *version, int next,
|
|
rpm-build |
3ee90c |
bool transform_expected)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
bool transform_onleave = FALSE;
|
|
rpm-build |
3ee90c |
int rc = pcmk_ok;
|
|
rpm-build |
3ee90c |
struct stat s;
|
|
rpm-build |
3ee90c |
char *xslt = NULL,
|
|
rpm-build |
3ee90c |
*transform_upgrade = NULL,
|
|
rpm-build |
3ee90c |
*transform_enter = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* prologue for further transform_expected handling */
|
|
rpm-build |
3ee90c |
if (transform_expected) {
|
|
rpm-build |
3ee90c |
/* check if there's suitable "upgrade" stylesheet */
|
|
rpm-build |
3ee90c |
transform_upgrade = schema_strdup_printf("upgrade-", *version, );
|
|
rpm-build |
3ee90c |
xslt = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_legacy_xslt,
|
|
rpm-build |
3ee90c |
transform_upgrade);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (!transform_expected) {
|
|
rpm-build |
3ee90c |
/* jump directly to the end */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (stat(xslt, &s) == 0) {
|
|
rpm-build |
3ee90c |
/* perhaps there's also a targeted "upgrade-enter" stylesheet */
|
|
rpm-build |
3ee90c |
transform_enter = schema_strdup_printf("upgrade-", *version, "-enter");
|
|
rpm-build |
3ee90c |
free(xslt);
|
|
rpm-build |
3ee90c |
xslt = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_legacy_xslt,
|
|
rpm-build |
3ee90c |
transform_enter);
|
|
rpm-build |
3ee90c |
if (stat(xslt, &s) != 0) {
|
|
rpm-build |
3ee90c |
/* or initially, at least a generic one */
|
|
rpm-build |
3ee90c |
crm_debug("Upgrade-enter transform %s.xsl not found", xslt);
|
|
rpm-build |
3ee90c |
free(xslt);
|
|
rpm-build |
3ee90c |
free(transform_enter);
|
|
rpm-build |
3ee90c |
transform_enter = strdup("upgrade-enter");
|
|
rpm-build |
3ee90c |
xslt = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_legacy_xslt,
|
|
rpm-build |
3ee90c |
transform_enter);
|
|
rpm-build |
3ee90c |
if (stat(xslt, &s) != 0) {
|
|
rpm-build |
3ee90c |
crm_debug("Upgrade-enter transform %s.xsl not found, either", xslt);
|
|
rpm-build |
3ee90c |
free(xslt);
|
|
rpm-build |
3ee90c |
xslt = NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
/* xslt contains full path to "upgrade-enter" stylesheet */
|
|
rpm-build |
3ee90c |
if (xslt != NULL) {
|
|
rpm-build |
3ee90c |
/* then there should be "upgrade-leave" counterpart (enter->leave) */
|
|
rpm-build |
3ee90c |
memcpy(strrchr(xslt, '-') + 1, "leave", sizeof("leave") - 1);
|
|
rpm-build |
3ee90c |
transform_onleave = (stat(xslt, &s) == 0);
|
|
rpm-build |
3ee90c |
free(xslt);
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
free(transform_enter);
|
|
rpm-build |
3ee90c |
transform_enter = NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
crm_err("Upgrade transform %s not found", xslt);
|
|
rpm-build |
3ee90c |
free(xslt);
|
|
rpm-build |
3ee90c |
free(transform_upgrade);
|
|
rpm-build |
3ee90c |
transform_upgrade = NULL;
|
|
rpm-build |
3ee90c |
next = -1;
|
|
rpm-build |
3ee90c |
rc = -ENOENT;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
add_schema(schema_validator_rng, version, NULL,
|
|
rpm-build |
3ee90c |
transform_upgrade, transform_enter, transform_onleave, next);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
free(transform_upgrade);
|
|
rpm-build |
3ee90c |
free(transform_enter);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return rc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static int
|
|
rpm-build |
3ee90c |
wrap_libxslt(bool finalize)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
static xsltSecurityPrefsPtr secprefs;
|
|
rpm-build |
3ee90c |
int ret = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* security framework preferences */
|
|
rpm-build |
3ee90c |
if (!finalize) {
|
|
rpm-build |
3ee90c |
CRM_ASSERT(secprefs == NULL);
|
|
rpm-build |
3ee90c |
secprefs = xsltNewSecurityPrefs();
|
|
rpm-build |
3ee90c |
ret = xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_WRITE_FILE,
|
|
rpm-build |
3ee90c |
xsltSecurityForbid)
|
|
rpm-build |
3ee90c |
| xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_CREATE_DIRECTORY,
|
|
rpm-build |
3ee90c |
xsltSecurityForbid)
|
|
rpm-build |
3ee90c |
| xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_READ_NETWORK,
|
|
rpm-build |
3ee90c |
xsltSecurityForbid)
|
|
rpm-build |
3ee90c |
| xsltSetSecurityPrefs(secprefs, XSLT_SECPREF_WRITE_NETWORK,
|
|
rpm-build |
3ee90c |
xsltSecurityForbid);
|
|
rpm-build |
3ee90c |
if (ret != 0) {
|
|
rpm-build |
3ee90c |
return -1;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
xsltFreeSecurityPrefs(secprefs);
|
|
rpm-build |
3ee90c |
secprefs = NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* cleanup only */
|
|
rpm-build |
3ee90c |
if (finalize) {
|
|
rpm-build |
3ee90c |
xsltCleanupGlobals();
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return ret;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/*!
|
|
rpm-build |
3ee90c |
* \internal
|
|
rpm-build |
3ee90c |
* \brief Load pacemaker schemas into cache
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* \note This currently also serves as an entry point for the
|
|
rpm-build |
3ee90c |
* generic initialization of the libxslt library.
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
void
|
|
rpm-build |
3ee90c |
crm_schema_init(void)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int lpc, max;
|
|
rpm-build |
3ee90c |
char *base = pcmk__xml_artefact_root(pcmk__xml_artefact_ns_legacy_rng);
|
|
rpm-build |
3ee90c |
struct dirent **namelist = NULL;
|
|
rpm-build |
3ee90c |
const schema_version_t zero = SCHEMA_ZERO;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
wrap_libxslt(false);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
max = scandir(base, &namelist, schema_filter, schema_sort);
|
|
rpm-build |
3ee90c |
if (max < 0) {
|
|
rpm-build |
3ee90c |
crm_notice("scandir(%s) failed: %s (%d)", base, strerror(errno), errno);
|
|
rpm-build |
3ee90c |
free(base);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
free(base);
|
|
rpm-build |
3ee90c |
for (lpc = 0; lpc < max; lpc++) {
|
|
rpm-build |
3ee90c |
bool transform_expected = FALSE;
|
|
rpm-build |
3ee90c |
int next = 0;
|
|
rpm-build |
3ee90c |
schema_version_t version = SCHEMA_ZERO;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (!version_from_filename(namelist[lpc]->d_name, &version)) {
|
|
rpm-build |
3ee90c |
// Shouldn't be possible, but makes static analysis happy
|
|
rpm-build |
3ee90c |
crm_err("Skipping schema '%s': could not parse version",
|
|
rpm-build |
3ee90c |
namelist[lpc]->d_name);
|
|
rpm-build |
3ee90c |
continue;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if ((lpc + 1) < max) {
|
|
rpm-build |
3ee90c |
schema_version_t next_version = SCHEMA_ZERO;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (version_from_filename(namelist[lpc+1]->d_name, &next_version)
|
|
rpm-build |
3ee90c |
&& (version.v[0] < next_version.v[0])) {
|
|
rpm-build |
3ee90c |
transform_expected = TRUE;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
next = -1;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (add_schema_by_version(&version, next, transform_expected)
|
|
rpm-build |
3ee90c |
== -ENOENT) {
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (lpc = 0; lpc < max; lpc++) {
|
|
rpm-build |
3ee90c |
free(namelist[lpc]);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
free(namelist);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
add_schema(schema_validator_rng, &zero, "pacemaker-next",
|
|
rpm-build |
3ee90c |
NULL, NULL, FALSE, -1);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
add_schema(schema_validator_none, &zero, "none", NULL, NULL, FALSE, -1);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#if 0
|
|
rpm-build |
3ee90c |
static void
|
|
rpm-build |
3ee90c |
relaxng_invalid_stderr(void *userData, xmlErrorPtr error)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
/*
|
|
rpm-build |
3ee90c |
Structure xmlError
|
|
rpm-build |
3ee90c |
struct _xmlError {
|
|
rpm-build |
3ee90c |
int domain : What part of the library raised this er
|
|
rpm-build |
3ee90c |
int code : The error code, e.g. an xmlParserError
|
|
rpm-build |
3ee90c |
char * message : human-readable informative error messag
|
|
rpm-build |
3ee90c |
xmlErrorLevel level : how consequent is the error
|
|
rpm-build |
3ee90c |
char * file : the filename
|
|
rpm-build |
3ee90c |
int line : the line number if available
|
|
rpm-build |
3ee90c |
char * str1 : extra string information
|
|
rpm-build |
3ee90c |
char * str2 : extra string information
|
|
rpm-build |
3ee90c |
char * str3 : extra string information
|
|
rpm-build |
3ee90c |
int int1 : extra number information
|
|
rpm-build |
3ee90c |
int int2 : column number of the error or 0 if N/A
|
|
rpm-build |
3ee90c |
void * ctxt : the parser context if available
|
|
rpm-build |
3ee90c |
void * node : the node in the tree
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
crm_err("Structured error: line=%d, level=%d %s", error->line, error->level, error->message);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
#endif
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static gboolean
|
|
rpm-build |
3ee90c |
validate_with_relaxng(xmlDocPtr doc, gboolean to_logs, const char *relaxng_file,
|
|
rpm-build |
3ee90c |
relaxng_ctx_cache_t **cached_ctx)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int rc = 0;
|
|
rpm-build |
3ee90c |
gboolean valid = TRUE;
|
|
rpm-build |
3ee90c |
relaxng_ctx_cache_t *ctx = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(doc != NULL, return FALSE);
|
|
rpm-build |
3ee90c |
CRM_CHECK(relaxng_file != NULL, return FALSE);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (cached_ctx && *cached_ctx) {
|
|
rpm-build |
3ee90c |
ctx = *cached_ctx;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
crm_debug("Creating RNG parser context");
|
|
rpm-build |
3ee90c |
ctx = calloc(1, sizeof(relaxng_ctx_cache_t));
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xmlLoadExtDtdDefaultValue = 1;
|
|
rpm-build |
3ee90c |
ctx->parser = xmlRelaxNGNewParserCtxt(relaxng_file);
|
|
rpm-build |
3ee90c |
CRM_CHECK(ctx->parser != NULL, goto cleanup);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (to_logs) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGSetParserErrors(ctx->parser,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityErrorFunc) xml_log,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityWarningFunc) xml_log,
|
|
rpm-build |
3ee90c |
GUINT_TO_POINTER(LOG_ERR));
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
xmlRelaxNGSetParserErrors(ctx->parser,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityErrorFunc) fprintf,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityWarningFunc) fprintf,
|
|
rpm-build |
3ee90c |
stderr);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
ctx->rng = xmlRelaxNGParse(ctx->parser);
|
|
rpm-build |
3ee90c |
CRM_CHECK(ctx->rng != NULL,
|
|
rpm-build |
3ee90c |
crm_err("Could not find/parse %s", relaxng_file);
|
|
rpm-build |
3ee90c |
goto cleanup);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
ctx->valid = xmlRelaxNGNewValidCtxt(ctx->rng);
|
|
rpm-build |
3ee90c |
CRM_CHECK(ctx->valid != NULL, goto cleanup);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (to_logs) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGSetValidErrors(ctx->valid,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityErrorFunc) xml_log,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityWarningFunc) xml_log,
|
|
rpm-build |
3ee90c |
GUINT_TO_POINTER(LOG_ERR));
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
xmlRelaxNGSetValidErrors(ctx->valid,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityErrorFunc) fprintf,
|
|
rpm-build |
3ee90c |
(xmlRelaxNGValidityWarningFunc) fprintf,
|
|
rpm-build |
3ee90c |
stderr);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* xmlRelaxNGSetValidStructuredErrors( */
|
|
rpm-build |
3ee90c |
/* valid, relaxng_invalid_stderr, valid); */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xmlLineNumbersDefault(1);
|
|
rpm-build |
3ee90c |
rc = xmlRelaxNGValidateDoc(ctx->valid, doc);
|
|
rpm-build |
3ee90c |
if (rc > 0) {
|
|
rpm-build |
3ee90c |
valid = FALSE;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (rc < 0) {
|
|
rpm-build |
3ee90c |
crm_err("Internal libxml error during validation");
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
cleanup:
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (cached_ctx) {
|
|
rpm-build |
3ee90c |
*cached_ctx = ctx;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
if (ctx->parser != NULL) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGFreeParserCtxt(ctx->parser);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx->valid != NULL) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGFreeValidCtxt(ctx->valid);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx->rng != NULL) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGFree(ctx->rng);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
free(ctx);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return valid;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/*!
|
|
rpm-build |
3ee90c |
* \internal
|
|
rpm-build |
3ee90c |
* \brief Clean up global memory associated with XML schemas
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
void
|
|
rpm-build |
3ee90c |
crm_schema_cleanup(void)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int lpc;
|
|
rpm-build |
3ee90c |
relaxng_ctx_cache_t *ctx = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
switch (known_schemas[lpc].validator) {
|
|
rpm-build |
3ee90c |
case schema_validator_none: // not cached
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
case schema_validator_rng: // cached
|
|
rpm-build |
3ee90c |
ctx = (relaxng_ctx_cache_t *) known_schemas[lpc].cache;
|
|
rpm-build |
3ee90c |
if (ctx == NULL) {
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx->parser != NULL) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGFreeParserCtxt(ctx->parser);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx->valid != NULL) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGFreeValidCtxt(ctx->valid);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx->rng != NULL) {
|
|
rpm-build |
3ee90c |
xmlRelaxNGFree(ctx->rng);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
free(ctx);
|
|
rpm-build |
3ee90c |
known_schemas[lpc].cache = NULL;
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
free(known_schemas[lpc].name);
|
|
rpm-build |
3ee90c |
free(known_schemas[lpc].transform);
|
|
rpm-build |
3ee90c |
free(known_schemas[lpc].transform_enter);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
free(known_schemas);
|
|
rpm-build |
3ee90c |
known_schemas = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
wrap_libxslt(true);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static gboolean
|
|
rpm-build |
3ee90c |
validate_with(xmlNode *xml, int method, gboolean to_logs)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
xmlDocPtr doc = NULL;
|
|
rpm-build |
3ee90c |
gboolean valid = FALSE;
|
|
rpm-build |
3ee90c |
char *file = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (method < 0) {
|
|
rpm-build |
3ee90c |
return FALSE;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (known_schemas[method].validator == schema_validator_none) {
|
|
rpm-build |
3ee90c |
return TRUE;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(xml != NULL, return FALSE);
|
|
rpm-build |
3ee90c |
doc = getDocPtr(xml);
|
|
rpm-build |
3ee90c |
file = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_legacy_rng,
|
|
rpm-build |
3ee90c |
known_schemas[method].name);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
crm_trace("Validating with: %s (type=%d)",
|
|
rpm-build |
3ee90c |
crm_str(file), known_schemas[method].validator);
|
|
rpm-build |
3ee90c |
switch (known_schemas[method].validator) {
|
|
rpm-build |
3ee90c |
case schema_validator_rng:
|
|
rpm-build |
3ee90c |
valid =
|
|
rpm-build |
3ee90c |
validate_with_relaxng(doc, to_logs, file,
|
|
rpm-build |
3ee90c |
(relaxng_ctx_cache_t **) & (known_schemas[method].cache));
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
default:
|
|
rpm-build |
3ee90c |
crm_err("Unknown validator type: %d",
|
|
rpm-build |
3ee90c |
known_schemas[method].validator);
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
free(file);
|
|
rpm-build |
3ee90c |
return valid;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static bool
|
|
rpm-build |
3ee90c |
validate_with_silent(xmlNode *xml, int method)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
bool rc, sl_backup = silent_logging;
|
|
rpm-build |
3ee90c |
silent_logging = TRUE;
|
|
rpm-build |
3ee90c |
rc = validate_with(xml, method, TRUE);
|
|
rpm-build |
3ee90c |
silent_logging = sl_backup;
|
|
rpm-build |
3ee90c |
return rc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static void
|
|
rpm-build |
3ee90c |
dump_file(const char *filename)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
FILE *fp = NULL;
|
|
rpm-build |
3ee90c |
int ch, line = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(filename != NULL, return);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
fp = fopen(filename, "r");
|
|
rpm-build |
3ee90c |
if (fp == NULL) {
|
|
rpm-build |
3ee90c |
crm_perror(LOG_ERR, "Could not open %s for reading", filename);
|
|
rpm-build |
3ee90c |
return;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
fprintf(stderr, "%4d ", ++line);
|
|
rpm-build |
3ee90c |
do {
|
|
rpm-build |
3ee90c |
ch = getc(fp);
|
|
rpm-build |
3ee90c |
if (ch == EOF) {
|
|
rpm-build |
3ee90c |
putc('\n', stderr);
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
} else if (ch == '\n') {
|
|
rpm-build |
3ee90c |
fprintf(stderr, "\n%4d ", ++line);
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
putc(ch, stderr);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
} while (1);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
fclose(fp);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
gboolean
|
|
rpm-build |
3ee90c |
validate_xml_verbose(xmlNode *xml_blob)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int fd = 0;
|
|
rpm-build |
3ee90c |
xmlDoc *doc = NULL;
|
|
rpm-build |
3ee90c |
xmlNode *xml = NULL;
|
|
rpm-build |
3ee90c |
gboolean rc = FALSE;
|
|
rpm-build |
3ee90c |
char *filename = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
filename = crm_strdup_printf("%s/cib-invalid.XXXXXX", crm_get_tmpdir());
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
umask(S_IWGRP | S_IWOTH | S_IROTH);
|
|
rpm-build |
3ee90c |
fd = mkstemp(filename);
|
|
rpm-build |
3ee90c |
write_xml_fd(xml_blob, filename, fd, FALSE);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
dump_file(filename);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
doc = xmlParseFile(filename);
|
|
rpm-build |
3ee90c |
xml = xmlDocGetRootElement(doc);
|
|
rpm-build |
3ee90c |
rc = validate_xml(xml, NULL, FALSE);
|
|
rpm-build |
3ee90c |
free_xml(xml);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
unlink(filename);
|
|
rpm-build |
3ee90c |
free(filename);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return rc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
gboolean
|
|
rpm-build |
3ee90c |
validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int version = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (validation == NULL) {
|
|
rpm-build |
3ee90c |
validation = crm_element_value(xml_blob, XML_ATTR_VALIDATION);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (validation == NULL) {
|
|
rpm-build |
3ee90c |
int lpc = 0;
|
|
rpm-build |
3ee90c |
bool valid = FALSE;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
rpm-build |
3ee90c |
if (validate_with(xml_blob, lpc, FALSE)) {
|
|
rpm-build |
3ee90c |
valid = TRUE;
|
|
rpm-build |
3ee90c |
crm_xml_add(xml_blob, XML_ATTR_VALIDATION,
|
|
rpm-build |
3ee90c |
known_schemas[lpc].name);
|
|
rpm-build |
3ee90c |
crm_info("XML validated against %s", known_schemas[lpc].name);
|
|
rpm-build |
3ee90c |
if(known_schemas[lpc].after_transform == 0) {
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return valid;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
version = get_schema_version(validation);
|
|
rpm-build |
3ee90c |
if (strcmp(validation, "none") == 0) {
|
|
rpm-build |
3ee90c |
return TRUE;
|
|
rpm-build |
3ee90c |
} else if (version < xml_schema_max) {
|
|
rpm-build |
3ee90c |
return validate_with(xml_blob, version, to_logs);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
crm_err("Unknown validator: %s", validation);
|
|
rpm-build |
3ee90c |
return FALSE;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#if HAVE_LIBXSLT
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static void
|
|
rpm-build |
3ee90c |
cib_upgrade_err(void *ctx, const char *fmt, ...)
|
|
rpm-build |
3ee90c |
G_GNUC_PRINTF(2, 3);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* With this arrangement, an attempt to identify the message severity
|
|
rpm-build |
3ee90c |
as explicitly signalled directly from XSLT is performed in rather
|
|
rpm-build |
3ee90c |
a smart way (no reliance on formatting string + arguments being
|
|
rpm-build |
3ee90c |
always specified as ["%s", purposeful_string], as it can also be
|
|
rpm-build |
3ee90c |
["%s: %s", some_prefix, purposeful_string] etc. so every argument
|
|
rpm-build |
3ee90c |
pertaining %s specifier is investigated), and if such a mark found,
|
|
rpm-build |
3ee90c |
the respective level is determined and, when the messages are to go
|
|
rpm-build |
3ee90c |
to the native logs, the mark itself gets dropped
|
|
rpm-build |
3ee90c |
(by the means of string shift).
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
NOTE: whether the native logging is the right sink is decided per
|
|
rpm-build |
3ee90c |
the ctx parameter -- NULL denotes this case, otherwise it
|
|
rpm-build |
3ee90c |
carries a pointer to the numeric expression of the desired
|
|
rpm-build |
3ee90c |
target logging level (messages with higher level will be
|
|
rpm-build |
3ee90c |
suppressed)
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
NOTE: on some architectures, this string shift may not have any
|
|
rpm-build |
3ee90c |
effect, but that's an acceptable tradeoff
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
The logging level for not explicitly designated messages
|
|
rpm-build |
3ee90c |
(suspicious, likely internal errors or some runaways) is
|
|
rpm-build |
3ee90c |
LOG_WARNING.
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
static void
|
|
rpm-build |
3ee90c |
cib_upgrade_err(void *ctx, const char *fmt, ...)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
va_list ap, aq;
|
|
rpm-build |
3ee90c |
char *arg_cur;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
bool found = FALSE;
|
|
rpm-build |
3ee90c |
const char *fmt_iter = fmt;
|
|
rpm-build |
3ee90c |
uint8_t msg_log_level = LOG_WARNING; /* default for runaway messages */
|
|
rpm-build |
3ee90c |
const unsigned * log_level = (const unsigned *) ctx;
|
|
rpm-build |
3ee90c |
enum {
|
|
rpm-build |
3ee90c |
escan_seennothing,
|
|
rpm-build |
3ee90c |
escan_seenpercent,
|
|
rpm-build |
3ee90c |
} scan_state = escan_seennothing;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
va_start(ap, fmt);
|
|
rpm-build |
3ee90c |
va_copy(aq, ap);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
while (!found && *fmt_iter != '\0') {
|
|
rpm-build |
3ee90c |
/* while casing schema borrowed from libqb:qb_vsnprintf_serialize */
|
|
rpm-build |
3ee90c |
switch (*fmt_iter++) {
|
|
rpm-build |
3ee90c |
case '%':
|
|
rpm-build |
3ee90c |
if (scan_state == escan_seennothing) {
|
|
rpm-build |
3ee90c |
scan_state = escan_seenpercent;
|
|
rpm-build |
3ee90c |
} else if (scan_state == escan_seenpercent) {
|
|
rpm-build |
3ee90c |
scan_state = escan_seennothing;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
case 's':
|
|
rpm-build |
3ee90c |
if (scan_state == escan_seenpercent) {
|
|
rpm-build |
3ee90c |
scan_state = escan_seennothing;
|
|
rpm-build |
3ee90c |
arg_cur = va_arg(aq, char *);
|
|
rpm-build |
3ee90c |
if (arg_cur != NULL) {
|
|
rpm-build |
3ee90c |
switch (arg_cur[0]) {
|
|
rpm-build |
3ee90c |
case 'W':
|
|
rpm-build |
3ee90c |
if (!strncmp(arg_cur, "WARNING: ",
|
|
rpm-build |
3ee90c |
sizeof("WARNING: ") - 1)) {
|
|
rpm-build |
3ee90c |
msg_log_level = LOG_WARNING;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx == NULL) {
|
|
rpm-build |
3ee90c |
memmove(arg_cur, arg_cur + sizeof("WARNING: ") - 1,
|
|
rpm-build |
3ee90c |
strlen(arg_cur + sizeof("WARNING: ") - 1) + 1);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
found = TRUE;
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
case 'I':
|
|
rpm-build |
3ee90c |
if (!strncmp(arg_cur, "INFO: ",
|
|
rpm-build |
3ee90c |
sizeof("INFO: ") - 1)) {
|
|
rpm-build |
3ee90c |
msg_log_level = LOG_INFO;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx == NULL) {
|
|
rpm-build |
3ee90c |
memmove(arg_cur, arg_cur + sizeof("INFO: ") - 1,
|
|
rpm-build |
3ee90c |
strlen(arg_cur + sizeof("INFO: ") - 1) + 1);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
found = TRUE;
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
case 'D':
|
|
rpm-build |
3ee90c |
if (!strncmp(arg_cur, "DEBUG: ",
|
|
rpm-build |
3ee90c |
sizeof("DEBUG: ") - 1)) {
|
|
rpm-build |
3ee90c |
msg_log_level = LOG_DEBUG;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (ctx == NULL) {
|
|
rpm-build |
3ee90c |
memmove(arg_cur, arg_cur + sizeof("DEBUG: ") - 1,
|
|
rpm-build |
3ee90c |
strlen(arg_cur + sizeof("DEBUG: ") - 1) + 1);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
found = TRUE;
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
case '#': case '-': case ' ': case '+': case '\'': case 'I': case '.':
|
|
rpm-build |
3ee90c |
case '0': case '1': case '2': case '3': case '4':
|
|
rpm-build |
3ee90c |
case '5': case '6': case '7': case '8': case '9':
|
|
rpm-build |
3ee90c |
case '*':
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
case 'l':
|
|
rpm-build |
3ee90c |
case 'z':
|
|
rpm-build |
3ee90c |
case 't':
|
|
rpm-build |
3ee90c |
case 'j':
|
|
rpm-build |
3ee90c |
case 'd': case 'i':
|
|
rpm-build |
3ee90c |
case 'o':
|
|
rpm-build |
3ee90c |
case 'u':
|
|
rpm-build |
3ee90c |
case 'x': case 'X':
|
|
rpm-build |
3ee90c |
case 'e': case 'E':
|
|
rpm-build |
3ee90c |
case 'f': case 'F':
|
|
rpm-build |
3ee90c |
case 'g': case 'G':
|
|
rpm-build |
3ee90c |
case 'a': case 'A':
|
|
rpm-build |
3ee90c |
case 'c':
|
|
rpm-build |
3ee90c |
case 'p':
|
|
rpm-build |
3ee90c |
if (scan_state == escan_seenpercent) {
|
|
rpm-build |
3ee90c |
(void) va_arg(aq, void *); /* skip forward */
|
|
rpm-build |
3ee90c |
scan_state = escan_seennothing;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
default:
|
|
rpm-build |
3ee90c |
scan_state = escan_seennothing;
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (log_level != NULL) {
|
|
rpm-build |
3ee90c |
/* intention of the following offset is:
|
|
rpm-build |
3ee90c |
cibadmin -V -> start showing INFO labelled messages */
|
|
rpm-build |
3ee90c |
if (*log_level + 4 >= msg_log_level) {
|
|
rpm-build |
3ee90c |
vfprintf(stderr, fmt, ap);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
CRM_XML_LOG_BASE(msg_log_level, TRUE, 0, "CIB upgrade: ", fmt, ap);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
va_end(aq);
|
|
rpm-build |
3ee90c |
va_end(ap);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* Denotes temporary emergency fix for "xmldiff'ing not text-node-ready";
|
|
rpm-build |
3ee90c |
proper fix is most likely to teach __xml_diff_object and friends to
|
|
rpm-build |
3ee90c |
deal with XML_TEXT_NODE (and more?), i.e., those nodes currently
|
|
rpm-build |
3ee90c |
missing "_private" field (implicitly as NULL) which clashes with
|
|
rpm-build |
3ee90c |
unchecked accesses (e.g. in __xml_offset) -- the outcome may be that
|
|
rpm-build |
3ee90c |
those unexpected XML nodes will simply be ignored for the purpose of
|
|
rpm-build |
3ee90c |
diff'ing, or it may be made more robust, or per the user's preference
|
|
rpm-build |
3ee90c |
(which then may be exposed as crm_diff switch).
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
Said XML_TEXT_NODE may appear unexpectedly due to how upgrade-2.10.xsl
|
|
rpm-build |
3ee90c |
is arranged.
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
The emergency fix is simple: reparse XSLT output with blank-ignoring
|
|
rpm-build |
3ee90c |
parser. */
|
|
rpm-build |
3ee90c |
#ifndef PCMK_SCHEMAS_EMERGENCY_XSLT
|
|
rpm-build |
3ee90c |
#define PCMK_SCHEMAS_EMERGENCY_XSLT 1
|
|
rpm-build |
3ee90c |
#endif
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
static xmlNode *
|
|
rpm-build |
3ee90c |
apply_transformation(xmlNode *xml, const char *transform, gboolean to_logs)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
char *xform = NULL;
|
|
rpm-build |
3ee90c |
xmlNode *out = NULL;
|
|
rpm-build |
3ee90c |
xmlDocPtr res = NULL;
|
|
rpm-build |
3ee90c |
xmlDocPtr doc = NULL;
|
|
rpm-build |
3ee90c |
xsltStylesheet *xslt = NULL;
|
|
rpm-build |
3ee90c |
#if PCMK_SCHEMAS_EMERGENCY_XSLT != 0
|
|
rpm-build |
3ee90c |
xmlChar *emergency_result;
|
|
rpm-build |
3ee90c |
int emergency_txt_len;
|
|
rpm-build |
3ee90c |
int emergency_res;
|
|
rpm-build |
3ee90c |
#endif
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(xml != NULL, return FALSE);
|
|
rpm-build |
3ee90c |
doc = getDocPtr(xml);
|
|
rpm-build |
3ee90c |
xform = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_legacy_xslt,
|
|
rpm-build |
3ee90c |
transform);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xmlLoadExtDtdDefaultValue = 1;
|
|
rpm-build |
3ee90c |
xmlSubstituteEntitiesDefault(1);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* for capturing, e.g., what's emitted via <xsl:message> */
|
|
rpm-build |
3ee90c |
if (to_logs) {
|
|
rpm-build |
3ee90c |
xsltSetGenericErrorFunc(NULL, cib_upgrade_err);
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
xsltSetGenericErrorFunc(&crm_log_level, cib_upgrade_err);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xslt = xsltParseStylesheetFile((pcmkXmlStr) xform);
|
|
rpm-build |
3ee90c |
CRM_CHECK(xslt != NULL, goto cleanup);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
res = xsltApplyStylesheet(xslt, doc, NULL);
|
|
rpm-build |
3ee90c |
CRM_CHECK(res != NULL, goto cleanup);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xsltSetGenericErrorFunc(NULL, NULL); /* restore default one */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#if PCMK_SCHEMAS_EMERGENCY_XSLT != 0
|
|
rpm-build |
3ee90c |
emergency_res = xsltSaveResultToString(&emergency_result,
|
|
rpm-build |
3ee90c |
&emergency_txt_len, res, xslt);
|
|
rpm-build |
3ee90c |
xmlFreeDoc(res);
|
|
rpm-build |
3ee90c |
CRM_CHECK(emergency_res == 0, goto cleanup);
|
|
rpm-build |
3ee90c |
out = string2xml((const char *) emergency_result);
|
|
rpm-build |
3ee90c |
free(emergency_result);
|
|
rpm-build |
3ee90c |
#else
|
|
rpm-build |
3ee90c |
out = xmlDocGetRootElement(res);
|
|
rpm-build |
3ee90c |
#endif
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
cleanup:
|
|
rpm-build |
3ee90c |
if (xslt) {
|
|
rpm-build |
3ee90c |
xsltFreeStylesheet(xslt);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
free(xform);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return out;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/*!
|
|
rpm-build |
3ee90c |
* \internal
|
|
rpm-build |
3ee90c |
* \brief Possibly full enter->upgrade->leave trip per internal bookkeeping.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* \note Only emits warnings about enter/leave phases in case of issues.
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
static xmlNode *
|
|
rpm-build |
3ee90c |
apply_upgrade(xmlNode *xml, const struct schema_s *schema, gboolean to_logs)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
bool transform_onleave = schema->transform_onleave;
|
|
rpm-build |
3ee90c |
char *transform_leave;
|
|
rpm-build |
3ee90c |
xmlNode *upgrade = NULL,
|
|
rpm-build |
3ee90c |
*final = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (schema->transform_enter) {
|
|
rpm-build |
3ee90c |
crm_debug("Upgrading %s-style configuration, pre-upgrade phase with %s.xsl",
|
|
rpm-build |
3ee90c |
schema->name, schema->transform_enter);
|
|
rpm-build |
3ee90c |
upgrade = apply_transformation(xml, schema->transform_enter, to_logs);
|
|
rpm-build |
3ee90c |
if (upgrade == NULL) {
|
|
rpm-build |
3ee90c |
crm_warn("Upgrade-enter transformation %s.xsl failed",
|
|
rpm-build |
3ee90c |
schema->transform_enter);
|
|
rpm-build |
3ee90c |
transform_onleave = FALSE;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (upgrade == NULL) {
|
|
rpm-build |
3ee90c |
upgrade = xml;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
crm_debug("Upgrading %s-style configuration, main phase with %s.xsl",
|
|
rpm-build |
3ee90c |
schema->name, schema->transform);
|
|
rpm-build |
3ee90c |
final = apply_transformation(upgrade, schema->transform, to_logs);
|
|
rpm-build |
3ee90c |
if (upgrade != xml) {
|
|
rpm-build |
3ee90c |
free_xml(upgrade);
|
|
rpm-build |
3ee90c |
upgrade = NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (final != NULL && transform_onleave) {
|
|
rpm-build |
3ee90c |
upgrade = final;
|
|
rpm-build |
3ee90c |
/* following condition ensured in add_schema_by_version */
|
|
rpm-build |
3ee90c |
CRM_ASSERT(schema->transform_enter != NULL);
|
|
rpm-build |
3ee90c |
transform_leave = strdup(schema->transform_enter);
|
|
rpm-build |
3ee90c |
/* enter -> leave */
|
|
rpm-build |
3ee90c |
memcpy(strrchr(transform_leave, '-') + 1, "leave", sizeof("leave") - 1);
|
|
rpm-build |
3ee90c |
crm_debug("Upgrading %s-style configuration, post-upgrade phase with %s.xsl",
|
|
rpm-build |
3ee90c |
schema->name, transform_leave);
|
|
rpm-build |
3ee90c |
final = apply_transformation(upgrade, transform_leave, to_logs);
|
|
rpm-build |
3ee90c |
if (final == NULL) {
|
|
rpm-build |
3ee90c |
crm_warn("Upgrade-leave transformation %s.xsl failed", transform_leave);
|
|
rpm-build |
3ee90c |
final = upgrade;
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
free_xml(upgrade);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
free(transform_leave);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return final;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#endif /* HAVE_LIBXSLT */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
const char *
|
|
rpm-build |
3ee90c |
get_schema_name(int version)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
if (version < 0 || version >= xml_schema_max) {
|
|
rpm-build |
3ee90c |
return "unknown";
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
return known_schemas[version].name;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
int
|
|
rpm-build |
3ee90c |
get_schema_version(const char *name)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int lpc = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (name == NULL) {
|
|
rpm-build |
3ee90c |
name = "none";
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
for (; lpc < xml_schema_max; lpc++) {
|
|
rpm-build |
3ee90c |
if (safe_str_eq(name, known_schemas[lpc].name)) {
|
|
rpm-build |
3ee90c |
return lpc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
return -1;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* set which validation to use */
|
|
rpm-build |
3ee90c |
int
|
|
rpm-build |
3ee90c |
update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
rpm-build |
3ee90c |
gboolean to_logs)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
xmlNode *xml = NULL;
|
|
rpm-build |
3ee90c |
char *value = NULL;
|
|
rpm-build |
3ee90c |
int max_stable_schemas = xml_latest_schema_index();
|
|
rpm-build |
3ee90c |
int lpc = 0, match = -1, rc = pcmk_ok;
|
|
rpm-build |
3ee90c |
int next = -1; /* -1 denotes "inactive" value */
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(best != NULL, return -EINVAL);
|
|
rpm-build |
3ee90c |
*best = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(xml_blob != NULL, return -EINVAL);
|
|
rpm-build |
3ee90c |
CRM_CHECK(*xml_blob != NULL, return -EINVAL);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xml = *xml_blob;
|
|
rpm-build |
3ee90c |
value = crm_element_value_copy(xml, XML_ATTR_VALIDATION);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (value != NULL) {
|
|
rpm-build |
3ee90c |
match = get_schema_version(value);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
lpc = match;
|
|
rpm-build |
3ee90c |
if (lpc >= 0 && transform == FALSE) {
|
|
rpm-build |
3ee90c |
*best = lpc++;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (lpc < 0) {
|
|
rpm-build |
3ee90c |
crm_debug("Unknown validation schema");
|
|
rpm-build |
3ee90c |
lpc = 0;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (match >= max_stable_schemas) {
|
|
rpm-build |
3ee90c |
/* nothing to do */
|
|
rpm-build |
3ee90c |
free(value);
|
|
rpm-build |
3ee90c |
*best = match;
|
|
rpm-build |
3ee90c |
return pcmk_ok;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
while (lpc <= max_stable_schemas) {
|
|
rpm-build |
3ee90c |
crm_debug("Testing '%s' validation (%d of %d)",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>",
|
|
rpm-build |
3ee90c |
lpc, max_stable_schemas);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (validate_with(xml, lpc, to_logs) == FALSE) {
|
|
rpm-build |
3ee90c |
if (next != -1) {
|
|
rpm-build |
3ee90c |
crm_info("Configuration not valid for schema: %s",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].name);
|
|
rpm-build |
3ee90c |
next = -1;
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
crm_trace("%s validation failed",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>");
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
if (*best) {
|
|
rpm-build |
3ee90c |
/* we've satisfied the validation, no need to check further */
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
rc = -pcmk_err_schema_validation;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
if (next != -1) {
|
|
rpm-build |
3ee90c |
crm_debug("Configuration valid for schema: %s",
|
|
rpm-build |
3ee90c |
known_schemas[next].name);
|
|
rpm-build |
3ee90c |
next = -1;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
rc = pcmk_ok;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (rc == pcmk_ok) {
|
|
rpm-build |
3ee90c |
*best = lpc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (rc == pcmk_ok && transform) {
|
|
rpm-build |
3ee90c |
xmlNode *upgrade = NULL;
|
|
rpm-build |
3ee90c |
next = known_schemas[lpc].after_transform;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (next <= lpc) {
|
|
rpm-build |
3ee90c |
/* There is no next version, or next would regress */
|
|
rpm-build |
3ee90c |
crm_trace("Stopping at %s", known_schemas[lpc].name);
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (max > 0 && (lpc == max || next > max)) {
|
|
rpm-build |
3ee90c |
crm_trace("Upgrade limit reached at %s (lpc=%d, next=%d, max=%d)",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].name, lpc, next, max);
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (known_schemas[lpc].transform == NULL
|
|
rpm-build |
3ee90c |
/* possibly avoid transforming when readily valid
|
|
rpm-build |
3ee90c |
(in general more restricted when crossing the major
|
|
rpm-build |
3ee90c |
version boundary, as X.0 "transitional" version is
|
|
rpm-build |
3ee90c |
expected to be more strict than it's successors that
|
|
rpm-build |
3ee90c |
may re-allow constructs from previous major line) */
|
|
rpm-build |
3ee90c |
|| validate_with_silent(xml, next)) {
|
|
rpm-build |
3ee90c |
crm_debug("%s-style configuration is also valid for %s",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].name, known_schemas[next].name);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
lpc = next;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
crm_debug("Upgrading %s-style configuration to %s with %s.xsl",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].name, known_schemas[next].name,
|
|
rpm-build |
3ee90c |
known_schemas[lpc].transform);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#if HAVE_LIBXSLT
|
|
rpm-build |
3ee90c |
upgrade = apply_upgrade(xml, &known_schemas[lpc], to_logs);
|
|
rpm-build |
3ee90c |
#endif
|
|
rpm-build |
3ee90c |
if (upgrade == NULL) {
|
|
rpm-build |
3ee90c |
crm_err("Transformation %s.xsl failed",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].transform);
|
|
rpm-build |
3ee90c |
rc = -pcmk_err_transform_failed;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (validate_with(upgrade, next, to_logs)) {
|
|
rpm-build |
3ee90c |
crm_info("Transformation %s.xsl successful",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].transform);
|
|
rpm-build |
3ee90c |
lpc = next;
|
|
rpm-build |
3ee90c |
*best = next;
|
|
rpm-build |
3ee90c |
free_xml(xml);
|
|
rpm-build |
3ee90c |
xml = upgrade;
|
|
rpm-build |
3ee90c |
rc = pcmk_ok;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
crm_err("Transformation %s.xsl did not produce a valid configuration",
|
|
rpm-build |
3ee90c |
known_schemas[lpc].transform);
|
|
rpm-build |
3ee90c |
crm_log_xml_info(upgrade, "transform:bad");
|
|
rpm-build |
3ee90c |
free_xml(upgrade);
|
|
rpm-build |
3ee90c |
rc = -pcmk_err_schema_validation;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
next = -1;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (transform == FALSE || rc != pcmk_ok) {
|
|
rpm-build |
3ee90c |
/* we need some progress! */
|
|
rpm-build |
3ee90c |
lpc++;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (*best > match && *best) {
|
|
rpm-build |
3ee90c |
crm_info("%s the configuration from %s to %s",
|
|
rpm-build |
3ee90c |
transform?"Transformed":"Upgraded",
|
|
rpm-build |
3ee90c |
value ? value : "<none>", known_schemas[*best].name);
|
|
rpm-build |
3ee90c |
crm_xml_add(xml, XML_ATTR_VALIDATION, known_schemas[*best].name);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
*xml_blob = xml;
|
|
rpm-build |
3ee90c |
free(value);
|
|
rpm-build |
3ee90c |
return rc;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
gboolean
|
|
rpm-build |
3ee90c |
cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
gboolean rc = TRUE;
|
|
rpm-build |
3ee90c |
const char *value = crm_element_value(*xml, XML_ATTR_VALIDATION);
|
|
rpm-build |
3ee90c |
char *const orig_value = strdup(value == NULL ? "(none)" : value);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
int version = get_schema_version(value);
|
|
rpm-build |
3ee90c |
int orig_version = version;
|
|
rpm-build |
3ee90c |
int min_version = xml_minimum_schema_index();
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (version < min_version) {
|
|
rpm-build |
3ee90c |
xmlNode *converted = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
converted = copy_xml(*xml);
|
|
rpm-build |
3ee90c |
update_validation(&converted, &version, 0, TRUE, to_logs);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
value = crm_element_value(converted, XML_ATTR_VALIDATION);
|
|
rpm-build |
3ee90c |
if (version < min_version) {
|
|
rpm-build |
3ee90c |
if (version < orig_version || orig_version == -1) {
|
|
rpm-build |
3ee90c |
if (to_logs) {
|
|
rpm-build |
3ee90c |
crm_config_err("Your current configuration %s could not"
|
|
rpm-build |
3ee90c |
" validate with any schema in range [%s, %s],"
|
|
rpm-build |
3ee90c |
" cannot upgrade to %s.",
|
|
rpm-build |
3ee90c |
orig_value,
|
|
rpm-build |
3ee90c |
get_schema_name(orig_version),
|
|
rpm-build |
3ee90c |
xml_latest_schema(),
|
|
rpm-build |
3ee90c |
get_schema_name(min_version));
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
fprintf(stderr, "Your current configuration %s could not"
|
|
rpm-build |
3ee90c |
" validate with any schema in range [%s, %s],"
|
|
rpm-build |
3ee90c |
" cannot upgrade to %s.\n",
|
|
rpm-build |
3ee90c |
orig_value,
|
|
rpm-build |
3ee90c |
get_schema_name(orig_version),
|
|
rpm-build |
3ee90c |
xml_latest_schema(),
|
|
rpm-build |
3ee90c |
get_schema_name(min_version));
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
} else if (to_logs) {
|
|
rpm-build |
3ee90c |
crm_config_err("Your current configuration could only be upgraded to %s... "
|
|
rpm-build |
3ee90c |
"the minimum requirement is %s.", crm_str(value),
|
|
rpm-build |
3ee90c |
get_schema_name(min_version));
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
fprintf(stderr, "Your current configuration could only be upgraded to %s... "
|
|
rpm-build |
3ee90c |
"the minimum requirement is %s.\n",
|
|
rpm-build |
3ee90c |
crm_str(value), get_schema_name(min_version));
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
free_xml(converted);
|
|
rpm-build |
3ee90c |
converted = NULL;
|
|
rpm-build |
3ee90c |
rc = FALSE;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
free_xml(*xml);
|
|
rpm-build |
3ee90c |
*xml = converted;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (version < xml_latest_schema_index()) {
|
|
rpm-build |
3ee90c |
crm_config_warn("Your configuration was internally updated to %s... "
|
|
rpm-build |
3ee90c |
"which is acceptable but not the most recent",
|
|
rpm-build |
3ee90c |
get_schema_name(version));
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (to_logs) {
|
|
rpm-build |
3ee90c |
crm_info("Your configuration was internally updated to the latest version (%s)",
|
|
rpm-build |
3ee90c |
get_schema_name(version));
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (version >= get_schema_version("none")) {
|
|
rpm-build |
3ee90c |
if (to_logs) {
|
|
rpm-build |
3ee90c |
crm_config_warn("Configuration validation is currently disabled."
|
|
rpm-build |
3ee90c |
" It is highly encouraged and prevents many common cluster issues.");
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
fprintf(stderr, "Configuration validation is currently disabled."
|
|
rpm-build |
3ee90c |
" It is highly encouraged and prevents many common cluster issues.\n");
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (best_version) {
|
|
rpm-build |
3ee90c |
*best_version = version;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
free(orig_value);
|
|
rpm-build |
3ee90c |
return rc;
|
|
rpm-build |
3ee90c |
}
|