Exemplo n.º 1
0
static void
save_cib_contents(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
    char *id = user_data;

    register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
    CRM_CHECK(id != NULL, return);

    if (rc == cib_ok) {
        int len = 15;
        char *filename = NULL;

        len += strlen(id);
        len += strlen(PE_STATE_DIR);

        crm_malloc0(filename, len);
        CRM_CHECK(filename != NULL, return);

        sprintf(filename, PE_STATE_DIR "/pe-core-%s.bz2", id);
        if (write_xml_file(output, filename, TRUE) < 0) {
            crm_err("Could not save CIB contents after PE crash to %s", filename);
        } else {
            crm_notice("Saved CIB contents after PE crash to %s", filename);
        }

        crm_free(filename);
    }
Exemplo n.º 2
0
int gen_nc_xml(const struct nc_state_t *nc_state_param)
{
    int ret = EUCA_ERROR;
    char path[MAX_PATH] = "";
    xmlDocPtr doc = NULL;
    xmlNodePtr nc = NULL;
    xmlNodePtr version = NULL;
    xmlNodePtr enabled = NULL;

    INIT();

    pthread_mutex_lock(&xml_mutex);
    {
        doc = xmlNewDoc(BAD_CAST "1.0");
        nc = xmlNewNode(NULL, BAD_CAST "nc");
        xmlDocSetRootElement(doc, nc);

        version = xmlNewChild(nc, NULL, BAD_CAST "version", BAD_CAST(nc_state_param->version));
        enabled = xmlNewChild(nc, NULL, BAD_CAST "enabled", BAD_CAST(nc_state_param->is_enabled ? "true" : "false"));

        snprintf(path, sizeof(path), EUCALYPTUS_NC_STATE_FILE, nc_state.home);
        ret = write_xml_file(doc, "global", path, "nc");
        xmlFreeDoc(doc);
    }
    pthread_mutex_unlock(&xml_mutex);

    return (ret);
}
Exemplo n.º 3
0
//!
//! Generates the XML content for a given volume
//!
//! @param[in] volumeId the volume identifier string (vol-XXXXXXXX)
//! @param[in] instance a pointer to our instance structure
//! @param[in] localDevReal a string containing the target device name
//! @param[in] remoteDev a string containing the disk path.
//!
//! @return The results of calling write_xml_file()
//!
//! @see write_xml_file()
//!
int gen_volume_xml(const char *volumeId, const ncInstance * instance, const char *localDevReal, const char *remoteDev)
{
    int ret = EUCA_ERROR;
    char bitness[4] = "";
    char path[MAX_PATH] = "";
    xmlDocPtr doc = NULL;
    xmlNodePtr volumeNode = NULL;
    xmlNodePtr hypervisor = NULL;
    xmlNodePtr os = NULL;
    xmlNodePtr backing = NULL;
    xmlNodePtr root = NULL;
    xmlNodePtr disk = NULL;

    INIT();

    pthread_mutex_lock(&xml_mutex);
    {
        doc = xmlNewDoc(BAD_CAST "1.0");
        volumeNode = xmlNewNode(NULL, BAD_CAST "volume");
        xmlDocSetRootElement(doc, volumeNode);

        // hypervisor-related specs
        hypervisor = xmlNewChild(volumeNode, NULL, BAD_CAST "hypervisor", NULL);
        _ATTRIBUTE(hypervisor, "type", instance->hypervisorType);
        _ATTRIBUTE(hypervisor, "capability", hypervsorCapabilityTypeNames[instance->hypervisorCapability]);
        snprintf(bitness, 4, "%d", instance->hypervisorBitness);
        _ATTRIBUTE(hypervisor, "bitness", bitness);

        _ELEMENT(volumeNode, "id", volumeId);
        _ELEMENT(volumeNode, "user", instance->userId);
        _ELEMENT(volumeNode, "instancePath", instance->instancePath);

        // OS-related specs
        os = _NODE(volumeNode, "os");
        _ATTRIBUTE(os, "platform", instance->platform);
        _ATTRIBUTE(os, "virtioRoot", _BOOL(config_use_virtio_root));
        _ATTRIBUTE(os, "virtioDisk", _BOOL(config_use_virtio_disk));
        _ATTRIBUTE(os, "virtioNetwork", _BOOL(config_use_virtio_net));

        //! backing specification (@todo maybe expand this with device maps or whatnot?)
        backing = xmlNewChild(volumeNode, NULL, BAD_CAST "backing", NULL);
        root = xmlNewChild(backing, NULL, BAD_CAST "root", NULL);
        assert(instance->params.root);
        _ATTRIBUTE(root, "type", ncResourceTypeName[instance->params.root->type]);

        // volume information
        disk = _ELEMENT(volumeNode, "diskPath", remoteDev);
        _ATTRIBUTE(disk, "targetDeviceType", "disk");
        _ATTRIBUTE(disk, "targetDeviceName", localDevReal);
        _ATTRIBUTE(disk, "targetDeviceBus", "scsi");
        _ATTRIBUTE(disk, "sourceType", "block");

        snprintf(path, sizeof(path), EUCALYPTUS_VOLUME_XML_PATH_FORMAT, instance->instancePath, volumeId);
        ret = write_xml_file(doc, instance->instanceId, path, "volume");
        xmlFreeDoc(doc);
    }
    pthread_mutex_unlock(&xml_mutex);
    return (ret);
}
Exemplo n.º 4
0
int gen_libvirt_attach_xml (const char *volumeId, const ncInstance *instance, const char * localDevReal, const char * remoteDev, char * xml, unsigned int xml_size)
{
    INIT();

    int ret = 1;
    pthread_mutex_lock (&xml_mutex);
    xmlDocPtr doc = xmlNewDoc (BAD_CAST "1.0");
    xmlNodePtr volumeNode = xmlNewNode (NULL, BAD_CAST "volume");
    xmlDocSetRootElement (doc, volumeNode);

    { // hypervisor-related specs
        xmlNodePtr hypervisor = xmlNewChild (volumeNode, NULL, BAD_CAST "hypervisor", NULL);
        _ATTRIBUTE(hypervisor, "type", instance->hypervisorType);
        _ATTRIBUTE(hypervisor, "capability", hypervsorCapabilityTypeNames[instance->hypervisorCapability]);
        char bitness[4];
        snprintf(bitness, 4,"%d", instance->hypervisorBitness);
        _ATTRIBUTE(hypervisor, "bitness", bitness);
    }

    _ELEMENT(volumeNode, "id", volumeId);
    _ELEMENT(volumeNode, "user", instance->userId);
    _ELEMENT(volumeNode, "instancePath", instance->instancePath);

    { // OS-related specs
        xmlNodePtr os = _NODE(volumeNode, "os");
        _ATTRIBUTE(os, "platform", instance->platform);
        _ATTRIBUTE(os, "virtioRoot", _BOOL(config_use_virtio_root));
        _ATTRIBUTE(os, "virtioDisk", _BOOL(config_use_virtio_disk));
        _ATTRIBUTE(os, "virtioNetwork", _BOOL(config_use_virtio_net));
    }

    { // backing specification (TODO: maybe expand this with device maps or whatnot?)
        xmlNodePtr backing = xmlNewChild (volumeNode, NULL, BAD_CAST "backing", NULL);
        xmlNodePtr root = xmlNewChild (backing, NULL, BAD_CAST "root", NULL);
        assert (instance->params.root);
        _ATTRIBUTE(root, "type", ncResourceTypeName[instance->params.root->type]);
    }

    { // volume information
        xmlNodePtr disk = _ELEMENT(volumeNode, "diskPath", remoteDev);
        _ATTRIBUTE(disk, "targetDeviceType", "disk");
        _ATTRIBUTE(disk, "targetDeviceName", localDevReal);
        _ATTRIBUTE(disk, "targetDeviceBus", "scsi");
        _ATTRIBUTE(disk, "sourceType", "block");
        
    }

    char path [MAX_PATH];
    snprintf (path, sizeof (path), EUCALYPTUS_VOLUME_XML_PATH_FORMAT, instance->instancePath, volumeId);
    ret = write_xml_file (doc, instance->instanceId, path, "volume")
        || apply_xslt_stylesheet (xslt_path, path, NULL, xml, xml_size);
    logprintfl (EUCATRACE, "XML={%s}\n", xml);

    xmlFreeDoc(doc);
    pthread_mutex_unlock (&xml_mutex);

    return ret;
}
Exemplo n.º 5
0
/*!
 * \internal
 * \brief Save CIB query result to file, raising FSA error
 *
 * \param[in] msg        Ignored
 * \param[in] call_id    Call ID of CIB query
 * \param[in] rc         Return code of CIB query
 * \param[in] output     Result of CIB query
 * \param[in] user_data  Unique identifier for filename (will be freed)
 *
 * \note This is intended to be called after a scheduler connection fails.
 */
static void
save_cib_contents(xmlNode *msg, int call_id, int rc, xmlNode *output,
                  void *user_data)
{
    char *id = user_data;

    register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
    CRM_CHECK(id != NULL, return);

    if (rc == pcmk_ok) {
        char *filename = crm_strdup_printf(PE_STATE_DIR "/pe-core-%s.bz2", id);

        if (write_xml_file(output, filename, TRUE) < 0) {
            crm_err("Could not save Cluster Information Base to %s after scheduler crash",
                    filename);
        } else {
            crm_notice("Saved Cluster Information Base to %s after scheduler crash",
                       filename);
        }
        free(filename);
    }
}
Exemplo n.º 6
0
// Encodes instance metadata (contained in ncInstance struct) in XML
// and writes it to file instance->xmlFilePath (/path/to/instance/instance.xml)
// That file gets processed through tools/libvirt.xsl (/etc/eucalyptus/libvirt.xsl)
// to produce /path/to/instance/libvirt.xml file that is passed to libvirt create.
int gen_instance_xml (const ncInstance * instance)
{
    INIT();

    int ret = 1;
    pthread_mutex_lock (&xml_mutex);
    xmlDocPtr doc = xmlNewDoc (BAD_CAST "1.0");
    xmlNodePtr instanceNode = xmlNewNode (NULL, BAD_CAST "instance");
    xmlDocSetRootElement (doc, instanceNode);

    { // hypervisor-related specs
        xmlNodePtr hypervisor = xmlNewChild (instanceNode, NULL, BAD_CAST "hypervisor", NULL);
        _ATTRIBUTE(hypervisor, "type", instance->hypervisorType);
        _ATTRIBUTE(hypervisor, "capability", hypervsorCapabilityTypeNames[instance->hypervisorCapability]);
        char bitness[4];
        snprintf(bitness, 4,"%d", instance->hypervisorBitness);
        _ATTRIBUTE(hypervisor, "bitness", bitness);
    }

    { // backing specification (TODO: maybe expand this with device maps or whatnot?)
        xmlNodePtr backing = xmlNewChild (instanceNode, NULL, BAD_CAST "backing", NULL);
        xmlNodePtr root = xmlNewChild (backing, NULL, BAD_CAST "root", NULL);
        assert (instance->params.root);
        _ATTRIBUTE(root, "type", ncResourceTypeName[instance->params.root->type]);
    }

    _ELEMENT(instanceNode, "name", instance->instanceId);
    _ELEMENT(instanceNode, "uuid", instance->uuid);
    _ELEMENT(instanceNode, "reservation", instance->reservationId);
    _ELEMENT(instanceNode, "user", instance->userId);
    _ELEMENT(instanceNode, "dnsName", instance->dnsName);
    _ELEMENT(instanceNode, "privateDnsName", instance->privateDnsName);
    _ELEMENT(instanceNode, "instancePath", instance->instancePath);
    if (instance->params.kernel) {
        char * path = instance->params.kernel->backingPath;
        if (path_check (path, "kernel")) goto free; // sanity check 
        _ELEMENT(instanceNode, "kernel", path);
    }
    if (instance->params.ramdisk) {
        char * path = instance->params.ramdisk->backingPath;
        if (path_check (path, "ramdisk")) goto free; // sanity check
        _ELEMENT(instanceNode, "ramdisk", path);
    }
    _ELEMENT(instanceNode, "consoleLogPath", instance->consoleFilePath);
    _ELEMENT(instanceNode, "userData", instance->userData);
    _ELEMENT(instanceNode, "launchIndex", instance->launchIndex);
    
    char cores_s  [10]; snprintf (cores_s,  sizeof (cores_s),  "%d", instance->params.cores);  _ELEMENT(instanceNode, "cores", cores_s);
    char memory_s [10]; snprintf (memory_s, sizeof (memory_s), "%d", instance->params.mem * 1024); _ELEMENT(instanceNode, "memoryKB", memory_s);

    { // SSH-key related
        xmlNodePtr key = _NODE(instanceNode, "key");
        _ATTRIBUTE(key, "isKeyInjected", _BOOL(instance->do_inject_key));
        _ATTRIBUTE(key, "sshKey", instance->keyName);
    }

    { // OS-related specs
        xmlNodePtr os = _NODE(instanceNode, "os");
        _ATTRIBUTE(os, "platform", instance->platform);
        _ATTRIBUTE(os, "virtioRoot", _BOOL(config_use_virtio_root));
        _ATTRIBUTE(os, "virtioDisk", _BOOL(config_use_virtio_disk));
        _ATTRIBUTE(os, "virtioNetwork", _BOOL(config_use_virtio_net));
    }

    { // disks specification
        xmlNodePtr disks = _NODE(instanceNode, "disks");

        // the first disk should be the root disk (at least for Windows)
        for (int root=1; root>=0; root--){ 
           for (int i=0; i<EUCA_MAX_VBRS && i<instance->params.virtualBootRecordLen; i++) {
               const virtualBootRecord * vbr = &(instance->params.virtualBootRecord[i]); 
               // skip empty entries, if any
               if (vbr==NULL)
                   continue;
               // do EMI on the first iteration of the outer loop
               if (root && vbr->type != NC_RESOURCE_IMAGE) 
                   continue;
               // ignore EMI on the second iteration of the outer loop
               if (!root && vbr->type == NC_RESOURCE_IMAGE)
                   continue;
               // skip anything without a device on the guest, e.g., kernel and ramdisk
               if (!strcmp ("none", vbr->guestDeviceName)) 
                   continue;
               // for Linux instances on Xen, partitions can be used directly, so disks can be skipped unless booting from EBS
               if (strstr (instance->platform, "linux") && strstr (instance->hypervisorType, "xen")) {
                   if (vbr->partitionNumber == 0 && vbr->type == NC_RESOURCE_IMAGE) {
                       continue;
                   }
               } else { // on all other os + hypervisor combinations, disks are used, so partitions must be skipped
                   if (vbr->partitionNumber > 0) {
                       continue;
                   }
               }
            
               xmlNodePtr disk = _ELEMENT(disks, "diskPath", vbr->backingPath);
               _ATTRIBUTE(disk, "targetDeviceType", libvirtDevTypeNames[vbr->guestDeviceType]);
               _ATTRIBUTE(disk, "targetDeviceName", vbr->guestDeviceName);
               char devstr[SMALL_CHAR_BUFFER_SIZE];
               snprintf(devstr, SMALL_CHAR_BUFFER_SIZE, "%s", vbr->guestDeviceName);             
               if (config_use_virtio_root) {
                   devstr[0] = 'v';
                   _ATTRIBUTE(disk, "targetDeviceNameVirtio", devstr);
                   _ATTRIBUTE(disk, "targetDeviceBusVirtio", "virtio");     
               }
               _ATTRIBUTE(disk, "targetDeviceBus", libvirtBusTypeNames[vbr->guestDeviceBus]);
               _ATTRIBUTE(disk, "sourceType", libvirtSourceTypeNames[vbr->backingType]);

               if (root) {
                   xmlNodePtr rootNode = _ELEMENT(disks, "root", NULL);
                   _ATTRIBUTE(rootNode, "device", devstr);
                   char root_uuid[64] = "";
                   if (get_blkid (vbr->backingPath, root_uuid, sizeof(root_uuid)) == 0) {
                       assert (strlen (root_uuid));
                       _ATTRIBUTE(rootNode, "uuid", root_uuid);
                   }
               }
           }
           if (strlen (instance->floppyFilePath)) {
               _ELEMENT(disks, "floppyPath", instance->floppyFilePath);
           }
       }
    }

    if (instance->params.nicType!=NIC_TYPE_NONE) { // NIC specification
        xmlNodePtr nics = _NODE(instanceNode, "nics");
        xmlNodePtr nic =  _NODE(nics, "nic");
        _ATTRIBUTE(nic, "bridgeDeviceName", instance->params.guestNicDeviceName);
        _ATTRIBUTE(nic, "mac", instance->ncnet.privateMac);
    }

    ret = write_xml_file (doc, instance->instanceId, instance->xmlFilePath, "instance");
 free:
    xmlFreeDoc(doc);
    pthread_mutex_unlock (&xml_mutex);

    return ret;
}
Exemplo n.º 7
0
int
main(int argc, char **argv)
{
    int rc = 0;
    int flag;
    int argerr = 0;
    static int command = '?';
    char *shadow = NULL;
    char *shadow_file = NULL;
    gboolean full_upload = FALSE;
    gboolean dangerous_cmd = FALSE;
    struct stat buf;
    int option_index = 0;

    crm_log_cli_init("crm_shadow");
    crm_set_options(NULL, "(query|command) [modifiers]", long_options,
                    "Perform configuration changes in a sandbox before updating the live cluster."
                    "\n\nSets up an environment in which configuration tools (cibadmin, crm_resource, etc) work"
                    " offline instead of against a live cluster, allowing changes to be previewed and tested"
                    " for side-effects.\n");

    if (argc < 2) {
        crm_help('?', LSB_EXIT_EINVAL);
    }

    while (1) {
        flag = crm_get_option(argc, argv, &option_index);
        if (flag == -1 || flag == 0)
            break;

        switch (flag) {
            case 'a':
                full_upload = TRUE;
                break;
            case 'd':
            case 'E':
            case 'p':
            case 'w':
            case 'F':
                command = flag;
                crm_free(shadow);
                shadow = crm_strdup(getenv("CIB_shadow"));
                break;
            case 'e':
            case 'c':
            case 's':
            case 'r':
                command = flag;
                crm_free(shadow);
                shadow = crm_strdup(optarg);
                break;
            case 'C':
            case 'D':
                command = flag;
                dangerous_cmd = TRUE;
                crm_free(shadow);
                shadow = crm_strdup(optarg);
                break;
            case 'V':
                command_options = command_options | cib_verbose;
                crm_bump_log_level();
                break;
            case '$':
            case '?':
                crm_help(flag, LSB_EXIT_OK);
                break;
            case 'f':
                command_options |= cib_quorum_override;
                force_flag = 1;
                break;
            case 'b':
                batch_flag = 1;
                break;
            default:
                printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
                ++argerr;
                break;
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
        crm_help('?', LSB_EXIT_EINVAL);
    }

    if (optind > argc) {
        ++argerr;
    }

    if (argerr) {
        crm_help('?', LSB_EXIT_GENERIC);
    }

    if (command == 'w') {
        /* which shadow instance is active? */
        const char *local = getenv("CIB_shadow");

        if (local == NULL) {
            fprintf(stderr, "No shadow instance provided\n");
            rc = cib_NOTEXISTS;
            goto done;
        }
        fprintf(stdout, "%s\n", local);
        rc = 0;
        goto done;
    }

    if (shadow == NULL) {
        fprintf(stderr, "No shadow instance provided\n");
        fflush(stderr);
        rc = CIBRES_MISSING_FIELD;
        goto done;

    } else if (command != 's' && command != 'c') {
        const char *local = getenv("CIB_shadow");

        if (local != NULL && safe_str_neq(local, shadow) && force_flag == FALSE) {
            fprintf(stderr,
                    "The supplied shadow instance (%s) is not the same as the active one (%s).\n"
                    "  To prevent accidental destruction of the cluster,"
                    " the --force flag is required in order to proceed.\n", shadow, local);
            fflush(stderr);
            rc = LSB_EXIT_GENERIC;
            goto done;
        }
    }

    if (dangerous_cmd && force_flag == FALSE) {
        fprintf(stderr, "The supplied command is considered dangerous."
                "  To prevent accidental destruction of the cluster,"
                " the --force flag is required in order to proceed.\n");
        fflush(stderr);
        rc = LSB_EXIT_GENERIC;
        goto done;
    }

    shadow_file = get_shadow_file(shadow);
    if (command == 'D') {
        /* delete the file */
        rc = stat(shadow_file, &buf);
        if (rc == 0) {
            rc = unlink(shadow_file);
            if (rc != 0) {
                fprintf(stderr, "Could not remove shadow instance '%s': %s\n", shadow,
                        strerror(errno));
                goto done;
            }
        }

        shadow_teardown(shadow);
        goto done;

    } else if (command == 'F') {
        printf("%s\n", shadow_file);
        rc = 0;
        goto done;
    }

    if (command == 'd' || command == 'r' || command == 'c' || command == 'C') {
        real_cib = cib_new_no_shadow();
        rc = real_cib->cmds->signon(real_cib, crm_system_name, cib_command);
        if (rc != cib_ok) {
            fprintf(stderr, "Signon to CIB failed: %s\n", cib_error2string(rc));
            goto done;
        }
    }

    rc = stat(shadow_file, &buf);

    if (command == 'e' || command == 'c') {
        if (rc == 0 && force_flag == FALSE) {
            fprintf(stderr, "A shadow instance '%s' already exists.\n"
                    "  To prevent accidental destruction of the cluster,"
                    " the --force flag is required in order to proceed.\n", shadow);
            rc = cib_EXISTS;
            goto done;
        }

    } else if (rc != 0) {
        fprintf(stderr, "Could not access shadow instance '%s': %s\n", shadow, strerror(errno));
        rc = cib_NOTEXISTS;
        goto done;
    }

    rc = cib_ok;
    if (command == 'c' || command == 'e') {
        xmlNode *output = NULL;

        /* create a shadow instance based on the current cluster config */
        if (command == 'c') {
            rc = real_cib->cmds->query(real_cib, NULL, &output, command_options);
            if (rc != cib_ok) {
                fprintf(stderr, "Could not connect to the CIB: %s\n", cib_error2string(rc));
                goto done;
            }

        } else {
            output = createEmptyCib();
            crm_xml_add(output, XML_ATTR_GENERATION, "0");
            crm_xml_add(output, XML_ATTR_NUMUPDATES, "0");
            crm_xml_add(output, XML_ATTR_GENERATION_ADMIN, "0");
            crm_xml_add(output, XML_ATTR_VALIDATION, LATEST_SCHEMA_VERSION);
        }

        rc = write_xml_file(output, shadow_file, FALSE);
        free_xml(output);

        if (rc < 0) {
            fprintf(stderr, "Could not create the shadow instance '%s': %s\n",
                    shadow, strerror(errno));
            goto done;
        }
        shadow_setup(shadow, FALSE);
        rc = cib_ok;

    } else if (command == 'E') {
        const char *err = NULL;
        char *editor = getenv("EDITOR");

        if (editor == NULL) {
            fprintf(stderr, "No value for $EDITOR defined\n");
            rc = cib_missing;
            goto done;
        }

        execlp(editor, "--", shadow_file, NULL);
        err = strerror(errno);
        fprintf(stderr, "Could not invoke $EDITOR (%s %s): %s\n", editor, shadow_file, err);
        rc = cib_missing;
        goto done;

    } else if (command == 's') {
        shadow_setup(shadow, TRUE);
        rc = 0;
        goto done;

    } else if (command == 'P') {
        /* display the current contents */
        char *output_s = NULL;
        xmlNode *output = filename2xml(shadow_file);

        output_s = dump_xml_formatted(output);
        printf("%s", output_s);

        crm_free(output_s);
        free_xml(output);

    } else if (command == 'd') {
        /* diff against cluster */
        xmlNode *diff = NULL;
        xmlNode *old_config = NULL;
        xmlNode *new_config = filename2xml(shadow_file);

        rc = real_cib->cmds->query(real_cib, NULL, &old_config, command_options);

        if (rc != cib_ok) {
            fprintf(stderr, "Could not query the CIB: %s\n", cib_error2string(rc));
            goto done;
        }

        diff = diff_xml_object(old_config, new_config, FALSE);
        if (diff != NULL) {
            print_xml_diff(stdout, diff);
            rc = 1;
            goto done;
        }
        rc = 0;
        goto done;

    } else if (command == 'C') {
        /* commit to the cluster */
        xmlNode *input = filename2xml(shadow_file);

        if (full_upload) {
            rc = real_cib->cmds->replace(real_cib, NULL, input, command_options);
        } else {
            xmlNode *config = first_named_child(input, XML_CIB_TAG_CONFIGURATION);

            rc = real_cib->cmds->replace(real_cib, XML_CIB_TAG_CONFIGURATION, config,
                                         command_options);
        }

        if (rc != cib_ok) {
            fprintf(stderr, "Could not commit shadow instance '%s' to the CIB: %s\n",
                    shadow, cib_error2string(rc));
            return rc;
        }
        shadow_teardown(shadow);
        free_xml(input);
    }
  done:
    crm_xml_cleanup();
    crm_free(shadow_file);
    crm_free(shadow);
    return rc;
}
Exemplo n.º 8
0
int
main(int argc, char **argv)
{
    xmlNode *cib_object = NULL;
    xmlNode *status = NULL;
    int argerr = 0;
    int flag;
    int option_index = 0;

    pe_working_set_t data_set;
    cib_t *cib_conn = NULL;
    int rc = cib_ok;

    gboolean xml_stdin = FALSE;
    const char *xml_tag = NULL;
    const char *xml_file = NULL;
    const char *xml_string = NULL;

    g_log_set_handler(NULL,
                      G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
                      | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
                      | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
                      | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL);

    /* and for good measure... - this enum is a bit field (!) */
    g_log_set_always_fatal((GLogLevelFlags) 0); /*value out of range */

    crm_log_init_quiet(NULL, LOG_ERR, FALSE, TRUE, argc, argv);
    crm_set_options(NULL, "[modifiers] data_source", long_options,
                    "Check a (complete) confiuration for syntax and common conceptual errors."
                    "\n\nChecks the well-formedness of an XML configuration, its conformance to the configured DTD/schema and for the presence of common misconfigurations."
                    "\n\nIt reports two classes of problems, errors and warnings."
                    " Errors must be fixed before the cluster will work properly."
                    " However, it is left up to the administrator to decide if the warnings should also be fixed.");

    while (1) {
        flag = crm_get_option(argc, argv, &option_index);
        if (flag == -1)
            break;

        switch (flag) {
#ifdef HAVE_GETOPT_H
            case 0:
                printf("option %s", long_options[option_index].name);
                if (optarg)
                    printf(" with arg %s", optarg);
                printf("\n");

                break;
#endif

            case 'X':
                crm_debug_2("Option %c => %s", flag, optarg);
                xml_string = crm_strdup(optarg);
                break;
            case 'x':
                crm_debug_2("Option %c => %s", flag, optarg);
                xml_file = crm_strdup(optarg);
                break;
            case 'p':
                xml_stdin = TRUE;
                break;
            case 'S':
                cib_save = crm_strdup(optarg);
                break;
            case 'V':
                alter_debug(DEBUG_INC);
                break;
            case 'L':
                USE_LIVE_CIB = TRUE;
                break;
            case '$':
            case '?':
                crm_help(flag, LSB_EXIT_OK);
                break;
            default:
                fprintf(stderr, "Option -%c is not yet supported\n", flag);
                ++argerr;
                break;
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc) {
            printf("%s ", argv[optind++]);
        }
        printf("\n");
    }

    if (optind > argc) {
        ++argerr;
    }

    if (argerr) {
        crm_err("%d errors in option parsing", argerr);
        crm_help(flag, LSB_EXIT_GENERIC);
    }

    crm_info("=#=#=#=#= Getting XML =#=#=#=#=");

    if (USE_LIVE_CIB) {
        cib_conn = cib_new();
        rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
    }

    if (USE_LIVE_CIB) {
        if (rc == cib_ok) {
            int options = cib_scope_local | cib_sync_call;

            crm_info("Reading XML from: live cluster");
            rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
        }

        if (rc != cib_ok) {
            fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc));
            return 3;
        }
        if (cib_object == NULL) {
            fprintf(stderr, "Live CIB query failed: empty result\n");
            return 3;
        }

    } else if (xml_file != NULL) {
        cib_object = filename2xml(xml_file);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input file: %s\n", xml_file);
            return 4;
        }

    } else if (xml_string != NULL) {
        cib_object = string2xml(xml_string);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input string: %s\n", xml_string);
            return 4;
        }
    } else if (xml_stdin) {
        cib_object = stdin2xml();
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input from STDIN.\n");
            return 4;
        }

    } else {
        fprintf(stderr, "No configuration source specified."
                "  Use --help for usage information.\n");
        return 5;
    }

    xml_tag = crm_element_name(cib_object);
    if (safe_str_neq(xml_tag, XML_TAG_CIB)) {
        fprintf(stderr,
                "This tool can only check complete configurations (ie. those starting with <cib>).\n");
        return 6;
    }

    if (cib_save != NULL) {
        write_xml_file(cib_object, cib_save, FALSE);
    }

    status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
    if (status == NULL) {
        create_xml_node(cib_object, XML_CIB_TAG_STATUS);
    }

    if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
        crm_config_err("CIB did not pass DTD/schema validation");
        free_xml(cib_object);
        cib_object = NULL;

    } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
        crm_config_error = TRUE;
        free_xml(cib_object);
        cib_object = NULL;
        fprintf(stderr, "The cluster will NOT be able to use this configuration.\n");
        fprintf(stderr, "Please manually update the configuration to conform to the %s syntax.\n",
                LATEST_SCHEMA_VERSION);
    }

    set_working_set_defaults(&data_set);
    if (cib_object == NULL) {
    } else if (USE_LIVE_CIB) {
        /* we will always have a status section and can do a full simulation */
        do_calculations(&data_set, cib_object, NULL);
        cleanup_alloc_calculations(&data_set);

    } else {
        data_set.now = new_ha_date(TRUE);
        data_set.input = cib_object;
        stage0(&data_set);
        cleanup_alloc_calculations(&data_set);
    }

    if (crm_config_error) {
        fprintf(stderr, "Errors found during check: config not valid\n");
        if (crm_log_level < LOG_WARNING) {
            fprintf(stderr, "  -V may provide more details\n");
        }
        rc = 2;

    } else if (crm_config_warning) {
        fprintf(stderr, "Warnings found during check: config may not be valid\n");
        if (crm_log_level < LOG_WARNING) {
            fprintf(stderr, "  Use -V for more details\n");
        }
        rc = 1;
    }

    if (USE_LIVE_CIB) {
        cib_conn->cmds->signoff(cib_conn);
        cib_delete(cib_conn);
    }

    return rc;
}
Exemplo n.º 9
0
gboolean
process_pe_message(xmlNode * msg, xmlNode * xml_data, crm_client_t * sender)
{
    static char *last_digest = NULL;
    static char *filename = NULL;

    time_t execution_date = time(NULL);
    const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
    const char *op = crm_element_value(msg, F_CRM_TASK);
    const char *ref = crm_element_value(msg, F_CRM_REFERENCE);

    crm_trace("Processing %s op (ref=%s)...", op, ref);

    if (op == NULL) {
        /* error */

    } else if (strcasecmp(op, CRM_OP_HELLO) == 0) {
        /* ignore */

    } else if (safe_str_eq(crm_element_value(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE)) {
        /* ignore */

    } else if (sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) {
        crm_trace("Bad sys-to %s", crm_str(sys_to));
        return FALSE;

    } else if (strcasecmp(op, CRM_OP_PECALC) == 0) {
        int seq = -1;
        int series_id = 0;
        int series_wrap = 0;
        char *digest = NULL;
        const char *value = NULL;
        pe_working_set_t data_set;
        xmlNode *converted = NULL;
        xmlNode *reply = NULL;
        gboolean is_repoke = FALSE;
        gboolean process = TRUE;

        crm_config_error = FALSE;
        crm_config_warning = FALSE;

        was_processing_error = FALSE;
        was_processing_warning = FALSE;

        set_working_set_defaults(&data_set);

        digest = calculate_xml_versioned_digest(xml_data, FALSE, FALSE, CRM_FEATURE_SET);
        converted = copy_xml(xml_data);
        if (cli_config_update(&converted, NULL, TRUE) == FALSE) {
            data_set.graph = create_xml_node(NULL, XML_TAG_GRAPH);
            crm_xml_add_int(data_set.graph, "transition_id", 0);
            crm_xml_add_int(data_set.graph, "cluster-delay", 0);
            process = FALSE;
            free(digest);

        } else if (safe_str_eq(digest, last_digest)) {
            crm_info("Input has not changed since last time, not saving to disk");
            is_repoke = TRUE;
            free(digest);

        } else {
            free(last_digest);
            last_digest = digest;
        }

        if (process) {
            do_calculations(&data_set, converted, NULL);
        }

        series_id = get_series();
        series_wrap = series[series_id].wrap;
        value = pe_pref(data_set.config_hash, series[series_id].param);

        if (value != NULL) {
            series_wrap = crm_int_helper(value, NULL);
            if (errno != 0) {
                series_wrap = series[series_id].wrap;
            }

        } else {
            crm_config_warn("No value specified for cluster"
                            " preference: %s", series[series_id].param);
        }

        seq = get_last_sequence(PE_STATE_DIR, series[series_id].name);
        crm_trace("Series %s: wrap=%d, seq=%d, pref=%s",
                  series[series_id].name, series_wrap, seq, value);

        data_set.input = NULL;
        reply = create_reply(msg, data_set.graph);
        CRM_ASSERT(reply != NULL);

        if (is_repoke == FALSE) {
            free(filename);
            filename =
                generate_series_filename(PE_STATE_DIR, series[series_id].name, seq, HAVE_BZLIB_H);
        }

        crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename);
        crm_xml_add_int(reply, "graph-errors", was_processing_error);
        crm_xml_add_int(reply, "graph-warnings", was_processing_warning);
        crm_xml_add_int(reply, "config-errors", crm_config_error);
        crm_xml_add_int(reply, "config-warnings", crm_config_warning);

        if (crm_ipcs_send(sender, 0, reply, crm_ipc_server_event) == FALSE) {
            crm_err("Couldn't send transition graph to peer, discarding");
        }

        free_xml(reply);
        cleanup_alloc_calculations(&data_set);

        if (was_processing_error) {
            crm_err("Calculated transition %d (with errors), saving inputs in %s",
                    transition_id, filename);

        } else if (was_processing_warning) {
            crm_warn("Calculated transition %d (with warnings), saving inputs in %s",
                     transition_id, filename);

        } else {
            crm_notice("Calculated transition %d, saving inputs in %s",
                       transition_id, filename);
        }

        if (crm_config_error) {
            crm_notice("Configuration ERRORs found during PE processing."
                       "  Please run \"crm_verify -L\" to identify issues.");
        }

        if (is_repoke == FALSE && series_wrap != 0) {
            unlink(filename);
            crm_xml_add_int(xml_data, "execution-date", execution_date);
            write_xml_file(xml_data, filename, HAVE_BZLIB_H);
            write_last_sequence(PE_STATE_DIR, series[series_id].name, seq + 1, series_wrap);
        } else {
            crm_trace("Not writing out %s: %d & %d", filename, is_repoke, series_wrap);
        }

        free_xml(converted);
    }

    return TRUE;
}
Exemplo n.º 10
0
gboolean
process_pe_message(xmlNode *msg, xmlNode *xml_data, IPC_Channel *sender)
{
    gboolean send_via_disk = FALSE;
    const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
    const char *op = crm_element_value(msg, F_CRM_TASK);
    const char *ref = crm_element_value(msg, XML_ATTR_REFERENCE);

    crm_debug_3("Processing %s op (ref=%s)...", op, ref);

    if(op == NULL) {
        /* error */

    } else if(strcasecmp(op, CRM_OP_HELLO) == 0) {
        /* ignore */

    } else if(safe_str_eq(crm_element_value(msg, F_CRM_MSG_TYPE),
                          XML_ATTR_RESPONSE)) {
        /* ignore */

    } else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) {
        crm_debug_3("Bad sys-to %s", crm_str(sys_to));
        return FALSE;

    } else if(strcasecmp(op, CRM_OP_PECALC) == 0) {
        int seq = -1;
        int series_id = 0;
        int series_wrap = 0;
        char *filename = NULL;
        char *graph_file = NULL;
        const char *value = NULL;
        pe_working_set_t data_set;
        xmlNode *converted = NULL;
        xmlNode *reply = NULL;
        gboolean process = TRUE;
#if HAVE_BZLIB_H
        gboolean compress = TRUE;
#else
        gboolean compress = FALSE;
#endif

        crm_config_error = FALSE;
        crm_config_warning = FALSE;

        was_processing_error = FALSE;
        was_processing_warning = FALSE;

        graph_file = crm_strdup(CRM_STATE_DIR"/graph.XXXXXX");
        graph_file = mktemp(graph_file);

        converted = copy_xml(xml_data);
        if(cli_config_update(&converted, NULL, TRUE) == FALSE) {
            set_working_set_defaults(&data_set);
            data_set.graph = create_xml_node(NULL, XML_TAG_GRAPH);
            crm_xml_add_int(data_set.graph, "transition_id", 0);
            crm_xml_add_int(data_set.graph, "cluster-delay", 0);
            process = FALSE;
        }

        if(process) {
            do_calculations(&data_set, converted, NULL);
        }

        series_id = get_series();
        series_wrap = series[series_id].wrap;
        value = pe_pref(data_set.config_hash, series[series_id].param);

        if(value != NULL) {
            series_wrap = crm_int_helper(value, NULL);
            if(errno != 0) {
                series_wrap = series[series_id].wrap;
            }

        } else {
            crm_config_warn("No value specified for cluster"
                            " preference: %s",
                            series[series_id].param);
        }

        seq = get_last_sequence(PE_STATE_DIR, series[series_id].name);

        data_set.input = NULL;
        reply = create_reply(msg, data_set.graph);
        CRM_ASSERT(reply != NULL);

        filename = generate_series_filename(
                       PE_STATE_DIR, series[series_id].name, seq, compress);
        crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename);
        crm_xml_add_int(reply, "graph-errors", was_processing_error);
        crm_xml_add_int(reply, "graph-warnings", was_processing_warning);
        crm_xml_add_int(reply, "config-errors", crm_config_error);
        crm_xml_add_int(reply, "config-warnings", crm_config_warning);

        if(send_ipc_message(sender, reply) == FALSE) {
            if(sender && sender->ops->get_chan_status(sender) == IPC_CONNECT) {
                send_via_disk = TRUE;
                crm_err("Answer could not be sent via IPC, send via the disk instead");
                crm_info("Writing the TE graph to %s", graph_file);
                if(write_xml_file(data_set.graph, graph_file, FALSE) < 0) {
                    crm_err("TE graph could not be written to disk");
                }
            } else {
                crm_info("Peer disconnected, discarding transition graph");
            }
        }

        free_xml(reply);
        cleanup_alloc_calculations(&data_set);

        if(series_wrap != 0) {
            write_xml_file(xml_data, filename, compress);
            write_last_sequence(PE_STATE_DIR, series[series_id].name,
                                seq+1, series_wrap);
        }

        if(was_processing_error) {
            crm_err("Transition %d:"
                    " ERRORs found during PE processing."
                    " PEngine Input stored in: %s",
                    transition_id, filename);

        } else if(was_processing_warning) {
            crm_warn("Transition %d:"
                     " WARNINGs found during PE processing."
                     " PEngine Input stored in: %s",
                     transition_id, filename);

        } else {
            crm_info("Transition %d: PEngine Input stored in: %s",
                     transition_id, filename);
        }

        if(crm_config_error) {
            crm_info("Configuration ERRORs found during PE processing."
                     "  Please run \"crm_verify -L\" to identify issues.");

        } else if(crm_config_warning) {
            crm_info("Configuration WARNINGs found during PE processing."
                     "  Please run \"crm_verify -L\" to identify issues.");
        }

        if(send_via_disk) {
            reply = create_reply(msg, NULL);
            crm_xml_add(reply, F_CRM_TGRAPH, graph_file);
            crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename);
            CRM_ASSERT(reply != NULL);
            if(send_ipc_message(sender, reply) == FALSE) {
                crm_err("Answer could not be sent");
            }
            free_xml(reply);
        }

        free_xml(converted);
        crm_free(graph_file);
        crm_free(filename);

    } else if(strcasecmp(op, CRM_OP_QUIT) == 0) {
        crm_warn("Received quit message, terminating");
        exit(0);
    }

    return TRUE;
}
Exemplo n.º 11
0
int
main(int argc, char **argv)
{
	crm_data_t *cib_object = NULL;
	crm_data_t *status = NULL;
	int argerr = 0;
	int flag;
		
	pe_working_set_t data_set;
	cib_t *	cib_conn = NULL;
	int rc = cib_ok;
	
	gboolean xml_stdin = FALSE;
	const char *xml_file = NULL;
	const char *xml_string = NULL;
	
	crm_system_name = basename(argv[0]);
	
	g_log_set_handler(NULL,
			  G_LOG_LEVEL_ERROR      | G_LOG_LEVEL_CRITICAL
			  | G_LOG_LEVEL_WARNING  | G_LOG_LEVEL_MESSAGE
			  | G_LOG_LEVEL_INFO     | G_LOG_LEVEL_DEBUG
			  | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL,
			  cl_glib_msg_handler, NULL);

	/* and for good measure... - this enum is a bit field (!) */
	g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/
	
	cl_log_set_entity(crm_system_name);
	cl_log_set_facility(HA_LOG_FACILITY);
	cl_log_enable_stderr(TRUE);
	set_crm_log_level(LOG_ERR);
	
	CL_SIGNAL(DEBUG_INC, alter_debug);
	CL_SIGNAL(DEBUG_DEC, alter_debug);
	
	while (1) {
#ifdef HAVE_GETOPT_H
		int option_index = 0;
		static struct option long_options[] = {
			/* Top-level Options */
			{F_CRM_DATA,    1, 0, 'X'},
			{"dtd-file",    1, 0, 'D'},
			{"xml-file",    1, 0, 'x'},
			{"xml-pipe",    0, 0, 'p'},
			{"save-xml",    1, 0, 'S'},
			{"live-check",  0, 0, 'L'},
			{"help", 0, 0, '?'},
      
			{0, 0, 0, 0}
		};
#endif
    
#ifdef HAVE_GETOPT_H
		flag = getopt_long(argc, argv, OPTARGS,
				   long_options, &option_index);
#else
		flag = getopt(argc, argv, OPTARGS);
#endif
		if (flag == -1)
			break;
    
		switch(flag) {
#ifdef HAVE_GETOPT_H
			case 0:
				printf("option %s", long_options[option_index].name);
				if (optarg)
					printf(" with arg %s", optarg);
				printf("\n");
    
				break;
#endif
      
			case 'D':
				crm_debug_2("Option %c => %s", flag, optarg);
				dtd_file = optarg;
				break;

			case 'X':
				crm_debug_2("Option %c => %s", flag, optarg);
				xml_string = crm_strdup(optarg);
				break;
			case 'x':
				crm_debug_2("Option %c => %s", flag, optarg);
				xml_file = crm_strdup(optarg);
				break;
			case 'p':
				xml_stdin = TRUE;
				break;
			case 'S':
				cib_save = crm_strdup(optarg);
				break;
			case 'V':
				alter_debug(DEBUG_INC);
				break;
			case 'L':
				USE_LIVE_CIB = TRUE;
				break;
			case '?':
				usage(crm_system_name, LSB_EXIT_GENERIC);
				break;
			default:
				printf("?? getopt returned character code 0%o ??\n", flag);
				++argerr;
				break;
		}
	}
  
	if (optind < argc) {
		printf("non-option ARGV-elements: ");
		while (optind < argc) {
			printf("%s ", argv[optind++]);
		}
		printf("\n");
	}
  
	if (optind > argc) {
		++argerr;
	}
  
	if (argerr) {
		crm_err("%d errors in option parsing", argerr);
		usage(crm_system_name, LSB_EXIT_GENERIC);
	}
  
	crm_info("=#=#=#=#= Getting XML =#=#=#=#=");

	if(USE_LIVE_CIB) {
		cib_conn = cib_new();
		rc = cib_conn->cmds->signon(
			cib_conn, crm_system_name, cib_command_synchronous);
	}
	
	
	if(USE_LIVE_CIB) {
		if(rc == cib_ok) {
			int options = cib_scope_local|cib_sync_call;
			crm_info("Reading XML from: live cluster");
			rc = cib_conn->cmds->query(
 				cib_conn, NULL, &cib_object, options);
		}

		
		if(rc != cib_ok) {
			fprintf(stderr, "Live CIB query failed: %s\n",
				cib_error2string(rc));
			return 3;
		}
		if(cib_object == NULL) {
			fprintf(stderr, "Live CIB query failed: empty result\n");
			return 3;
		}
	
	} else if(xml_file != NULL) {
		FILE *xml_strm = fopen(xml_file, "r");
		cib_object = file2xml(xml_strm, FALSE);
		if(cib_object == NULL) {
			fprintf(stderr,
				"Couldn't parse input file: %s\n", xml_file);
			return 1;
		}
		fclose(xml_strm);
		
	} else if(xml_string != NULL) {
		cib_object = string2xml(xml_string);
		if(cib_object == NULL) {
			fprintf(stderr,
				"Couldn't parse input string: %s\n", xml_string);
			return 1;
		}
	} else if(xml_stdin) {
		cib_object = stdin2xml();
		if(cib_object == NULL) {
			fprintf(stderr, "Couldn't parse input from STDIN.\n");
			return 1;
		}

	} else {
		fprintf(stderr, "No configuration source specified."
			"  Use --help for usage information.\n");
		return 3;
	}
	
	if(cib_save != NULL) {
		write_xml_file(cib_object, cib_save, FALSE);
	}
	
	status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
	if(status == NULL) {
		create_xml_node(cib_object, XML_CIB_TAG_STATUS);
	}
	
#if CRM_DEPRECATED_SINCE_2_0_4
	xml_child_iter_filter(status, node_state, XML_CIB_TAG_STATE,
		       xml_remove_prop(node_state, XML_CIB_TAG_LRM);
		);
Exemplo n.º 12
0
int
main(int argc, char **argv)
{
    xmlNode *cib_object = NULL;
    xmlNode *status = NULL;
    int argerr = 0;
    int flag;
    int option_index = 0;

    pe_working_set_t data_set;
    cib_t *cib_conn = NULL;
    int rc = pcmk_ok;

    bool verbose = FALSE;
    gboolean xml_stdin = FALSE;
    const char *xml_tag = NULL;
    const char *xml_file = NULL;
    const char *xml_string = NULL;

    crm_log_cli_init("crm_verify");
    crm_set_options(NULL, "[modifiers] data_source", long_options,
                    "Check a (complete) confiuration for syntax and common conceptual errors."
                    "\n\nChecks the well-formedness of an XML configuration, its conformance to the configured DTD/schema and for the presence of common misconfigurations."
                    "\n\nIt reports two classes of problems, errors and warnings."
                    " Errors must be fixed before the cluster will work properly."
                    " However, it is left up to the administrator to decide if the warnings should also be fixed.");

    while (1) {
        flag = crm_get_option(argc, argv, &option_index);
        if (flag == -1)
            break;

        switch (flag) {
            case 'X':
                crm_trace("Option %c => %s", flag, optarg);
                xml_string = optarg;
                break;
            case 'x':
                crm_trace("Option %c => %s", flag, optarg);
                xml_file = optarg;
                break;
            case 'p':
                xml_stdin = TRUE;
                break;
            case 'S':
                cib_save = optarg;
                break;
            case 'V':
                verbose = TRUE;
                crm_bump_log_level(argc, argv);
                break;
            case 'L':
                USE_LIVE_CIB = TRUE;
                break;
            case '$':
            case '?':
                crm_help(flag, EX_OK);
                break;
            default:
                fprintf(stderr, "Option -%c is not yet supported\n", flag);
                ++argerr;
                break;
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc) {
            printf("%s ", argv[optind++]);
        }
        printf("\n");
    }

    if (optind > argc) {
        ++argerr;
    }

    if (argerr) {
        crm_err("%d errors in option parsing", argerr);
        crm_help(flag, EX_USAGE);
    }

    crm_info("=#=#=#=#= Getting XML =#=#=#=#=");

    if (USE_LIVE_CIB) {
        cib_conn = cib_new();
        rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
    }

    if (USE_LIVE_CIB) {
        if (rc == pcmk_ok) {
            int options = cib_scope_local | cib_sync_call;

            crm_info("Reading XML from: live cluster");
            rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
        }

        if (rc != pcmk_ok) {
            fprintf(stderr, "Live CIB query failed: %s\n", pcmk_strerror(rc));
            goto done;
        }
        if (cib_object == NULL) {
            fprintf(stderr, "Live CIB query failed: empty result\n");
            rc = -ENOMSG;
            goto done;
        }

    } else if (xml_file != NULL) {
        cib_object = filename2xml(xml_file);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input file: %s\n", xml_file);
            rc = -ENODATA;
            goto done;
        }

    } else if (xml_string != NULL) {
        cib_object = string2xml(xml_string);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input string: %s\n", xml_string);
            rc = -ENODATA;
            goto done;
        }
    } else if (xml_stdin) {
        cib_object = stdin2xml();
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input from STDIN.\n");
            rc = -ENODATA;
            goto done;
        }

    } else {
        fprintf(stderr, "No configuration source specified."
                "  Use --help for usage information.\n");
        rc = -ENODATA;
        goto done;
    }

    xml_tag = crm_element_name(cib_object);
    if (safe_str_neq(xml_tag, XML_TAG_CIB)) {
        fprintf(stderr,
                "This tool can only check complete configurations (ie. those starting with <cib>).\n");
        rc = -EBADMSG;
        goto done;
    }

    if (cib_save != NULL) {
        write_xml_file(cib_object, cib_save, FALSE);
    }

    status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
    if (status == NULL) {
        create_xml_node(cib_object, XML_CIB_TAG_STATUS);
    }

    if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
        crm_config_err("CIB did not pass DTD/schema validation");
        free_xml(cib_object);
        cib_object = NULL;

    } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
        crm_config_error = TRUE;
        free_xml(cib_object);
        cib_object = NULL;
        fprintf(stderr, "The cluster will NOT be able to use this configuration.\n");
        fprintf(stderr, "Please manually update the configuration to conform to the %s syntax.\n",
                xml_latest_schema());
    }

    set_working_set_defaults(&data_set);
    if (cib_object == NULL) {
    } else if (USE_LIVE_CIB) {
        /* we will always have a status section and can do a full simulation */
        do_calculations(&data_set, cib_object, NULL);
        cleanup_alloc_calculations(&data_set);

    } else {
        data_set.now = crm_time_new(NULL);
        data_set.input = cib_object;
        stage0(&data_set);
        cleanup_alloc_calculations(&data_set);
    }

    if (crm_config_error) {
        fprintf(stderr, "Errors found during check: config not valid\n");
        if (verbose == FALSE) {
            fprintf(stderr, "  -V may provide more details\n");
        }
        rc = -pcmk_err_generic;

    } else if (crm_config_warning) {
        fprintf(stderr, "Warnings found during check: config may not be valid\n");
        if (verbose == FALSE) {
            fprintf(stderr, "  Use -V for more details\n");
        }
        rc = -pcmk_err_generic;
    }

    if (USE_LIVE_CIB && cib_conn) {
        cib_conn->cmds->signoff(cib_conn);
        cib_delete(cib_conn);
    }

  done:
    return rc;
}