diff --git a/crm/cib/io.c b/crm/cib/io.c new file mode 100644 index 0000000000..48b0e30f97 --- /dev/null +++ b/crm/cib/io.c @@ -0,0 +1,396 @@ +/* $Id: io.c,v 1.1 2004/09/15 09:16:55 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); + create_xml_node(cib_root, XML_CIB_TAG_CRMCONFIG); + + 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); + + 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 */ + + 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); + res = write_xml_file(new_cib, CIB_FILENAME); +#ifdef DEVEL_CIB_COPY + write_xml_file(new_cib, DEVEL_DIR"/cib.xml"); +#endif + 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/main.c b/crm/cib/main.c new file mode 100644 index 0000000000..604ec8290c --- /dev/null +++ b/crm/cib/main.c @@ -0,0 +1,274 @@ +/* $Id: main.c,v 1.1 2004/09/15 09:16:55 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 + +#include + +/* #define REALTIME_SUPPORT 0 */ +#define PID_FILE WORKING_DIR"/cib.pid" +#define DAEMON_LOG LOG_DIR"/cib.log" +#define DAEMON_DEBUG LOG_DIR"/cib.debug" + +GMainLoop* mainloop = NULL; +const char* crm_system_name = CRM_SYSTEM_CIB; + +void usage(const char* cmd, int exit_status); +int init_start(void); +void cib_shutdown(int nsig); +gboolean cib_msg_callback(IPC_Channel *client, gpointer user_data); +gboolean process_maincib_message(xmlNodePtr msg, IPC_Channel *sender); + +#define OPTARGS "skrh" + +int +main(int argc, char ** argv) +{ + + int req_comms_restart = FALSE; + int req_restart = FALSE; + int req_status = FALSE; + int req_stop = FALSE; + int argerr = 0; + int flag; + + /* Redirect messages from glib functions to our handler */ + 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... */ + g_log_set_always_fatal((GLogLevelFlags)0); + + cl_log_set_entity(crm_system_name); + cl_log_set_facility(LOG_USER); + cl_log_set_logfile(DAEMON_LOG); + cl_log_set_debugfile(DAEMON_DEBUG); + CL_SIGNAL(DEBUG_INC, alter_debug); + CL_SIGNAL(DEBUG_DEC, alter_debug); + + while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { + switch(flag) { + case 's': /* Status */ + req_status = TRUE; + break; + case 'k': /* Stop (kill) */ + req_stop = TRUE; + break; + case 'r': /* Restart */ + req_restart = TRUE; + break; + case 'c': /* Restart */ + req_comms_restart = TRUE; + break; + case 'h': /* Help message */ + usage(crm_system_name, LSB_EXIT_OK); + break; + default: + ++argerr; + break; + } + } + + if (optind > argc) { + ++argerr; + } + + if (argerr) { + usage(crm_system_name,LSB_EXIT_GENERIC); + } + + /* read local config file */ + + if (req_status){ + return init_status(PID_FILE, crm_system_name); + } + + if (req_stop){ + return init_stop(PID_FILE); + } + + if (req_restart) { + init_stop(PID_FILE); + } + + return init_start(); +} + + +int +init_start(void) +{ + long pid; + ll_cluster_t *hb_fd; + int facility; + IPC_Channel *crm_ch = NULL; +#ifdef REALTIME_SUPPORT + static int crm_realtime = 1; +#endif + + if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { + crm_crit("already running: [pid %ld].", pid); + exit(LSB_EXIT_OK); + } + + crm_info("Register PID"); + register_pid(PID_FILE, FALSE, cib_shutdown); + + cl_log_set_logfile(DAEMON_LOG); +/* if (crm_verbose()) { */ + cl_log_set_debugfile(DAEMON_DEBUG); +/* } */ + + hb_fd = ll_cluster_new("heartbeat"); + + crm_info("Switching to Heartbeat logger"); + if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { + cl_log_set_facility(facility); + } + + if(startCib(CIB_FILENAME) == FALSE){ + crm_crit("Cannot start CIB... terminating"); + exit(1); + } + + crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, + subsystem_input_dispatch, + (void*)process_maincib_message); + + if(crm_ch != NULL) { + send_hello_message(crm_ch, "-", CRM_SYSTEM_CIB, "0", "1"); + + /* Create the mainloop and run it... */ + mainloop = g_main_new(FALSE); + crm_info("Starting %s", crm_system_name); + +#ifdef REALTIME_SUPPORT + if (crm_realtime == 1) { + cl_enable_realtime(); + } else if (crm_realtime == 0) { + cl_disable_realtime(); + } + cl_make_realtime(SCHED_RR, 5, 64, 64); +#endif + + g_main_run(mainloop); + return_to_orig_privs(); + } else { + crm_err("Connection to CRM not valid, exiting."); + } + + + if (unlink(PID_FILE) == 0) { + crm_info("[%s] stopped", crm_system_name); + } + return 0; +} + +gboolean +process_maincib_message(xmlNodePtr msg, IPC_Channel *sender) +{ + const char *op = get_xml_attr (msg, XML_TAG_OPTIONS, + XML_ATTR_OP, FALSE); + + const char *sys_to = xmlGetProp(msg, XML_ATTR_SYSTO); + + crm_debug("Processing %s message", op); + + if(safe_str_eq(xmlGetProp(msg, XML_ATTR_MSGTYPE), XML_ATTR_REQUEST)) { + crm_info("Message was a response not a request." + " Discarding"); + + } else if (strcmp(sys_to, CRM_SYSTEM_CIB) == 0 + || strcmp(sys_to, CRM_SYSTEM_DCIB) == 0) { + + xmlNodePtr answer = process_cib_message(msg, TRUE); + if (send_xmlipc_message(sender, answer)==FALSE) + crm_warn("Cib answer could not be sent"); + free_xml(answer); + + } else { + crm_warn("Received a message destined for %s by mistake", + sys_to); + return FALSE; + } + + return TRUE; +} + + + +void +usage(const char* cmd, int exit_status) +{ + FILE* stream; + + stream = exit_status ? stderr : stdout; + + fprintf(stream, "usage: %s [-srkh]" + "[-c configure file]\n", cmd); +/* fprintf(stream, "\t-d\tsets debug level\n"); */ +/* fprintf(stream, "\t-s\tgets daemon status\n"); */ +/* fprintf(stream, "\t-r\trestarts daemon\n"); */ +/* fprintf(stream, "\t-k\tstops daemon\n"); */ +/* fprintf(stream, "\t-h\thelp message\n"); */ + fflush(stream); + + exit(exit_status); +} + +void +cib_shutdown(int nsig) +{ + static int shuttingdown = 0; + CL_SIGNAL(nsig, cib_shutdown); + + if (!shuttingdown) { + shuttingdown = 1; + } + if (mainloop != NULL && g_main_is_running(mainloop)) { + g_main_quit(mainloop); + } else { + exit(LSB_EXIT_OK); + } +} diff --git a/crm/cib/messages.c b/crm/cib/messages.c new file mode 100644 index 0000000000..5dac290c00 --- /dev/null +++ b/crm/cib/messages.c @@ -0,0 +1,459 @@ +/* $Id: messages.c,v 1.1 2004/09/15 09:16:55 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 *id = 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); + id = xmlGetProp(options, XML_ATTR_FILTER_ID); + failed = create_xml_node(NULL, XML_TAG_FAILED); + +#ifdef MSG_LOG + if(msg_cib_strm == NULL) { + msg_cib_strm = fopen(DEVEL_DIR"/cib.log", "w"); + } + fprintf(msg_cib_strm, "\n====================\n"); + fprintf(msg_cib_strm, "[Input %s]\t%s\n", op, dump_xml_formatted(fragment)); + 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); + + /* grab the whole section by forcing a pick-up of + * the relevant section before returning + */ + verbose = XML_BOOLEAN_TRUE; + + } else if (strcmp(CRM_OP_ERASE, op) == 0) { + + crm_err("Op %s is not currently supported", op); + *result = CIBRES_FAILED_NOTSUPPORTED; + + } 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); + + 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()); + + 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) { + /* 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"); + + fprintf(msg_cib_strm, "[Activating CIB (%s - %s)]\t%s\n", op, + cib_error2string(*result), + dump_xml_formatted(tmpCib)); + /* 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; + + } + fprintf(msg_cib_strm, "[New CIB (%s - %s)]\t%s\n", op, + cib_error2string(*result), + dump_xml_formatted(get_the_CIB())); + fflush(msg_cib_strm); + + 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:%s)]\t%s\n", + op, cib_error2string(*result), + dump_xml_formatted(cib_answer)); + 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 this_section = get_object_root(section, local_cib); + xmlNodePtr cib_updates = NULL; + xmlNodePtr xml_section = NULL; + + cib_updates = find_xml_node(update_fragment, XML_TAG_CIB); + 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); + + xml_child_iter( + xml_section, a_child, NULL, + + crm_debug("%s to section %s with <%s id=%s>", + cib_op2string(operation), section, a_child->name, xmlGetProp(a_child, "id")); + + if(operation == CIB_OP_DELETE) { + update_results( + failed, a_child, operation, + delete_cib_object(this_section, a_child)); + + } else if(operation == CIB_OP_MODIFY) { + + update_results( + failed, a_child, operation, + update_cib_object(this_section, a_child, FALSE)); + + } else { + update_results( + failed, a_child, operation, + add_cib_object(this_section, a_child)); + } + + ); + + 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; + + operation_msg = cib_op2string(operation); + + if (return_code != CIBRES_OK) { + error_msg = cib_error2string(return_code); + + 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); + + } else { + crm_debug("CIB %s passed", operation_msg); + } + + return was_error; +} + diff --git a/crm/cib/primatives.c b/crm/cib/primatives.c new file mode 100644 index 0000000000..5eeb3ad7de --- /dev/null +++ b/crm/cib/primatives.c @@ -0,0 +1,601 @@ +/* $Id: primatives.c,v 1.1 2004/09/15 09:16:55 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 + + +/* + * In case of confusion, this is the memory management policy for + * all functions in this file. + * + * All add/modify functions use copies of supplied data. + * It is therefore appropriate that the callers free the supplied data + * at some point after the function has finished. + * + * All delete functions will handle the freeing of deleted data + * but not the function arguments. + */ + + +void update_node_state(xmlNodePtr existing_node, xmlNodePtr update); + + + +/* --- Resource */ + +int +addResource(xmlNodePtr cib, xmlNodePtr anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Adding " XML_CIB_TAG_RESOURCE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_RESOURCES, cib); + return add_cib_object(root, anXmlNode); +} + + +xmlNodePtr +findResource(xmlNodePtr cib, const char *id) +{ + xmlNodePtr root = NULL, ret = NULL; + + + root = get_object_root(XML_CIB_TAG_RESOURCES, cib); + ret = find_entity(root, XML_CIB_TAG_RESOURCE, id, FALSE); + + return ret; +} + +int +updateResource(xmlNodePtr cib, xmlNodePtr anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Updating " XML_CIB_TAG_RESOURCE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_RESOURCES, cib); + return update_cib_object(root, anXmlNode, FALSE); +} + +int +delResource(xmlNodePtr cib, xmlNodePtr delete_spec) +{ + const char *id = ID(delete_spec); + xmlNodePtr root; + + if(id == NULL || strlen(id) == 0) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Deleting " XML_CIB_TAG_RESOURCE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_RESOURCES, cib); + return delete_cib_object(root, delete_spec); +} + + +/* --- Constraint */ + +int +addConstraint(xmlNodePtr cib, xmlNodePtr anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Adding " XML_CIB_TAG_CONSTRAINT " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); + return add_cib_object(root, anXmlNode); +} + +xmlNodePtr +findConstraint(xmlNodePtr cib, const char *id) +{ + xmlNodePtr root = NULL, ret = NULL; + + + root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); + ret = find_entity(root, XML_CIB_TAG_CONSTRAINT, id, FALSE); + + return ret; +} + + +int +updateConstraint(xmlNodePtr cib, xmlNodePtr anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Updating " XML_CIB_TAG_CONSTRAINT " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); + return update_cib_object(root, anXmlNode, FALSE); +} + +int +delConstraint(xmlNodePtr cib, xmlNodePtr delete_spec) +{ + const char *id = ID(delete_spec); + xmlNodePtr root; + + if(id == NULL || strlen(id) == 0) { + return CIBRES_MISSING_ID; + } + crm_verbose("Deleting " XML_CIB_TAG_CONSTRAINT " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); + return delete_cib_object(root, delete_spec); +} + +/* --- HaNode */ + +int +addHaNode(xmlNodePtr cib, xmlNodePtr anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Adding " XML_CIB_TAG_NODE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_NODES, cib); + return add_cib_object(root, anXmlNode); +} + +xmlNodePtr +findHaNode(xmlNodePtr cib, const char *id) +{ + xmlNodePtr root = NULL, ret = NULL; + + + root = get_object_root(XML_CIB_TAG_NODES, cib); + ret = find_entity(root, XML_CIB_TAG_NODE, id, FALSE); + + return ret; +} + + + +int +updateHaNode(xmlNodePtr cib, cibHaNode *anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Updating " XML_CIB_TAG_NODE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_NODES, cib); + return update_cib_object(root, anXmlNode, FALSE); +} + +int +delHaNode(xmlNodePtr cib, xmlNodePtr delete_spec) +{ + const char *id = ID(delete_spec); + xmlNodePtr root; + + if(id == NULL || strlen(id) == 0) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Deleting " XML_CIB_TAG_NODE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); + return delete_cib_object(root, delete_spec); +} + +/* --- Status */ + +int +addStatus(xmlNodePtr cib, xmlNodePtr anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Adding " XML_CIB_TAG_NODE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_STATUS, cib); + return add_cib_object(root, anXmlNode); +} + +xmlNodePtr +findStatus(xmlNodePtr cib, const char *id) +{ + xmlNodePtr root = NULL, ret = NULL; + + root = get_object_root(XML_CIB_TAG_STATUS, cib); + ret = find_entity(root, XML_CIB_TAG_STATE, id, FALSE); + + return ret; +} + +int +updateStatus(xmlNodePtr cib, xmlNodePtr anXmlNode) +{ + const char *id = ID(anXmlNode); + xmlNodePtr root; + + if (id == NULL || strlen(id) < 1) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Updating " XML_CIB_TAG_NODE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_STATUS, cib); + return update_cib_object(root, anXmlNode, FALSE); +} + +int +delStatus(xmlNodePtr cib, xmlNodePtr delete_spec) +{ + const char *id = ID(delete_spec); + xmlNodePtr root; + + if(id == NULL || strlen(id) == 0) { + return CIBRES_MISSING_ID; + } + + crm_verbose("Deleting " XML_CIB_TAG_STATE " (%s)...", id); + + root = get_object_root(XML_CIB_TAG_STATUS, cib); + return delete_cib_object(root, delete_spec); +} + + + + + +int +delete_cib_object(xmlNodePtr parent, xmlNodePtr delete_spec) +{ + const char *object_name = NULL; + const char *object_id = NULL; + xmlNodePtr equiv_node = NULL; + int result = CIBRES_OK; + + if(delete_spec == NULL) { + return CIBRES_FAILED_NOOBJECT; + } else if(parent == NULL) { + return CIBRES_FAILED_NOPARENT; + } + + object_name = delete_spec->name; + object_id = xmlGetProp(delete_spec, XML_ATTR_ID); + + if(object_id == NULL) { + /* placeholder object */ + equiv_node = find_xml_node(parent, object_name); + + } else { + equiv_node = + find_entity(parent, object_name, object_id, FALSE); + + } + + if(equiv_node == NULL) { + return CIBRES_FAILED_NOTEXISTS; + + } else if(delete_spec->children == NULL) { + + /* only leaves are deleted */ + unlink_xml_node(equiv_node); + free_xml(equiv_node); + + } else { + + xml_child_iter( + delete_spec, child, NULL, + + int tmp_result = delete_cib_object(equiv_node, child); + + /* only the first error is likely to be interesting */ + if(tmp_result != CIBRES_OK && result == CIBRES_OK) { + result = tmp_result; + } + ); + } + + return result; +} + +int +add_cib_object(xmlNodePtr parent, xmlNodePtr new_obj) +{ + const char *object_name = NULL; + const char *object_id = NULL; + xmlNodePtr equiv_node = NULL; + + if(new_obj == NULL) { + return CIBRES_FAILED_NOOBJECT; + } else if(parent == NULL) { + return CIBRES_FAILED_NOPARENT; + } + + object_name = new_obj->name; + object_id = xmlGetProp(new_obj, XML_ATTR_ID); + + if(object_id == NULL) { + /* placeholder object */ + equiv_node = find_xml_node(parent, object_name); + + } else { + equiv_node = + find_entity(parent, object_name, object_id, FALSE); + + } + + if(equiv_node != NULL) { + return CIBRES_FAILED_EXISTS; + + } else if(add_node_copy(parent, new_obj) == NULL) { + return CIBRES_FAILED_NODECOPY; + + } + + return CIBRES_OK; +} + + +int +update_cib_object(xmlNodePtr parent, xmlNodePtr new_obj, gboolean force) +{ + const char *replace = NULL; + const char *object_name = NULL; + const char *object_id = NULL; + xmlNodePtr equiv_node = NULL; + int result = CIBRES_OK; + + if(new_obj == NULL) { + return CIBRES_FAILED_NOOBJECT; + + } else if(parent == NULL) { + return CIBRES_FAILED_NOPARENT; + + } + + object_name = new_obj->name; + object_id = xmlGetProp(new_obj, XML_ATTR_ID); + + crm_debug("Processing update to <%s id=%s>", object_name, object_id); + + if(object_id == NULL) { + /* placeholder object */ + equiv_node = find_xml_node(parent, object_name); + + } else { + equiv_node = find_entity(parent, object_name, object_id, FALSE); + } + + if(equiv_node == NULL) { + crm_debug("No node to update, creating %s instead", new_obj->name); + if(parent == NULL) { + crm_warn("Failed to add <%s id=%s> (NULL parent)", + object_name, object_id); + return CIBRES_FAILED_NODECOPY; + + } else if(add_node_copy(parent, new_obj) == NULL) { + crm_warn("Failed to add <%s id=%s>", object_name, object_id); + return CIBRES_FAILED_NODECOPY; + } else { + crm_debug("Added <%s id=%s>", object_name, object_id); + + if(object_id == NULL) { + /* placeholder object */ + equiv_node = find_xml_node(parent, object_name); + + } else { + equiv_node = find_entity(parent, object_name, object_id, FALSE); + } + } + + } else { + crm_verbose("Found node <%s id=%s> to update", object_name, object_id); + + replace = xmlGetProp(new_obj, "replace"); + + if(force == FALSE) { + const char *ts_existing = NULL; + const char *ts_new = NULL; + + /* default to false? + * + * that would mean every node would have to + * carry a timestamp + */ + gboolean is_update = TRUE; + + ts_existing = TSTAMP(equiv_node); + ts_new = TSTAMP(new_obj); + + if(ts_new != NULL && ts_existing != NULL) { + is_update = (strcmp(ts_new, ts_existing) > 0); + } + + if(is_update == FALSE) { + crm_err( + "Ignoring old update to <%s id=\"%s\">" + "(%s vs. %s)", + object_name, object_id, + ts_new, ts_existing); + return CIBRES_FAILED_STALE; + } + } + + if(replace != NULL) { + xmlNodePtr remove = find_xml_node(equiv_node, replace); + if(remove != NULL) { + crm_debug("Replacing node <%s> in <%s>", + replace, equiv_node->name); + xmlUnlinkNode(remove); + remove->doc = NULL; + free_xml(remove); + } + xmlUnsetProp(new_obj, "replace"); + xmlUnsetProp(equiv_node, "replace"); + } + + if(safe_str_eq(XML_CIB_TAG_STATE, object_name)){ + update_node_state(equiv_node, new_obj); + + } else { + copy_in_properties(equiv_node, new_obj); + + } + + crm_debug("Processing children of <%s id=%s>", + object_name, object_id); + + xml_child_iter( + new_obj, a_child, NULL, + int tmp_result = 0; + crm_debug("Updating child <%s id=%s>", + a_child->name, + xmlGetProp(a_child, XML_ATTR_ID)); + + tmp_result = + update_cib_object(equiv_node, a_child, force); + + /* only the first error is likely to be interesting */ + if(tmp_result != CIBRES_OK) { + crm_err("Error updating child <%s id=%s>", + a_child->name, + xmlGetProp(a_child, XML_ATTR_ID)); + + if(result == CIBRES_OK) { + result = tmp_result; + } + } + ); + + } + crm_debug("Finished with <%s id=%s>", object_name, object_id); + + return result; +} + + +void +update_node_state(xmlNodePtr target, xmlNodePtr update) +{ + const char *source = NULL; + xmlAttrPtr prop_iter = NULL; + gboolean any_updates = FALSE; + gboolean clear_stonith = FALSE; + gboolean clear_shutdown = FALSE; + + prop_iter = update->properties; + while(prop_iter != NULL) { + const char *local_prop_name = prop_iter->name; + const char *local_prop_value = + xmlGetProp(update, local_prop_name); + + if(local_prop_name == NULL) { + /* error */ + + } else if(strcmp(local_prop_name, XML_ATTR_ID) == 0) { + + } else if(strcmp(local_prop_name, XML_ATTR_TSTAMP) == 0) { + + } else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_SHUTDOWN) == 0) { + clear_shutdown = TRUE; + + } else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_STONITH) == 0) { + clear_stonith = TRUE; + clear_shutdown = TRUE; + + } else if(strcmp(local_prop_name, "source") == 0) { + source = local_prop_value; + + } else { + any_updates = TRUE; + set_xml_property_copy(target, + local_prop_name, + local_prop_value); + } + + prop_iter = prop_iter->next; + } + + if(clear_shutdown) { + /* unset XML_CIB_ATTR_SHUTDOWN */ + crm_verbose("Clearing %s", XML_CIB_ATTR_SHUTDOWN); + xmlUnsetProp(target, XML_CIB_ATTR_SHUTDOWN); + any_updates = TRUE; + } + + if(clear_stonith) { + /* unset XML_CIB_ATTR_STONITH */ + crm_verbose("Clearing %s", XML_CIB_ATTR_STONITH); + xmlUnsetProp(target, XML_CIB_ATTR_STONITH); + any_updates = TRUE; + } + + if(any_updates) { + set_node_tstamp(target); + set_xml_property_copy(target, "source", source); + } + +} diff --git a/crm/crmd/main.c b/crm/crmd/main.c new file mode 100644 index 0000000000..8e2affe23a --- /dev/null +++ b/crm/crmd/main.c @@ -0,0 +1,227 @@ +/* $Id: main.c,v 1.1 2004/09/15 09:16:55 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 + +#include +#include +#include +#include + +#include +#include + +#include + +const char* crm_system_name = SYS_NAME; +#define OPTARGS "skrhV" + +void usage(const char* cmd, int exit_status); +int init_start(void); +void crmd_hamsg_callback(const struct ha_msg* msg, void* private_data); +gboolean crmd_tickle_apphb(gpointer data); + +GMainLoop* crmd_mainloop = NULL; + +int +main(int argc, char ** argv) +{ + int req_restart = FALSE; + int req_status = FALSE; + int req_stop = FALSE; + int argerr = 0; + int flag; + +#ifdef DEVEL_DIR + mkdir(DEVEL_DIR, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif + + /* Redirect messages from glib functions to our handler */ + 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... */ + g_log_set_always_fatal((GLogLevelFlags)0); + + cl_log_set_entity(crm_system_name); + cl_log_set_logfile(DAEMON_LOG); + cl_log_set_debugfile(DAEMON_DEBUG); + cl_log_set_facility(LOG_USER); + CL_SIGNAL(DEBUG_INC, alter_debug); + CL_SIGNAL(DEBUG_DEC, alter_debug); + + struct stat buf; + if(stat(DEVEL_DIR, &buf) != 0) { + cl_perror("Stat of %s failed... exiting", DEVEL_DIR); + exit(100); + } + + while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { + switch(flag) { + case 'V': + alter_debug(DEBUG_INC); + break; + case 's': /* Status */ + req_status = TRUE; + break; + case 'k': /* Stop (kill) */ + req_stop = TRUE; + break; + case 'r': /* Restart */ + req_restart = TRUE; + break; + case 'h': /* Help message */ + usage(crm_system_name, LSB_EXIT_OK); + break; + default: + ++argerr; + break; + } + } + + if (optind > argc) { + ++argerr; + } + + if (argerr) { + usage(crm_system_name,LSB_EXIT_GENERIC); + } + + /* read local config file */ + + if (req_status){ + return init_status(PID_FILE, crm_system_name); + } + + if (req_stop){ + return init_stop(PID_FILE); + } + + if (req_restart) { + init_stop(PID_FILE); + } + + return init_start(); +} + + +int +init_start(void) +{ + long pid; + enum crmd_fsa_state state; + + if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { + crm_crit("already running: [pid %ld].", pid); + exit(LSB_EXIT_OK); + } + + fsa_state = S_PENDING; + state = s_crmd_fsa(C_STARTUP, I_STARTUP, NULL); + + if (state == S_PENDING) { + /* Create the mainloop and run it... */ + crmd_mainloop = g_main_new(FALSE); + crm_info("Starting %s", crm_system_name); + +#ifdef REALTIME_SUPPORT + static int crm_realtime = 1; + if (crm_realtime == 1){ + cl_enable_realtime(); + }else if (crm_realtime == 0){ + cl_disable_realtime(); + } + cl_make_realtime(SCHED_RR, 5, 64, 64); +#endif + + g_main_run(crmd_mainloop); + return_to_orig_privs(); + } else { + + crm_err("Startup of CRMd failed. Current state: %s", + fsa_state2string(state)); + + } + + + if (unlink(PID_FILE) == 0) { + crm_info("[%s] stopped", crm_system_name); + } + + return state != S_PENDING; +} + + + +void +usage(const char* cmd, int exit_status) +{ + FILE* stream; + + stream = exit_status ? stderr : stdout; + + fprintf(stream, "usage: %s [-srkh]" + "[-c configure file]\n", cmd); +/* fprintf(stream, "\t-d\tsets debug level\n"); */ +/* fprintf(stream, "\t-s\tgets daemon status\n"); */ +/* fprintf(stream, "\t-r\trestarts daemon\n"); */ +/* fprintf(stream, "\t-k\tstops daemon\n"); */ +/* fprintf(stream, "\t-h\thelp message\n"); */ + fflush(stream); + + exit(exit_status); +} + + +gboolean +crmd_tickle_apphb(gpointer data) +{ + char app_instance[APPNAME_LEN]; + int rc = 0; + sprintf(app_instance, "%s_%ld", crm_system_name, (long)getpid()); + + rc = apphb_hb(); + if (rc < 0) { + cl_perror("%s apphb_hb failure", app_instance); + exit(3); + } + return TRUE; +} diff --git a/crm/pengine/main.c b/crm/pengine/main.c new file mode 100644 index 0000000000..c7bd6ca3d0 --- /dev/null +++ b/crm/pengine/main.c @@ -0,0 +1,232 @@ +/* $Id: main.c,v 1.1 2004/09/15 09:16:55 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 + +#define SYS_NAME CRM_SYSTEM_PENGINE +#define OPTARGS "skrhV" +#define PID_FILE WORKING_DIR "/" SYS_NAME ".pid" +#define DAEMON_LOG DEVEL_DIR"/"SYS_NAME".log" +#define DAEMON_DEBUG DEVEL_DIR"/"SYS_NAME".debug" + +GMainLoop* mainloop = NULL; +const char* crm_system_name = SYS_NAME; + + +void usage(const char* cmd, int exit_status); +int init_start(void); +void pengine_shutdown(int nsig); +extern gboolean process_pe_message(xmlNodePtr msg, IPC_Channel *sender); + +int +main(int argc, char ** argv) +{ + int req_restart = FALSE; + int req_status = FALSE; + int req_stop = FALSE; + int argerr = 0; + int flag; + + /* Redirect messages from glib functions to our handler */ + 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... */ + g_log_set_always_fatal((GLogLevelFlags)0); + + cl_log_set_entity(crm_system_name); + cl_log_set_facility(LOG_USER); + + cl_log_set_logfile(DAEMON_LOG); + cl_log_set_debugfile(DAEMON_DEBUG); + CL_SIGNAL(DEBUG_INC, alter_debug); + CL_SIGNAL(DEBUG_DEC, alter_debug); + + while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { + switch(flag) { + case 'V': + alter_debug(DEBUG_INC); + break; + case 's': /* Status */ + req_status = TRUE; + break; + case 'k': /* Stop (kill) */ + req_stop = TRUE; + break; + case 'r': /* Restart */ + req_restart = TRUE; + break; + case 'h': /* Help message */ + usage(crm_system_name, LSB_EXIT_OK); + break; + default: + ++argerr; + break; + } + } + + if (optind > argc) { + ++argerr; + } + + if (argerr) { + usage(crm_system_name,LSB_EXIT_GENERIC); + } + + /* read local config file */ + + if (req_status){ + return init_status(PID_FILE, crm_system_name); + } + + if (req_stop){ + return init_stop(PID_FILE); + } + + if (req_restart) { + init_stop(PID_FILE); + } + + return init_start(); + +} + + +int +init_start(void) +{ + long pid; + ll_cluster_t* hb_fd = NULL; + int facility; + IPC_Channel *crm_ch = NULL; +#ifdef REALTIME_SUPPORT + static int crm_realtime = 1; +#endif + + if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { + crm_crit("already running: [pid %ld].", pid); + exit(LSB_EXIT_OK); + } + + /* change the logging facility to the one used by heartbeat daemon */ + hb_fd = ll_cluster_new("heartbeat"); + + crm_info("Switching to Heartbeat logger"); + if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { + cl_log_set_facility(facility); + } + + crm_info("Register PID"); + register_pid(PID_FILE, FALSE, pengine_shutdown); + + crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, + subsystem_input_dispatch, + (void*)process_pe_message); + + if(crm_ch != NULL) { + send_hello_message(crm_ch, "1234", CRM_SYSTEM_PENGINE, "0", "1"); + + /* Create the mainloop and run it... */ + mainloop = g_main_new(FALSE); + crm_info("Starting %s", crm_system_name); + + +#ifdef REALTIME_SUPPORT + if (crm_realtime == 1){ + cl_enable_realtime(); + }else if (crm_realtime == 0){ + cl_disable_realtime(); + } + cl_make_realtime(SCHED_RR, 5, 64, 64); +#endif + + g_main_run(mainloop); + + } else { + crm_err("Could not connect to the CRMd"); + } + + return_to_orig_privs(); + + if (unlink(PID_FILE) == 0) { + crm_info("[%s] stopped", crm_system_name); + } + + if(crm_ch != NULL) + return 0; + + return 1; +} + + +void +usage(const char* cmd, int exit_status) +{ + FILE* stream; + + stream = exit_status ? stderr : stdout; + + fprintf(stream, "usage: %s [-srkh]" + "[-c configure file]\n", cmd); +/* fprintf(stream, "\t-d\tsets debug level\n"); */ +/* fprintf(stream, "\t-s\tgets daemon status\n"); */ +/* fprintf(stream, "\t-r\trestarts daemon\n"); */ +/* fprintf(stream, "\t-k\tstops daemon\n"); */ +/* fprintf(stream, "\t-h\thelp message\n"); */ + fflush(stream); + + exit(exit_status); +} + +void +pengine_shutdown(int nsig) +{ + static int shuttingdown = 0; + CL_SIGNAL(nsig, pengine_shutdown); + + if (!shuttingdown) { + shuttingdown = 1; + } + if (mainloop != NULL && g_main_is_running(mainloop)) { + g_main_quit(mainloop); + }else{ + exit(LSB_EXIT_OK); + } +} + diff --git a/crm/tengine/main.c b/crm/tengine/main.c new file mode 100644 index 0000000000..991c8546d1 --- /dev/null +++ b/crm/tengine/main.c @@ -0,0 +1,230 @@ +/* $Id: main.c,v 1.1 2004/09/15 09:16:55 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 + +#define SYS_NAME CRM_SYSTEM_TENGINE +#define OPTARGS "skrhV" +#define PID_FILE WORKING_DIR "/" SYS_NAME ".pid" +#define DAEMON_LOG DEVEL_DIR"/"SYS_NAME".log" +#define DAEMON_DEBUG DEVEL_DIR"/"SYS_NAME".debug" + +GMainLoop* mainloop = NULL; +const char* crm_system_name = SYS_NAME; + + +void usage(const char* cmd, int exit_status); +int init_start(void); +void tengine_shutdown(int nsig); + +int +main(int argc, char ** argv) +{ + int req_restart = FALSE; + int req_status = FALSE; + int req_stop = FALSE; + int argerr = 0; + int flag; + + /* Redirect messages from glib functions to our handler */ + 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... */ + g_log_set_always_fatal((GLogLevelFlags)0); + + cl_log_set_entity(crm_system_name); + cl_log_set_facility(LOG_USER); + cl_log_set_logfile(DAEMON_LOG); + cl_log_set_debugfile(DAEMON_DEBUG); + CL_SIGNAL(DEBUG_INC, alter_debug); + CL_SIGNAL(DEBUG_DEC, alter_debug); + + while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { + switch(flag) { + case 'V': + alter_debug(DEBUG_INC); + break; + case 's': /* Status */ + req_status = TRUE; + break; + case 'k': /* Stop (kill) */ + req_stop = TRUE; + break; + case 'r': /* Restart */ + req_restart = TRUE; + break; + case 'h': /* Help message */ + usage(crm_system_name, LSB_EXIT_OK); + break; + default: + ++argerr; + break; + } + } + + if (optind > argc) { + ++argerr; + } + + if (argerr) { + usage(crm_system_name,LSB_EXIT_GENERIC); + } + + /* read local config file */ + + if (req_status){ + return init_status(PID_FILE, crm_system_name); + } + + if (req_stop){ + return init_stop(PID_FILE); + } + + if (req_restart) { + init_stop(PID_FILE); + } + + return init_start(); + +} + + +int +init_start(void) +{ + long pid; + ll_cluster_t* hb_fd = NULL; + int facility; +#ifdef REALTIME_SUPPORT + static int crm_realtime = 1; +#endif + + if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { + crm_crit("already running: [pid %ld].", pid); + exit(LSB_EXIT_OK); + } + + /* change the logging facility to the one used by heartbeat daemon */ + hb_fd = ll_cluster_new("heartbeat"); + + crm_info("Switching to Heartbeat logger"); + if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { + cl_log_set_facility(facility); + } + + crm_info("Register PID"); + register_pid(PID_FILE, FALSE, tengine_shutdown); + + crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, + subsystem_input_dispatch, + (void*)process_te_message); + + if(crm_ch != NULL) { + send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "0", "1"); + + /* Create the mainloop and run it... */ + mainloop = g_main_new(FALSE); + crm_info("Starting %s", crm_system_name); + + +#ifdef REALTIME_SUPPORT + if (crm_realtime == 1){ + cl_enable_realtime(); + }else if (crm_realtime == 0){ + cl_disable_realtime(); + } + cl_make_realtime(SCHED_RR, 5, 64, 64); +#endif + + g_main_run(mainloop); + + } else { + crm_err("Could not connect to the CRMd"); + } + + return_to_orig_privs(); + + if (unlink(PID_FILE) == 0) { + crm_info("[%s] stopped", crm_system_name); + } + + if(crm_ch != NULL) + return 0; + + return 1; +} + + +void +usage(const char* cmd, int exit_status) +{ + FILE* stream; + + stream = exit_status ? stderr : stdout; + + fprintf(stream, "usage: %s [-srkh]" + "[-c configure file]\n", cmd); +/* fprintf(stream, "\t-d\tsets debug level\n"); */ +/* fprintf(stream, "\t-s\tgets daemon status\n"); */ +/* fprintf(stream, "\t-r\trestarts daemon\n"); */ +/* fprintf(stream, "\t-k\tstops daemon\n"); */ +/* fprintf(stream, "\t-h\thelp message\n"); */ + fflush(stream); + + exit(exit_status); +} + +void +tengine_shutdown(int nsig) +{ + static int shuttingdown = 0; + CL_SIGNAL(nsig, tengine_shutdown); + + if (!shuttingdown) { + shuttingdown = 1; + } + if (mainloop != NULL && g_main_is_running(mainloop)) { + g_main_quit(mainloop); + }else{ + exit(LSB_EXIT_OK); + } +}