dhodovsk / source-git / pacemaker

Forked from source-git/pacemaker 3 years ago
Clone

Blame lib/common/schemas.c

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
}