diff --git a/crm/cib/cib.c b/crm/cib/cib.c index 23058beeea..91fc57cff4 100644 --- a/crm/cib/cib.c +++ b/crm/cib/cib.c @@ -1,310 +1,324 @@ -/* $Id: cib.c,v 1.41 2004/06/03 07:52:16 andrew Exp $ */ +/* $Id: cib.c,v 1.42 2004/06/28 08:17:46 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include gboolean startCib(const char *filename) { xmlNodePtr cib = readCibXmlFile(filename); if (initializeCib(cib)) { crm_info("CIB Initialization completed successfully"); } else { // free_xml(cib); crm_warn("CIB Initialization failed, " "starting with an empty default."); activateCibXml(createEmptyCib(), filename); } return TRUE; } xmlNodePtr get_cib_copy() { return copy_xml_node_recursive(get_the_CIB()); } /* * The caller should never free the return value */ xmlNodePtr get_object_root(const char *object_type, xmlNodePtr the_root) { const char *node_stack[2]; xmlNodePtr tmp_node = NULL; node_stack[0] = XML_CIB_TAG_CONFIGURATION; node_stack[1] = object_type; if(object_type == NULL || strlen(object_type) == 0) { return the_root; /* get the whole cib */ } else if(strcmp(object_type, XML_CIB_TAG_STATUS) == 0) { node_stack[0] = XML_CIB_TAG_STATUS; node_stack[1] = NULL; /* these live in a different place */ } tmp_node = find_xml_node_nested(the_root, node_stack, 2); if (tmp_node == NULL) { crm_err( "[cib] Section cib[%s[%s]] not present", node_stack[0], node_stack[1]); } return tmp_node; } xmlNodePtr process_cib_message(xmlNodePtr message, gboolean auto_reply) { xmlNodePtr data; xmlNodePtr reply; enum cib_result result = CIBRES_OK; xmlNodePtr fragment = find_xml_node(message, XML_TAG_FRAGMENT); xmlNodePtr options = find_xml_node(message, XML_TAG_OPTIONS); - const char *op = get_xml_attr (message, XML_TAG_OPTIONS, - XML_ATTR_OP, TRUE); + const char *section = xmlGetProp(fragment, XML_ATTR_SECTION); + const char *op = xmlGetProp(options , XML_ATTR_OP); + + if(section != NULL) { + set_xml_property_copy( + options, XML_ATTR_FILTER_TYPE, section); + } data = cib_process_request(op, options, fragment, &result); crm_verbose("[cib] operation returned result %d", result); if(auto_reply) { reply = create_reply(message, data); free_xml(data); - // TODO: put real result in here set_xml_attr(reply, XML_TAG_OPTIONS, - XML_ATTR_RESULT, "ok", TRUE); + XML_ATTR_RESULT, cib_error2string(result), TRUE); return reply; } return data; } xmlNodePtr process_cib_request(const char *op, const xmlNodePtr options, const xmlNodePtr fragment) { enum cib_result result = CIBRES_OK; + const char *section = xmlGetProp(fragment, XML_ATTR_SECTION); + + if(section != NULL) { + set_xml_property_copy( + options, XML_ATTR_FILTER_TYPE, section); + } + return cib_process_request(op, options, fragment, &result); } xmlNodePtr create_cib_fragment(xmlNodePtr update, const char *section) { gboolean whole_cib = FALSE; xmlNodePtr fragment = create_xml_node(NULL, XML_TAG_FRAGMENT); xmlNodePtr cib = NULL; xmlNodePtr object_root = NULL; char *auto_section = pluralSection(update?update->name:NULL); if(update == NULL) { crm_err("No update to create a fragment for"); crm_free(auto_section); return NULL; } else if(section == NULL) { section = auto_section; } else if(strcmp(auto_section, section) != 0) { crm_err("Values for update (tag=%s) and section (%s)" " were not consistent", update->name, section); crm_free(auto_section); return NULL; } if(strcmp(section, "all")==0 && strcmp(update->name, XML_TAG_CIB)==0) { whole_cib = TRUE; } set_xml_property_copy(fragment, XML_ATTR_SECTION, section); if(whole_cib == FALSE) { cib = createEmptyCib(); object_root = get_object_root(section, cib); xmlAddChildList(object_root, xmlCopyNodeList(update)); } else { cib = xmlCopyNodeList(update); } xmlAddChild(fragment, cib); crm_free(auto_section); return fragment; } char * pluralSection(const char *a_section) { char *a_section_parent = NULL; if (a_section == NULL) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_TAG_CIB) == 0) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_CIB_TAG_NODE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_NODES); } else if(strcmp(a_section, XML_CIB_TAG_STATE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_STATUS); } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CIB_TAG_RESOURCE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); + } else if(strcmp(a_section, XML_CIB_TAG_NVPAIR) == 0) { + a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG); + } else { crm_err("Unknown section %s", a_section); a_section_parent = crm_strdup("all"); } crm_verbose("Plural is %s", a_section_parent); return a_section_parent; } const char * cib_error2string(enum cib_result return_code) { const char *error_msg = NULL; switch(return_code) { case CIBRES_MISSING_ID: error_msg = "The id field is missing"; break; case CIBRES_MISSING_TYPE: error_msg = "The type field is missing"; break; case CIBRES_MISSING_FIELD: error_msg = "A required field is missing"; break; case CIBRES_OBJTYPE_MISMATCH: error_msg = "CIBRES_OBJTYPE_MISMATCH"; break; case CIBRES_FAILED_EXISTS: error_msg = "The object already exists"; break; case CIBRES_FAILED_NOTEXISTS: error_msg = "The object does not exist"; break; case CIBRES_CORRUPT: error_msg = "The CIB is corrupt"; break; case CIBRES_FAILED_NOOBJECT: error_msg = "The update was empty"; break; case CIBRES_FAILED_NOPARENT: error_msg = "The parent object does not exist"; break; case CIBRES_FAILED_NODECOPY: error_msg = "Failed while copying update"; break; case CIBRES_OTHER: error_msg = "CIBRES_OTHER"; break; case CIBRES_OK: error_msg = "ok"; break; case CIBRES_FAILED: error_msg = "Failed"; break; case CIBRES_FAILED_STALE: error_msg = "Discarded old update"; break; case CIBRES_FAILED_ACTIVATION: error_msg = "Activation Failed"; break; case CIBRES_FAILED_NOSECTION: error_msg = "Required section was missing"; break; case CIBRES_FAILED_NOTSUPPORTED: error_msg = "Supplied information is not supported"; break; } if(error_msg == NULL) { crm_err("Unknown CIB Error %d", return_code); error_msg = ""; } return error_msg; } const char * cib_op2string(enum cib_op operation) { const char *operation_msg = NULL; switch(operation) { case 0: operation_msg = "none"; break; case 1: operation_msg = "add"; break; case 2: operation_msg = "modify"; break; case 3: operation_msg = "delete"; break; case CIB_OP_MAX: operation_msg = "invalid operation"; break; } if(operation_msg == NULL) { crm_err("Unknown CIB operation %d", operation); operation_msg = ""; } return operation_msg; } diff --git a/crm/cib/cibio.c b/crm/cib/cibio.c index 2f9aa51068..9daec30d8f 100644 --- a/crm/cib/cibio.c +++ b/crm/cib/cibio.c @@ -1,421 +1,424 @@ -/* $Id: cibio.c,v 1.28 2004/06/07 21:28:39 msoffen Exp $ */ +/* $Id: cibio.c,v 1.29 2004/06/28 08:17:46 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char * local_resource_path[] = { XML_CIB_TAG_STATUS, }; const char * resource_path[] = { XML_CIB_TAG_RESOURCES, }; const char * node_path[] = { XML_CIB_TAG_NODES, }; const char * constraint_path[] = { XML_CIB_TAG_CONSTRAINTS, }; gboolean initialized = FALSE; xmlNodePtr the_cib = NULL; xmlNodePtr node_search = NULL; xmlNodePtr resource_search = NULL; xmlNodePtr constraint_search = NULL; xmlNodePtr status_search = NULL; /* * It is the callers responsibility to free both the new CIB (output) * and the new CIB (input) */ xmlNodePtr createEmptyCib(void) { xmlNodePtr cib_root = NULL, config = NULL, status = NULL; cib_root = create_xml_node(NULL, XML_TAG_CIB); config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION); status = create_xml_node(cib_root, XML_CIB_TAG_STATUS); set_node_tstamp(cib_root); set_node_tstamp(config); set_node_tstamp(status); set_xml_property_copy(cib_root, "version", "1"); set_xml_property_copy(cib_root, "generated", XML_BOOLEAN_TRUE); create_xml_node(config, XML_CIB_TAG_NODES); create_xml_node(config, XML_CIB_TAG_RESOURCES); create_xml_node(config, XML_CIB_TAG_CONSTRAINTS); + create_xml_node(config, XML_CIB_TAG_CRMCONFIG); if (verifyCibXml(cib_root)) { return cib_root; } crm_crit( "The generated CIB did not pass integrity testing!!" " All hope is lost."); return NULL; } gboolean verifyCibXml(xmlNodePtr cib) { gboolean is_valid = TRUE; xmlNodePtr tmp_node = NULL; if (cib == NULL) { crm_err("XML Buffer was empty."); return FALSE; } tmp_node = get_object_root(XML_CIB_TAG_NODES, cib); if (tmp_node == NULL) is_valid = FALSE; tmp_node = get_object_root(XML_CIB_TAG_RESOURCES, cib); if (tmp_node == NULL) is_valid = FALSE; tmp_node = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); if (tmp_node == NULL) is_valid = FALSE; tmp_node = get_object_root(XML_CIB_TAG_STATUS, cib); if (tmp_node == NULL) is_valid = FALSE; + tmp_node = get_object_root(XML_CIB_TAG_CRMCONFIG, cib); + if (tmp_node == NULL) is_valid = FALSE; + // more integrity tests return is_valid; } /* * It is the callers responsibility to free the output of this function */ xmlNodePtr readCibXml(char *buffer) { xmlNodePtr root = string2xml(buffer); if (verifyCibXml(root) == FALSE) { free_xml(root); return createEmptyCib(); } return root; } /* * It is the callers responsibility to free the output of this function */ xmlNodePtr readCibXmlFile(const char *filename) { int s_res = -1; struct stat buf; xmlNodePtr root = NULL; if(filename != NULL) { s_res = stat(filename, &buf); } if (s_res == 0) { FILE *cib_file = fopen(filename, "r"); root = file2xml(cib_file); set_xml_property_copy(root, "generated", XML_BOOLEAN_FALSE); fclose(cib_file); } else { crm_warn("Stat of (%s) failed, file does not exist.", CIB_FILENAME); } if (verifyCibXml(root) == FALSE) { free_xml(root); // return createEmptyCib(); root = NULL; } return root; } /* * The caller should never free the return value */ xmlNodePtr get_the_CIB(void) { - return the_cib; } gboolean uninitializeCib(void) { xmlNodePtr tmp_cib = the_cib; if(tmp_cib == NULL) { crm_err("The CIB has already been deallocated."); return FALSE; } initialized = FALSE; the_cib = NULL; node_search = NULL; resource_search = NULL; constraint_search = NULL; status_search = NULL; crm_err("Deallocating the CIB."); free_xml(tmp_cib); crm_err("The CIB has been deallocated."); return TRUE; } /* * This method will not free the old CIB pointer or the new one. * We rely on the caller to have saved a pointer to the old CIB * and to free the old/bad one depending on what is appropriate. */ gboolean initializeCib(xmlNodePtr new_cib) { if (verifyCibXml(new_cib)) { initialized = FALSE; the_cib = new_cib; // update search paths /* not used yet... node_search = get_object_root(XML_CIB_TAG_NODES, new_cib); resource_search = get_object_root(XML_CIB_TAG_RESOURCES, new_cib); constraint_search = get_object_root(XML_CIB_TAG_CONSTRAINTS, new_cib); status_search = get_object_root(XML_CIB_TAG_STATUS, new_cib); */ initialized = TRUE; crm_trace("CIB initialized"); return TRUE; } else { crm_err("CIB Verification failed"); } return FALSE; } int moveFile(const char *oldname, const char *newname, gboolean backup, char *ext) { /* move 'oldname' to 'newname' by creating a hard link to it * and then removing the original hard link */ int res = 0; struct stat tmp; int s_res = stat(newname, &tmp); if (s_res >= 0) { if (backup == TRUE) { char backname[1024]; static const char *back_ext = "bak"; if (ext != NULL) back_ext = (char*)ext; snprintf(backname, sizeof(backname)-1, "%s.%s", newname, back_ext); moveFile(newname, backname, FALSE, NULL); } else { res = unlink(newname); if (res < 0) { perror("Could not remove the current backup of Cib"); return -1; } } } s_res = stat(oldname, &tmp); if (s_res >= 0) { res = link(oldname, newname); if (res < 0) { perror("Could not create backup of current Cib"); return -2; } res = unlink(oldname); if (res < 0) { perror("Could not unlink the current Cib"); return -3; } } return 0; } int activateCibBuffer(char *buffer, const char *filename) { int result = -1; xmlNodePtr local_cib = NULL; local_cib = readCibXml(buffer); result = activateCibXml(local_cib, filename); return result; } /* * This method will free the old CIB pointer on success and the new one * on failure. */ int activateCibXml(xmlNodePtr new_cib, const char *filename) { int error_code = 0; xmlNodePtr saved_cib = get_the_CIB(); const char *filename_bak = CIB_BACKUP; // calculate xmlDocPtr foo; time_t now; char *now_str = NULL; if (initializeCib(new_cib) == TRUE) { int res = moveFile(filename, filename_bak, FALSE, NULL); if (res < 0) { crm_info("Could not make backup of the current Cib " "(code: %d)... aborting update.", res); error_code = -1; } else { crm_info("Writing CIB out to %s", CIB_FILENAME); if (new_cib->doc == NULL) { foo = xmlNewDoc("1.0"); xmlDocSetRootElement(foo, new_cib); xmlSetTreeDoc(new_cib,foo); } now = time(NULL); now_str = asctime(localtime(&now)); set_xml_property_copy(new_cib, "last_written",now_str); free(now_str); /* save it. * set arg 3 to 0 to disable line breaks,1 to enable * res == num bytes saved */ res = xmlSaveFormatFile(filename, new_cib->doc, 1); /* for some reason, reading back after saving with * line-breaks doesnt go real well */ crm_info("Saved %d bytes to the Cib as XML", res); if (res < 0) { // assume 0 is good if (moveFile(filename_bak, filename, FALSE, NULL) < -1) { crm_crit("Could not restore the " "backup of the current Cib " "(code: %d)... panic!", res); error_code = -2; // should probably exit here } else if (initializeCib(saved_cib) == FALSE) { // oh we are so dead crm_crit("Could not re-initialize " "with the old CIB. " "Everything is about to go " "pear shaped"); error_code = -3; } else { crm_crit("Update of Cib failed " "(code: %d)... reverted to " "last known valid version", res); error_code = -4; } } } } else { crm_info("Ignoring invalid or NULL Cib"); error_code = -5; } // Make sure memory is cleaned up appropriately if (error_code != 0) { crm_trace("Freeing new CIB %p", new_cib); free_xml(new_cib); } else { crm_trace("Freeing saved CIB %p", saved_cib); free_xml(saved_cib); } return error_code; } diff --git a/crm/cib/cibmessages.c b/crm/cib/cibmessages.c index 05ac3cb5c6..0862ab3cae 100644 --- a/crm/cib/cibmessages.c +++ b/crm/cib/cibmessages.c @@ -1,466 +1,464 @@ -/* $Id: cibmessages.c,v 1.41 2004/06/04 09:18:30 andrew Exp $ */ +/* $Id: cibmessages.c,v 1.42 2004/06/28 08:17:46 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FILE *msg_cib_strm = NULL; enum cib_result updateList(xmlNodePtr local_cib, xmlNodePtr update_command, xmlNodePtr failed, int operation, const char *section); xmlNodePtr createCibFragmentAnswer(const char *section, xmlNodePtr failed); gboolean replace_section(const char *section, xmlNodePtr tmpCib, xmlNodePtr command); gboolean check_generation(xmlNodePtr newCib, xmlNodePtr oldCib); gboolean update_results(xmlNodePtr failed, xmlNodePtr target, int operation, int return_code); xmlNodePtr cib_process_request(const char *op, const xmlNodePtr options, const xmlNodePtr fragment, enum cib_result *result) { const char *verbose = NULL; const char *section = NULL; const char *output_section = NULL; xmlNodePtr failed = NULL; xmlNodePtr cib_answer = NULL; gboolean update_the_cib = FALSE; int cib_update_op = CIB_OP_NONE; xmlNodePtr tmpCib; char *new_value = NULL; char *old_value = NULL; int int_value = -1; *result = CIBRES_OK; verbose = xmlGetProp(options, XML_ATTR_VERBOSE); section = xmlGetProp(options, XML_ATTR_FILTER_TYPE); failed = create_xml_node(NULL, XML_TAG_FAILED); #ifdef MSG_LOG if(msg_cib_strm == NULL) { msg_cib_strm = fopen("/tmp/cib.log", "w"); } fprintf(msg_cib_strm, "[Input %s]\t%s\n", op, dump_xml_node(fragment, FALSE)); fflush(msg_cib_strm); #endif crm_debug("[cib] Processing \"%s\" event", op); if(op == NULL) { *result = CIBRES_FAILED; crm_err("No operation specified\n"); } else if(strcmp("noop", op) == 0) { ; } else if(strcmp(CRM_OP_QUIT, op) == 0) { crm_warn( "The CRMd has asked us to exit... complying"); exit(0); } else if (strcmp(CRM_OP_PING, op) == 0) { cib_answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok"); } else if (strcmp(CRM_OP_BUMP, op) == 0) { tmpCib = get_cib_copy(); crm_verbose("Handling a %s for section=%s of the cib", CRM_OP_BUMP, section); // modify the timestamp set_node_tstamp(tmpCib); old_value = xmlGetProp(get_the_CIB(), XML_ATTR_GENERATION); if(old_value != NULL) { new_value = (char*)crm_malloc(128*(sizeof(char))); int_value = atoi(old_value); sprintf(new_value, "%d", ++int_value); } else { new_value = crm_strdup("0"); } crm_debug("Generation %d(%s)->%s", int_value, old_value, new_value); set_xml_property_copy(tmpCib, XML_ATTR_GENERATION, new_value); crm_free(new_value); if(activateCibXml(tmpCib, CIB_FILENAME) >= 0) { verbose = XML_BOOLEAN_TRUE; } else { *result = CIBRES_FAILED; } } else if (strcmp("query", op) == 0) { crm_verbose("Handling a query for section=%s of the cib", section); /* force a pick-up of the relevant section before * returning */ verbose = XML_BOOLEAN_TRUE; } else if (strcmp(CRM_OP_ERASE, op) == 0) { xmlNodePtr new_cib = createEmptyCib(); // Preserve generation counters etc copy_in_properties(new_cib, get_the_CIB()); if (activateCibXml(new_cib, CIB_FILENAME) < 0) { *result = CIBRES_FAILED; } } else if (strcmp(CRM_OP_CREATE, op) == 0) { update_the_cib = TRUE; cib_update_op = CIB_OP_ADD; } else if (strcmp(CRM_OP_UPDATE, op) == 0 || strcmp(CRM_OP_WELCOME, op) == 0 || strcmp(CRM_OP_SHUTDOWN_REQ, op) == 0) { update_the_cib = TRUE; cib_update_op = CIB_OP_MODIFY; } else if (strcmp(CRM_OP_DELETE, op) == 0) { update_the_cib = TRUE; cib_update_op = CIB_OP_DELETE; } else if (strcmp(CRM_OP_REPLACE, op) == 0) { crm_verbose("Replacing section=%s of the cib", section); - section = xmlGetProp(fragment, XML_ATTR_SECTION); if (section == NULL || strlen(section) == 0 || strcmp("all", section) == 0) { tmpCib = copy_xml_node_recursive( find_xml_node(fragment, XML_TAG_CIB)); } else { tmpCib = copy_xml_node_recursive(get_the_CIB()); replace_section(section, tmpCib, fragment); } /*if(check_generation(cib_updates, tmpCib) == FALSE) *result = "discarded old update"; else */ if (activateCibXml(tmpCib, CIB_FILENAME) < 0) *result = CIBRES_FAILED; } else { *result = CIBRES_FAILED_NOTSUPPORTED; crm_err("Action [%s] is not supported by the CIB", op); } if (update_the_cib) { tmpCib = copy_xml_node_recursive(get_the_CIB()); - section = xmlGetProp(fragment, XML_ATTR_SECTION); crm_verbose("Updating section=%s of the cib (op=%s)", section, op); // should we be doing this? // do logging // make changes to a temp copy then activate if(section == NULL) { crm_err("No section specified in %s", XML_ATTR_FILTER_TYPE); *result = CIBRES_FAILED_NOSECTION; } else if(strcmp("all", section) == 0 && cib_update_op == CIB_OP_DELETE) { // delete /* order is no longer important here */ updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_STATUS); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_CONSTRAINTS); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_RESOURCES); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_NODES); } else if(strcmp("all", section) == 0) { /* order is no longer important here */ updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_NODES); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_RESOURCES); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_CONSTRAINTS); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_STATUS); } else { *result = updateList(tmpCib, fragment, failed, cib_update_op, section); } crm_trace("Activating temporary CIB"); /* if(check_generation(cib_updates, tmpCib) == FALSE) */ /* status = "discarded old update"; */ /* else */ if (activateCibXml(tmpCib, CIB_FILENAME) < 0) { *result = CIBRES_FAILED_ACTIVATION; } else if (failed->children != NULL) { *result = CIBRES_FAILED; } crm_verbose("CIB update status: %d", *result); } output_section = section; if (failed->children != NULL || *result != CIBRES_OK) { cib_answer = createCibFragmentAnswer(NULL /*"all"*/, failed); } else if (verbose != NULL && strcmp(XML_BOOLEAN_TRUE, verbose) == 0) { cib_answer = createCibFragmentAnswer(output_section, failed); } free_xml(failed); #ifdef MSG_LOG fprintf(msg_cib_strm, "[Reply (%s)]\t%s\n", op, dump_xml_node(cib_answer, FALSE)); fflush(msg_cib_strm); #endif return cib_answer; } gboolean replace_section(const char *section, xmlNodePtr tmpCib, xmlNodePtr fragment) { xmlNodePtr parent = NULL, cib_updates = NULL, new_section = NULL, old_section = NULL; cib_updates = find_xml_node(fragment, XML_TAG_CIB); /* find the old and new versions of the section */ new_section = get_object_root(section, cib_updates); old_section = get_object_root(section, tmpCib); if(old_section == NULL) { crm_err("The CIB is corrupt, cannot replace missing section %s", section); return FALSE; } else if(new_section == NULL) { crm_err("The CIB is corrupt, cannot set section %s to nothing", section); return FALSE; } parent = old_section->parent; /* unlink and free the old one */ unlink_xml_node(old_section); free_xml(old_section); /* add the new copy */ add_node_copy(parent, new_section); return TRUE; } enum cib_result updateList(xmlNodePtr local_cib, xmlNodePtr update_fragment, xmlNodePtr failed, int operation, const char *section) { xmlNodePtr child = NULL; xmlNodePtr this_section = get_object_root(section, local_cib); xmlNodePtr cib_updates = find_xml_node(update_fragment, XML_TAG_CIB); xmlNodePtr xml_section = get_object_root(section, cib_updates); if (section == NULL || xml_section == NULL) { crm_err("Section %s not found in message." " CIB update is corrupt, ignoring.", section); return CIBRES_FAILED_NOSECTION; } if(CIB_OP_NONE > operation > CIB_OP_MAX) { crm_err("Invalid operation on section %s", section); return CIBRES_FAILED; } set_node_tstamp(this_section); child = xml_section->children; while(child != NULL) { if(operation == CIB_OP_DELETE) { update_results( failed, child, operation, delete_cib_object(this_section, child)); } else if(operation == CIB_OP_MODIFY) { update_results( failed, child, operation, update_cib_object(this_section, child, FALSE)); } else { update_results( failed, child, operation, add_cib_object(this_section, child)); } child = child->next; } if (failed->children != NULL) return CIBRES_FAILED; else return CIBRES_OK; } xmlNodePtr createCibFragmentAnswer(const char *section, xmlNodePtr failed) { xmlNodePtr fragment = create_xml_node(NULL, XML_TAG_FRAGMENT); set_xml_property_copy(fragment, XML_ATTR_SECTION, section); if (section == NULL || strlen(section) == 0 || strcmp("all", section) == 0) { add_node_copy(fragment, get_the_CIB()); } else { xmlNodePtr cib = create_xml_node(fragment, XML_TAG_CIB); add_node_copy(cib, get_object_root(section, get_the_CIB())); copy_in_properties(cib, get_the_CIB()); } if (failed != NULL && failed->children != NULL) { add_node_copy(fragment, failed); } return fragment; } gboolean check_generation(xmlNodePtr newCib, xmlNodePtr oldCib) { char *new_value = xmlGetProp(newCib, XML_ATTR_GENERATION); char *old_value = xmlGetProp(oldCib, XML_ATTR_GENERATION); int int_new_value = -1; int int_old_value = -1; if(old_value != NULL) int_old_value = atoi(old_value); if(new_value != NULL) int_new_value = atoi(new_value); if(int_new_value >= int_old_value) { return TRUE; } else { crm_err("Generation from update (%d) is older than %d", int_new_value, int_old_value); } return FALSE; } gboolean update_results(xmlNodePtr failed, xmlNodePtr target, int operation, int return_code) { gboolean was_error = FALSE; const char *error_msg = NULL; const char *operation_msg = NULL; xmlNodePtr xml_node; if (return_code != CIBRES_OK) { error_msg = cib_error2string(return_code); operation_msg = cib_op2string(operation); xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB); was_error = TRUE; set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_ID, ID(target)); set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target)); set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_OP, operation_msg); set_xml_property_copy( xml_node, XML_FAILCIB_ATTR_REASON, error_msg); crm_debug("Action %s failed: %s (cde=%d)", operation_msg, error_msg, return_code); } return was_error; }