diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c index 9dc532a689..7eb1729cb1 100644 --- a/crm/admin/cibadmin.c +++ b/crm/admin/cibadmin.c @@ -1,574 +1,570 @@ -/* $Id: cibadmin.c,v 1.31 2005/05/18 20:15:57 andrew Exp $ */ +/* $Id: cibadmin.c,v 1.32 2005/05/19 10:50:08 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 /* someone complaining about _ha_msg_mod not being found */ #include int exit_code = cib_ok; int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; const char *crm_system_name = "cibadmin"; IPC_Channel *crmd_channel = NULL; const char *host = NULL; void usage(const char *cmd, int exit_status); enum cib_errors do_init(void); int do_work(const char *xml_text, int command_options, crm_data_t **output); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); crm_data_t *handleCibMod(const char *xml); gboolean admin_message_timeout(gpointer data); void cib_connection_destroy(gpointer user_data); void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); int command_options = 0; const char *cib_action = NULL; typedef struct str_list_s { int num_items; char *value; struct str_list_s *next; } str_list_t; char *id = NULL; char *this_msg_reference = NULL; char *obj_type = NULL; char *clear = NULL; char *status = NULL; char *migrate_from = NULL; char *migrate_res = NULL; char *subtype = NULL; char *reset = NULL; int request_id = 0; int operation_status = 0; cib_t *the_cib = NULL; #define OPTARGS "V?i:o:QDUCEX:t:Srwlsh:MBfb" int main(int argc, char **argv) { int option_index = 0; int argerr = 0; int flag; char *admin_input_xml = NULL; crm_data_t *output = NULL; static struct option long_options[] = { /* Top-level Options */ {CRM_OP_CIB_ERASE, 0, 0, 'E'}, {CRM_OP_CIB_QUERY, 0, 0, 'Q'}, {CRM_OP_CIB_CREATE, 0, 0, 'C'}, {CRM_OP_CIB_REPLACE, 0, 0, 'R'}, {CRM_OP_CIB_UPDATE, 0, 0, 'U'}, {CRM_OP_CIB_DELETE, 0, 0, 'D'}, {CRM_OP_CIB_BUMP, 0, 0, 'B'}, {CRM_OP_CIB_SYNC, 0, 0, 'S'}, {CRM_OP_CIB_SLAVE, 0, 0, 'r'}, {CRM_OP_CIB_MASTER, 0, 0, 'w'}, {CRM_OP_CIB_ISMASTER,0, 0, 'M'}, {"force-quorum",0, 0, 'f'}, {"local", 0, 0, 'l'}, {"sync-call", 0, 0, 's'}, {"no-bcast", 0, 0, 'b'}, {"host", 0, 0, 'h'}, {F_CRM_DATA, 1, 0, 'X'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"reference", 1, 0, 0}, {"timeout", 1, 0, 't'}, /* common options */ {XML_ATTR_ID, 1, 0, 'i'}, {"obj_type", 1, 0, 'o'}, {0, 0, 0, 0} }; crm_log_init(crm_system_name); cl_log_set_facility(LOG_USER); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (safe_str_eq("reference", long_options[option_index].name)) { this_msg_reference = crm_strdup(optarg); } else { printf("Long option (--%s) is not (yet?) properly supported\n", long_options[option_index].name); ++argerr; } break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case 'E': cib_action = CRM_OP_CIB_ERASE; break; case 'Q': cib_action = CRM_OP_CIB_QUERY; break; case 'S': cib_action = CRM_OP_CIB_SYNC; break; case 'U': cib_action = CRM_OP_CIB_UPDATE; break; case 'R': cib_action = CRM_OP_CIB_REPLACE; break; case 'C': cib_action = CRM_OP_CIB_CREATE; break; case 'D': cib_action = CRM_OP_CIB_DELETE; break; case 'M': cib_action = CRM_OP_CIB_ISMASTER; command_options |= cib_scope_local; break; case 'B': cib_action = CRM_OP_CIB_BUMP; break; case 'r': cib_action = CRM_OP_CIB_SLAVE; break; case 'w': cib_action = CRM_OP_CIB_MASTER; command_options |= cib_scope_local; break; case 'V': command_options = command_options | cib_verbose; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); id = crm_strdup(optarg); break; case 'o': crm_debug_2("Option %c => %s", flag, optarg); obj_type = crm_strdup(optarg); break; case 'X': admin_input_xml = crm_strdup(optarg); break; case 'h': host = crm_strdup(optarg); break; case 'l': command_options |= cib_scope_local; break; case 'b': command_options |= cib_inhibit_bcast; break; case 's': command_options |= cib_sync_call; break; case 'f': command_options |= cib_quorum_override; 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"); } if (optind > argc) { ++argerr; } if(cib_action == NULL) { usage(crm_system_name, cib_operation); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } exit_code = do_init(); if(exit_code != cib_ok) { crm_err("Init failed, could not perform requested operations"); fprintf(stderr, "Init failed, could not perform requested operations\n"); return -exit_code; } exit_code = do_work(admin_input_xml, command_options, &output); if (exit_code > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ request_id = exit_code; add_cib_op_callback( request_id, FALSE, NULL, cibadmin_op_callback); mainloop = g_main_new(FALSE); crm_debug_3("Setting operation timeout to %dms", message_timeout_ms); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); crm_debug_3("%s waiting for reply from the local CIB", crm_system_name); crm_info("Starting mainloop"); g_main_run(mainloop); } else if(exit_code < 0) { crm_err("Call failed: %s", cib_error2string(exit_code)); fprintf(stderr, "Call failed: %s\n", cib_error2string(exit_code)); operation_status = exit_code; } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } crm_debug_3("%s exiting normally", crm_system_name); return -exit_code; } crm_data_t* handleCibMod(const char *xml) { const char *attr_name = NULL; const char *attr_value = NULL; crm_data_t *fragment = NULL; crm_data_t *cib_object = NULL; if(xml == NULL) { cib_object = stdin2xml(); } else { cib_object = string2xml(xml); } if(cib_object == NULL) { return NULL; } attr_name = XML_ATTR_ID; attr_value = crm_element_value(cib_object, attr_name); if(attr_name == NULL || strlen(attr_name) == 0) { crm_err("No value for %s specified.", attr_name); return NULL; } crm_debug_4("Object creation complete"); /* create the cib request */ fragment = create_cib_fragment(cib_object, NULL); return fragment; } int do_work(const char *admin_input_xml, int call_options, crm_data_t **output) { /* construct the request */ crm_data_t *msg_data = NULL; char *obj_type_parent = NULL; obj_type_parent = cib_pluralSection(obj_type); if(strcmp(CRM_OP_CIB_QUERY, cib_action) == 0) { crm_debug_2("Querying the CIB for section: %s", obj_type_parent); return the_cib->cmds->query_from( the_cib, host, obj_type_parent, output, call_options); } else if (strcmp(CRM_OP_CIB_ERASE, cib_action) == 0) { crm_debug_4("CIB Erase op in progress"); return the_cib->cmds->erase(the_cib, output, call_options); } else if (strcmp(CRM_OP_CIB_CREATE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->create( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; } else if (strcmp(CRM_OP_CIB_UPDATE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->modify( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; } else if (strcmp(CRM_OP_CIB_DELETE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->delete( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; } else if (strcmp(CRM_OP_CIB_SYNC, cib_action) == 0) { crm_debug_4("Performing %s op...", cib_action); return the_cib->cmds->sync_from( the_cib, host, obj_type_parent, call_options); } else if (strcmp(CRM_OP_CIB_SLAVE, cib_action) == 0 && (call_options ^ cib_scope_local) ) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_slave_all(the_cib, call_options); } else if (strcmp(CRM_OP_CIB_MASTER, cib_action) == 0) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_master(the_cib, call_options); } else if(cib_action != NULL) { crm_debug_4("Passing \"%s\" to variant_op...", cib_action); return the_cib->cmds->variant_op( the_cib, cib_action, host, obj_type_parent, NULL, output, call_options); } else { crm_err("You must specify an operation"); } return cib_operation; } enum cib_errors do_init(void) { enum cib_errors rc = cib_ok; -#ifdef USE_LIBXML - /* docs say only do this once, but in their code they do it every time! */ - xmlInitParser(); -#endif the_cib = cib_new(); rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command); if(rc != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(rc)); fprintf(stderr, "Signon to CIB failed: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; fprintf(stream, "usage: %s [-?Vio] command\n" "\twhere necessary, XML data will be expected using -X" " or on STDIN if -X isnt specified\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c) \tid of the object being operated on\n", XML_ATTR_ID, 'i'); fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", "obj_type", 'o'); fprintf(stream, "\t--%s (-%c)\tturn on debug info." " additional instance increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ERASE, 'E'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_QUERY, 'Q'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_CREATE, 'C'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_REPLACE,'R'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_UPDATE, 'U'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_DELETE, 'D'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_BUMP, 'B'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ISMASTER,'M'); fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_SYNC, 'S'); fprintf(stream, "\nXML data\n"); fprintf(stream, "\t--%s (-%c) \t\n", F_CRM_DATA, 'X'); fprintf(stream, "\nAdvanced Options\n"); fprintf(stream, "\t--%s (-%c)\tsend command to specified host." " Applies to %s and %s commands only\n", "host", 'h', CRM_OP_CIB_QUERY, CRM_OP_CIB_SYNC); fprintf(stream, "\t--%s (-%c)\tcommand takes effect locally" " on the specified host\n", "local", 'l'); fprintf(stream, "\t--%s (-%c)\tcommand will not be broadcast even if" " it altered the CIB\n", "no-bcast", 'b'); fprintf(stream, "\t--%s (-%c)\twait for call to complete before" " returning\n", "sync-call", 's'); fflush(stream); exit(exit_status); } gboolean admin_message_timeout(gpointer data) { if(safe_str_eq(cib_action, CRM_OP_CIB_SLAVE)) { exit_code = cib_ok; fprintf(stdout, "CIB service(s) are in slave mode.\n"); } else { exit_code = cib_reply_failed; fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); } g_main_quit(mainloop); return FALSE; } void cib_connection_destroy(gpointer user_data) { crm_err("Connection to the CIB terminated... exiting"); g_main_quit(mainloop); return; } void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { char *admin_input_xml = NULL; crm_info("our callback was invoked"); crm_log_message(LOG_MSG, msg); exit_code = rc; if(output != NULL) { admin_input_xml = dump_xml_formatted(output); } if(safe_str_eq(cib_action, CRM_OP_CIB_ISMASTER) && rc != cib_ok) { crm_info("Local CIB is _not_ the master instance"); fprintf(stderr, "Local CIB is _not_ the master instance\n"); } else if(safe_str_eq(cib_action, CRM_OP_CIB_ISMASTER)) { crm_info("Local CIB _is_ the master instance"); fprintf(stderr, "Local CIB _is_ the master instance\n"); } else if(rc != 0) { crm_warn("Call %s failed (%d): %s", cib_action, rc, cib_error2string(rc)); fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, cib_error2string(rc)); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } else if(safe_str_eq(cib_action, CRM_OP_CIB_QUERY) && output==NULL) { crm_err("Output expected in query response"); crm_log_message(LOG_ERR, msg); } else if(output == NULL) { crm_info("Call passed"); } else { crm_info("Call passed"); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } crm_free(admin_input_xml); if(call_id == request_id) { g_main_quit(mainloop); } else { crm_info("Message was not the response we were looking for (%d vs. %d", call_id, request_id); } } diff --git a/crm/admin/crmadmin.c b/crm/admin/crmadmin.c index 04dadb901e..bb0004e4fb 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,916 +1,912 @@ -/* $Id: crmadmin.c,v 1.41 2005/05/18 20:15:57 andrew Exp $ */ +/* $Id: crmadmin.c,v 1.42 2005/05/19 10:50:08 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 int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); ll_cluster_t *do_init(void); int do_work(ll_cluster_t * hb_cluster); void crmd_ipc_connection_destroy(gpointer user_data); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); crm_data_t *handleCibMod(void); int do_find_resource(const char *rsc, crm_data_t *xml_node); int do_find_resource_list(crm_data_t *xml_node); int do_find_node_list(crm_data_t *xml_node); gboolean admin_message_timeout(gpointer data); gboolean is_node_online(crm_data_t *node_state); enum debug { debug_none, debug_dec, debug_inc }; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean DO_HEALTH = FALSE; gboolean DO_RESET = FALSE; gboolean DO_RESOURCE = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_NODE_LIST = FALSE; gboolean BE_SILENT = FALSE; gboolean DO_RESOURCE_LIST = FALSE; gboolean DO_OPTION = FALSE; gboolean DO_STANDBY = FALSE; enum debug DO_DEBUG = debug_none; const char *crmd_operation = NULL; crm_data_t *msg_options = NULL; const char *standby_on_off = "on"; const char *admin_verbose = XML_BOOLEAN_FALSE; char *id = NULL; char *this_msg_reference = NULL; char *disconnect = NULL; char *dest_node = NULL; char *rsc_name = NULL; char *crm_option = NULL; int operation_status = 0; const char *sys_to = NULL; const char *crm_system_name = "crmadmin"; #define OPTARGS "V?K:S:HE:DW:d:i:RNs:a:qt:o:" int main(int argc, char **argv) { int option_index = 0; int argerr = 0; int flag; ll_cluster_t *hb_cluster = NULL; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'q'}, {"reference", 1, 0, 0}, {XML_ATTR_TIMEOUT, 1, 0, 't'}, /* daemon options */ {"kill", 1, 0, 'K'}, /* stop a node */ {"die", 0, 0, 0}, /* kill a node, no respawn */ {"crm_debug_inc", 1, 0, 'i'}, {"crm_debug_dec", 1, 0, 'd'}, {"status", 1, 0, 'S'}, {"standby", 1, 0, 's'}, {"active", 1, 0, 'a'}, {"health", 0, 0, 'H'}, {"election", 0, 0, 'E'}, {"dc_lookup", 0, 0, 'D'}, {"resources", 0, 0, 'R'}, {"nodes", 0, 0, 'N'}, {"whereis", 1, 0, 'W'}, {"option", 1, 0, 'o'}, {0, 0, 0, 0} }; crm_system_name = basename(argv[0]); crm_log_level = 0; crm_log_init(crm_system_name); crm_log_level = 0; if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (strcmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_strdup(optarg); } else if (strcmp("die", long_options[option_index].name) == 0) { DO_RESET = TRUE; crmd_operation = CRM_OP_DIE; } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'V': BE_VERBOSE = TRUE; admin_verbose = XML_BOOLEAN_TRUE; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'D': DO_WHOIS_DC = TRUE; break; case 'W': DO_RESOURCE = TRUE; crm_debug_2("Option %c => %s", flag, optarg); rsc_name = crm_strdup(optarg); break; case 'K': DO_RESET = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); crmd_operation = CRM_OP_LOCAL_SHUTDOWN; break; case 'o': DO_OPTION = TRUE; crm_debug_2("Option %c => %s", flag, optarg); crm_option = crm_strdup(optarg); break; case 'q': BE_SILENT = TRUE; break; case 'i': DO_DEBUG = debug_inc; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'd': DO_DEBUG = debug_dec; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 's': DO_STANDBY = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'a': DO_STANDBY = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); standby_on_off = "off"; break; case 'S': DO_HEALTH = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'E': DO_ELECT_DC = TRUE; break; case 'N': DO_NODE_LIST = TRUE; break; case 'R': DO_RESOURCE_LIST = TRUE; break; case 'H': DO_HEALTH = TRUE; 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"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } hb_cluster = do_init(); if (hb_cluster != NULL) { int res = do_work(hb_cluster); if (res > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); crm_debug_2("%s waiting for reply from the local CRM", crm_system_name); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else if(res == 0) { crm_debug_2("%s: no reply expected", crm_system_name); } else { crm_err("No message to send"); operation_status = -1; } } else { crm_err("Init failed, could not perform requested operations"); operation_status = -2; } crm_debug_2("%s exiting normally", crm_system_name); return operation_status; } int do_work(ll_cluster_t * hb_cluster) { int ret = 1; /* construct the request */ crm_data_t *msg_data = NULL; gboolean all_is_good = TRUE; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); set_xml_property_copy(msg_options, XML_ATTR_VERBOSE, admin_verbose); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_HEALTH == TRUE) { crm_debug_2("Querying the system"); sys_to = CRM_SYSTEM_DC; if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_PING; if (BE_VERBOSE) { expected_responses = -1;/* wait until timeout instead */ } set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); } else { crm_info("Cluster-wide health not available yet"); all_is_good = FALSE; } } else if(DO_ELECT_DC) { /* tell the local node to initiate an election */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_VOTE; set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; ret = 0; /* no return message */ } else if(DO_WHOIS_DC) { sys_to = CRM_SYSTEM_DC; crmd_operation = CRM_OP_PING; set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; } else if(DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST || DO_OPTION){ cib_t * the_cib = cib_new(); crm_data_t *output = NULL; int call_options = cib_sync_call; enum cib_errors rc = the_cib->cmds->signon( the_cib, crm_system_name, cib_command); if(rc != cib_ok) { return -1; } else if(DO_RESOURCE) { output = get_cib_copy(the_cib); do_find_resource(rsc_name, output); } else if(DO_RESOURCE_LIST) { output = get_cib_copy(the_cib); do_find_resource_list(output); } else if(DO_NODE_LIST) { output = get_cib_copy(the_cib); do_find_node_list(output); } else if(DO_OPTION) { char *name = NULL; char *value = NULL; crm_data_t *xml_option = NULL; crm_data_t *fragment = NULL; if(decodeNVpair(crm_option, '=', &name, &value)==FALSE){ crm_err("%s needs to be of the form" " =", crm_option); return -1; } xml_option = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); set_xml_property_copy( xml_option, XML_NVPAIR_ATTR_NAME, name); set_xml_property_copy( xml_option, XML_NVPAIR_ATTR_VALUE, value); fragment = create_cib_fragment(xml_option, NULL); free_xml(xml_option); crm_free(name); crm_free(value); rc = the_cib->cmds->modify( the_cib, XML_CIB_TAG_CRMCONFIG, fragment, NULL, call_options|cib_discard_reply); free_xml(fragment); } else if(DO_STANDBY) { char *name = NULL; char *value = NULL; crm_data_t *a_node = NULL; crm_data_t *xml_obj = NULL; crm_data_t *fragment = NULL; if(decodeNVpair(crm_option, '=', &name, &value)==FALSE){ crm_err("%s needs to be of the form" " =", crm_option); return -1; } a_node = create_xml_node(NULL, XML_CIB_TAG_NODE); set_xml_property_copy(a_node, XML_ATTR_ID, dest_node); xml_obj = create_xml_node(a_node, XML_TAG_ATTR_SETS); xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); set_xml_property_copy( xml_obj, XML_NVPAIR_ATTR_NAME, "standby"); set_xml_property_copy( xml_obj, XML_NVPAIR_ATTR_VALUE, standby_on_off); fragment = create_cib_fragment(a_node, NULL); free_xml(a_node); crm_free(name); crm_free(value); rc = the_cib->cmds->modify( the_cib, XML_CIB_TAG_NODES, fragment, NULL, call_options|cib_discard_reply); free_xml(fragment); } free_xml(output); the_cib->cmds->signoff(the_cib); return rc; } else if(DO_RESET) { /* tell dest_node to initiate the shutdown proceedure * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else if(DO_DEBUG == debug_inc) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_UP; ret = 0; /* no return message */ } else if(DO_DEBUG == debug_dec) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_DOWN; ret = 0; /* no return message */ } else { crm_err("Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { crm_err("Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { crm_err("The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) sys_to = CRM_SYSTEM_CRMD; else sys_to = CRM_SYSTEM_DC; } { HA_Message *cmd = create_request( crmd_operation, msg_data, dest_node, sys_to, crm_system_name, admin_uuid); if(this_msg_reference != NULL) { ha_msg_mod(cmd, XML_ATTR_REFERENCE, this_msg_reference); } send_ipc_message(crmd_channel, cmd); } return ret; } void crmd_ipc_connection_destroy(gpointer user_data) { crm_err("Connection to CRMd was terminated"); exit(1); } ll_cluster_t * do_init(void) { int facility; GCHSource *src = NULL; ll_cluster_t *hb_cluster = NULL; -#ifdef USE_LIBXML - /* docs say only do this once, but in their code they do it every time! */ - xmlInitParser (); -#endif /* change the logging facility to the one used by heartbeat daemon */ hb_cluster = ll_cluster_new("heartbeat"); crm_debug_2("Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } crm_malloc0(admin_uuid, sizeof(char) * 11); if(admin_uuid != NULL) { snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; } src = init_client_ipc_comms( CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel); if(crmd_channel != NULL) { send_hello_message( crmd_channel, admin_uuid, crm_system_name,"0", "1"); set_IPC_Channel_dnotify(src, crmd_ipc_connection_destroy); return hb_cluster; } return NULL; } gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; char *filename = NULL; int filename_len = 0; const char *result = NULL; g_source_remove(message_timer_id); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if(new_input != NULL) { delete_ha_msg_input(new_input); } if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; new_input = new_ipc_msg_input(msg); msg->msg_done(msg); crm_log_message(LOG_MSG, new_input->msg); if (new_input->xml == NULL) { crm_info( "XML in IPC message was not valid... " "discarding."); continue; } else if (validate_crm_message( new_input->msg, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) { crm_info( "Message was not a CRM response. Discarding."); continue; } result = cl_get_string(new_input->msg, XML_ATTR_RESULT); if(result == NULL || strcmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } received_responses++; if(DO_HEALTH) { const char *state = crm_element_value( new_input->xml, "crmd_state"); printf("Status of %s@%s: %s (%s)\n", crm_element_value(new_input->xml,XML_PING_ATTR_SYSFROM), cl_get_string(new_input->msg, F_CRM_HOST_FROM), state, crm_element_value(new_input->xml,XML_PING_ATTR_STATUS)); if(BE_SILENT && state != NULL) { fprintf(stderr, "%s\n", state); } } else if(DO_WHOIS_DC) { const char *dc = cl_get_string( new_input->msg, F_CRM_HOST_FROM); printf("Designated Controller is: %s\n", dc); if(BE_SILENT && dc != NULL) { fprintf(stderr, "%s\n", dc); } } if (this_msg_reference != NULL) { /* in testing mode... */ /* 31 = "test-_.xml" + an_int_as_string + '\0' */ filename_len = 31 + strlen(this_msg_reference); crm_malloc0(filename, sizeof(char) * filename_len); if(filename != NULL) { sprintf(filename, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (0 > write_xml_file(new_input->xml, filename)) { crm_crit("Could not save response to" " %s", filename); } } } } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } if (received_responses >= expected_responses) { crm_debug_2( "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); g_main_quit(mainloop); return !hack_return_good; } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); return hack_return_good; } gboolean admin_message_timeout(gpointer data) { fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); g_main_quit(mainloop); return FALSE; } int do_find_resource(const char *rsc, crm_data_t *xml_node) { int found = 0; crm_data_t *nodestates = get_object_root(XML_CIB_TAG_STATUS, xml_node); const char *path2[] = { XML_CIB_TAG_LRM, XML_LRM_TAG_RESOURCES }; xml_child_iter( nodestates, a_node, XML_CIB_TAG_STATE, crm_data_t *rscstates = NULL; if(is_node_online(a_node) == FALSE) { crm_debug_3("Skipping offline node: %s", crm_element_value(a_node, XML_ATTR_ID)); continue; } rscstates = find_xml_node_nested(a_node, path2, DIMOF(path2)); xml_child_iter( rscstates, rsc_state, XML_LRM_TAG_RESOURCE, const char *id = crm_element_value( rsc_state,XML_ATTR_ID); const char *target = crm_element_value( a_node, XML_ATTR_UNAME); const char *last_op = crm_element_value( rsc_state,XML_LRM_ATTR_LASTOP); const char *op_code = crm_element_value( rsc_state,XML_LRM_ATTR_OPSTATUS); crm_debug_3("checking %s:%s for %s", target, id, rsc); if(safe_str_neq(rsc, id)){ crm_debug_4("no match"); continue; } if(safe_str_eq("stop", last_op)) { crm_debug_3("resource %s is stopped on: %s", rsc, target); } else if(safe_str_eq(op_code, "-1")) { crm_debug_3("resource %s is pending on: %s", rsc, target); } else if(safe_str_neq(op_code, "0")) { crm_debug_3("resource %s is failed on: %s", rsc, target); } else { crm_debug_3("resource %s is running on: %s", rsc, target); printf("resource %s is running on: %s\n", rsc, target); if(BE_SILENT) { fprintf(stderr, "%s ", target); } found++; } ); if(BE_SILENT) { fprintf(stderr, "\n"); } ); if(found == 0) { printf("resource %s is NOT running\n", rsc); } return found; } gboolean is_node_online(crm_data_t *node_state) { const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE); const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE); const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE); const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE); const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM); if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) && crm_is_true(ccm_state) && safe_str_eq(crm_state, ONLINESTATUS)) { crm_debug_3("Node %s is online", uname); return TRUE; } crm_debug_3("Node %s: ha=%s ccm=%s join=%s exp=%s crm=%s", uname, crm_str(ha_state), crm_str(ccm_state), crm_str(join_state), crm_str(exp_state), crm_str(crm_state)); crm_debug_3("Node %s is offline", uname); return FALSE; } int do_find_resource_list(crm_data_t *xml_node) { int found = 0; crm_data_t *rscs = get_object_root(XML_CIB_TAG_RESOURCES, xml_node); xml_child_iter( rscs, rsc, XML_CIB_TAG_RESOURCE, printf("%s resource: %s (%s)\n", crm_element_value(rsc, "class"), crm_element_value(rsc, XML_ATTR_ID), crm_element_value(rsc, XML_ATTR_TYPE)); found++; ); if(found == 0) { printf("NO resources configured\n"); } return found; } int do_find_node_list(crm_data_t *xml_node) { int found = 0; crm_data_t *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); xml_child_iter( nodes, node, XML_CIB_TAG_NODE, printf("%s node: %s (%s)\n", crm_element_value(node, XML_ATTR_TYPE), crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); found++; ); if(found == 0) { printf("NO nodes configured\n"); } return found; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?vs] [command] [command args]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: be very *very* quiet\n", "quiet", 'q'); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c) \t: " "increment the CRMd debug level on \n", CRM_OP_DEBUG_UP,'i'); fprintf(stream, "\t--%s (-%c) \t: " "decrement the CRMd debug level on \n", CRM_OP_DEBUG_DOWN,'d'); fprintf(stream, "\t--%s (-%c) \t: " "shutdown the CRMd on \n", "kill", 'K'); fprintf(stream, "\t--%s (-%c) \t: " "request the status of \n", "status", 'S'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the status of all nodes\n", "health", 'H'); fprintf(stream, "\t--%s (-%c) \t: " "initiate an election from \n", "election", 'E'); fprintf(stream, "\t--%s (-%c)\t: " "request the uname of the DC\n", "dc_lookup", 'D'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the uname of all member nodes\n", "nodes", 'N'); fprintf(stream, "\t--%s (-%c)\t: " "request the names of all resources\n", "resources", 'R'); fprintf(stream, "\t--%s (-%c) \t: " "request the location of \n", "whereis", 'W'); fprintf(stream, "\t--%s (-%c) \t: " "Tell the node to enter \"standby\" mode\n", "standby", 's'); fprintf(stream, "\t--%s (-%c) \t: " "Tell the node to exit \"standby\" mode\n", "active", 'a'); /* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */ fflush(stream); exit(exit_status); } diff --git a/lib/crm/common/ipc.c b/lib/crm/common/ipc.c index b1c82254a4..2c0672fc0a 100644 --- a/lib/crm/common/ipc.c +++ b/lib/crm/common/ipc.c @@ -1,388 +1,382 @@ -/* $Id: ipc.c,v 1.6 2005/05/18 20:15:58 andrew Exp $ */ +/* $Id: ipc.c,v 1.7 2005/05/19 10:50:08 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 -#ifdef USE_LIBXML -# include -# include -# include -#endif - #include #include #include #include gboolean send_ha_message(ll_cluster_t *hb_conn, HA_Message *msg, const char *node) { gboolean all_is_good = TRUE; if (msg == NULL) { crm_err("cant send NULL message"); all_is_good = FALSE; } else if(hb_conn == NULL) { crm_err("No heartbeat connection specified"); all_is_good = FALSE; } else if(hb_conn->llc_ops->chan_is_connected(hb_conn) != HA_OK) { crm_err("Not connected to Heartbeat"); all_is_good = FALSE; } else if(node != NULL) { if(hb_conn->llc_ops->send_ordered_nodemsg( hb_conn, msg, node) != HA_OK) { IPC_Channel *ipc = hb_conn->llc_ops->ipcchan(hb_conn); all_is_good = FALSE; crm_err("Send failed"); CRM_DEV_ASSERT(ipc->send_queue->current_qlen < ipc->send_queue->max_qlen); } else { crm_debug_2("Message sent..."); } } else { if(hb_conn->llc_ops->sendclustermsg(hb_conn, msg) != HA_OK) { IPC_Channel *ipc = hb_conn->llc_ops->ipcchan(hb_conn); all_is_good = FALSE; crm_err("Broadcast Send failed"); CRM_DEV_ASSERT(ipc->send_queue->current_qlen < ipc->send_queue->max_qlen); } else { crm_debug_2("Broadcast message sent..."); } } crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"HA[outbound]",msg); return all_is_good; } #define ipc_log(fmt...) do_crm_log(server?LOG_WARNING:LOG_ERR, __FILE__, __FUNCTION__, fmt) /* frees msg */ gboolean crm_send_ipc_message(IPC_Channel *ipc_client, HA_Message *msg, gboolean server) { gboolean all_is_good = TRUE; if (msg == NULL) { crm_err("cant send NULL message"); all_is_good = FALSE; } else if (ipc_client == NULL) { crm_err("cant send message without an IPC Channel"); all_is_good = FALSE; } else if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { ipc_log("IPC Channel is not connected"); all_is_good = FALSE; } if(all_is_good && msg2ipcchan(msg, ipc_client) != HA_OK) { ipc_log("Could not send IPC, message"); all_is_good = FALSE; if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { ipc_log("IPC Channel is no longer connected"); } else if(server == FALSE) { CRM_DEV_ASSERT(ipc_client->send_queue->current_qlen < ipc_client->send_queue->max_qlen); } } crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"IPC[outbound]",msg); crm_msg_del(msg); return all_is_good; } void default_ipc_connection_destroy(gpointer user_data) { return; } int init_server_ipc_comms( char *channel_name, gboolean (*channel_client_connect)(IPC_Channel *newclient,gpointer user_data), void (*channel_connection_destroy)(gpointer user_data)) { /* the clients wait channel is the other source of events. * This source delivers the clients connection events. * listen to this source at a relatively lower priority. */ char commpath[SOCKET_LEN]; IPC_WaitConnection *wait_ch; sprintf(commpath, WORKING_DIR "/%s", channel_name); wait_ch = wait_channel_init(commpath); if (wait_ch == NULL) { return 1; } G_main_add_IPC_WaitConnection( G_PRIORITY_LOW, wait_ch, NULL, FALSE, channel_client_connect, channel_name, channel_connection_destroy); crm_debug_3("Listening on: %s", commpath); return 0; } GCHSource* init_client_ipc_comms(const char *channel_name, gboolean (*dispatch)( IPC_Channel* source_data, gpointer user_data), void *client_data, IPC_Channel **ch) { IPC_Channel *a_ch = NULL; GCHSource *the_source = NULL; void *callback_data = client_data; a_ch = init_client_ipc_comms_nodispatch(channel_name); if(ch != NULL) { *ch = a_ch; if(callback_data == NULL) { callback_data = a_ch; } } if(a_ch == NULL) { crm_err("Setup of client connection failed," " not adding channel to mainloop"); return NULL; } if(dispatch == NULL) { crm_warn("No dispatch method specified..." "maybe you meant init_client_ipc_comms_nodispatch()?"); } else { crm_debug_3("Adding dispatch method to channel"); the_source = G_main_add_IPC_Channel( G_PRIORITY_HIGH, a_ch, FALSE, dispatch, callback_data, default_ipc_connection_destroy); } return the_source; } IPC_Channel * init_client_ipc_comms_nodispatch(const char *channel_name) { IPC_Channel *ch; GHashTable *attrs; static char path[] = IPC_PATH_ATTR; char *commpath = NULL; int local_socket_len = 2; /* 2 = '/' + '\0' */ local_socket_len += strlen(channel_name); local_socket_len += strlen(WORKING_DIR); crm_malloc0(commpath, sizeof(char)*local_socket_len); if(commpath != NULL) { sprintf(commpath, WORKING_DIR "/%s", channel_name); commpath[local_socket_len - 1] = '\0'; crm_debug_3("Attempting to talk on: %s", commpath); } attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, commpath); ch = ipc_channel_constructor(IPC_ANYTYPE, attrs); g_hash_table_destroy(attrs); if (ch == NULL) { crm_err("Could not access channel on: %s", commpath); return NULL; } else if (ch->ops->initiate_connection(ch) != IPC_OK) { crm_debug("Could not init comms on: %s", commpath); return NULL; } ch->ops->set_recv_qlen(ch, 100); ch->ops->set_send_qlen(ch, 100); /* ch->should_send_block = TRUE; */ crm_debug_3("Processing of %s complete", commpath); return ch; } IPC_WaitConnection * wait_channel_init(char daemonsocket[]) { IPC_WaitConnection *wait_ch; mode_t mask; char path[] = IPC_PATH_ATTR; GHashTable * attrs; attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, daemonsocket); mask = umask(0); wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs); if (wait_ch == NULL) { cl_perror("Can't create wait channel of type %s", IPC_ANYTYPE); exit(1); } mask = umask(mask); g_hash_table_destroy(attrs); return wait_ch; } longclock_t ipc_call_start = 0; longclock_t ipc_call_stop = 0; longclock_t ipc_call_diff = 0; gboolean subsystem_msg_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean all_is_well = TRUE; const char *sys_to; const char *task; while(sender->ops->is_message_pending(sender)) { gboolean process = FALSE; if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if (sender->ops->recv(sender, &msg) != IPC_OK) { perror("Receive failure:"); return !all_is_well; } if (msg == NULL) { crm_err("No message this time"); continue; } lpc++; new_input = new_ipc_msg_input(msg); msg->msg_done(msg); crm_log_message(LOG_MSG, new_input->msg); sys_to = cl_get_string(new_input->msg, F_CRM_SYS_TO); task = cl_get_string(new_input->msg, F_CRM_TASK); if(safe_str_eq(task, CRM_OP_HELLO)) { process = TRUE; } else if(sys_to == NULL) { crm_err("Value of %s was NULL!!", F_CRM_SYS_TO); } else if(task == NULL) { crm_err("Value of %s was NULL!!", F_CRM_TASK); } else { process = TRUE; } if(process){ gboolean (*process_function) (HA_Message *msg, crm_data_t *data, IPC_Channel *sender) = NULL; process_function = user_data; #ifdef MSG_LOG crm_log_message_adv( LOG_MSG, __FUNCTION__, new_input->msg); #endif if(ipc_call_diff_max_ms > 0) { ipc_call_start = time_longclock(); } if(FALSE == process_function( new_input->msg, new_input->xml, sender)) { crm_warn("Received a message destined for %s" " by mistake", sys_to); } if(ipc_call_diff_max_ms > 0) { unsigned int ipc_call_diff_ms = 0; ipc_call_stop = time_longclock(); ipc_call_diff = sub_longclock( ipc_call_stop, ipc_call_start); ipc_call_diff_ms = longclockto_ms( ipc_call_diff); if(ipc_call_diff_ms > ipc_call_diff_max_ms) { crm_err("%s took %dms to complete", sys_to, ipc_call_diff_ms); } } } else { #ifdef MSG_LOG crm_log_message_adv( LOG_ERR, NULL, new_input->msg); #endif } delete_ha_msg_input(new_input); msg = NULL; } /* clean up after a break */ if(msg != NULL) { msg->msg_done(msg); } crm_debug_2("Processed %d messages", lpc); if (sender->ch_status != IPC_CONNECT) { crm_err("The server has left us: Shutting down...NOW"); exit(1); /* shutdown properly later */ return !all_is_well; } return all_is_well; } diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c index 159914db05..e0c79b8fb1 100644 --- a/lib/crm/common/xml.c +++ b/lib/crm/common/xml.c @@ -1,1650 +1,1371 @@ -/* $Id: xml.c,v 1.5 2005/05/18 20:15:58 andrew Exp $ */ +/* $Id: xml.c,v 1.6 2005/05/19 10:50:08 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 void dump_array( int log_level, const char *message, const char **array, int depth); int print_spaces(char *buffer, int spaces); int log_data_element( const char *function, int log_level, int depth, crm_data_t *data, gboolean formatted); int dump_data_element( int depth, char **buffer, crm_data_t *data, gboolean formatted); -#ifndef USE_LIBXML - crm_data_t *parse_xml(const char *input, int *offset); int get_tag_name(const char *input); int get_attr_name(const char *input); int get_attr_value(const char *input); -#endif - crm_data_t * find_xml_node(crm_data_t *root, const char * search_path, gboolean must_find) { if(must_find || root != NULL) { crm_validate_data(root); } if(search_path == NULL) { crm_warn("Will never find "); return NULL; } xml_child_iter( root, a_child, search_path, /* crm_debug_5("returning node (%s).", xmlGetNodePath(a_child)); */ crm_log_xml_debug_5(a_child, "contents\t%s"); crm_log_xml_debug_5(root, "found in\t%s"); crm_validate_data(a_child); return a_child; ); if(must_find) { crm_warn("Could not find %s in %s.", search_path, xmlGetNodePath(root)); } else if(root != NULL) { crm_debug_3("Could not find %s in %s.", search_path, xmlGetNodePath(root)); } else { crm_debug_3("Could not find %s in .", search_path); } return NULL; } crm_data_t* find_xml_node_nested(crm_data_t *root, const char **search_path, int len) { int j; gboolean is_found = TRUE; crm_data_t *match = NULL; crm_data_t *lastMatch = root; crm_validate_data(root); if(search_path == NULL || search_path[0] == NULL) { crm_warn("Will never find NULL"); return NULL; } dump_array(LOG_DEBUG_5, "Looking for.", search_path, len); for (j=0; j < len; ++j) { if (search_path[j] == NULL) { /* a NULL also means stop searching */ break; } match = find_xml_node(lastMatch, search_path[j], FALSE); if(match == NULL) { is_found = FALSE; break; } else { lastMatch = match; } } if (is_found) { crm_debug_5("returning node (%s).", xmlGetNodePath(lastMatch)); crm_log_xml_debug_5(lastMatch, "found\t%s"); crm_log_xml_debug_5(root, "in \t%s"); crm_validate_data(lastMatch); return lastMatch; } dump_array(LOG_WARNING, "Could not find the full path to the node you specified.", search_path, len); crm_warn("Closest point was node (%s) starting from %s.", xmlGetNodePath(lastMatch), crm_element_name(root)); return NULL; } const char * get_xml_attr_nested(crm_data_t *parent, const char **node_path, int length, const char *attr_name, gboolean error) { const char *attr_value = NULL; crm_data_t *attr_parent = NULL; if(error || parent != NULL) { crm_validate_data(parent); } if(parent == NULL) { crm_debug_3("Can not find attribute %s in NULL parent",attr_name); return NULL; } if(attr_name == NULL || strlen(attr_name) == 0) { crm_err("Can not find attribute with no name in %s", xmlGetNodePath(parent)); return NULL; } if(length == 0) { attr_parent = parent; } else { attr_parent = find_xml_node_nested(parent, node_path, length); if(attr_parent == NULL && error) { crm_err("No node at the path you specified."); return NULL; } } attr_value = crm_element_value(attr_parent, attr_name); if((attr_value == NULL || strlen(attr_value) == 0) && error) { crm_err( "No value present for %s at %s", attr_name, xmlGetNodePath(attr_parent)); return NULL; } return attr_value; } crm_data_t* find_entity(crm_data_t *parent, const char *node_name, const char *id, gboolean siblings) { crm_validate_data(parent); xml_child_iter( parent, a_child, node_name, if(id == NULL || safe_str_eq(id,crm_element_value(a_child,XML_ATTR_ID))){ crm_debug_3("returning node (%s).", xmlGetNodePath(a_child)); return a_child; } ); if(siblings) { abort(); } crm_debug("node <%s id=%s> not found in %s.", node_name, id, xmlGetNodePath(parent)); return NULL; } void copy_in_properties(crm_data_t* target, crm_data_t *src) { crm_validate_data(src); crm_validate_data(target); if(src == NULL) { crm_warn("No node to copy properties from"); } else if (target == NULL) { crm_err("No node to copy properties into"); } else { xml_prop_iter( src, local_prop_name, local_prop_value, set_xml_property_copy( target, local_prop_name, local_prop_value); ); crm_validate_data(target); } return; } crm_data_t* add_node_copy(crm_data_t *new_parent, crm_data_t *xml_node) { crm_data_t *node_copy = NULL; crm_validate_data(new_parent); crm_validate_data(xml_node); if(xml_node != NULL && new_parent != NULL) { -#ifdef USE_LIBXML - node_copy = copy_xml_node_recursive(xml_node); - xmlAddChild(new_parent, node_copy); -#else const char *name = crm_element_name(xml_node); CRM_DEV_ASSERT(HA_OK == ha_msg_addstruct( new_parent, name, xml_node)); node_copy = find_entity(new_parent, crm_element_name(xml_node), ID(xml_node), FALSE); crm_validate_data(node_copy); crm_update_parents(new_parent); crm_validate_data(new_parent); -#endif } else if(xml_node == NULL) { crm_err("Could not add copy of NULL node"); } else { crm_err("Could not add copy of node to NULL parent"); } crm_validate_data(node_copy); return node_copy; } const char * set_xml_property_copy(crm_data_t* node, const char *name, const char *value) { const char *parent_name = NULL; if(node != NULL) { parent_name = crm_element_name(node); } crm_debug_5("[%s] Setting %s to %s", crm_str(parent_name), name, value); if (name == NULL || strlen(name) <= 0) { } else if(node == NULL) { } else if(parent_name == NULL && strcmp(name, F_XML_TAGNAME) != 0) { } else if (value == NULL || strlen(value) <= 0) { xml_remove_prop(node, name); return NULL; } else { -#ifdef USE_LIBXML - const char *local_name = NULL; - const char *local_value = NULL; - local_value = crm_strdup(value); - local_name = crm_strdup(name); - xmlUnsetProp(node, local_name); - xmlSetProp(node, local_name, local_value); - return xmlGetProp(node, local_name); -#else crm_validate_data(node); ha_msg_mod(node, name, value); return crm_element_value(node, name); -#endif } return NULL; } crm_data_t* create_xml_node(crm_data_t *parent, const char *name) { const char *local_name = NULL; const char *parent_name = NULL; crm_data_t *ret_value = NULL; if (name == NULL || strlen(name) < 1) { ret_value = NULL; } else { -#ifdef USE_LIBXML - local_name = crm_strdup(name); - - if(parent == NULL) - ret_value = xmlNewNode(NULL, local_name); - else { - parent_name = parent->name; - ret_value = - xmlNewChild(parent, NULL, local_name, NULL); - } -#else local_name = name; ret_value = ha_msg_new(1); CRM_DEV_ASSERT(ret_value != NULL); set_xml_property_copy(ret_value, F_XML_TAGNAME, name); crm_validate_data(ret_value); if(parent) { crm_validate_data(parent); parent_name = crm_element_name(parent); crm_debug_5("Attaching %s to parent %s", local_name, parent_name); CRM_DEV_ASSERT(HA_OK == ha_msg_addstruct( parent, name, ret_value)); crm_msg_del(ret_value); crm_update_parents(parent); crm_validate_data(parent); ret_value = parent->values[parent->nfields-1]; crm_validate_data(ret_value); } -#endif } crm_debug_5("Created node [%s [%s]]", crm_str(parent_name), crm_str(local_name)); /* set_node_tstamp(ret_value); */ return ret_value; } void free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node) { CRM_DEV_ASSERT(parent != NULL); if(parent == NULL) { return; } else if(a_node == NULL) { return; } crm_validate_data(parent); -#ifdef USE_LIBXML - xmlUnlinkNode(a_node); - node->doc = NULL; - free_xml_fn(a_node); -#else cl_msg_remove_value(parent, a_node); -#endif crm_validate_data(parent); } void free_xml_fn(crm_data_t *a_node) { if(a_node == NULL) { ; /* nothing to do */ -#ifdef USE_LIBXML - } else if (a_node->doc != NULL) { - xmlFreeDoc(a_node->doc); - } else { - /* make sure the node is unlinked first */ - xmlUnlinkNode(a_node); - xmlFreeNode(a_node); -#else } else { int has_parent = 0; crm_validate_data(a_node); ha_msg_value_int(a_node, F_XML_PARENT, &has_parent); /* there is no way in hell we should be deleting anything * with a parent and without the parent knowning */ CRM_DEV_ASSERT(has_parent == 0); if(has_parent == 0) { crm_validate_data(a_node); crm_msg_del(a_node); } -#endif } return; } void set_node_tstamp(crm_data_t *a_node) { char *since_epoch = NULL; time_t a_time = time(NULL); crm_validate_data(a_node); if(a_time == (time_t)-1) { cl_perror("set_node_tstamp(): Invalid time returned"); return; } crm_malloc0(since_epoch, 128*(sizeof(char))); if(since_epoch != NULL) { sprintf(since_epoch, "%ld", (unsigned long)a_time); -#ifdef USE_LIBXML - xmlUnsetProp(a_node, XML_ATTR_TSTAMP); - xmlSetProp(a_node, XML_ATTR_TSTAMP, since_epoch); -#else ha_msg_mod(a_node, XML_ATTR_TSTAMP, since_epoch); crm_validate_data(a_node); crm_free(since_epoch); -#endif } } crm_data_t* copy_xml_node_recursive(crm_data_t *src_node) { crm_data_t *new_xml = NULL; -#ifdef USE_LIBXML -# if 1 - return xmlCopyNode(src_node, 1); -# else - xmlNodePtr local_node = NULL, local_child = NULL; - - if(src_node == NULL || src_node->name == NULL) { - return NULL; - } - - local_node = create_xml_node(NULL, src_node->name); - - copy_in_properties(local_node, src_node); - - xml_child_iter( - src_node, node_iter, NULL, - local_child = copy_xml_node_recursive(node_iter); - if(local_child != NULL) { - xmlAddChild(local_node, local_child); - crm_debug_5("Copied node [%s [%s]", - local_node->name, local_child->name); - } - ); - - crm_debug_5("Returning [%s]", local_node->name); - return local_node; -# endif -#else CRM_DEV_ASSERT(src_node != NULL); CRM_DEV_ASSERT(crm_element_name(src_node) != NULL); if(src_node == NULL) { crm_warn("Attempt to dup NULL XML"); return NULL; } else if(crm_element_name(src_node) == NULL) { crm_log_xml_err(src_node, "Attempt to dup XML with no name"); return NULL; } crm_validate_data(src_node); new_xml = ha_msg_copy(src_node); crm_set_element_parent(new_xml, NULL); crm_update_parents(new_xml); crm_validate_data(new_xml); -#endif return new_xml; } crm_data_t* string2xml(const char *input) { -#ifdef USE_LIBXML - int lpc = 0; - char ch = 0; - int input_len = 0; - gboolean more = TRUE; - gboolean inTag = FALSE; - crm_data_t *xml_object = NULL; - const char *the_xml; - xmlDocPtr doc; - xmlBufferPtr xml_buffer = NULL; - - if(input == NULL || (input_len = strlen(input)) < 0) { - return NULL; - } - - xml_buffer = xmlBufferCreate(); - - for(lpc = 0; (lpc < input_len) && more; lpc++) { - ch = input[lpc]; - switch(ch) { - case EOF: - case 0: - ch = 0; - more = FALSE; - xmlBufferAdd(xml_buffer, &ch, 1); - break; - case '>': - case '<': - inTag = TRUE; - if(ch == '>') inTag = FALSE; - xmlBufferAdd(xml_buffer, &ch, 1); - break; - case '\n': - case '\t': - case ' ': - ch = ' '; - if(inTag) { - xmlBufferAdd(xml_buffer, &ch, 1); - } - break; - default: - xmlBufferAdd(xml_buffer, &ch, 1); - break; - } - } - - - xmlInitParser(); - the_xml = xmlBufferContent(xml_buffer); - doc = xmlParseMemory(the_xml, strlen(the_xml)); - xmlCleanupParser(); - - if (doc == NULL) { - crm_err("Malformed XML [xml=%s]", the_xml); - xmlBufferFree(xml_buffer); - return NULL; - } - - xmlBufferFree(xml_buffer); - xml_object = xmlDocGetRootElement(doc); - - return xml_object; -#else crm_data_t *output = parse_xml(input, NULL); if(output != NULL) { crm_update_parents(output); crm_validate_data(output); } return output; -#endif } crm_data_t * stdin2xml(void) { -#ifdef USE_LIBXML - return file2xml(stdin); -#else int lpc = 0; int MAX_XML_BUFFER = 20000; int ch = 0; gboolean more = TRUE; gboolean inTag = FALSE; FILE *input = stdin; char *xml_buffer = NULL; crm_data_t *xml_obj = NULL; crm_malloc0(xml_buffer, sizeof(char)*(MAX_XML_BUFFER+1)); while (more && lpc < MAX_XML_BUFFER) { ch = fgetc(input); /* crm_debug_3("Got [%c]", ch); */ switch(ch) { case EOF: case 0: ch = 0; more = FALSE; xml_buffer[lpc++] = ch; break; case '>': case '<': inTag = TRUE; if(ch == '>') { inTag = FALSE; } xml_buffer[lpc++] = ch; break; case '\n': case '\t': case ' ': ch = ' '; if(inTag) { xml_buffer[lpc++] = ch; } break; default: xml_buffer[lpc++] = ch; break; } } xml_buffer[MAX_XML_BUFFER] = 0; xml_obj = string2xml(xml_buffer); crm_free(xml_buffer); crm_log_xml_debug_3(xml_obj, "Created fragment"); return xml_obj; -#endif } crm_data_t* file2xml(FILE *input) { -#ifdef USE_LIBXML - char ch = 0; - gboolean more = TRUE; - gboolean inTag = FALSE; - crm_data_t *xml_object = NULL; - xmlBufferPtr xml_buffer = xmlBufferCreate(); - const char *the_xml; - xmlDocPtr doc; - - if(input == NULL) { - crm_err("File pointer was NULL"); - return NULL; - } - - while (more) { - ch = fgetc(input); -/* crm_debug_3("Got [%c]", ch); */ - switch(ch) { - case EOF: - case 0: - ch = 0; - more = FALSE; - xmlBufferAdd(xml_buffer, &ch, 1); - break; - case '>': - case '<': - inTag = TRUE; - if(ch == '>') inTag = FALSE; - xmlBufferAdd(xml_buffer, &ch, 1); - break; - case '\n': - case '\t': - case ' ': - ch = ' '; - if(inTag) { - xmlBufferAdd(xml_buffer, &ch, 1); - } - break; - default: - xmlBufferAdd(xml_buffer, &ch, 1); - break; - } - } - - xmlInitParser(); - the_xml = xmlBufferContent(xml_buffer); - doc = xmlParseMemory(the_xml, strlen(the_xml)); - xmlCleanupParser(); - - if (doc == NULL) { - crm_err("Malformed XML [xml=%s]", the_xml); - xmlBufferFree(xml_buffer); - return NULL; - } - xmlBufferFree(xml_buffer); - xml_object = xmlDocGetRootElement(doc); - - crm_log_xml_debug_3(xml_object, "Created fragment"); - - return xml_object; -#else char *buffer = NULL; crm_data_t *new_obj = NULL; int start = 0, length = 0, read_len = 0; /* see how big the file is */ start = ftell(input); fseek(input, 0L, SEEK_END); length = ftell(input); fseek(input, 0L, start); if(start != ftell(input)) { crm_err("fseek not behaving"); return NULL; } crm_debug_3("Reading %d bytes from file", length); crm_malloc0(buffer, sizeof(char) * (length+1)); read_len = fread(buffer, sizeof(char), length, input); if(read_len != length) { crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len); } else if(length > 0) { new_obj = string2xml(buffer); } else { crm_warn("File contained no XML"); } crm_free(buffer); return new_obj; -#endif } void dump_array(int log_level, const char *message, const char **array, int depth) { int j; if(message != NULL) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s", message); } do_crm_log(log_level, __FILE__, __FUNCTION__, "Contents of the array:"); if(array == NULL || array[0] == NULL || depth == 0) { do_crm_log(log_level, __FILE__, __FUNCTION__, "\t"); return; } for (j=0; j < depth && array[j] != NULL; j++) { if (array[j] == NULL) { break; } do_crm_log(log_level, __FILE__, __FUNCTION__, "\t--> (%s).", array[j]); } } int write_xml_file(crm_data_t *xml_node, const char *filename) { int res = 0; char now_str[30]; time_t now; crm_debug_3("Writing XML out to %s", filename); crm_validate_data(xml_node); if (xml_node == NULL) { return -1; } crm_validate_data(xml_node); crm_log_xml_debug_4(xml_node, "Writing out"); crm_validate_data(xml_node); now = time(NULL); ctime_r(&now, now_str); now_str[24] = EOS; /* replace the newline */ set_xml_property_copy(xml_node, "last_written", now_str); crm_validate_data(xml_node); -#ifdef USE_LIBXML - if (xml_node->doc == NULL) { - xmlDocPtr foo = NULL; - crm_debug_5("Creating doc pointer for %s", xml_node->name); - foo = xmlNewDoc("1.0"); - xmlDocSetRootElement(foo, xml_node); - xmlSetTreeDoc(xml_node, foo); - } - - /* save it. - * set arg 3 to 0 to disable line breaks,1 to enable - * res == num bytes saved - */ - res = xmlSaveFormatFile(filename, xml_node->doc, 1); - /* for some reason, reading back after saving with - * line-breaks doesnt go real well - */ -#else { FILE *file_output_strm = fopen(filename, "w"); char *buffer = dump_xml_formatted(xml_node); CRM_DEV_ASSERT(buffer != NULL && strlen(buffer) > 0); if(file_output_strm == NULL) { res = -1; crm_err("Cannot write to %s", filename); } else if(buffer != NULL && strlen(buffer) > 0) { res = fprintf(file_output_strm, "%s", buffer); } if(file_output_strm != NULL) { fflush(file_output_strm); fclose(file_output_strm); } crm_free(buffer); } -#endif crm_debug_3("Saved %d bytes to the Cib as XML", res); return res; } void print_xml_formatted(int log_level, const char *function, crm_data_t *msg, const char *text) { if(msg == NULL) { do_crm_log(log_level, function, NULL, "%s: %s", crm_str(text), ""); return; } crm_validate_data(msg); do_crm_log(log_level, function, NULL, "%s:", crm_str(text)); log_data_element(function, log_level, 0, msg, TRUE); return; } crm_data_t * get_message_xml(const HA_Message *msg, const char *field) { crm_data_t *xml_node = NULL; -#ifdef USE_LIBXML - const char *xml_text = cl_get_string(msg, field); - xml_node = string2xml(xml_text); -#else crm_data_t *tmp_node = NULL; crm_validate_data(msg); tmp_node = cl_get_struct(msg, field); if(tmp_node != NULL) { xml_node = copy_xml_node_recursive(tmp_node); } -#endif return xml_node; } gboolean add_message_xml(HA_Message *msg, const char *field, crm_data_t *xml) { crm_validate_data(xml); -#ifdef USE_LIBXML - char *buffer = dump_xml_unformatted(xml); - CRM_DEV_ASSERT(buffer != NULL); - if(buffer != NULL) { - CRM_DEV_ASSERT(cl_is_allocated(buffer)); - ha_msg_add(msg, field, buffer); - crm_debug_3("Added XML to message"); - CRM_DEV_ASSERT(cl_is_allocated(buffer)); - crm_free(buffer); - } -#else crm_validate_data(msg); ha_msg_addstruct(msg, field, xml); crm_update_parents(msg); -#endif return TRUE; } char * dump_xml_formatted(crm_data_t *an_xml_node) { char *buffer = NULL; #if 0 int len = 0; xmlChar *xml_buffer = NULL; xmlDocPtr foo = NULL; crm_data_t* xml_node = NULL; xml_node = copy_xml_node_recursive(an_xml_node); if (xml_node == NULL) { return NULL; } else { /* reset the doc pointer */ crm_debug_5("Creating doc pointer for %s", xml_node->name); foo = xmlNewDoc("1.0"); xmlDocSetRootElement(foo, xml_node); xmlSetTreeDoc(xml_node, foo); crm_debug_5("Doc pointer set for %s", xml_node->name); } crm_debug_5("Initializing Parser"); xmlInitParser(); crm_debug_5("Dumping data"); xmlDocDumpFormatMemory(xml_node->doc, &xml_buffer, &len, 1); crm_debug_5("Cleaning up parser"); xmlCleanupParser(); crm_debug_5("Copying memory into crm_ space"); if(xml_buffer != NULL && len > 0) { /* copy the text into crm_ memory */ buffer = crm_strdup(xml_buffer); xmlFree(xml_buffer); } crm_debug_5("Buffer coppied"); free_xml(xml_node); #else char *mutable_ptr = NULL; /* crm_malloc0(buffer, 2*(an_xml_node->stringlen)); */ crm_malloc0(buffer, sizeof(char)*30000); mutable_ptr = buffer; crm_validate_data(an_xml_node); CRM_DEV_ASSERT(dump_data_element( 0, &mutable_ptr, an_xml_node, TRUE) >= 0); if(crm_assert_failed) { crm_crit("Could not dump the whole message"); } crm_debug_4("Dumped: %s", buffer); #endif return buffer; } char * dump_xml_unformatted(crm_data_t *an_xml_node) { char *buffer = NULL; #if 0 int lpc = 0; int len = 0; xmlChar *xml_buffer = NULL; xmlDocPtr foo = NULL; crm_data_t* xml_node = NULL; xml_node = copy_xml_node_recursive(an_xml_node); if (xml_node == NULL) { return NULL; } else { /* reset the doc pointer */ crm_debug_5("Creating doc pointer for %s", xml_node->name); foo = xmlNewDoc("1.0"); xmlDocSetRootElement(foo, xml_node); xmlSetTreeDoc(xml_node, foo); crm_debug_5("Doc pointer set for %s", xml_node->name); } crm_debug_5("Initializing Parser"); xmlInitParser(); crm_debug_5("Dumping data"); xmlDocDumpFormatMemory(xml_node->doc, &xml_buffer, &len, 0); crm_debug_5("Cleaning up parser"); xmlCleanupParser(); crm_debug_5("Copying memory into crm_ space"); if(xml_buffer != NULL && len > 0) { /* copy the text into crm_ memory */ buffer = crm_strdup(xml_buffer); xmlFree(xml_buffer); } crm_debug_5("Buffer coppied"); free_xml(xml_node); /* remove and the newline */ /* for(lpc = 0; lpc < len; lpc++) { */ /* if(buffer[lpc] == '\n') { */ /* buffer[lpc] = ' '; */ /* break; */ /* } else { */ /* buffer[lpc] = ' '; */ /* } */ /* } */ /* for(lpc = len - 2; lpc > 0 && lpc < len; lpc++) { */ for(lpc = 0; lpc < len; lpc++) { if(buffer[lpc] == '\n') { crm_debug_3("Reset newline at %d", lpc); buffer[lpc] = ' '; } } crm_debug_3("Processed %d chars for newlines", lpc); #else char *mutable_ptr = NULL; /* crm_malloc0(buffer, 2*(an_xml_node->stringlen)); */ crm_malloc0(buffer, sizeof(char)*20000); mutable_ptr = buffer; crm_validate_data(an_xml_node); CRM_DEV_ASSERT(dump_data_element( 0, &mutable_ptr, an_xml_node, TRUE) >= 0); if(crm_assert_failed) { crm_crit("Could not dump the whole message"); } crm_debug_4("Dumped: %s", buffer); #endif return buffer; } #define update_buffer_head(buffer, len) if(len < 0) { \ (*buffer) = EOS; return -1; \ } else { \ buffer += len; \ } int print_spaces(char *buffer, int depth) { int lpc = 0; int spaces = 2*depth; /* <= so that we always print 1 space - prevents problems with syslog */ for(lpc = 0; lpc <= spaces; lpc++) { if(sprintf(buffer, "%c", ' ') < 1) { return -1; } buffer += 1; } return lpc; } int log_data_element( const char *function, int log_level, int depth, crm_data_t *data, gboolean formatted) { int printed = 0; int child_result = 0; int has_children = 0; char print_buffer[1000]; char *buffer = print_buffer; const char *name = crm_element_name(data); crm_debug_5("Dumping %s...", name); crm_validate_data(data); if(data == NULL) { crm_warn("No data to dump as XML"); return 0; } else if(name == NULL && depth == 0) { xml_child_iter( data, a_child, NULL, child_result = log_data_element( function, log_level, depth, a_child, formatted); if(child_result < 0) { return child_result; } ); return 0; } else if(name == NULL) { crm_err("Cannot dump NULL element at depth %d", depth); return -1; } if(formatted) { printed = print_spaces(buffer, depth); update_buffer_head(buffer, printed); } printed = sprintf(buffer, "<%s", name); update_buffer_head(buffer, printed); xml_prop_iter( data, prop_name, prop_value, if(safe_str_eq(F_XML_TAGNAME, prop_name)) { continue; } else if(safe_str_eq(F_XML_PARENT, prop_name)) { continue; } crm_debug_5("Dumping <%s %s=\"%s\"...", name, prop_name, prop_value); printed = sprintf(buffer, " %s=\"%s\"", prop_name, prop_value); update_buffer_head(buffer, printed); ); xml_child_iter( data, child, NULL, if(child != NULL) { has_children++; break; } ); printed = sprintf(buffer, "%s>", has_children==0?"/":""); update_buffer_head(buffer, printed); do_crm_log(log_level, function, NULL, "%s", print_buffer); buffer = print_buffer; if(has_children == 0) { return 0; } xml_child_iter( data, a_child, NULL, child_result = log_data_element( function, log_level, depth+1, a_child, formatted); if(child_result < 0) { return -1; } ); if(formatted) { printed = print_spaces(buffer, depth); update_buffer_head(buffer, printed); } do_crm_log(log_level, function, NULL, "%s", print_buffer, name); crm_debug_5("Dumped %s...", name); return has_children; } int dump_data_element( int depth, char **buffer, crm_data_t *data, gboolean formatted) { int printed = 0; int child_result = 0; int has_children = 0; const char *name = crm_element_name(data); crm_debug_5("Dumping %s...", name); crm_validate_data(data); if(buffer == NULL || *buffer == NULL) { crm_err("No buffer supplied to dump XML into"); return -1; } else if(data == NULL) { crm_warn("No data to dump as XML"); (*buffer)[0] = EOS; return 0; } else if(name == NULL && depth == 0) { xml_child_iter( data, a_child, NULL, child_result = dump_data_element( depth, buffer, a_child, formatted); if(child_result < 0) { return child_result; } ); return 0; } else if(name == NULL) { crm_err("Cannot dump NULL element at depth %d", depth); return -1; } if(formatted) { printed = print_spaces(*buffer, depth); update_buffer_head(*buffer, printed); } printed = sprintf(*buffer, "<%s", name); update_buffer_head(*buffer, printed); xml_prop_iter(data, prop_name, prop_value, if(safe_str_eq(F_XML_TAGNAME, prop_name)) { continue; } else if(safe_str_eq(F_XML_PARENT, prop_name)) { continue; } crm_debug_5("Dumping <%s %s=\"%s\"...", name, prop_name, prop_value); printed = sprintf(*buffer, " %s=\"%s\"", prop_name, prop_value); update_buffer_head(*buffer, printed); ); xml_child_iter( data, child, NULL, if(child != NULL) { has_children++; break; } ); printed = sprintf(*buffer, "%s>%s", has_children==0?"/":"", formatted?"\n":""); update_buffer_head(*buffer, printed); if(has_children == 0) { return 0; } xml_child_iter( data, child, NULL, child_result = dump_data_element( depth+1, buffer, child, formatted); if(child_result < 0) { return -1; } ); if(formatted) { printed = print_spaces(*buffer, depth); update_buffer_head(*buffer, printed); } printed = sprintf(*buffer, "%s", name, formatted?"\n":""); update_buffer_head(*buffer, printed); crm_debug_5("Dumped %s...", name); return has_children; } gboolean xml_has_children(crm_data_t *xml_root) { crm_validate_data(xml_root); -#ifdef USE_LIBXML - if(xml_root != NULL && xml_root->children != NULL) { - return TRUE; - } -#else xml_child_iter( xml_root, a_child, NULL, return TRUE; ); -#endif return FALSE; } void crm_validate_data(const crm_data_t *xml_root) { -#ifdef USE_LIBXML +#ifndef XML_PARANOIA_CHECKS CRM_DEV_ASSERT(xml_root != NULL); #else -# ifndef XML_PARANOIA_CHECKS - CRM_DEV_ASSERT(xml_root != NULL); -# else int lpc = 0; CRM_ASSERT(xml_root != NULL); - CRM_ASSERT(cl_is_allocated(xml_root) == 1); + CRM_ASSERT(crm_is_allocated(xml_root) == 1); CRM_ASSERT(xml_root->nfields < 500); for (lpc = 0; lpc < xml_root->nfields; lpc++) { void *child = xml_root->values[lpc]; - CRM_ASSERT(cl_is_allocated(xml_root->names[lpc]) == 1); + CRM_ASSERT(crm_is_allocated(xml_root->names[lpc]) == 1); if(child == NULL) { } else if(xml_root->types[lpc] == FT_STRUCT) { crm_validate_data(child); } else if(xml_root->types[lpc] == FT_STRING) { - CRM_ASSERT(cl_is_allocated(child) == 1); + CRM_ASSERT(crm_is_allocated(child) == 1); /* } else { */ /* CRM_DEV_ASSERT(FALSE); */ } } -# endif #endif } -/* FIXME!! This whole function is evil!! */ void crm_set_element_parent(crm_data_t *data, crm_data_t *parent) { -#ifdef USE_LIBXML - CRM_DEV_ASSERT(FALSE/* not implemented*/); -#else crm_validate_data(data); if(parent != NULL) { ha_msg_mod_int(data, F_XML_PARENT, 1); } else { ha_msg_mod_int(data, F_XML_PARENT, 0); } -#endif } const char * crm_element_value(crm_data_t *data, const char *name) { -#ifdef USE_LIBXML - return xmlGetProp(data, name); -#else const char *value = NULL; crm_validate_data(data); value = cl_get_string(data, name); if(value != NULL) { - cl_is_allocated(value); + CRM_DEV_ASSERT(crm_is_allocated(value) == 1); } return value; -#endif } char * crm_element_value_copy(crm_data_t *data, const char *name) { const char *value = NULL; char *value_copy = NULL; -#ifdef USE_LIBXML - value = xmlGetProp(data, name); -#else crm_validate_data(data); value = cl_get_string(data, name); if(value != NULL) { - cl_is_allocated(value); + CRM_DEV_ASSERT(crm_is_allocated(value) == 1); } -#endif CRM_DEV_ASSERT(value != NULL); if(value != NULL) { value_copy = crm_strdup(value); } return value_copy; } const char * crm_element_name(crm_data_t *data) { -#ifdef USE_LIBXML - return (data ? data->name : NULL); -#else crm_validate_data(data); return cl_get_string(data, F_XML_TAGNAME); -#endif } void xml_remove_prop(crm_data_t *obj, const char *name) { -#ifdef USE_LIBXML - xmlUnsetProp(obj, name); -#else if(crm_element_value(obj, name) != NULL) { cl_msg_remove(obj, name); } -#endif } void crm_update_parents(crm_data_t *xml_root) { -#ifndef USE_LIBXML crm_validate_data(xml_root); xml_child_iter( xml_root, a_child, NULL, crm_set_element_parent(a_child, xml_root); crm_update_parents(a_child); ); -#endif } -#ifndef USE_LIBXML int get_tag_name(const char *input) { int lpc = 0; char ch = 0; const char *error = NULL; gboolean do_special = FALSE; for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c [%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '?': if(lpc == 0) { /* weird xml tag that we dont care about */ do_special = TRUE; } else { return lpc; } break; case '/': case '>': case '\t': case '\n': case ' ': if(!do_special) { return lpc; } break; default: if(do_special) { } else if('a' <= ch && ch <= 'z') { } else if('A' <= ch && ch <= 'Z') { } else if(ch == '_') { } else { error = "bad character, not in [a-zA-Z_]"; } break; } } crm_err("Error parsing token near %.15s: %s", input, crm_str(error)); return -1; } int get_attr_name(const char *input) { int lpc = 0; char ch = 0; const char *error = NULL; for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c[%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '\t': case '\n': case ' ': error = "unexpected whitespace"; break; case '=': return lpc; default: if('a' <= ch && ch <= 'z') { } else if('A' <= ch && ch <= 'Z') { } else if(ch == '_') { } else { error = "bad character, not in [a-zA-Z_]"; } break; } } crm_err("Error parsing token near %.15s: %s", input, crm_str(error)); return -1; } int get_attr_value(const char *input) { int lpc = 0; char ch = 0; const char *error = NULL; for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c [%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '\\': if(input[lpc+1] == '"') { /* skip over the next char */ lpc++; break; } /*fall through*/ case '"': return lpc; default: break; } } crm_err("Error parsing token near %.15s: %s", input, crm_str(error)); return -1; } crm_data_t* parse_xml(const char *input, int *offset) { int len = 0, lpc = 0; char ch = 0; char *tag_name = NULL; char *attr_name = NULL; char *attr_value = NULL; gboolean more = TRUE; const char *error = NULL; const char *our_input = input; crm_data_t *new_obj = NULL; if(offset != NULL) { our_input = input + (*offset); } len = strlen(our_input); while(lpc < len) { if(our_input[lpc] != '<') { } else if(our_input[lpc+1] == '!') { crm_err("XML Comments are not supported"); crm_debug_5("Skipping char %c", our_input[lpc]); lpc++; } else if(our_input[lpc+1] == '?') { crm_debug_5("Skipping char %c", our_input[lpc]); lpc++; } else { lpc++; our_input += lpc; break; } crm_debug_5("Skipping char %c", our_input[lpc]); lpc++; } len = get_tag_name(our_input); if(len < 0) { return NULL; } crm_malloc0(tag_name, len+1); strncpy(tag_name, our_input, len+1); tag_name[len] = EOS; crm_debug_3("Processing tag %s", tag_name); new_obj = ha_msg_new(1); - CRM_DEV_ASSERT(cl_is_allocated(new_obj) == 1); + CRM_DEV_ASSERT(crm_is_allocated(new_obj) == 1); ha_msg_add(new_obj, F_XML_TAGNAME, tag_name); lpc = len; for(; more && error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = our_input[lpc]; crm_debug_5("Processing char %c[%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '/': if(our_input[lpc+1] == '>') { more = FALSE; } break; case '<': if(our_input[lpc+1] != '/') { crm_data_t *child = NULL; crm_debug_3("Start parsing child..."); child = parse_xml(our_input, &lpc); if(child == NULL) { error = "error parsing child"; } else { - CRM_DEV_ASSERT(cl_is_allocated(child) == 1); + CRM_DEV_ASSERT(crm_is_allocated(child) == 1); ha_msg_addstruct( new_obj, crm_element_name(child), child); + ha_msg_del(child); + crm_debug_3("Finished parsing child: %s", crm_element_name(child)); /* lpc++; /\* > *\/ */ } } else { lpc += 2; /* *\/ */ if(our_input[lpc] != '>') { error = "clase tag cannot contain attrs"; } crm_debug_3("Finished parsing ourselves: %s", crm_element_name(new_obj)); } else { error = "Mismatching close tag"; crm_err("Expected: %s", tag_name); } } break; case '=': lpc++; /* = */ /*fall through*/ case '"': lpc++; /* " */ len = get_attr_value(our_input+lpc); if(len < 0) { error = "couldnt find attr_value"; } else { crm_malloc0(attr_value, len+1); strncpy(attr_value, our_input+lpc, len+1); attr_value[len] = EOS; lpc += len; /* lpc++; /\* " *\/ */ crm_debug_3("creating nvpair: <%s %s=\"%s\"...", tag_name, crm_str(attr_name), crm_str(attr_value)); ha_msg_add(new_obj, attr_name, attr_value); crm_free(attr_name); crm_free(attr_value); } break; case '>': case ' ': case '\t': case '\n': break; default: len = get_attr_name(our_input+lpc); if(len < 0) { error = "couldnt find attr_name"; } else { crm_malloc0(attr_name, len+1); strncpy(attr_name, our_input+lpc, len+1); attr_name[len] = EOS; lpc += len; crm_debug_4("found attr name: %s", attr_name); lpc--; /* make sure the '=' is seen next time around */ } break; } } if(error) { crm_err("Error parsing token: %s", error); crm_err("Error at or before: %s", our_input+lpc-3); return NULL; } crm_debug_3("Finished processing %s tag", tag_name); crm_free(tag_name); if(offset != NULL) { (*offset) += lpc; } - CRM_DEV_ASSERT(cl_is_allocated(new_obj) == 1); + CRM_DEV_ASSERT(crm_is_allocated(new_obj) == 1); return new_obj; } -#endif