diff --git a/crm/pengine/incarnation.c b/crm/pengine/incarnation.c index 1bf3f340c7..71e7cf0675 100644 --- a/crm/pengine/incarnation.c +++ b/crm/pengine/incarnation.c @@ -1,658 +1,658 @@ -/* $Id: incarnation.c,v 1.25 2005/06/14 11:21:02 davidlee Exp $ */ +/* $Id: incarnation.c,v 1.26 2005/06/15 10:12:25 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 extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); typedef struct incarnation_variant_data_s { resource_t *self; int incarnation_max; int incarnation_max_node; int active_incarnation; gboolean interleave; gboolean ordered; GListPtr child_list; /* resource_t* */ gboolean child_starting; gboolean child_stopping; } incarnation_variant_data_t; void child_stopping_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); void child_starting_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); #define get_incarnation_variant_data(data, rsc) \ if(rsc->variant == pe_incarnation) { \ data = (incarnation_variant_data_t *)rsc->variant_opaque; \ } else { \ pe_err("Resource %s was not an \"incarnation\" variant", \ rsc->id); \ return; \ } void incarnation_unpack(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0; crm_data_t * xml_obj_child = NULL; crm_data_t * xml_obj = rsc->xml; crm_data_t * xml_self = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); incarnation_variant_data_t *incarnation_data = NULL; resource_t *self = NULL; char *inc_max = NULL; const char *ordered = crm_element_value(xml_obj, XML_RSC_ATTR_ORDERED); const char *interleave = crm_element_value(xml_obj, XML_RSC_ATTR_INTERLEAVE); const char *max_incarn = get_rsc_param(rsc, XML_RSC_ATTR_INCARNATION_MAX); const char *max_incarn_node = get_rsc_param(rsc, XML_RSC_ATTR_INCARNATION_NODEMAX); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(incarnation_data, sizeof(incarnation_variant_data_t)); incarnation_data->child_list = NULL; incarnation_data->interleave = FALSE; incarnation_data->ordered = FALSE; incarnation_data->active_incarnation = 0; incarnation_data->incarnation_max = crm_atoi(max_incarn, "1"); incarnation_data->incarnation_max_node = crm_atoi(max_incarn_node,"1"); /* this is a bit of a hack - but simplifies everything else */ copy_in_properties(xml_self, xml_obj); xml_obj_child = find_xml_node(xml_obj, "resource_group", FALSE); if(xml_obj_child == NULL) { xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_RESOURCE, TRUE); } CRM_DEV_ASSERT(xml_obj_child != NULL); if(crm_assert_failed) { return; } if(common_unpack(xml_self, &self, data_set)) { incarnation_data->self = self; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return; } if(crm_is_true(interleave)) { incarnation_data->interleave = TRUE; } if(crm_is_true(ordered)) { incarnation_data->ordered = TRUE; } inherit_parent_attributes(xml_self, xml_obj_child, FALSE); inc_max = crm_itoa(incarnation_data->incarnation_max); for(lpc = 0; lpc < incarnation_data->incarnation_max; lpc++) { resource_t *child_rsc = NULL; crm_data_t * child_copy = copy_xml( xml_obj_child); set_id(child_copy, rsc->id, lpc); if(common_unpack(child_copy, &child_rsc, data_set)) { char *inc_num = crm_itoa(lpc); incarnation_data->child_list = g_list_append( incarnation_data->child_list, child_rsc); add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION, inc_num); add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION_MAX, inc_max); crm_action_debug_3( print_resource("Added", child_rsc, FALSE)); crm_free(inc_num); } else { pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID)); } } crm_free(inc_max); crm_debug_3("Added %d children to resource %s...", incarnation_data->incarnation_max, rsc->id); rsc->variant_opaque = incarnation_data; } resource_t * incarnation_find_child(resource_t *rsc, const char *id) { incarnation_variant_data_t *incarnation_data = NULL; if(rsc->variant == pe_incarnation) { incarnation_data = (incarnation_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"incarnation\" variant", rsc->id); return NULL; } return pe_find_resource(incarnation_data->child_list, id); } int incarnation_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; incarnation_variant_data_t *incarnation_data = NULL; if(rsc->variant == pe_incarnation) { incarnation_data = (incarnation_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not an \"incarnation\" variant", rsc->id); return 0; } /* what *should* we return here? */ slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, int tmp_num_nodes = child_rsc->fns->num_allowed_nodes(child_rsc); if(tmp_num_nodes > num_nodes) { num_nodes = tmp_num_nodes; } ); return num_nodes; } void incarnation_color(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0, lpc2 = 0, max_nodes = 0; resource_t *child_0 = NULL; resource_t *child_lh = NULL; resource_t *child_rh = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); child_0 = g_list_nth_data(incarnation_data->child_list, 0); max_nodes = rsc->fns->num_allowed_nodes(rsc); /* generate up to max_nodes * incarnation_node_max constraints */ lpc = 0; crm_info("Distributing %d incarnations over %d nodes", incarnation_data->incarnation_max, max_nodes); for(; lpc < max_nodes && lpc < incarnation_data->incarnation_max; lpc++) { child_lh = child_0; incarnation_data->active_incarnation++; if(lpc != 0) { child_rh = g_list_nth_data(incarnation_data->child_list, lpc); crm_debug_4("Incarnation %d will run on a differnt node to 0", lpc); rsc_colocation_new("pe_incarnation_internal_must_not", pecs_must_not, child_lh, child_rh); } else { child_rh = child_0; } child_lh = child_rh; for(lpc2 = 1; lpc2 < incarnation_data->incarnation_max_node; lpc2++) { int offset = lpc + (lpc2 * max_nodes); if(offset >= incarnation_data->incarnation_max) { break; } crm_debug_4("Incarnation %d will run on the same node as %d", offset, lpc); incarnation_data->active_incarnation++; child_rh = g_list_nth_data( incarnation_data->child_list, offset); rsc_colocation_new("pe_incarnation_internal_must", pecs_must, child_lh, child_rh); } } slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, if(lpc < incarnation_data->active_incarnation) { crm_debug_4("Coloring Incarnation %d", lpc); child_rsc->fns->color(child_rsc, data_set); } else { /* TODO: assign "no color"? Doesnt seem to need it */ pe_warn("Incarnation %d cannot be started", lpc+1); } ); crm_info("%d Incarnations are active", incarnation_data->active_incarnation); } void incarnation_update_pseudo_status(resource_t *parent, resource_t *child); void incarnation_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *op = NULL; resource_t *last_start_rsc = NULL; resource_t *last_stop_rsc = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->create_actions(child_rsc, data_set); incarnation_update_pseudo_status(rsc, child_rsc); if(child_rsc->starting) { last_start_rsc = child_rsc; } if(child_rsc->stopping) { last_stop_rsc = child_rsc; } ); op = start_action(incarnation_data->self, NULL); op->optional = !incarnation_data->child_starting; op->pseudo = TRUE; op = custom_action(incarnation_data->self, started_key(rsc), CRMD_ACTION_STARTED, NULL, data_set); op->optional = !incarnation_data->child_starting; op->pseudo = TRUE; child_starting_constraints( incarnation_data, pe_ordering_optional, NULL, last_start_rsc, data_set); op = stop_action(incarnation_data->self, NULL); op->optional = !incarnation_data->child_stopping; op->pseudo = TRUE; op = custom_action(incarnation_data->self, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, data_set); op->optional = !incarnation_data->child_stopping; op->pseudo = TRUE; child_stopping_constraints( incarnation_data, pe_ordering_optional, NULL, last_stop_rsc, data_set); } void incarnation_update_pseudo_status(resource_t *parent, resource_t *child) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, parent); if(incarnation_data->child_stopping && incarnation_data->child_starting) { return; } slist_iter( action, action_t, child->actions, lpc, if(action->optional) { continue; } if(safe_str_eq(CRMD_ACTION_STOP, action->task)) { incarnation_data->child_stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task)) { incarnation_data->child_starting = TRUE; } ); } void child_starting_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(incarnation_data->ordered || incarnation_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(incarnation_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* last child start before global started */ custom_action_order( last, start_key(last), NULL, incarnation_data->self, started_key(incarnation_data->self), NULL, type, data_set); } } else if(incarnation_data->ordered) { crm_debug_4("Ordered version"); if(last == NULL) { /* global start before first child start */ last = incarnation_data->self; } /* else: child/child relative start */ order_start_start(last, child, type); } else { crm_debug_4("Un-ordered version"); /* child start before global started */ custom_action_order( child, start_key(child), NULL, incarnation_data->self, started_key(incarnation_data->self), NULL, type, data_set); /* global start before child start */ /* order_start_start(incarnation_data->self, child, type); */ order_start_start( incarnation_data->self, child, pe_ordering_manditory); } } void child_stopping_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(incarnation_data->ordered || incarnation_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(incarnation_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* global stop before first child stop */ order_stop_stop(incarnation_data->self, last, pe_ordering_manditory); } } else if(incarnation_data->ordered && last != NULL) { crm_debug_4("Ordered version"); /* child/child relative stop */ order_stop_stop(child, last, type); } else if(incarnation_data->ordered) { crm_debug_4("Ordered version (1st node)"); /* first child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, incarnation_data->self, stopped_key(incarnation_data->self), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, incarnation_data->self, stopped_key(incarnation_data->self), NULL, type, data_set); /* global stop before child stop */ order_stop_stop(incarnation_data->self, child, type); } } void incarnation_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); /* global stopped before start */ custom_action_order( incarnation_data->self, stopped_key(incarnation_data->self), NULL, incarnation_data->self, start_key(incarnation_data->self), NULL, pe_ordering_manditory, data_set); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, /* child stop before start */ order_restart(child_rsc); child_starting_constraints( incarnation_data, pe_ordering_optional, child_rsc, last_rsc, data_set); child_stopping_constraints( incarnation_data, pe_ordering_optional, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); } void incarnation_rsc_colocation_lh(rsc_colocation_t *constraint) { resource_t *rsc = constraint->rsc_lh; incarnation_variant_data_t *incarnation_data = NULL; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else if(constraint->strength != pecs_must_not) { - pe_warn("rsc_dependancies other than \"must_not\" " + pe_warn("rsc_colocations other than \"-INFINITY\" " "are not supported for incarnation resources"); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } get_incarnation_variant_data(incarnation_data, rsc); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, crm_action_debug_3(print_resource("LHS", child_rsc, TRUE)); child_rsc->fns->rsc_colocation_rh(child_rsc, constraint); ); } void incarnation_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint) { incarnation_variant_data_t *incarnation_data = NULL; crm_debug_3("Processing RH of constraint %s", constraint->id); if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_dependancies other than \"must_not\" " "are not supported for incarnation resources"); return; } else { crm_action_debug_3(print_resource("LHS", rsc, FALSE)); } get_incarnation_variant_data(incarnation_data, rsc); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, crm_action_debug_3(print_resource("RHS", child_rsc, FALSE)); child_rsc->fns->rsc_colocation_rh(child_rsc, constraint); ); } void incarnation_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing LH of ordering constraint %d", order->id); stop_id = stop_key(rsc); start_id = start_key(rsc); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(rsc); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(rsc); } crm_free(start_id); crm_free(stop_id); incarnation_data->self->fns->rsc_order_lh(incarnation_data->self, order); } void incarnation_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); incarnation_data->self->fns->rsc_order_rh(lh_action, incarnation_data->self, order); } void incarnation_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); incarnation_data->self->fns->rsc_location(incarnation_data->self, constraint); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->rsc_location(child_rsc, constraint); ); } void incarnation_expand(resource_t *rsc, pe_working_set_t *data_set) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); incarnation_data->self->fns->expand(incarnation_data->self, data_set); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->expand(child_rsc, data_set); ); } void incarnation_dump(resource_t *rsc, const char *pre_text, gboolean details) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); common_dump(rsc, pre_text, details); incarnation_data->self->fns->dump( incarnation_data->self, pre_text, details); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->dump(child_rsc, pre_text, details); ); } void incarnation_free(resource_t *rsc) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, crm_debug_3("Freeing child %s", child_rsc->id); free_xml(child_rsc->xml); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(incarnation_data->child_list, FALSE); free_xml(incarnation_data->self->xml); incarnation_data->self->fns->free(incarnation_data->self); common_free(rsc); } void incarnation_agent_constraints(resource_t *rsc) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->agent_constraints(child_rsc); ); } diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c index 60c2a131bc..f66d5b3af3 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,437 +1,433 @@ -/* $Id: utils.c,v 1.34 2005/06/14 11:38:26 davidlee Exp $ */ +/* $Id: utils.c,v 1.35 2005/06/15 10:12:25 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 extern cib_t *te_cib_conn; extern int global_transition_timer; void print_input(const char *prefix, action_t *input, gboolean to_file); void print_action(const char *prefix, action_t *action, gboolean to_file); gboolean timer_callback(gpointer data); void send_complete(const char *text, crm_data_t *msg, te_reason_t reason, te_fsa_input_t input) { HA_Message *cmd = NULL; const char *op = CRM_OP_TEABORT; static te_reason_t last_reason = te_done; static crm_data_t *last_msg = NULL; static const char *last_text = NULL; te_fsa_state_t last_state = te_fsa_state; te_fsa_state = te_state_matrix[input][te_fsa_state]; if(te_fsa_state == s_abort_pending && num_cib_op_callbacks() == 0) { te_fsa_state = te_state_matrix[i_cib_complete][te_fsa_state]; } if(te_fsa_state != s_idle && input != i_cib_complete) { if(last_msg) { free_xml(last_msg); } last_msg = NULL; if(msg != NULL) { last_msg = copy_xml(msg); } last_text = text; last_reason = reason; crm_info("CIB updates are pending. Delay until they complete."); return; } else if(te_fsa_state != s_idle) { crm_err("Delaying \"%s\" notification until we are idle.",text); return; } else if(input == i_cib_complete) { msg = last_msg; text = last_text; reason = last_reason; } CRM_DEV_ASSERT(num_cib_op_callbacks() == 0); switch(reason) { case te_update: te_log_action(LOG_DEBUG, "Transition status: %s by CIB update: %s", last_state!=s_idle?"Aborted":"Triggered", text); if(msg != NULL) { if(safe_str_eq(crm_element_name(msg), XML_TAG_CIB)) { crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, msg); crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB); crm_debug("Cause:" " full CIB replace/update"); copy_in_properties(generation, msg); crm_log_xml_debug(generation, "[generation]"); crm_log_xml_debug(status, "[in ]"); free_xml(generation); } else { crm_log_xml_debug(msg, "Cause"); } } print_state(LOG_DEBUG); break; case te_halt: te_log_action(LOG_INFO,"Transition status: Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TECOMPLETE; break; case te_abort_confirmed: te_log_action(LOG_INFO, "Transition status: Confirmed Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TEABORTED; break; case te_abort: te_log_action(LOG_INFO,"Transition status: Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); break; case te_done: te_log_action(LOG_INFO, "Transition status: Complete%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TECOMPLETE; break; case te_timeout: te_log_action(LOG_ERR, "Transition status: Timed out after %dms", transition_timer->timeout); print_state(LOG_WARNING); op = CRM_OP_TETIMEOUT; break; case te_failed: te_log_action(LOG_ERR, "Transition status: Aborted by failed action: %s", text); crm_log_xml_debug(msg, "Cause"); print_state(LOG_WARNING); break; } initialize_graph(); cmd = create_request( op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); if(text != NULL) { ha_msg_add(cmd, "message", text); } free_xml(last_msg); #ifdef TESTING if(reason == te_done) { crm_log_message(LOG_INFO, cmd); } else { crm_log_message(LOG_ERR, cmd); } g_main_quit(mainloop); return; #else send_ipc_message(crm_ch, cmd); #endif #if 0 if(is_ipc_empty(crm_ch) && is_ipc_empty(te_cib_conn->cmds->channel(te_cib_conn)) ) { static gboolean mem_needs_init = TRUE; if(mem_needs_init) { crm_debug("Reached a stable point:" " reseting memory usage stats to zero"); crm_zero_mem_stats(NULL); mem_needs_init = FALSE; } else { crm_err("Reached a stable point:" " checking memory usage"); crm_mem_stats(NULL); } } #endif } void print_state(int log_level) { if(graph == NULL && log_level > LOG_DEBUG) { - do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "###########"); - do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, - "\tEmpty transition graph"); - do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "###########"); + crm_debug("## Empty transition graph ##"); return; } - do_crm_log(log_level, __FILE__, __FUNCTION__, "###########"); + crm_log_maybe(log_level, "###########"); slist_iter( synapse, synapse_t, graph, lpc, - do_crm_log(log_level, __FILE__, __FUNCTION__, "Synapse %d %s", - synapse->id, - synapse->confirmed?"was confirmed":synapse->complete?"was executed":"is pending"); + crm_log_maybe(log_level, "Synapse %d %s", synapse->id, + synapse->confirmed?"was confirmed":synapse->complete?"was executed":"is pending"); if(synapse->confirmed == FALSE) { slist_iter( action, action_t, synapse->actions, lpc2, print_action("\t", action, log_level); ); } if(synapse->complete == FALSE) { slist_iter( input, action_t, synapse->inputs, lpc2, print_input("\t", input, log_level); ); } ); - do_crm_log(log_level, __FILE__, __FUNCTION__, "###########"); + crm_log_maybe(log_level, "###########"); } void print_input(const char *prefix, action_t *input, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Input %d] %s (%s)", prefix, input->id, input->complete?"Satisfied":"Pending", actiontype2text(input->type)); if(input->complete == FALSE) { crm_log_xml((unsigned)log_level, "\t Raw input", input->xml); } } void print_action(const char *prefix, action_t *action, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Action %d] %s (%s fail)", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight":"Pending", action->can_fail?"can":"cannot"); switch(action->type) { case action_type_pseudo: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tPseudo Op: %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK)); break; case action_type_rsc: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tResource Op: %s/%s on %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_RSCID), crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET)); break; case action_type_crm: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tCRM Op: %s on %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET)); break; } if(action->timeout > 0 || action->timer->source_id > 0) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\ttimeout=%d, timer=%d", prefix, action->timeout, action->timer->source_id); } if(action->complete == FALSE) { crm_log_xml(LOG_DEBUG_2, "\tRaw action", action->xml); } } gboolean timer_callback(gpointer data) { te_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (te_timer_t*)data; if(timer->source_id > 0) { g_source_remove(timer->source_id); } timer->source_id = -1; crm_err("Timer popped in state=%d", te_fsa_state); if(te_fsa_state != s_in_transition) { crm_debug("Ignoring timeout while not in transition"); return TRUE; } else if(timer->reason == timeout_timeout) { /* global timeout - abort the transition */ crm_warn("Transition timeout reached..." " marking transition complete."); crm_warn("Some actions may not have been executed."); send_complete(XML_ATTR_TIMEOUT, NULL, te_timeout, i_cancel); return TRUE; } else if(timer->action == NULL) { crm_err("Action not present!"); return FALSE; } else if(timer->reason == timeout_action_warn) { crm_warn("Action %d is taking more than 2x its timeout (%d)", timer->action->id, timer->action->timeout); crm_log_xml_debug(timer->action->xml, "Slow action"); return TRUE; } else { /* fail the action * - which may or may not abort the transition */ /* TODO: send a cancel notice to the LRM */ /* TODO: use the ack from above to update the CIB */ return cib_action_update(timer->action, LRM_OP_TIMEOUT); } } gboolean start_te_timer(te_timer_t *timer) { if(((int)timer->source_id) < 0 && timer->timeout > 0) { timer->source_id = Gmain_timeout_add( timer->timeout, timer_callback, (void*)timer); return TRUE; } else if(timer->timeout < 0) { crm_err("Tried to start timer with -ve period"); } else { crm_debug_3("#!!#!!# Timer already running (%d)", timer->source_id); } return FALSE; } gboolean stop_te_timer(te_timer_t *timer) { if(timer == NULL) { return FALSE; } if(((int)timer->source_id) > 0) { g_source_remove(timer->source_id); timer->source_id = -2; } else { return FALSE; } return TRUE; } const char * actiontype2text(action_type_e type) { switch(type) { case action_type_pseudo: return "pseduo"; case action_type_rsc: return "rsc"; case action_type_crm: return "crm"; } return ""; } const char * get_rsc_state(const char *task, op_status_t status) { if(safe_str_eq(CRMD_ACTION_START, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_START_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STARTED; } else { return CRMD_ACTION_START_FAIL; } } else if(safe_str_eq(CRMD_ACTION_STOP, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_STOP_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STOPPED; } else { return CRMD_ACTION_STOP_FAIL; } } else { if(safe_str_eq(CRMD_ACTION_MON, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_MON_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_MON_OK; } else { return CRMD_ACTION_MON_FAIL; } } else { const char *rsc_state = NULL; if(status == LRM_OP_PENDING) { rsc_state = CRMD_ACTION_GENERIC_PENDING; } else if(status == LRM_OP_DONE) { rsc_state = CRMD_ACTION_GENERIC_OK; } else { rsc_state = CRMD_ACTION_GENERIC_FAIL; } crm_warn("Using status \"%s\" for op \"%s\"..." " this is still in the experimental stage.", rsc_state, task); return rsc_state; } } } diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c index c6f41e3eb8..383f515ee8 100755 --- a/lib/crm/cib/cib_client.c +++ b/lib/crm/cib/cib_client.c @@ -1,1454 +1,1454 @@ /* * Copyright (c) 2004 International Business Machines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 /* short term hack to reduce callback messages */ typedef struct cib_native_opaque_s { IPC_Channel *command_channel; IPC_Channel *callback_channel; GCHSource *callback_source; } cib_native_opaque_t; GHashTable *cib_op_callback_table = NULL; gboolean verify_cib_cmds(cib_t *cib); int cib_client_set_op_callback( cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, int rc, crm_data_t *output)); int cib_client_noop(cib_t *cib, int call_options); int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options); int cib_client_query(cib_t *cib, const char *section, crm_data_t **output_data, int call_options); int cib_client_query_from(cib_t *cib, const char *host, const char *section, crm_data_t **output_data, int call_options); int cib_client_sync(cib_t *cib, const char *section, int call_options); int cib_client_sync_from( cib_t *cib, const char *host, const char *section, int call_options); int cib_client_is_master(cib_t *cib); int cib_client_set_slave(cib_t *cib, int call_options); int cib_client_set_slave_all(cib_t *cib, int call_options); int cib_client_set_master(cib_t *cib, int call_options); int cib_client_bump_epoch(cib_t *cib, int call_options); int cib_client_create(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) ; int cib_client_erase( cib_t *cib, crm_data_t **output_data, int call_options); int cib_client_quit(cib_t *cib, int call_options); int cib_client_add_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)); int cib_client_del_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)); gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b); extern cib_t *cib_native_new(cib_t *cib); static enum cib_variant configured_variant = cib_native; /* define of the api functions*/ cib_t* cib_new(void) { cib_t* new_cib = NULL; if(configured_variant != cib_native) { crm_err("Only the native CIB type is currently implemented"); return NULL; } if(cib_op_callback_table != NULL) { g_hash_table_destroy(cib_op_callback_table); cib_op_callback_table = NULL; } if(cib_op_callback_table == NULL) { cib_op_callback_table = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, g_hash_destroy_str); } crm_malloc0(new_cib, sizeof(cib_t)); new_cib->call_id = 1; new_cib->type = cib_none; new_cib->state = cib_disconnected; new_cib->op_callback = NULL; new_cib->variant_opaque = NULL; new_cib->notify_list = NULL; /* the rest will get filled in by the variant constructor */ crm_malloc0(new_cib->cmds, sizeof(cib_api_operations_t)); memset(new_cib->cmds, 0, sizeof(cib_api_operations_t)); new_cib->cmds->set_op_callback = cib_client_set_op_callback; new_cib->cmds->add_notify_callback = cib_client_add_notify_callback; new_cib->cmds->del_notify_callback = cib_client_del_notify_callback; new_cib->cmds->noop = cib_client_noop; new_cib->cmds->ping = cib_client_ping; new_cib->cmds->query = cib_client_query; new_cib->cmds->sync = cib_client_sync; new_cib->cmds->query_from = cib_client_query_from; new_cib->cmds->sync_from = cib_client_sync_from; new_cib->cmds->is_master = cib_client_is_master; new_cib->cmds->set_master = cib_client_set_master; new_cib->cmds->set_slave = cib_client_set_slave; new_cib->cmds->set_slave_all = cib_client_set_slave_all; new_cib->cmds->bump_epoch = cib_client_bump_epoch; new_cib->cmds->create = cib_client_create; new_cib->cmds->modify = cib_client_modify; new_cib->cmds->replace = cib_client_replace; new_cib->cmds->delete = cib_client_delete; new_cib->cmds->erase = cib_client_erase; new_cib->cmds->quit = cib_client_quit; cib_native_new(new_cib); if(verify_cib_cmds(new_cib) == FALSE) { return NULL; } return new_cib; } int cib_client_set_op_callback( cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, int rc, crm_data_t *output)) { if(callback == NULL) { crm_info("Un-Setting operation callback"); } else { crm_debug_3("Setting operation callback"); } cib->op_callback = callback; return cib_ok; } int cib_client_noop(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_NOOP, NULL, NULL, NULL, NULL, call_options); } int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_PING, NULL,NULL,NULL, output_data, call_options); } int cib_client_query(cib_t *cib, const char *section, crm_data_t **output_data, int call_options) { return cib->cmds->query_from( cib, NULL, section, output_data, call_options); } int cib_client_query_from(cib_t *cib, const char *host, const char *section, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_QUERY, host, section, NULL, output_data, call_options); } int cib_client_is_master(cib_t *cib) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_ISMASTER, NULL, NULL,NULL,NULL, cib_scope_local|cib_sync_call); } int cib_client_set_slave(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SLAVE, NULL,NULL,NULL,NULL, call_options); } int cib_client_set_slave_all(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SLAVEALL, NULL,NULL,NULL,NULL, call_options); } int cib_client_set_master(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } crm_debug_3("Adding cib_scope_local to options"); return cib->cmds->variant_op( cib, CIB_OP_MASTER, NULL,NULL,NULL,NULL, call_options|cib_scope_local); } int cib_client_bump_epoch(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_BUMP, NULL, NULL, NULL, NULL, call_options); } int cib_client_sync(cib_t *cib, const char *section, int call_options) { return cib->cmds->sync_from(cib, NULL, section, call_options); } int cib_client_sync_from( cib_t *cib, const char *host, const char *section, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SYNC, host, section, NULL, NULL, call_options); } int cib_client_create(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_CREATE, NULL, section, data, output_data, call_options); } int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_UPDATE, NULL, section, data, output_data, call_options); } int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } else if(data == NULL) { return cib_missing_data; } return cib->cmds->variant_op(cib, CIB_OP_REPLACE, NULL, section, data, output_data, call_options); } int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_DELETE, NULL, section, data, output_data, call_options); } int cib_client_erase( cib_t *cib, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_ERASE, NULL, NULL, NULL, output_data, call_options); } int cib_client_quit(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_QUIT, NULL, NULL, NULL, NULL, call_options); } int cib_client_add_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)) { GList *list_item = NULL; cib_notify_client_t *new_client = NULL; crm_debug_2("Adding callback for %s events (%d)", event, g_list_length(cib->notify_list)); crm_malloc0(new_client, sizeof(cib_notify_client_t)); new_client->event = event; new_client->callback = callback; list_item = g_list_find_custom( cib->notify_list, new_client, ciblib_GCompareFunc); if(list_item != NULL) { crm_warn("Callback already present"); } else { cib->notify_list = g_list_append( cib->notify_list, new_client); cib->cmds->register_callback(cib, event, 1); crm_debug_3("Callback added (%d)", g_list_length(cib->notify_list)); } return cib_ok; } int cib_client_del_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)) { GList *list_item = NULL; cib_notify_client_t *new_client = NULL; crm_debug("Removing callback for %s events", event); crm_malloc0(new_client, sizeof(cib_notify_client_t)); new_client->event = event; new_client->callback = callback; list_item = g_list_find_custom( cib->notify_list, new_client, ciblib_GCompareFunc); cib->cmds->register_callback(cib, event, 0); if(list_item != NULL) { cib_notify_client_t *list_client = list_item->data; cib->notify_list = g_list_remove(cib->notify_list, list_client); crm_free(list_client); crm_debug_3("Removed callback"); } else { crm_debug_3("Callback not present"); } crm_free(new_client); return cib_ok; } gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b) { const cib_notify_client_t *a_client = a; const cib_notify_client_t *b_client = b; if(a_client->callback == b_client->callback && safe_str_neq(a_client->event, b_client->event)) { return 0; } else if(((long)a_client->callback) < ((long)b_client->callback)) { return -1; } return 1; } gboolean add_cib_op_callback( int call_id, gboolean only_success, void *user_data, void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)) { cib_callback_client_t *blob = NULL; if(call_id < 0) { crm_warn("CIB call failed: %s", cib_error2string(call_id)); if(only_success == FALSE) { callback(NULL, call_id, call_id, NULL, user_data); } return FALSE; } crm_malloc0(blob, sizeof(cib_callback_client_t)); blob->only_success = only_success; blob->user_data = user_data; blob->callback = callback; g_hash_table_insert( cib_op_callback_table, GINT_TO_POINTER(call_id), blob); return TRUE; } void remove_cib_op_callback(int call_id, gboolean all_callbacks) { if(all_callbacks) { if(cib_op_callback_table != NULL) { g_hash_table_destroy(cib_op_callback_table); } cib_op_callback_table = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, g_hash_destroy_str); } else { g_hash_table_remove( cib_op_callback_table, GINT_TO_POINTER(call_id)); } } int num_cib_op_callbacks(void) { return g_hash_table_size(cib_op_callback_table); } char * cib_pluralSection(const char *a_section) { char *a_section_parent = NULL; if (a_section == NULL) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_TAG_CIB) == 0) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_CIB_TAG_NODE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_NODES); } else if(strcmp(a_section, XML_CIB_TAG_STATE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_STATUS); } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CONS_TAG_RSC_LOCATION) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CONS_TAG_RSC_DEPEND) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CONS_TAG_RSC_ORDER) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CIB_TAG_RESOURCE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcmp(a_section, XML_CIB_TAG_NVPAIR) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG); } else { crm_err("Unknown section %s", a_section); a_section_parent = crm_strdup("all"); } crm_debug_2("Plural of %s is %s", crm_str(a_section), a_section_parent); return a_section_parent; } const char * cib_error2string(enum cib_errors return_code) { const char *error_msg = NULL; switch(return_code) { case cib_msg_field_add: error_msg = "failed adding field to cib message"; break; case cib_operation: error_msg = "invalid operation"; break; case cib_create_msg: error_msg = "couldnt create cib message"; break; case cib_client_gone: error_msg = "client left before we could send reply"; break; case cib_not_connected: error_msg = "not connected"; break; case cib_not_authorized: error_msg = "not authorized"; break; case cib_send_failed: error_msg = "send failed"; break; case cib_reply_failed: error_msg = "reply failed"; break; case cib_return_code: error_msg = "no return code"; break; case cib_output_ptr: error_msg = "nowhere to store output"; break; case cib_output_data: error_msg = "corrupt output data"; break; case cib_connection: error_msg = "connection failed"; break; case cib_callback_register: error_msg = "couldnt register callback channel"; break; case cib_authentication: error_msg = ""; break; case cib_registration_msg: error_msg = "invalid registration msg"; break; case cib_callback_token: error_msg = "callback token not found"; break; case cib_missing: error_msg = "cib object missing"; break; case cib_variant: error_msg = "unknown/corrupt cib variant"; break; case CIBRES_MISSING_ID: error_msg = "The id field is missing"; break; case CIBRES_MISSING_TYPE: error_msg = "The type field is missing"; break; case CIBRES_MISSING_FIELD: error_msg = "A required field is missing"; break; case CIBRES_OBJTYPE_MISMATCH: error_msg = "CIBRES_OBJTYPE_MISMATCH"; break; case cib_EXISTS: error_msg = "The object already exists"; break; case cib_NOTEXISTS: error_msg = "The object does not exist"; break; case CIBRES_CORRUPT: error_msg = "The CIB is corrupt"; break; case cib_NOOBJECT: error_msg = "The update was empty"; break; case cib_NOPARENT: error_msg = "The parent object does not exist"; break; case cib_NODECOPY: error_msg = "Failed while copying update"; break; case CIBRES_OTHER: error_msg = "CIBRES_OTHER"; break; case cib_ok: error_msg = "ok"; break; case cib_unknown: error_msg = "Unknown error"; break; case cib_STALE: error_msg = "Discarded old update"; break; case cib_ACTIVATION: error_msg = "Activation Failed"; break; case cib_NOSECTION: error_msg = "Required section was missing"; break; case cib_NOTSUPPORTED: error_msg = "Supplied information is not supported"; break; case cib_not_master: error_msg = "Local service is not the master instance"; break; case cib_client_corrupt: error_msg = "Service client not valid"; break; case cib_remote_timeout: error_msg = "Remote node did not respond"; break; case cib_master_timeout: error_msg = "No master service is currently active"; break; case cib_revision_unsupported: error_msg = "The required CIB revision number is not supported"; break; case cib_revision_unknown: error_msg = "The CIB revision number could not be determined"; break; case cib_missing_data: error_msg = "Required data for this CIB API call not found"; break; case cib_no_quorum: error_msg = "Write requires quorum"; break; case cib_diff_failed: error_msg = "Application of an update diff failed"; break; case cib_diff_resync: error_msg = "Application of an update diff failed, requesting a full refresh"; break; case cib_old_data: error_msg = "Update was older than existing configuration"; break; } if(error_msg == NULL) { crm_err("Unknown CIB Error Code: %d", return_code); error_msg = ""; } return error_msg; } const char * cib_op2string(enum cib_update_op operation) { const char *operation_msg = NULL; switch(operation) { case 0: operation_msg = "none"; break; case 1: operation_msg = "add"; break; case 2: operation_msg = "modify"; break; case 3: operation_msg = "delete"; break; case CIB_UPDATE_OP_MAX: operation_msg = "invalid operation"; break; } if(operation_msg == NULL) { crm_err("Unknown CIB operation %d", operation); operation_msg = ""; } return operation_msg; } int cib_section2enum(const char *a_section) { if(a_section == NULL || strcmp(a_section, "all") == 0) { return cib_section_all; } else if(strcmp(a_section, XML_CIB_TAG_NODES) == 0) { return cib_section_nodes; } else if(strcmp(a_section, XML_CIB_TAG_STATUS) == 0) { return cib_section_status; } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINTS) == 0) { return cib_section_constraints; } else if(strcmp(a_section, XML_CIB_TAG_RESOURCES) == 0) { return cib_section_resources; } else if(strcmp(a_section, XML_CIB_TAG_CRMCONFIG) == 0) { return cib_section_crmconfig; } crm_err("Unknown CIB section: %s", a_section); return cib_section_none; } int cib_compare_generation(crm_data_t *left, crm_data_t *right) { int lpc = 0; const char *attributes[] = { XML_ATTR_GENERATION_ADMIN, XML_ATTR_GENERATION, XML_ATTR_NUMUPDATES, XML_ATTR_NUMPEERS }; crm_log_xml_debug_3(left, "left"); crm_log_xml_debug_3(right, "right"); for(lpc = 0; lpc < DIMOF(attributes); lpc++) { int int_elem_l = -1; int int_elem_r = -1; const char *elem_r = NULL; const char *elem_l = crm_element_value(left, attributes[lpc]); if(right != NULL) { elem_r = crm_element_value(right, attributes[lpc]); } if(elem_l != NULL) { int_elem_l = atoi(elem_l); } if(elem_r != NULL) { int_elem_r = atoi(elem_r); } if(int_elem_l < int_elem_r) { crm_debug_2("%s (%s < %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r)); return -1; } else if(int_elem_l > int_elem_r) { crm_debug_2("%s (%s > %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r)); return 1; } } return 0; } crm_data_t* get_cib_copy(cib_t *cib) { crm_data_t *xml_cib; crm_data_t *xml_cib_copy; int options = cib_scope_local|cib_sync_call; if(cib->cmds->query(cib, NULL, &xml_cib, options) != cib_ok) { crm_err("Couldnt retrieve the CIB"); return NULL; } else if(xml_cib == NULL) { crm_err("The CIB result was empty"); return NULL; } xml_cib_copy = copy_xml( find_xml_node(xml_cib, XML_TAG_CIB, TRUE)); free_xml(xml_cib); return xml_cib_copy; } crm_data_t* cib_get_generation(cib_t *cib) { crm_data_t *the_cib = get_cib_copy(cib); crm_data_t *generation = create_xml_node( NULL, XML_CIB_TAG_GENERATION_TUPPLE); if(the_cib != NULL) { copy_in_properties(generation, the_cib); free_xml(the_cib); } return generation; } gboolean apply_cib_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new) { gboolean result = TRUE; const char *value = NULL; int this_updates = 0; int this_epoche = 0; int this_admin_epoche = 0; int diff_add_updates = 0; int diff_add_epoche = 0; int diff_add_admin_epoche = 0; int diff_del_updates = 0; int diff_del_epoche = 0; int diff_del_admin_epoche = 0; CRM_DEV_ASSERT(diff != NULL); CRM_DEV_ASSERT(old != NULL); value = crm_element_value(old, XML_ATTR_GENERATION_ADMIN); this_admin_epoche = atoi(value?value:"0"); crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION_ADMIN, this_admin_epoche, value); value = crm_element_value(old, XML_ATTR_GENERATION); this_epoche = atoi(value?value:"0"); crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION, this_epoche, value); value = crm_element_value(old, XML_ATTR_NUMUPDATES); this_updates = atoi(value?value:"0"); crm_debug_3("%s=%d (%s)", XML_ATTR_NUMUPDATES, this_updates, value); cib_diff_version_details( diff, &diff_add_admin_epoche, &diff_add_epoche, &diff_add_updates, &diff_del_admin_epoche, &diff_del_epoche, &diff_del_updates); value = NULL; if(result && diff_del_admin_epoche != this_admin_epoche) { value = XML_ATTR_GENERATION_ADMIN; result = FALSE; crm_debug_3("%s=%d", value, diff_del_admin_epoche); } else if(result && diff_del_epoche != this_epoche) { value = XML_ATTR_GENERATION; result = FALSE; crm_debug_3("%s=%d", value, diff_del_epoche); } else if(result && diff_del_updates != this_updates) { value = XML_ATTR_NUMUPDATES; result = FALSE; crm_debug_3("%s=%d", value, diff_del_updates); } if(result) { int len = 0; crm_data_t *tmp = NULL; crm_data_t *diff_copy = copy_xml(diff); tmp = find_xml_node(diff_copy, "diff-removed", TRUE); if(tmp != NULL) { len = tmp->nfields; cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN); cl_msg_remove(tmp, XML_ATTR_GENERATION); cl_msg_remove(tmp, XML_ATTR_NUMUPDATES); CRM_DEV_ASSERT(tmp->nfields == len - 3); } tmp = find_xml_node(diff_copy, "diff-added", TRUE); if(tmp != NULL) { len = tmp->nfields; cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN); cl_msg_remove(tmp, XML_ATTR_GENERATION); cl_msg_remove(tmp, XML_ATTR_NUMUPDATES); CRM_DEV_ASSERT(tmp->nfields == len - 3); } result = apply_xml_diff(old, diff_copy, new); free_xml(diff_copy); } else { crm_err("target and diff %s values didnt match", value); } return result; } crm_data_t * diff_cib_object(crm_data_t *old_cib, crm_data_t *new_cib, gboolean suppress) { crm_data_t *diff = diff_xml_object(old_cib, new_cib, suppress); crm_data_t *dest = NULL; crm_data_t *src = NULL; const char *name = NULL; const char *value = NULL; /* add complete version information */ src = old_cib; dest = find_xml_node(diff, "diff-removed", FALSE); if(src != NULL && dest != NULL) { name = XML_ATTR_GENERATION_ADMIN; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } set_xml_property_copy(dest, name, value); name = XML_ATTR_GENERATION; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } set_xml_property_copy(dest, name, value); name = XML_ATTR_NUMUPDATES; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } set_xml_property_copy(dest, name, value); } src = new_cib; dest = find_xml_node(diff, "diff-added", FALSE); if(src != NULL && dest != NULL) { name = XML_ATTR_GENERATION_ADMIN; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } set_xml_property_copy(dest, name, value); name = XML_ATTR_GENERATION; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } set_xml_property_copy(dest, name, value); name = XML_ATTR_NUMUPDATES; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } set_xml_property_copy(dest, name, value); } return diff; } void log_cib_diff(int log_level, crm_data_t *diff, const char *function) { int add_updates = 0; int add_epoche = 0; int add_admin_epoche = 0; int del_updates = 0; int del_epoche = 0; int del_admin_epoche = 0; if(diff == NULL) { return; } cib_diff_version_details( diff, &add_admin_epoche, &add_epoche, &add_updates, &del_admin_epoche, &del_epoche, &del_updates); if(add_updates != del_updates) { do_crm_log(log_level, NULL, function, "Diff: --- %d.%d.%d", del_admin_epoche, del_epoche, del_updates); do_crm_log(log_level, NULL, function, "Diff: +++ %d.%d.%d", add_admin_epoche, add_epoche, add_updates); } else if(diff != NULL) { do_crm_log(log_level, NULL, function, "Local-only Change: %d.%d.%d", add_admin_epoche, add_epoche, add_updates); } log_xml_diff(log_level, diff, function); } gboolean cib_version_details( crm_data_t *cib, int *admin_epoche, int *epoche, int *updates) { const char *value = NULL; if(cib == NULL) { *admin_epoche = -1; *epoche = -1; *updates = -1; return FALSE; } else { value = crm_element_value(cib, XML_ATTR_GENERATION_ADMIN); *admin_epoche = atoi(value?value:"-1"); value = crm_element_value(cib, XML_ATTR_GENERATION); *epoche = atoi(value?value:"-1"); value = crm_element_value(cib, XML_ATTR_NUMUPDATES); *updates = atoi(value?value:"-1"); } return TRUE; } gboolean cib_diff_version_details( crm_data_t *diff, int *admin_epoche, int *epoche, int *updates, int *_admin_epoche, int *_epoche, int *_updates) { crm_data_t *tmp = NULL; tmp = find_xml_node(diff, "diff-added", FALSE); cib_version_details(tmp, admin_epoche, epoche, updates); tmp = find_xml_node(diff, "diff-removed", FALSE); cib_version_details(tmp, _admin_epoche, _epoche, _updates); return TRUE; } /* * The caller should never free the return value */ crm_data_t* get_object_root(const char *object_type, crm_data_t *the_root) { const char *node_stack[2]; crm_data_t *tmp_node = NULL; if(the_root == NULL) { crm_err("CIB root object was NULL"); return NULL; } node_stack[0] = XML_CIB_TAG_CONFIGURATION; node_stack[1] = object_type; if(object_type == NULL || strlen(object_type) == 0 || safe_str_eq("all", object_type) || safe_str_eq(XML_TAG_CIB, object_type)) { /* get the whole cib */ return the_root; } else if(strcmp(object_type, XML_CIB_TAG_STATUS) == 0) { /* these live in a different place */ - tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS, TRUE); + tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS, FALSE); node_stack[0] = XML_CIB_TAG_STATUS; node_stack[1] = NULL; } else { tmp_node = find_xml_node_nested(the_root, node_stack, 2); } if (tmp_node == NULL) { - crm_err("Section [%s [%s]] not present in %s", - node_stack[0], - node_stack[1]?node_stack[1]:"", - crm_element_name(the_root)); + crm_debug("Section [%s [%s]] not present in %s", + node_stack[0], + node_stack[1]?node_stack[1]:"", + crm_element_name(the_root)); } return tmp_node; } const char * get_crm_option(crm_data_t *cib, const char *name, gboolean do_warn) { const char * value = NULL; crm_data_t * a_default = NULL; crm_data_t * config = get_object_root(XML_CIB_TAG_CRMCONFIG, cib); if(config != NULL) { a_default = find_entity(config, XML_CIB_TAG_NVPAIR, name); } if(a_default == NULL) { if(do_warn) { crm_warn("Option %s not set", name); } return NULL; } value = crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE); if(safe_str_eq(value, "")) { value = NULL; } return value; } crm_data_t* create_cib_fragment_adv( crm_data_t *update, const char *section, const char *source) { crm_data_t *cib = NULL; gboolean whole_cib = FALSE; crm_data_t *fragment = create_xml_node(NULL, XML_TAG_FRAGMENT); crm_data_t *object_root = NULL; char *auto_section = NULL; const char *update_name = NULL; if(update != NULL) { update_name = crm_element_name(update); } auto_section = cib_pluralSection(update_name); if(update == NULL && section == NULL) { crm_debug_3("Creating a blank fragment"); update = createEmptyCib(); section = auto_section; } else if(update == NULL) { crm_err("No update to create a fragment for"); cib = createEmptyCib(); return NULL; } else if(section == NULL) { section = auto_section; } else if(strcmp(auto_section, section) != 0) { crm_err("Values for update (tag=%s) and section (%s)" " were not consistent", crm_element_name(update), section); crm_free(auto_section); return NULL; } if(safe_str_eq(section, "all") && safe_str_eq(crm_element_name(update), XML_TAG_CIB)) { whole_cib = TRUE; } set_xml_property_copy(fragment, XML_ATTR_SECTION, section); if(whole_cib == FALSE) { cib = createEmptyCib(); set_xml_property_copy(cib, "debug_source", source); object_root = get_object_root(section, cib); add_node_copy(object_root, update); add_node_copy(fragment, cib); free_xml(cib); cib = find_xml_node(fragment, XML_TAG_CIB, TRUE); } else { add_node_copy(fragment, update); cib = find_xml_node(fragment, XML_TAG_CIB, TRUE); set_xml_property_copy(cib, "debug_source", source); } crm_free(auto_section); crm_debug_3("Verifying created fragment"); if(verifyCibXml(cib) == FALSE) { crm_err("Fragment creation failed"); crm_log_xml_err(update, "[src]"); crm_log_xml_err(fragment, "[created]"); free_xml(fragment); fragment = NULL; } return fragment; } /* * It is the callers responsibility to free both the new CIB (output) * and the new CIB (input) */ crm_data_t* createEmptyCib(void) { crm_data_t *cib_root = NULL, *config = NULL, *status = NULL; cib_root = create_xml_node(NULL, XML_TAG_CIB); config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION); status = create_xml_node(cib_root, XML_CIB_TAG_STATUS); set_node_tstamp(cib_root); set_node_tstamp(config); set_node_tstamp(status); /* set_xml_property_copy(cib_root, "version", "1"); */ set_xml_property_copy(cib_root, "generated", XML_BOOLEAN_TRUE); set_xml_property_copy( cib_root, XML_ATTR_CIB_REVISION, cib_feature_revision_s); create_xml_node(config, XML_CIB_TAG_CRMCONFIG); 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; } free_xml(cib_root); crm_crit("The generated CIB did not pass integrity testing!!" " All hope is lost."); return NULL; } gboolean verifyCibXml(crm_data_t *cib) { gboolean is_valid = TRUE; crm_data_t *tmp_node = NULL; if (cib == NULL) { crm_warn("CIB 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; } gboolean verify_cib_cmds(cib_t *cib) { gboolean valid = TRUE; if(cib->cmds->variant_op == NULL) { crm_err("Operation variant_op not set"); valid = FALSE; } if(cib->cmds->signon == NULL) { crm_err("Operation signon not set"); valid = FALSE; } if(cib->cmds->signoff == NULL) { crm_err("Operation signoff not set"); valid = FALSE; } if(cib->cmds->free == NULL) { crm_err("Operation free not set"); valid = FALSE; } if(cib->cmds->set_op_callback == NULL) { crm_err("Operation set_op_callback not set"); valid = FALSE; } if(cib->cmds->add_notify_callback == NULL) { crm_err("Operation add_notify_callback not set"); valid = FALSE; } if(cib->cmds->del_notify_callback == NULL) { crm_err("Operation del_notify_callback not set"); valid = FALSE; } if(cib->cmds->set_connection_dnotify == NULL) { crm_err("Operation set_connection_dnotify not set"); valid = FALSE; } if(cib->cmds->channel == NULL) { crm_err("Operation channel not set"); valid = FALSE; } if(cib->cmds->inputfd == NULL) { crm_err("Operation inputfd not set"); valid = FALSE; } if(cib->cmds->noop == NULL) { crm_err("Operation noop not set"); valid = FALSE; } if(cib->cmds->ping == NULL) { crm_err("Operation ping not set"); valid = FALSE; } if(cib->cmds->query == NULL) { crm_err("Operation query not set"); valid = FALSE; } if(cib->cmds->query_from == NULL) { crm_err("Operation query_from not set"); valid = FALSE; } if(cib->cmds->is_master == NULL) { crm_err("Operation is_master not set"); valid = FALSE; } if(cib->cmds->set_master == NULL) { crm_err("Operation set_master not set"); valid = FALSE; } if(cib->cmds->set_slave == NULL) { crm_err("Operation set_slave not set"); valid = FALSE; } if(cib->cmds->set_slave_all == NULL) { crm_err("Operation set_slave_all not set"); valid = FALSE; } if(cib->cmds->sync == NULL) { crm_err("Operation sync not set"); valid = FALSE; } if(cib->cmds->sync_from == NULL) { crm_err("Operation sync_from not set"); valid = FALSE; } if(cib->cmds->bump_epoch == NULL) { crm_err("Operation bump_epoch not set"); valid = FALSE; } if(cib->cmds->create == NULL) { crm_err("Operation create not set"); valid = FALSE; } if(cib->cmds->modify == NULL) { crm_err("Operation modify not set"); valid = FALSE; } if(cib->cmds->replace == NULL) { crm_err("Operation replace not set"); valid = FALSE; } if(cib->cmds->delete == NULL) { crm_err("Operation delete not set"); valid = FALSE; } if(cib->cmds->erase == NULL) { crm_err("Operation erase not set"); valid = FALSE; } if(cib->cmds->quit == NULL) { crm_err("Operation quit not set"); valid = FALSE; } if(cib->cmds->msgready == NULL) { crm_err("Operation msgready not set"); valid = FALSE; } if(cib->cmds->rcvmsg == NULL) { crm_err("Operation rcvmsg not set"); valid = FALSE; } if(cib->cmds->dispatch == NULL) { crm_err("Operation dispatch not set"); valid = FALSE; } return valid; } diff --git a/lib/crm/common/ipc.c b/lib/crm/common/ipc.c index 5c648956df..4e015f79f4 100644 --- a/lib/crm/common/ipc.c +++ b/lib/crm/common/ipc.c @@ -1,397 +1,398 @@ -/* $Id: ipc.c,v 1.9 2005/06/13 15:57:58 davidlee Exp $ */ +/* $Id: ipc.c,v 1.10 2005/06/15 10:12:25 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 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"); + crm_warn("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 */ + crm_debug("Channel is disconnected"); 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; } gboolean is_ipc_empty(IPC_Channel *ch) { if(ch == NULL) { return TRUE; } else if(ch->send_queue->current_qlen == 0 && ch->recv_queue->current_qlen == 0) { return TRUE; } return FALSE; } diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c index 0d08022607..df62b6f05e 100644 --- a/lib/crm/common/xml.c +++ b/lib/crm/common/xml.c @@ -1,1815 +1,1815 @@ -/* $Id: xml.c,v 1.14 2005/06/14 08:35:14 andrew Exp $ */ +/* $Id: xml.c,v 1.15 2005/06/15 10:12:25 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 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, const char *prefix, int log_level, int depth, const crm_data_t *data, gboolean formatted); int dump_data_element( int depth, char **buffer, const crm_data_t *data, gboolean formatted); 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); gboolean can_prune_leaf(crm_data_t *xml_node); void diff_filter_context(int context, int upper_bound, int lower_bound, crm_data_t *xml_node, crm_data_t *parent); int in_upper_context(int depth, int context, crm_data_t *xml_node); 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, + dump_array(LOG_DEBUG_2, "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)); + crm_debug_2("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) { 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_4("returning node (%s).", xmlGetNodePath(a_child)); return a_child; } ); crm_debug_3("node <%s id=%s> not found in %s.", node_name, id, xmlGetNodePath(parent)); return NULL; } void copy_in_properties(crm_data_t* target, const 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, const 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) { 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)); crm_validate_data(node_copy); crm_update_parents(new_parent); crm_validate_data(new_parent); } 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 { crm_validate_data(node); ha_msg_mod(node, name, value); return crm_element_value(node, name); } 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 { 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); } } 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); cl_msg_remove_value(parent, a_node); crm_validate_data(parent); } void free_xml_fn(crm_data_t *a_node) { if(a_node == NULL) { ; /* nothing to do */ } 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); } } return; } void set_node_tstamp(crm_data_t *a_node) { #if 0 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); 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(const crm_data_t *src_node) { crm_data_t *new_xml = NULL; 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); return new_xml; } crm_data_t* string2xml(const char *input) { crm_data_t *output = parse_xml(input, NULL); if(output != NULL) { crm_update_parents(output); crm_validate_data(output); } return output; } crm_data_t * stdin2xml(void) { 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; } crm_data_t* file2xml(FILE *input) { 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; } 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 = NULL; 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); now_str = ctime(&now); now_str[24] = EOS; /* replace the newline */ set_xml_property_copy(xml_node, "last_written", now_str); crm_validate_data(xml_node); { 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); } crm_debug_3("Saved %d bytes to the Cib as XML", res); return res; } void print_xml_formatted(int log_level, const char *function, const crm_data_t *msg, const char *text) { if(msg == NULL) { do_crm_log(log_level,NULL,function, "%s: NULL", crm_str(text)); return; } crm_validate_data(msg); do_crm_log(log_level, NULL, function, "%s:", crm_str(text)); log_data_element(function, NULL, 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; 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(tmp_node); } return xml_node; } gboolean add_message_xml(HA_Message *msg, const char *field, const crm_data_t *xml) { crm_validate_data(xml); crm_validate_data(msg); ha_msg_addstruct(msg, field, xml); crm_update_parents(msg); return TRUE; } char * dump_xml_formatted(const 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(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(const 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(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, const char *prefix, int log_level, int depth, const 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, prefix, 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%s", prefix?prefix:"", print_buffer); buffer = print_buffer; if(has_children == 0) { return 0; } xml_child_iter( data, a_child, NULL, child_result = log_data_element( function, prefix, 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%s", prefix?prefix:"", print_buffer, name); crm_debug_5("Dumped %s...", name); return has_children; } int dump_data_element( int depth, char **buffer, const 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); xml_child_iter( xml_root, a_child, NULL, return TRUE; ); return FALSE; } void crm_validate_data(const crm_data_t *xml_root) { #ifndef XML_PARANOIA_CHECKS CRM_DEV_ASSERT(xml_root != NULL); #else int lpc = 0; CRM_ASSERT(xml_root != NULL); 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(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(crm_is_allocated(child) == 1); /* } else { */ /* CRM_DEV_ASSERT(FALSE); */ } } #endif } void crm_set_element_parent(crm_data_t *data, crm_data_t *parent) { 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); } } const char * crm_element_value(const crm_data_t *data, const char *name) { const char *value = NULL; crm_validate_data(data); value = cl_get_string(data, name); if(value != NULL) { CRM_DEV_ASSERT(crm_is_allocated(value) == 1); } return value; } char * crm_element_value_copy(const crm_data_t *data, const char *name) { const char *value = NULL; char *value_copy = NULL; crm_validate_data(data); value = cl_get_string(data, name); if(value != NULL) { CRM_DEV_ASSERT(crm_is_allocated(value) == 1); } CRM_DEV_ASSERT(value != NULL); if(value != NULL) { value_copy = crm_strdup(value); } return value_copy; } const char * crm_element_name(const crm_data_t *data) { crm_validate_data(data); return cl_get_string(data, F_XML_TAGNAME); } void xml_remove_prop(crm_data_t *obj, const char *name) { if(crm_element_value(obj, name) != NULL) { cl_msg_remove(obj, name); } } void crm_update_parents(crm_data_t *xml_root) { 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); ); } 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 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 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(input == NULL) { return 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_warn("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_4("Processing tag %s", tag_name); new_obj = ha_msg_new(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_4("Start parsing child..."); child = parse_xml(our_input, &lpc); if(child == NULL) { error = "error parsing child"; } else { CRM_DEV_ASSERT(crm_is_allocated(child) == 1); ha_msg_addstruct( new_obj, crm_element_name(child), child); crm_debug_4("Finished parsing child: %s", crm_element_name(child)); ha_msg_del(child); /* lpc++; /\* > *\/ */ } } else { lpc += 2; /* *\/ */ if(our_input[lpc] != '>') { error = "clase tag cannot contain attrs"; } crm_debug_4("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_4("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_4("Finished processing %s tag", tag_name); crm_free(tag_name); if(offset != NULL) { (*offset) += lpc; } CRM_DEV_ASSERT(crm_is_allocated(new_obj) == 1); return new_obj; } void log_xml_diff(int log_level, crm_data_t *diff, const char *function) { crm_data_t *added = find_xml_node(diff, "diff-added", FALSE); crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE); gboolean is_first = TRUE; xml_child_iter( removed, child, NULL, log_data_element(function, "-", log_level, 0, child, TRUE); if(is_first) { is_first = FALSE; } else { crm_log_maybe(log_level, " --- "); } ); /* crm_log_maybe(log_level, " === "); */ is_first = TRUE; xml_child_iter( added, child, NULL, log_data_element(function, "+", log_level, 0, child, TRUE); if(is_first) { is_first = FALSE; } else { crm_log_maybe(log_level, " --- "); } ); } gboolean apply_xml_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new) { gboolean result = TRUE; crm_data_t *added = find_xml_node(diff, "diff-added", FALSE); crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE); crm_data_t *intermediate = NULL; crm_data_t *diff_of_diff = NULL; int root_nodes_seen = 0; CRM_DEV_ASSERT(new != NULL); if(crm_assert_failed) { return FALSE; } crm_debug_2("Substraction Phase"); xml_child_iter(removed, child_diff, NULL, CRM_DEV_ASSERT(root_nodes_seen == 0); if(root_nodes_seen == 0) { *new = subtract_xml_object(old, child_diff, FALSE); } root_nodes_seen++; ); if(root_nodes_seen == 0) { *new = copy_xml(old); } else if(root_nodes_seen > 1) { crm_err("(-) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen); result = FALSE; } root_nodes_seen = 0; crm_debug_2("Addition Phase"); if(result) { xml_child_iter(added, child_diff, NULL, CRM_DEV_ASSERT(root_nodes_seen == 0); if(root_nodes_seen == 0) { add_xml_object(NULL, *new, child_diff); } root_nodes_seen++; ); } if(root_nodes_seen > 1) { crm_err("(+) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen); result = FALSE; #if CRM_DEV_BUILD } else if(result) { crm_debug_2("Verification Phase"); intermediate = diff_xml_object(old, *new, FALSE); diff_of_diff = diff_xml_object(intermediate, diff, TRUE); if(diff_of_diff != NULL) { - crm_err("Diff application failed!"); + crm_warn("Diff application failed!"); /* log_xml_diff(LOG_DEBUG, diff_of_diff, "diff:diff_of_diff"); */ log_xml_diff(LOG_DEBUG, intermediate, "diff:actual_diff"); result = FALSE; } crm_free(diff_of_diff); crm_free(intermediate); #endif diff_of_diff = NULL; intermediate = NULL; } if(result == FALSE) { log_xml_diff(LOG_DEBUG, diff, "diff:input_diff"); - log_data_element("diff:input", NULL, LOG_DEBUG, 0, old, TRUE); + log_data_element("diff:input", NULL, LOG_DEBUG_2, 0, old, TRUE); /* CRM_DEV_ASSERT(diff_of_diff != NULL); */ result = FALSE; } return result; } crm_data_t * diff_xml_object(crm_data_t *old, crm_data_t *new, gboolean suppress) { crm_data_t *diff = NULL; crm_data_t *tmp1 = NULL; crm_data_t *added = NULL; crm_data_t *removed = NULL; tmp1 = subtract_xml_object(old, new, suppress); if(tmp1 != NULL) { diff = create_xml_node(NULL, "diff"); if(can_prune_leaf(tmp1)) { ha_msg_del(tmp1); tmp1 = NULL; } else { removed = create_xml_node(diff, "diff-removed"); added = create_xml_node(diff, "diff-added"); add_node_copy(removed, tmp1); } free_xml(tmp1); } tmp1 = subtract_xml_object(new, old, suppress); if(tmp1 != NULL) { if(diff == NULL) { diff = create_xml_node(NULL, "diff"); } if(can_prune_leaf(tmp1)) { ha_msg_del(tmp1); tmp1 = NULL; } else { if(removed == NULL) { removed = create_xml_node(diff, "diff-removed"); } if(added == NULL) { added = create_xml_node(diff, "diff-added"); } add_node_copy(added, tmp1); } free_xml(tmp1); } return diff; } gboolean can_prune_leaf(crm_data_t *xml_node) { gboolean can_prune = TRUE; /* return FALSE; */ xml_prop_iter(xml_node, prop_name, prop_value, if(safe_str_eq(prop_name, XML_ATTR_ID)) { continue; } else if(safe_str_eq(prop_name, XML_ATTR_TSTAMP)) { continue; } can_prune = FALSE; ); xml_child_iter(xml_node, child, NULL, if(can_prune_leaf(child)) { cl_msg_remove_value(xml_node, child); __counter--; } else { can_prune = FALSE; } ); return can_prune; } void diff_filter_context(int context, int upper_bound, int lower_bound, crm_data_t *xml_node, crm_data_t *parent) { crm_data_t *us = NULL; crm_data_t *new_parent = parent; const char *name = crm_element_name(xml_node); CRM_DEV_ASSERT(xml_node != NULL && name != NULL); if(crm_assert_failed) { return; } us = create_xml_node(parent, name); xml_prop_iter(xml_node, prop_name, prop_value, lower_bound = context; set_xml_property_copy(us, prop_name, prop_value); ); if(lower_bound >= 0 || upper_bound >= 0) { set_xml_property_copy(us, XML_ATTR_ID, ID(xml_node)); new_parent = us; } else { upper_bound = in_upper_context(0, context, xml_node); if(upper_bound >= 0) { set_xml_property_copy(us, XML_ATTR_ID, ID(xml_node)); new_parent = us; } else { free_xml(us); us = NULL; } } xml_child_iter(us, child, NULL, diff_filter_context( context, upper_bound-1, lower_bound-1, child, new_parent); ); } int in_upper_context(int depth, int context, crm_data_t *xml_node) { gboolean has_attributes = FALSE; if(context == 0) { return 0; } xml_prop_iter(xml_node, prop_name, prop_value, has_attributes = TRUE; break; ); if(has_attributes) { return depth; } else if(depth < context) { xml_child_iter(xml_node, child, NULL, if(in_upper_context(depth+1, context, child)) { return depth; } ); } return 0; } crm_data_t * subtract_xml_object(crm_data_t *left, crm_data_t *right, gboolean suppress) { gboolean skip = FALSE; gboolean differences = FALSE; crm_data_t *diff = NULL; crm_data_t *child_diff = NULL; crm_data_t *right_child = NULL; const char *right_val = NULL; const char *name = NULL; int lpc = 0; const char *filter[] = { XML_ATTR_TSTAMP, "last_written", "debug_source", "origin" }; if(left == NULL) { return NULL; } else if(right == NULL) { crm_debug_2("Processing <%s id=%s> (complete copy)", crm_element_name(left), ID(left)); return copy_xml(left); } name = crm_element_name(left); /* sanity check */ CRM_DEV_ASSERT(name != NULL); if(crm_assert_failed) { return NULL; } CRM_DEV_ASSERT(safe_str_eq(crm_element_name(left), crm_element_name(right))); if(crm_assert_failed) { return NULL; } CRM_DEV_ASSERT(safe_str_eq(ID(left), ID(right))); if(crm_assert_failed) { return NULL; } diff = create_xml_node(NULL, name); /* changes to name/value pairs */ crm_debug_2("Processing <%s id=%s>", crm_str(name), ID(left)); xml_prop_iter(left, prop_name, left_value, skip = FALSE; if(safe_str_eq(prop_name, XML_ATTR_ID)) { skip = TRUE; } for(lpc = 0; skip == FALSE && suppress && lpc < DIMOF(filter); lpc++) { if(safe_str_eq(prop_name, filter[lpc])) { skip = TRUE; } } if(skip) { continue; } right_val = crm_element_value(right, prop_name); if(right_val == NULL) { differences = TRUE; set_xml_property_copy( diff, prop_name, left_value); crm_debug_3("\t%s: %s", crm_str(prop_name), crm_str(left_value)); } else if(safe_str_eq(left_value, right_val)) { crm_debug_2("\t%s: %s (removed)", crm_str(prop_name), crm_str(left_value)); } else { differences = TRUE; set_xml_property_copy( diff, prop_name, left_value); crm_debug_2("\t%s: %s->%s", crm_str(prop_name), crm_str(left_value), right_val); } ); /* changes to child objects */ xml_child_iter( left, left_child, NULL, right_child = find_entity( right, crm_element_name(left_child), ID(left_child)); child_diff = subtract_xml_object( left_child, right_child, suppress); if(child_diff != NULL) { differences = TRUE; add_node_copy(diff, child_diff); free_xml(child_diff); } ); if(differences == FALSE) { free_xml(diff); crm_debug_2("\tNo changes"); return NULL; } set_xml_property_copy(diff, XML_ATTR_ID, ID(left)); return diff; } int add_xml_object(crm_data_t *parent, crm_data_t *target, const crm_data_t *update) { const char *object_id = NULL; const char *object_name = NULL; const char *right_val = NULL; int result = 0; CRM_DEV_ASSERT(update != NULL); if(crm_assert_failed) { return 0; } object_name = crm_element_name(update); object_id = ID(update); CRM_DEV_ASSERT(object_name != NULL); if(crm_assert_failed) { return 0; } if(target == NULL && object_id == NULL) { /* placeholder object */ target = find_xml_node(parent, object_name, FALSE); } else if(target == NULL) { target = find_entity(parent, object_name, object_id); } if(target == NULL) { target = add_node_copy(parent, update); crm_debug_2("Added <%s id=%s>", crm_str(object_name), crm_str(object_id)); CRM_DEV_ASSERT(target != NULL); return 0; } crm_debug_2("Found node <%s id=%s> to update", crm_str(object_name), crm_str(object_id)); xml_prop_iter(update, prop_name, left_value, right_val = crm_element_value(target, prop_name); if(right_val == NULL) { set_xml_property_copy( target, prop_name, left_value); crm_debug_2("\t%s: %s (added)", crm_str(prop_name), crm_str(left_value)); } else if(safe_str_neq(left_value, right_val)) { set_xml_property_copy( target, prop_name, left_value); crm_debug_2("\t%s: %s->%s", crm_str(prop_name), crm_str(left_value), right_val); } ); CRM_DEV_ASSERT(cl_is_allocated(object_name)); if(object_id != NULL) { CRM_DEV_ASSERT(cl_is_allocated(object_id)); } crm_debug_3("Processing children of <%s id=%s>", crm_str(object_name), crm_str(object_id)); xml_child_iter( update, a_child, NULL, int tmp_result = 0; crm_debug_3("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child)); tmp_result = add_xml_object(target, NULL, a_child); if(tmp_result < 0) { crm_err("Error updating child <%s id=%s>", crm_element_name(a_child), ID(a_child)); /* only the first error is likely to be interesting */ if(result >= 0) { result = tmp_result; } } ); crm_debug_3("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id)); return result; }