diff --git a/crm/pengine/unpack.c b/crm/pengine/unpack.c
index b9d9d1a4d6..fb3a709cfe 100644
--- a/crm/pengine/unpack.c
+++ b/crm/pengine/unpack.c
@@ -1,2073 +1,2075 @@
-/* $Id: unpack.c,v 1.189 2006/04/22 18:14:10 andrew Exp $ */
+/* $Id: unpack.c,v 1.190 2006/04/24 14:29:20 lars Exp $ */
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * 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 <portability.h>
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/msg.h>
 #include <clplumbing/cl_misc.h>
 
 #include <lrm/lrm_api.h>
 
 #include <glib.h>
 
 #include <heartbeat.h> /* for ONLINESTATUS */
 
 #include <pengine.h>
 #include <pe_utils.h>
 #include <pe_rules.h>
 
 gint sort_op_by_callid(gconstpointer a, gconstpointer b);
 
 gboolean unpack_rsc_to_attr(crm_data_t *xml_obj, pe_working_set_t *data_set);
 
 gboolean unpack_rsc_to_node(crm_data_t *xml_obj, pe_working_set_t *data_set);
 
 gboolean unpack_rsc_order(crm_data_t *xml_obj, pe_working_set_t *data_set);
 
 gboolean unpack_rsc_colocation(crm_data_t *xml_obj, pe_working_set_t *data_set);
 
 gboolean unpack_rsc_location(crm_data_t *xml_obj, pe_working_set_t *data_set);
 
 gboolean unpack_lrm_resources(
 	node_t *node, crm_data_t * lrm_state, pe_working_set_t *data_set);
 
 gboolean add_node_attrs(
 	crm_data_t * attrs, node_t *node, pe_working_set_t *data_set);
 
 gboolean unpack_rsc_op(
 	resource_t *rsc, node_t *node, crm_data_t *xml_op,
 	int *max_call_id, enum action_fail_response *failed, pe_working_set_t *data_set);
 
 gboolean determine_online_status(
 	crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set);
 
 gboolean rsc_colocation_new(
 	const char *id, enum con_strength strength,
 	resource_t *rsc_lh, resource_t *rsc_rh,
 	const char *state_lh, const char *state_rh);
 
 gboolean create_ordering(
 	const char *id, enum con_strength strength,
 	resource_t *rsc_lh, resource_t *rsc_rh, pe_working_set_t *data_set);
 
 const char *param_value(
 	GHashTable *hash, crm_data_t * parent, const char *name);
 
 rsc_to_node_t *generate_location_rule(
 	resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set);
 
 #define get_cluster_pref(pref) value = g_hash_table_lookup(config_hash, pref); \
 	if(value == NULL) {						\
 		pe_config_warn("No value specified for cluster preference: %s", pref); \
 	}
 
 gboolean
 unpack_config(crm_data_t * config, pe_working_set_t *data_set)
 {
 	const char *name = NULL;
 	const char *value = NULL;
 	GHashTable *config_hash = g_hash_table_new_full(
 		g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str);
 
 	data_set->config_hash = config_hash;	
 
 	unpack_instance_attributes(
 		config, XML_CIB_TAG_PROPSET, NULL, config_hash,
 		NULL, 0, data_set);
 
 #if CRM_DEPRECATED_SINCE_2_0_1
 	xml_child_iter_filter(
 		config, a_child, XML_CIB_TAG_NVPAIR,
 
 		name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME);
 
 		value = crm_element_value(a_child, XML_NVPAIR_ATTR_VALUE);
 		if(g_hash_table_lookup(config_hash, name) == NULL) {
 			g_hash_table_insert(
 				config_hash,crm_strdup(name),crm_strdup(value));
 		}
 		pe_config_err("Creating <nvpair id=%s name=%s/> directly"
 			      "beneath <crm_config> has been depreciated since"
 			      " 2.0.1", ID(a_child), name);
 		);
 #else
 	xml_child_iter_filter(
 		config, a_child, XML_CIB_TAG_NVPAIR,
 
 		name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME);
 		pe_config_err("Creating <nvpair id=%s name=%s/> directly"
 			      "beneath <crm_config> has been depreciated since"
 			      " 2.0.1 and is now disabled", ID(a_child), name);
 		);
 #endif
 	
 	get_cluster_pref("transition_idle_timeout");
 	if(value != NULL) {
 		long tmp = crm_get_msec(value);
 		if(tmp > 0) {
 			crm_free(data_set->transition_idle_timeout);
 			data_set->transition_idle_timeout = crm_strdup(value);
 		} else {
 			crm_err("Invalid value for transition_idle_timeout: %s",
 				value);
 		}
 	}
 	
 	crm_debug("%s set to: %s",
 		 "transition_idle_timeout", data_set->transition_idle_timeout);
 
 	get_cluster_pref("default_"XML_RSC_ATTR_STICKINESS);
 	data_set->default_resource_stickiness = char2score(value);
 	crm_info("Default stickiness: %d",
 		 data_set->default_resource_stickiness);
 
 	get_cluster_pref("default_"XML_RSC_ATTR_FAIL_STICKINESS);
 	data_set->default_resource_fail_stickiness = char2score(value);
 	crm_info("Default failure stickiness: %d",
 		 data_set->default_resource_fail_stickiness);
 	
 	get_cluster_pref("stonith_enabled");
 	if(value != NULL) {
 		cl_str_to_boolean(value, &data_set->stonith_enabled);
 	}
 	crm_info("STONITH of failed nodes is %s",
 		 data_set->stonith_enabled?"enabled":"disabled");	
 
 	get_cluster_pref("stonith_action");
 	if(value == NULL || safe_str_neq(value, "poweroff")) {
 		value = "reboot";
 	}
 	data_set->stonith_action = value;
 	crm_info("STONITH will %s nodes", data_set->stonith_action);	
 	
 	get_cluster_pref("symmetric_cluster");
 	if(value != NULL) {
 		cl_str_to_boolean(value, &data_set->symmetric_cluster);
 	}
 	if(data_set->symmetric_cluster) {
 		crm_info("Cluster is symmetric"
 			 " - resources can run anywhere by default");
 	}
 
 	get_cluster_pref("short_resource_names");
 	if(value != NULL) {
 		cl_str_to_boolean(value, &data_set->short_rsc_names);
 	}
 	crm_info("Using short resource names: %s",
 		 data_set->short_rsc_names?"true":"false");
 	
 	get_cluster_pref("no_quorum_policy");
 	if(safe_str_eq(value, "ignore")) {
 		data_set->no_quorum_policy = no_quorum_ignore;
 		
 	} else if(safe_str_eq(value, "freeze")) {
 		data_set->no_quorum_policy = no_quorum_freeze;
 
 	} else {
 		data_set->no_quorum_policy = no_quorum_stop;
 	}
 	
 	switch (data_set->no_quorum_policy) {
 		case no_quorum_freeze:
 			crm_info("On loss of CCM Quorum: Freeze resources");
 			break;
 		case no_quorum_stop:
 			crm_info("On loss of CCM Quorum: Stop ALL resources");
 			break;
 		case no_quorum_ignore:
 			crm_notice("On loss of CCM Quorum: Ignore");
 			break;
 	}
 
 	get_cluster_pref("stop_orphan_resources");
 	if(value != NULL) {
 		cl_str_to_boolean(value, &data_set->stop_rsc_orphans);
 	}
 	crm_info("Orphan resources are %s",
 		 data_set->stop_rsc_orphans?"stopped":"ignored");	
 	
 	get_cluster_pref("stop_orphan_actions");
 	if(value != NULL) {
 		cl_str_to_boolean(value, &data_set->stop_action_orphans);
 	}
 	crm_info("Orphan resource actions are %s",
 		 data_set->stop_action_orphans?"stopped":"ignored");	
 
 	get_cluster_pref("remove_after_stop");
 	if(value != NULL) {
 		cl_str_to_boolean(value, &data_set->remove_after_stop);
 	}
 	crm_info("Stopped resources are removed from the status section: %s",
 		 data_set->remove_after_stop?"true":"false");	
 	
 	get_cluster_pref("is_managed_default");
 	if(value != NULL) {
 		cl_str_to_boolean(value, &data_set->is_managed_default);
 	}
 	crm_info("By default resources are %smanaged",
 		 data_set->is_managed_default?"":"not ");
 
 	return TRUE;
 }
 
 gboolean
 unpack_nodes(crm_data_t * xml_nodes, pe_working_set_t *data_set)
 {
 	node_t *new_node   = NULL;
 	const char *id     = NULL;
 	const char *uname  = NULL;
 	const char *type   = NULL;
 
 	crm_debug_2("Begining unpack... %s",
 		    xml_nodes?crm_element_name(xml_nodes):"<none>");
 	xml_child_iter_filter(
 		xml_nodes, xml_obj, XML_CIB_TAG_NODE,
 
 		new_node = NULL;
 
 		id     = crm_element_value(xml_obj, XML_ATTR_ID);
 		uname  = crm_element_value(xml_obj, XML_ATTR_UNAME);
 		type   = crm_element_value(xml_obj, XML_ATTR_TYPE);
 		crm_debug_3("Processing node %s/%s", uname, id);
 
 		if(id == NULL) {
 			pe_config_err("Must specify id tag in <node>");
 			continue;
 		}
 		if(type == NULL) {
 			pe_config_err("Must specify type tag in <node>");
 			continue;
 		}
 		crm_malloc0(new_node, sizeof(node_t));
 		if(new_node == NULL) {
 			return FALSE;
 		}
 		
 		new_node->weight = 0;
 		new_node->fixed  = FALSE;
 		crm_malloc0(new_node->details,
 			   sizeof(struct node_shared_s));
 
 		if(new_node->details == NULL) {
 			crm_free(new_node);
 			return FALSE;
 		}
 
 		crm_debug_3("Creaing node for entry %s/%s", uname, id);
 		new_node->details->id		= id;
 		new_node->details->uname	= uname;
 		new_node->details->type		= node_ping;
 		new_node->details->online	= FALSE;
 		new_node->details->shutdown	= FALSE;
 		new_node->details->running_rsc	= NULL;
 		new_node->details->attrs        = g_hash_table_new_full(
 			g_str_hash, g_str_equal,
 			g_hash_destroy_str, g_hash_destroy_str);
 		
 /* 		if(data_set->have_quorum == FALSE */
 /* 		   && data_set->no_quorum_policy == no_quorum_stop) { */
 /* 			/\* start shutting resources down *\/ */
 /* 			new_node->weight = -INFINITY; */
 /* 		} */
 		
 		if(data_set->stonith_enabled) {
 			/* all nodes are unclean until we've seen their
 			 * status entry
 			 */
 			new_node->details->unclean = TRUE;
 		} else {
 			/* blind faith... */
 			new_node->details->unclean = FALSE; 
 		}
 		
 		
 		if(type == NULL
 		   || safe_str_eq(type, "member")
 		   || safe_str_eq(type, NORMALNODE)) {
 			new_node->details->type = node_member;
 		}
 
 		add_node_attrs(xml_obj, new_node, data_set);
 
 		if(crm_is_true(g_hash_table_lookup(
 				       new_node->details->attrs, "standby"))) {
 			crm_info("Node %s is in standby-mode",
 				 new_node->details->uname);
 			new_node->weight = -INFINITY;
 			new_node->details->standby = TRUE;
 		}
 		
 		data_set->nodes = g_list_append(data_set->nodes, new_node);    
 		crm_debug_3("Done with node %s",
 			    crm_element_value(xml_obj, XML_ATTR_UNAME));
 
 		crm_action_debug_3(print_node("Added", new_node, FALSE));
 		);
   
 /* 	data_set->nodes = g_list_sort(data_set->nodes, sort_node_weight); */
 
 	return TRUE;
 }
 
 gboolean 
 unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set)
 {
 	crm_debug_2("Begining unpack... %s",
 		    xml_resources?crm_element_name(xml_resources):"<none>");
 	xml_child_iter(
 		xml_resources, xml_obj, 
 
 		resource_t *new_rsc = NULL;
 		crm_debug_2("Begining unpack... %s",
 			    xml_obj?crm_element_name(xml_obj):"<none>");
 		if(common_unpack(xml_obj, &new_rsc, NULL, data_set)) {
 			data_set->resources = g_list_append(
 				data_set->resources, new_rsc);
 			
 			print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE);
 
 		} else {
 			pe_config_err("Failed unpacking %s %s",
 				      crm_element_name(xml_obj),
 				      crm_element_value(xml_obj, XML_ATTR_ID));
 		}
 		);
 	
 	data_set->resources = g_list_sort(
 		data_set->resources, sort_rsc_priority);
 
 	return TRUE;
 }
 
 gboolean 
 unpack_constraints(crm_data_t * xml_constraints, pe_working_set_t *data_set)
 {
 	crm_data_t *lifetime = NULL;
 	crm_debug_2("Begining unpack... %s",
 		    xml_constraints?crm_element_name(xml_constraints):"<none>");
 	xml_child_iter(
 		xml_constraints, xml_obj, 
 
 		const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
 		if(id == NULL) {
 			pe_config_err("Constraint <%s...> must have an id",
 				crm_element_name(xml_obj));
 			continue;
 		}
 
 		crm_debug_3("Processing constraint %s %s",
 			    crm_element_name(xml_obj),id);
 
 		lifetime = cl_get_struct(xml_obj, "lifetime");
 
 		if(test_ruleset(lifetime, NULL, data_set) == FALSE) {
 			crm_info("Constraint %s %s is not active",
 				 crm_element_name(xml_obj), id);
 
 		} else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER,
 				      crm_element_name(xml_obj))) {
 			unpack_rsc_order(xml_obj, data_set);
 
 		} else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND,
 				      crm_element_name(xml_obj))) {
 			unpack_rsc_colocation(xml_obj, data_set);
 
 		} else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION,
 				      crm_element_name(xml_obj))) {
 			unpack_rsc_location(xml_obj, data_set);
 
 		} else {
 			pe_err("Unsupported constraint type: %s",
 				crm_element_name(xml_obj));
 		}
 		);
 
 	return TRUE;
 }
 
 /* remove nodes that are down, stopping */
 /* create +ve rsc_to_node constraints between resources and the nodes they are running on */
 /* anything else? */
 gboolean
 unpack_status(crm_data_t * status, pe_working_set_t *data_set)
 {
 	const char *id    = NULL;
 	const char *uname = NULL;
 
 	crm_data_t * lrm_rsc    = NULL;
 	crm_data_t * attrs      = NULL;
 	node_t    *this_node  = NULL;
 	
 	crm_debug_3("Begining unpack");
 	xml_child_iter_filter(
 		status, node_state, XML_CIB_TAG_STATE,
 
 		id         = crm_element_value(node_state, XML_ATTR_ID);
 		uname = crm_element_value(node_state,    XML_ATTR_UNAME);
 		attrs = find_xml_node(
 			node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
 
 		lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
 		lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
 
 		crm_debug_3("Processing node %s", uname);
 		this_node = pe_find_node_id(data_set->nodes, id);
 
 		if(uname == NULL) {
 			/* error */
 			continue;
 
 		} else if(this_node == NULL) {
 			pe_config_warn("Node %s in status section no longer exists",
 				       uname);
 			continue;
 		}
 
 		/* Mark the node as provisionally clean
 		 * - at least we have seen it in the current cluster's lifetime
 		 */
 		this_node->details->unclean = FALSE;
 		
 		crm_debug_3("Adding runtime node attrs");
 		add_node_attrs(attrs, this_node, data_set);
 
 		crm_debug_3("determining node state");
 		determine_online_status(node_state, this_node, data_set);
 
 		if(this_node->details->online || data_set->stonith_enabled) {
 			/* offline nodes run no resources...
 			 * unless stonith is enabled in which case we need to
 			 *   make sure rsc start events happen after the stonith
 			 */
 			crm_debug_3("Processing lrm resource entries");
 			unpack_lrm_resources(this_node, lrm_rsc, data_set);
 		}
 		);
 
 	return TRUE;
 	
 }
 
 static gboolean
 determine_online_status_no_fencing(crm_data_t * node_state, node_t *this_node)
 {
 	gboolean online = FALSE;
 	const char *join_state = crm_element_value(node_state,
 						   XML_CIB_ATTR_JOINSTATE);
 	const char *crm_state  = crm_element_value(node_state,
 						   XML_CIB_ATTR_CRMDSTATE);
 	const char *ccm_state  = crm_element_value(node_state,
 						   XML_CIB_ATTR_INCCM);
 	const char *ha_state   = crm_element_value(node_state,
 						   XML_CIB_ATTR_HASTATE);
 	const char *exp_state  = crm_element_value(node_state,
 						   XML_CIB_ATTR_EXPSTATE);
 
 	if(!crm_is_true(ccm_state) || safe_str_eq(ha_state,DEADSTATUS)){
 		crm_debug_2("Node is down: ha_state=%s, ccm_state=%s",
 			    crm_str(ha_state), crm_str(ccm_state));
 		
 	} else if(!crm_is_true(ccm_state)
 		  || safe_str_eq(ha_state, DEADSTATUS)) {
 		
 	} else if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)
 		  && safe_str_eq(crm_state, ONLINESTATUS)) {
 		online = TRUE;
 		
 	} else if(this_node->details->expected_up == FALSE) {
 		crm_debug_2("CRMd is down: ha_state=%s, ccm_state=%s",
 			    crm_str(ha_state), crm_str(ccm_state));
 		crm_debug_2("\tcrm_state=%s, join_state=%s, expected=%s",
 			    crm_str(crm_state), crm_str(join_state),
 			    crm_str(exp_state));
 		
 	} else {
 		/* mark it unclean */
 		this_node->details->unclean = TRUE;
 		
 		crm_warn("Node %s is partially & un-expectedly down",
 			 this_node->details->uname);
 		crm_info("\tha_state=%s, ccm_state=%s,"
 			 " crm_state=%s, join_state=%s, expected=%s",
 			 crm_str(ha_state), crm_str(ccm_state),
 			 crm_str(crm_state), crm_str(join_state),
 			 crm_str(exp_state));
 	}
 	return online;
 }
 
 static gboolean
 determine_online_status_fencing(crm_data_t * node_state, node_t *this_node)
 {
 	gboolean online = FALSE;
 	const char *join_state = crm_element_value(node_state,
 						   XML_CIB_ATTR_JOINSTATE);
 	const char *crm_state  = crm_element_value(node_state,
 						   XML_CIB_ATTR_CRMDSTATE);
 	const char *ccm_state  = crm_element_value(node_state,
 						   XML_CIB_ATTR_INCCM);
 	const char *ha_state   = crm_element_value(node_state,
 						   XML_CIB_ATTR_HASTATE);
 	const char *exp_state  = crm_element_value(node_state,
 						   XML_CIB_ATTR_EXPSTATE);
 
 	if(crm_is_true(ccm_state)
 	   && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS))
 	   && safe_str_eq(crm_state, ONLINESTATUS)
 	   && safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
 		online = TRUE;
 		
 	} else if(crm_is_true(ccm_state) == FALSE
 /* 		  && safe_str_eq(ha_state, DEADSTATUS) */
 		  && safe_str_eq(crm_state, OFFLINESTATUS)
 		  && this_node->details->expected_up == FALSE) {
 		crm_debug("Node %s is down: join_state=%s, expected=%s",
 			  this_node->details->uname,
 			  crm_str(join_state), crm_str(exp_state));
 		
 	} else if(this_node->details->expected_up == FALSE) {
 		crm_info("Node %s is comming up", this_node->details->uname);
 		crm_debug("\tha_state=%s, ccm_state=%s,"
 			  " crm_state=%s, join_state=%s, expected=%s",
 			  crm_str(ha_state), crm_str(ccm_state),
 			  crm_str(crm_state), crm_str(join_state),
 			  crm_str(exp_state));
 
 	} else {
 		/* mark it unclean */
 		this_node->details->unclean = TRUE;
 		
 		crm_warn("Node %s (%s)is un-expectedly down",
 			 this_node->details->uname, this_node->details->id);
 		crm_info("\tha_state=%s, ccm_state=%s,"
 			 " crm_state=%s, join_state=%s, expected=%s",
 			 crm_str(ha_state), crm_str(ccm_state),
 			 crm_str(crm_state), crm_str(join_state),
 			 crm_str(exp_state));
 	}
 	return online;
 }
 
 gboolean
 determine_online_status(
 	crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set)
 {
 	int shutdown = 0;
 	gboolean online = FALSE;
 	const char *exp_state  =
 		crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE);
 	
 	if(this_node == NULL) {
 		pe_config_err("No node to check");
 		return online;
 	}
 
 	ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown);
 	
 	this_node->details->expected_up = FALSE;
 	if(safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) {
 		this_node->details->expected_up = TRUE;
 	}
 
 	this_node->details->shutdown = FALSE;
 	if(shutdown != 0) {
 		this_node->details->shutdown = TRUE;
 		this_node->details->expected_up = FALSE;
 	}
 
 	if(data_set->stonith_enabled == FALSE) {
 		online = determine_online_status_no_fencing(
 			node_state, this_node);
 		
 	} else {
 		online = determine_online_status_fencing(
 			node_state, this_node);
 	}
 	
 	if(online) {
 		crm_debug_2("Node %s is online", this_node->details->uname);
 		this_node->details->online = TRUE;
 
 	} else {
 		/* remove node from contention */
 		this_node->fixed = TRUE;
 		this_node->weight = -INFINITY;
 		crm_debug_2("Node %s is down", this_node->details->uname);
 	}
 
 	if(online && this_node->details->shutdown) {
 		/* dont run resources here */
 		this_node->fixed = TRUE;
 		this_node->weight = -INFINITY;
 		crm_debug_2("Node %s is due for shutdown",
 			    this_node->details->uname);
 	}	
 	
 	if(this_node->details->unclean) {
 		pe_proc_warn("Node %s is unclean", this_node->details->uname);
 	}
 
 	return online;
 }
 
 #define set_char(x) last_rsc_id[len] = x; complete = TRUE;
 
 static void
 increment_clone(char *last_rsc_id)
 {
 	gboolean complete = FALSE;
 	int len = 0;
 
 	CRM_CHECK(last_rsc_id != NULL, return);
 	if(last_rsc_id != NULL) {
 		len = strlen(last_rsc_id);
 	}
 	len--;
 	while(complete == FALSE && len > 0) {
 		switch (last_rsc_id[len]) {
 			case 0:
 				len--;
 				break;
 			case '0':
 				set_char('1');
 				break;
 			case '1':
 				set_char('2');
 				break;
 			case '2':
 				set_char('3');
 				break;
 			case '3':
 				set_char('4');
 				break;
 			case '4':
 				set_char('5');
 				break;
 			case '5':
 				set_char('6');
 				break;
 			case '6':
 				set_char('7');
 				break;
 			case '7':
 				set_char('8');
 				break;
 			case '8':
 				set_char('9');
 				break;
 			case '9':
 				last_rsc_id[len] = '0';
 				len--;
 				break;
 			default:
 				crm_err("Unexpected char: %c (%d)",
 					last_rsc_id[len], len);
 				break;
 		}
 	}
 }
 
 extern gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set);
 
 static resource_t *
 unpack_find_resource(
 	pe_working_set_t *data_set, node_t *node, const char *rsc_id)
 {
 	resource_t *rsc = NULL;
 	gboolean is_duped_clone = FALSE;
 	char *alt_rsc_id = crm_strdup(rsc_id);
 	
 	while(rsc == NULL) {
 		crm_debug_3("looking for: %s", alt_rsc_id);
 		rsc = pe_find_resource(data_set->resources, alt_rsc_id);
 		/* no match */
 		if(rsc == NULL) {
 			crm_debug_3("not found");
 			break;
 			
 			/* not running anywhere else */
 		} else if(rsc->running_on == NULL) {
 			crm_debug_3("not active yet");
 			break;
 			
 			/* always unique */
 		} else if(rsc->globally_unique) {
 			crm_debug_3("unique");
 			break;
 			
 			/* running somewhere already but we dont care
 			 *   find another clone instead
 			 */
 		} else {
 			crm_debug_2("find another one");
 			rsc = NULL;
 			is_duped_clone = TRUE;
 			increment_clone(alt_rsc_id);
 		}
 	}
 	crm_free(alt_rsc_id);
 	if(is_duped_clone && rsc != NULL) {
 		crm_info("Internally renamed %s on %s to %s",
 			 rsc_id, node->details->uname, rsc->id);
 /* 		rsc->name = rsc_id; */
 	}
 	return rsc;
 }
 
 static resource_t *
 process_orphan_resource(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set) 
 {
 	resource_t *rsc = NULL;
 	gboolean is_duped_clone = FALSE;
 	const char *rsc_id   = crm_element_value(rsc_entry, XML_ATTR_ID);
 	crm_data_t *xml_rsc  = create_xml_node(NULL, XML_CIB_TAG_RESOURCE);
 	
 	crm_log_xml_info(rsc_entry, "Orphan resource");
 	
 	pe_config_warn("Nothing known about resource %s running on %s",
 		       rsc_id, node->details->uname);
 
 	if(pe_find_resource(data_set->resources, rsc_id) != NULL) {
 		is_duped_clone = TRUE;
 	}
 	
 	copy_in_properties(xml_rsc, rsc_entry);
 	
 	common_unpack(xml_rsc, &rsc, NULL, data_set);
 	rsc->orphan = TRUE;
 	
 	data_set->resources = g_list_append(data_set->resources, rsc);
 	
 	if(data_set->stop_rsc_orphans == FALSE && is_duped_clone == FALSE) {
 		rsc->is_managed = FALSE;
 		
 	} else {
 		crm_info("Making sure orphan %s is stopped", rsc_id);
 		
 		print_resource(LOG_DEBUG_3, "Added orphan", rsc, FALSE);
 			
 		CRM_CHECK(rsc != NULL, return NULL);
 		slist_iter(
 			any_node, node_t, data_set->nodes, lpc,
 			rsc2node_new(
 				"__orphan_dont_run__", rsc,
 				-INFINITY, any_node, data_set);
 			);
 	}
 	return rsc;
 }
 
 static gboolean
 check_rsc_parameters(resource_t *rsc, node_t *node, crm_data_t *rsc_entry,
 		     pe_working_set_t *data_set) 
 {
 	int attr_lpc = 0;
 	gboolean force_restart = FALSE;
 	gboolean delete_resource = FALSE;
 	
 	const char *value = NULL;
 	const char *old_value = NULL;
 	const char *attr_list[] = {
 		XML_ATTR_TYPE, 
 		XML_AGENT_ATTR_CLASS,
  		XML_AGENT_ATTR_PROVIDER
 	};
 
 	for(; attr_lpc < DIMOF(attr_list); attr_lpc++) {
 		value = crm_element_value(rsc->xml, attr_list[attr_lpc]);
 		old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]);
 		if(safe_str_eq(value, old_value)) {
 			continue;
 		}
 		
 		force_restart = TRUE;
 		crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s",
 			   rsc->id, node->details->uname, attr_list[attr_lpc],
 			   crm_str(old_value), crm_str(value));
 	}
 	if(force_restart) {
 		/* make sure the restart happens */
 		stop_action(rsc, node, FALSE);
 		rsc->start_pending = TRUE;
 		delete_resource = TRUE;
 	}
 	return delete_resource;
 }
 
 static void
 process_rsc_state(resource_t *rsc, node_t *node,
 		  enum action_fail_response on_fail,
 		  pe_working_set_t *data_set) 
 {
 	crm_debug_2("Resource %s is %s on %s",
 		    rsc->id, role2text(rsc->role),
 		    node->details->uname);
 
 	rsc->known_on = g_list_append(rsc->known_on, node);
 
 	if(rsc->role != RSC_ROLE_STOPPED) { 
 		if(on_fail != action_fail_ignore) {
 			rsc->failed = TRUE;
 			crm_debug_2("Force stop");
 		}
 
 		crm_debug_2("Adding %s to %s",
 			    rsc->id, node->details->uname);
 		native_add_running(rsc, node, data_set);
 			
 		if(on_fail == action_fail_ignore) {
 			/* nothing to do */
 		} else if(node->details->unclean) {
 			stop_action(rsc, node, FALSE);
 
 		} else if(on_fail == action_fail_fence) {
 			/* treat it as if it is still running
 			 * but also mark the node as unclean
 			 */
 			node->details->unclean = TRUE;
 			stop_action(rsc, node, FALSE);
 				
 		} else if(on_fail == action_fail_block) {
 			/* is_managed == FALSE will prevent any
 			 * actions being sent for the resource
 			 */
 			rsc->is_managed = FALSE;
 				
 		} else if(on_fail == action_fail_migrate) {
 			stop_action(rsc, node, FALSE);
 
 			/* make sure it comes up somewhere else
 			 * or not at all
 			 */
 			rsc2node_new("__action_migration_auto__",
 				     rsc, -INFINITY, node, data_set);
 				
 		} else {
 			stop_action(rsc, node, FALSE);
 		}
 			
 	} else {
 		char *key = stop_key(rsc);
 		GListPtr possible_matches = find_actions(rsc->actions, key, node);
 		slist_iter(stop, action_t, possible_matches, lpc,
 			   stop->optional = TRUE;
 			);
 		crm_free(key);
 			
 /* 			if(rsc->failed == FALSE && node->details->online) { */
 /* 				delete_resource = TRUE; */
 /* 			}			 */
 	}
 }
 
 static const char *
 get_interval(crm_data_t *xml_op) 
 {
 	const char *interval_s = NULL;
         interval_s  = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
 #if CRM_DEPRECATED_SINCE_2_0_4
 	if(interval_s == NULL) {
 		crm_data_t *params = NULL;
 		params = find_xml_node(xml_op, XML_TAG_PARAMS, FALSE);
 		if(params != NULL) {
 			interval_s = crm_element_value(
 				params, XML_LRM_ATTR_INTERVAL);
 		}
 	}
 #endif
 	
 	CRM_CHECK(interval_s != NULL,
 		  crm_err("Invalid rsc op: %s", ID(xml_op)); return "0");
 	
 	return interval_s;
 }
 
 static void
 unpack_lrm_rsc_state(
 	node_t *node, crm_data_t * rsc_entry, pe_working_set_t *data_set)
 {
 	int fail_count = 0;
 	char *fail_attr = NULL;
 	const char *value = NULL;
 	const char *fail_val = NULL;
 	gboolean delete_resource = FALSE;
 
 	const char *rsc_id    = crm_element_value(rsc_entry, XML_ATTR_ID);
 
 	int max_call_id = -1;
 	GListPtr op_list = NULL;
 	GListPtr sorted_op_list = NULL;
 
 	enum action_fail_response on_fail = FALSE;
 	enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN;
 	
 	resource_t *rsc = unpack_find_resource(data_set, node, rsc_id);
 	
 	crm_debug_3("[%s] Processing %s on %s",
 		    crm_element_name(rsc_entry), rsc_id, node->details->uname);
 	
 	if(rsc == NULL) {
 		rsc = process_orphan_resource(rsc_entry, node, data_set);
 	} 
 	CRM_ASSERT(rsc != NULL);
 	
 	delete_resource = check_rsc_parameters(rsc, node, rsc_entry, data_set);
 
 	/* process failure stickiness */
 	fail_count = 0;
 	fail_attr = crm_concat("fail-count", rsc->id, '-');
 	fail_val = g_hash_table_lookup(node->details->attrs, fail_attr);
 	if(fail_val != NULL) {
 		crm_debug("%s: %s", fail_attr, fail_val);
 		fail_count = crm_parse_int(fail_val, "0");
 	}
 	crm_free(fail_attr);
 	if(fail_count > 0 && rsc->fail_stickiness != 0) {
 		rsc2node_new("fail_stickiness", rsc,
 			     fail_count * rsc->fail_stickiness,
 			     node, data_set);
 		crm_debug("Setting failure stickiness for %s on %s: %d",
 			  rsc->id, node->details->uname,
 			  fail_count * rsc->fail_stickiness);
 	}
 
 	/* process operations */
 	max_call_id = -1;
 
 	op_list = NULL;
 	sorted_op_list = NULL;
 		
 	xml_child_iter_filter(
 		rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP,
 		op_list = g_list_append(op_list, rsc_op);
 		);
 
 	if(op_list != NULL) {
 		int stop_index = -1;
 		int start_index = -1;
 		const char *task = NULL;
 		const char *status = NULL;
 		saved_role = rsc->role;
 		on_fail = action_fail_ignore;
 		rsc->role = RSC_ROLE_STOPPED;
 		sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
 
 		slist_iter(
 			rsc_op, crm_data_t, sorted_op_list, lpc,
 			task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
 			status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS);
 			if(safe_str_eq(task, CRMD_ACTION_STOP)
 			   && safe_str_eq(status, "0")) {
 				stop_index = lpc;
 
 			} else if(safe_str_eq(task, CRMD_ACTION_START)) {
 				start_index = lpc;
 
 			} else if(start_index <= stop_index
 				  && safe_str_eq(task, CRMD_ACTION_STATUS)) {
 				const char *rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC);
 				if(safe_str_eq(rc, "0")
 				   || safe_str_eq(rc, "8")) {
 					start_index = lpc;
 				}
 			}
 			
 			unpack_rsc_op(rsc, node, rsc_op,
 				      &max_call_id, &on_fail, data_set);
 			);
 
 		crm_debug_2("%s: Start index %d, stop index = %d",
 			    rsc->id, start_index, stop_index);
 		slist_iter(rsc_op, crm_data_t, sorted_op_list, lpc,
 			   const char *id = ID(rsc_op);
 			   const char *interval = NULL;
 			   if(start_index < stop_index) {
 				   crm_debug_2("Skipping %s/%s: not active",
 					       rsc->id, node->details->uname);
 				   break;
 				   
 			   } else if(lpc <= start_index) {
 				   crm_debug_3("Skipping %s/%s: old",
 					       id, node->details->uname);
 				   continue;
 			   }
 			   
 			   interval = get_interval(rsc_op);
 			   if(safe_str_eq(interval, "0")) {
 				   crm_debug_4("Skipping %s/%s: non-recurring",
 					       id, node->details->uname);
 				   continue;
 			   }
 
 			   status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS);
 			   if(safe_str_eq(status, "-1")) {
 				   crm_debug_3("Skipping %s/%s: status",
 					       id, node->details->uname);
 				   continue;
 			   }
 			   task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
 			   /* create the action */
 			   crm_debug_2("Creating %s/%s", id, node->details->uname);
 			   custom_action(rsc, crm_strdup(id), task, node,
 					 TRUE, TRUE, data_set);
 			);
 		
 		/* no need to free the contents */
 		g_list_free(sorted_op_list);
 		
 		process_rsc_state(rsc, node, on_fail, data_set);
 	}
 	
 	value = g_hash_table_lookup(rsc->parameters, XML_RSC_ATTR_TARGET_ROLE);
 	if(value != NULL) {
 		enum rsc_role_e req_role = text2role(value);
 		if(req_role != RSC_ROLE_UNKNOWN && req_role != rsc->next_role){
 			crm_debug("%s: Overwriting calculated next role %s"
 				  " with requested next role %s",
 				  rsc->id, role2text(rsc->next_role),
 				  role2text(req_role));
 			rsc->next_role = req_role;
 		}
 	}
 
 	if(delete_resource) {
 		DeleteRsc(rsc, node, data_set);
 	}
 		
 	if(saved_role > rsc->role) {
 		rsc->role = saved_role;
 	}
 }
 
 gboolean
 unpack_lrm_resources(node_t *node, crm_data_t * lrm_rsc_list, pe_working_set_t *data_set)
 {
 	CRM_CHECK(node != NULL, return FALSE);
 
 	crm_debug_3("Unpacking resources on %s", node->details->uname);
 	
 	xml_child_iter_filter(
 		lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE,
 		unpack_lrm_rsc_state(node, rsc_entry, data_set);
 		);
 	
 	return TRUE;
 }
 
 #define sort_return(an_int) crm_free(a_uuid); crm_free(b_uuid); return an_int
 
 gint
 sort_op_by_callid(gconstpointer a, gconstpointer b)
 {
 	char *a_uuid = NULL;
 	char *b_uuid = NULL;
  	const char *a_task_id = cl_get_string(a, XML_LRM_ATTR_CALLID);
  	const char *b_task_id = cl_get_string(b, XML_LRM_ATTR_CALLID);
 
 	const char *a_key = cl_get_string(a, XML_ATTR_TRANSITION_MAGIC);
  	const char *b_key = cl_get_string(b, XML_ATTR_TRANSITION_MAGIC);
 
 	const char *a_xml_id = ID(a);
 	const char *b_xml_id = ID(b);
 	
 	int a_id = -1;
 	int b_id = -1;
 
 	int a_rc = -1;
 	int b_rc = -1;
 
 	int a_status = -1;
 	int b_status = -1;
 	
 	int a_call_id = -1;
 	int b_call_id = -1;
 
 	if(safe_str_eq(a_xml_id, b_xml_id)) {
 		/* We have duplicate lrm_rsc_op entries in the status
 		 *    section which is unliklely to be a good thing
 		 *    - we can handle it easily enough, but we need to get
 		 *    to the bottom of why its happening.
 		 */
 		pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
 		sort_return(0);
 	}
 	
 	CRM_CHECK(a_task_id != NULL && b_task_id != NULL, sort_return(0));	
 	a_call_id = crm_parse_int(a_task_id, NULL);
 	b_call_id = crm_parse_int(b_task_id, NULL);
 	
 	if(a_call_id == -1 && b_call_id == -1) {
 		/* both are pending ops so it doesnt matter since
 		 *   stops are never pending
 		 */
 		sort_return(0);
 
 	} else if(a_call_id >= 0 && a_call_id < b_call_id) {
 		crm_debug_2("%s (%d) < %s (%d) : call id",
 			    ID(a), a_call_id, ID(b), b_call_id);
 		sort_return(-1);
 
 	} else if(b_call_id >= 0 && a_call_id > b_call_id) {
 		crm_debug_2("%s (%d) > %s (%d) : call id",
 			    ID(a), a_call_id, ID(b), b_call_id);
 		sort_return(1);
 	}
 
 	crm_debug_3("%s (%d) == %s (%d) : continuing",
 		    ID(a), a_call_id, ID(b), b_call_id);
 	
 	/* now process pending ops */
 	CRM_CHECK(a_key != NULL && b_key != NULL, sort_return(0));
 	CRM_CHECK(decode_transition_magic(
 			       a_key,&a_uuid,&a_id,&a_status, &a_rc), sort_return(0));
 	CRM_CHECK(decode_transition_magic(
 			       b_key,&b_uuid,&b_id,&b_status, &b_rc), sort_return(0));
 
 	/* try and determin the relative age of the operation...
 	 * some pending operations (ie. a start) may have been supuerceeded
 	 *   by a subsequent stop
 	 *
 	 * [a|b]_id == -1 means its a shutdown operation and _always_ comes last
 	 */
 	if(safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
 		/*
 		 * some of the logic in here may be redundant...
 		 *
 		 * if the UUID from the TE doesnt match then one better
 		 *   be a pending operation.
 		 * pending operations dont survive between elections and joins
 		 *   because we query the LRM directly
 		 */
 		
 		CRM_CHECK(a_call_id == -1 || b_call_id == -1, sort_return(0));
 		CRM_CHECK(a_call_id >= 0  || b_call_id >= 0, sort_return(0));
 
 		if(b_call_id == -1) {
 			crm_debug_2("%s (%d) < %s (%d) : transition + call id",
 				    ID(a), a_call_id, ID(b), b_call_id);
 			sort_return(-1);
 		}
 
 		if(a_call_id == -1) {
 			crm_debug_2("%s (%d) > %s (%d) : transition + call id",
 				    ID(a), a_call_id, ID(b), b_call_id);
 			sort_return(1);
 		}
 		
 	} else if((a_id >= 0 && a_id < b_id) || b_id == -1) {
 		crm_debug_2("%s (%d) < %s (%d) : transition",
 			    ID(a), a_id, ID(b), b_id);
 		sort_return(-1);
 
 	} else if((b_id >= 0 && a_id > b_id) || a_id == -1) {
 		crm_debug_2("%s (%d) > %s (%d) : transition",
 			    ID(a), a_id, ID(b), b_id);
 		sort_return(1);
 	}
 
 	/* we should never end up here */
 	crm_err("%s (%d:%d:%s) ?? %s (%d:%d:%s) : default",
 		ID(a), a_call_id, a_id, a_uuid, ID(b), b_call_id, b_id, b_uuid);
 	CRM_CHECK(FALSE, sort_return(0)); 
 }
 
 static gboolean
 check_action_definition(resource_t *rsc, node_t *active_node, crm_data_t *xml_op,
 			pe_working_set_t *data_set)
 {
 	gboolean did_change = FALSE;
 
 	crm_data_t *pnow = NULL;
 	GHashTable *local_rsc_params = NULL;
 	
 	char *pnow_digest = NULL;
 	const char *param_digest = NULL;
 	char *local_param_digest = NULL;
 
+#if CRM_DEPRECATED_SINCE_2_0_4
 	crm_data_t *params = NULL;
-	
+#endif
+
 	const char *id   = ID(xml_op);
 	const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
 	action_t *action = custom_action(rsc, crm_strdup(id), task, active_node,
 					 TRUE, FALSE, data_set);
 
 	CRM_CHECK(active_node != NULL, return FALSE);
 	
 	local_rsc_params = g_hash_table_new_full(
 		g_str_hash, g_str_equal,
 		g_hash_destroy_str, g_hash_destroy_str);
 	
 	unpack_instance_attributes(
 		rsc->xml, XML_TAG_ATTR_SETS, active_node, local_rsc_params,
 		NULL, 0, data_set);
 	
 	pnow = create_xml_node(NULL, XML_TAG_PARAMS);
 	g_hash_table_foreach(action->extra, hash2field, pnow);
 	g_hash_table_foreach(rsc->parameters, hash2field, pnow);
 	g_hash_table_foreach(local_rsc_params, hash2field, pnow);
 
 	filter_action_parameters(pnow);
 	pnow_digest = calculate_xml_digest(pnow, TRUE);
 	param_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
 
 #if CRM_DEPRECATED_SINCE_2_0_4
 	if(param_digest == NULL) {
 		params = find_xml_node(xml_op, XML_TAG_PARAMS, TRUE);
 	}
 	if(params != NULL) {
 		crm_data_t *local_params = copy_xml(params);
 
 		crm_info("Faking parameter digest creation for %s", ID(xml_op));
 
 		filter_action_parameters(local_params);
 		local_param_digest = calculate_xml_digest(local_params, TRUE);
 		param_digest = local_param_digest;
 		
 		free_xml(local_params);
 	}
 #endif
 
 	if(safe_str_neq(pnow_digest, param_digest)) {
 		crm_data_t *params = find_xml_node(xml_op,XML_TAG_PARAMS,FALSE);
 		if(params) {
 			crm_data_t *local_params = copy_xml(params);
 			filter_action_parameters(local_params);
 			
 			crm_log_xml_err(pnow, "params:calc");
 			crm_log_xml_err(local_params, "params:used");
 			free_xml(local_params);
 		}
 
 		did_change = TRUE;
 		crm_info("Parameters to %s on %s changed: %s vs. %s",
 			 ID(xml_op), active_node->details->uname,
 			 pnow_digest, crm_str(param_digest));
 		
 		
 		custom_action(rsc, crm_strdup(id), task, NULL,
 			      FALSE, TRUE, data_set);
 	}
 	
 	g_hash_table_destroy(action->extra);
 	crm_free(action->uuid);
 	crm_free(action);
 	free_xml(pnow);
 	crm_free(pnow_digest);
 	crm_free(local_param_digest);
 	
 	g_hash_table_destroy(local_rsc_params);
 
 	return did_change;
 }
 
 gboolean
 unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op,
 	      int *max_call_id, enum action_fail_response *on_fail,
 	      pe_working_set_t *data_set) 
 {
 	const char *id          = NULL;
 	const char *task        = NULL;
  	const char *task_id     = NULL;
  	const char *actual_rc   = NULL;
 /* 	const char *target_rc   = NULL;	 */
 	const char *task_status = NULL;
 	const char *interval_s  = NULL;
 	const char *op_digest   = NULL;
 
 	int interval = 0;
 	int task_id_i = -1;
 	int task_status_i = -2;
 	int actual_rc_i = 0;
 	
 	action_t *action = NULL;
 	gboolean is_probe = FALSE;
 	gboolean is_stop_action = FALSE;
 	
 	CRM_CHECK(rsc    != NULL, return FALSE);
 	CRM_CHECK(node   != NULL, return FALSE);
 	CRM_CHECK(xml_op != NULL, return FALSE);
 
 	id	    = ID(xml_op);
 	task        = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
  	task_id     = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
 	task_status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS);
 	op_digest   = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
 
 	CRM_CHECK(id != NULL, return FALSE);
 	CRM_CHECK(task != NULL, return FALSE);
 	CRM_CHECK(task_status != NULL, return FALSE);
 
 	task_status_i = crm_parse_int(task_status, NULL);
 
 	CRM_CHECK(task_status_i <= LRM_OP_ERROR, return FALSE);
 	CRM_CHECK(task_status_i >= LRM_OP_PENDING, return FALSE);
 
 	if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) {
 		/* safe to ignore these */
 		return TRUE;
 	}
 
 	crm_debug_2("Unpacking task %s/%s (call_id=%s, status=%s) on %s (role=%s)",
 		    id, task, task_id, task_status, node->details->uname,
 		    role2text(rsc->role));
 
 	interval_s = get_interval(xml_op);
 	interval = crm_parse_int(interval_s, "0");
 	
 	if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) {
 		is_probe = TRUE;
 
 	} else if(interval > 0 && rsc->role < RSC_ROLE_STARTED) {
 		crm_debug_2("Skipping recurring action %s for stopped resource", id);
 		return FALSE;
 	}
 	
 	if(rsc->orphan) {
 		crm_debug_2("Skipping param check for orphan: %s %s",
 			    rsc->id, task);
 
 	} else if(safe_str_eq(task, CRMD_ACTION_STOP)) {
 		crm_debug_2("Ignoring stop params: %s", id);
 
 	} else if(is_probe || safe_str_eq(task, CRMD_ACTION_START)) {
 		crm_debug_2("Checking resource definition: %s", rsc->id);
 		check_action_definition(rsc, node, xml_op, data_set);
 		
 	} else if(interval > 0) {
 		crm_data_t *op_match = NULL;
 		
 		crm_debug_2("Checking parameters for %s %s", id, task);
 		op_match = find_rsc_op_entry(rsc, id);
 
 		if(op_match == NULL && data_set->stop_action_orphans) {
 			/* create a cancel action */
 			action_t *cancel = NULL;
 			pe_config_warn("Orphan action will be stopped: %s", id);
 
 			cancel = custom_action(
 				rsc, crm_strdup(id), CRMD_ACTION_CANCEL, node,
 				FALSE, TRUE, data_set);
 
 			add_hash_param(cancel->extra, XML_LRM_ATTR_TASK, task);
 			add_hash_param(cancel->extra,
 				       XML_LRM_ATTR_INTERVAL, interval_s);
 			
 			custom_action_order(
 				rsc, NULL, cancel,
 				rsc, stop_key(rsc), NULL,
 				pe_ordering_optional, data_set);
 
 		} else if(op_match == NULL) {
 			pe_config_warn("Ignoring orphan action: %s", id);
 
 		} else {
 			check_action_definition(rsc, node, xml_op, data_set);
 		}		
 	}
 	
 	if(safe_str_eq(task, CRMD_ACTION_STOP)) {
 		is_stop_action = TRUE;
 	}
 	
 	if(task_status_i != LRM_OP_PENDING) {
 
 		task_id_i = crm_parse_int(task_id, "-1");
 
 		CRM_CHECK(task_id != NULL, return FALSE);
 		CRM_CHECK(task_id_i >= 0, return FALSE);
 
 		if(task_id_i == *max_call_id) {
 			crm_debug_2("Already processed this call");
 			return TRUE;
 		}
 
 		CRM_CHECK(task_id_i > *max_call_id, return FALSE);
 	}
 
 	if(*max_call_id < task_id_i) {
 		*max_call_id = task_id_i;
 	}
 	
 	if(node->details->unclean) {
 		crm_debug_2("Node %s (where %s is running) is unclean."
 			  " Further action depends on the value of %s",
 			  node->details->uname, rsc->id, XML_RSC_ATTR_STOPFAIL);
 	}
 
 	actual_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
 	CRM_CHECK(actual_rc != NULL, return FALSE);	
 	actual_rc_i = crm_parse_int(actual_rc, NULL);
 	
 	if(EXECRA_NOT_RUNNING == actual_rc_i) {
 		if(is_probe) {
 			/* treat these like stops */
 			is_stop_action = TRUE;
 		}
 		if(is_stop_action) {
 			task_status_i = LRM_OP_DONE;
  		} else {
 			CRM_CHECK(task_status_i == LRM_OP_ERROR,
 				task_status_i = LRM_OP_ERROR);
 		}
 		
 	} else if(EXECRA_RUNNING_MASTER == actual_rc_i) {
 		if(is_probe
 		   || (rsc->role == RSC_ROLE_MASTER
 		       && safe_str_eq(task, CRMD_ACTION_STATUS))) {
 			task_status_i = LRM_OP_DONE;
 		} else {
 			if(rsc->role != RSC_ROLE_MASTER) {
 				crm_err("%s reported %s in master mode on %s",
 					id, rsc->graph_name,
 					node->details->uname);
 			}
 			
 			CRM_CHECK(task_status_i == LRM_OP_ERROR,
 				task_status_i = LRM_OP_ERROR);
 		}
 		rsc->role = RSC_ROLE_MASTER;
 
 	} else if(EXECRA_FAILED_MASTER == actual_rc_i) {
 		rsc->role = RSC_ROLE_MASTER;
 		task_status_i = LRM_OP_ERROR;
 
 	} else if(EXECRA_OK == actual_rc_i
 		  && interval > 0
 		  && rsc->role == RSC_ROLE_MASTER) {
 		/* catch status ops that return 0 instead of 8 while they
 		 *   are supposed to be in master mode
 		 */
 		task_status_i = LRM_OP_ERROR;
 	}
 
 	if(task_status_i == LRM_OP_ERROR
 	   || task_status_i == LRM_OP_TIMEOUT
 	   || task_status_i == LRM_OP_NOTSUPPORTED) {
 		action = custom_action(rsc, crm_strdup(id), task, NULL,
 				       TRUE, FALSE, data_set);
 		if(action->on_fail == action_fail_ignore) {
 			task_status_i = LRM_OP_DONE;
 		}
 	}
 	
 	switch(task_status_i) {
 		case LRM_OP_PENDING:
 			/*
 			 * TODO: this may need some more thought
 			 * Some cases:
 			 * - PE reinvoked with pending action that will succeed
 			 * - PE reinvoked with pending action that will fail
 			 * - After DC election
 			 * - After startup
 			 *
 			 * pending start - required start
 			 * pending stop  - required stop
 			 * pending <any> on unavailable node - stonith
 			 *
 			 * For now this should do
 			 */
 
 			if(safe_str_eq(task, CRMD_ACTION_START)) {
 				rsc->start_pending = TRUE;
 				rsc->role = RSC_ROLE_STARTED;
 				
 			} else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
 				rsc->role = RSC_ROLE_MASTER;
 			}
 			break;
 		
 		case LRM_OP_DONE:
 			crm_debug_3("%s/%s completed on %s",
 				    rsc->id, task, node->details->uname);
 
 			if(is_stop_action) {
 				rsc->role = RSC_ROLE_STOPPED;
 
 				/* clear any previous failure actions */
 				*on_fail = action_fail_ignore;
 				rsc->next_role = RSC_ROLE_UNKNOWN;
 				
 			} else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
 				rsc->role = RSC_ROLE_MASTER;
 
 			} else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) {
 				rsc->role = RSC_ROLE_SLAVE;
 				
 			} else if(rsc->role < RSC_ROLE_STARTED) {
 				crm_debug_2("%s active on %s",
 					    rsc->id, node->details->uname);
 				rsc->role = RSC_ROLE_STARTED;
 			}
 			break;
 
 		case LRM_OP_ERROR:
 		case LRM_OP_TIMEOUT:
 		case LRM_OP_NOTSUPPORTED:
 			crm_warn("Processing failed op (%s) for %s on %s",
 				 id, rsc->id, node->details->uname);
 
 			if(*on_fail < action->on_fail) {
 				*on_fail = action->on_fail;
 			}
 			
 			if(task_status_i == LRM_OP_NOTSUPPORTED
 			   || is_stop_action
 			   || safe_str_eq(task, CRMD_ACTION_START) ) {
 				crm_warn("Handling failed %s for %s on %s",
 					 task, rsc->id, node->details->uname);
 				rsc2node_new("dont_run__failed_stopstart",
 					     rsc, -INFINITY, node, data_set);
 			}
 			
 			if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
 				rsc->role = RSC_ROLE_MASTER;
 
 			} else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) {
 				rsc->role = RSC_ROLE_MASTER;
 				
 			} else if(rsc->role < RSC_ROLE_STARTED) {
 				rsc->role = RSC_ROLE_STARTED;
 			}
 
 			crm_debug_2("Resource %s: role=%s, unclean=%s, on_fail=%s, fail_role=%s",
 				    rsc->id, role2text(rsc->role),
 				    node->details->unclean?"true":"false",
 				    fail2text(action->on_fail),
 				    role2text(action->fail_role));
 
 			if(action->fail_role != RSC_ROLE_STARTED
 			   && rsc->next_role < action->fail_role) {
 				rsc->next_role = action->fail_role;
 			}
 
 			if(action->fail_role == RSC_ROLE_STOPPED) {
 				/* make sure it doesnt come up again */
 				native_assign_color(rsc, data_set->no_color);
 			}
 			
 			pe_free_action(action);
 			action = NULL;
 			break;
 		case LRM_OP_CANCELLED:
 			/* do nothing?? */
 			pe_err("Dont know what to do for cancelled ops yet");
 			break;
 	}
 
 	crm_debug_2("Resource %s after %s: role=%s",
 		    rsc->id, task, role2text(rsc->role));
 
 	pe_free_action(action);
 	
 	return TRUE;
 }
 
 gboolean
 rsc_colocation_new(const char *id, enum con_strength strength,
 		   resource_t *rsc_lh, resource_t *rsc_rh,
 		   const char *state_lh, const char *state_rh)
 {
 	rsc_colocation_t *new_con      = NULL;
  	rsc_colocation_t *inverted_con = NULL; 
 
 	if(rsc_lh == NULL){
 		pe_config_err("No resource found for LHS %s", id);
 		return FALSE;
 
 	} else if(rsc_rh == NULL){
 		pe_config_err("No resource found for RHS of %s", id);
 		return FALSE;
 	}
 
 	crm_malloc0(new_con, sizeof(rsc_colocation_t));
 	if(new_con == NULL) {
 		return FALSE;
 	}
 	if(safe_str_eq(state_lh, CRMD_ACTION_STARTED)) {
 		state_lh = NULL;
 	}
 	if(safe_str_eq(state_rh, CRMD_ACTION_STARTED)) {
 		state_rh = NULL;
 	}
 
 	new_con->id       = id;
 	new_con->rsc_lh   = rsc_lh;
 	new_con->rsc_rh   = rsc_rh;
 	new_con->strength = strength;
 	new_con->state_lh = state_lh;
 	new_con->state_rh = state_rh;
 
 	inverted_con = invert_constraint(new_con);
 	
 	crm_debug_4("Adding constraint %s (%p) to %s",
 		  new_con->id, new_con, rsc_lh->id);
 	
 	rsc_lh->rsc_cons = g_list_insert_sorted(
 		rsc_lh->rsc_cons, new_con, sort_cons_strength);
 	
 	crm_debug_4("Adding constraint %s (%p) to %s",
 		  inverted_con->id, inverted_con, rsc_rh->id);
 	
 	rsc_rh->rsc_cons = g_list_insert_sorted(
 		rsc_rh->rsc_cons, inverted_con, sort_cons_strength);
 	
 	return TRUE;
 }
 
 /* LHS before RHS */
 gboolean
 custom_action_order(
 	resource_t *lh_rsc, char *lh_action_task, action_t *lh_action,
 	resource_t *rh_rsc, char *rh_action_task, action_t *rh_action,
 	enum pe_ordering type, pe_working_set_t *data_set)
 {
 	order_constraint_t *order = NULL;
 
 	if((lh_action == NULL && lh_rsc == NULL)
 	   || (rh_action == NULL && rh_rsc == NULL)){
 		pe_config_err("Invalid inputs lh_rsc=%p, lh_a=%p,"
 			      " rh_rsc=%p, rh_a=%p",
 			      lh_rsc, lh_action, rh_rsc, rh_action);
 		crm_free(lh_action_task);
 		crm_free(rh_action_task);
 		return FALSE;
 	}
 
 	crm_malloc0(order, sizeof(order_constraint_t));
 	if(order == NULL) { return FALSE; }
 	
 	order->id             = data_set->order_id++;
 	order->type           = type;
 	order->lh_rsc         = lh_rsc;
 	order->rh_rsc         = rh_rsc;
 	order->lh_action      = lh_action;
 	order->rh_action      = rh_action;
 	order->lh_action_task = lh_action_task;
 	order->rh_action_task = rh_action_task;
 	
 	data_set->ordering_constraints = g_list_append(
 		data_set->ordering_constraints, order);
 	
 	if(lh_rsc != NULL && rh_rsc != NULL) {
 		crm_debug_4("Created ordering constraint %d (%s):"
 			 " %s/%s before %s/%s",
 			 order->id, ordering_type2text(order->type),
 			 lh_rsc->id, lh_action_task,
 			 rh_rsc->id, rh_action_task);
 		
 	} else if(lh_rsc != NULL) {
 		crm_debug_4("Created ordering constraint %d (%s):"
 			 " %s/%s before action %d (%s)",
 			 order->id, ordering_type2text(order->type),
 			 lh_rsc->id, lh_action_task,
 			 rh_action->id, rh_action_task);
 		
 	} else if(rh_rsc != NULL) {
 		crm_debug_4("Created ordering constraint %d (%s):"
 			 " action %d (%s) before %s/%s",
 			 order->id, ordering_type2text(order->type),
 			 lh_action->id, lh_action_task,
 			 rh_rsc->id, rh_action_task);
 		
 	} else {
 		crm_debug_4("Created ordering constraint %d (%s):"
 			 " action %d (%s) before action %d (%s)",
 			 order->id, ordering_type2text(order->type),
 			 lh_action->id, lh_action_task,
 			 rh_action->id, rh_action_task);
 	}
 	
 	return TRUE;
 }
 
 gboolean
 unpack_rsc_colocation(crm_data_t * xml_obj, pe_working_set_t *data_set)
 {
 	enum con_strength strength_e = pecs_ignore;
 
 	const char *id    = crm_element_value(xml_obj, XML_ATTR_ID);
 	const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
 	const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
 	const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
 	const char *state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE);
 	const char *state_rh = crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE);
 
 	resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh);
 	resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh);
  
 	if(rsc_lh == NULL) {
 		pe_config_err("No resource (con=%s, rsc=%s)", id, id_lh);
 		return FALSE;
 		
 	} else if(rsc_rh == NULL) {
 		pe_config_err("No resource (con=%s, rsc=%s)", id, id_rh);
 		return FALSE;
 	}
 
 	/* the docs indicate that only +/- INFINITY are allowed,
 	 *   but no-one ever reads the docs so all positive values will
 	 *   count as "must" and negative values as "must not"
 	 */
 	if(score == NULL || score[0] != '-') {
 		strength_e = pecs_must;
 	} else {
 		strength_e = pecs_must_not;
 	}
 	return rsc_colocation_new(id, strength_e, rsc_lh, rsc_rh,
 				  state_lh, state_rh);
 }
 
 static const char *
 invert_action(const char *action) 
 {
 	if(safe_str_eq(action, CRMD_ACTION_START)) {
 		return CRMD_ACTION_STOP;
 
 	} else if(safe_str_eq(action, CRMD_ACTION_STOP)) {
 		return CRMD_ACTION_START;
 		
 	} else if(safe_str_eq(action, CRMD_ACTION_PROMOTE)) {
 		return CRMD_ACTION_DEMOTE;
 		
 	} else if(safe_str_eq(action, CRMD_ACTION_DEMOTE)) {
 		return CRMD_ACTION_PROMOTE;
 
 	} else if(safe_str_eq(action, CRMD_ACTION_STARTED)) {
 		return CRMD_ACTION_STOPPED;
 		
 	} else if(safe_str_eq(action, CRMD_ACTION_STOPPED)) {
 		return CRMD_ACTION_STARTED;
 		
 	}
 	pe_err("Unknown action: %s", action);
 	return NULL;
 }
 
 
 gboolean
 unpack_rsc_order(crm_data_t * xml_obj, pe_working_set_t *data_set)
 {
 	gboolean symmetrical_bool = TRUE;
 	
 	const char *id     = crm_element_value(xml_obj, XML_ATTR_ID);
 	const char *type   = crm_element_value(xml_obj, XML_ATTR_TYPE);
 	const char *id_rh  = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
 	const char *id_lh  = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
 	const char *action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION);
 	const char *action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION);
 
 	const char *symmetrical = crm_element_value(
 		xml_obj, XML_CONS_ATTR_SYMMETRICAL);
 
 	resource_t *rsc_lh   = NULL;
 	resource_t *rsc_rh   = NULL;
 
 	if(xml_obj == NULL) {
 		pe_config_err("No constraint object to process.");
 		return FALSE;
 
 	} else if(id == NULL) {
 		pe_config_err("%s constraint must have an id",
 			crm_element_name(xml_obj));
 		return FALSE;
 		
 	} else if(id_lh == NULL || id_rh == NULL) {
 		pe_config_err("Constraint %s needs two sides lh: %s rh: %s",
 			      id, crm_str(id_lh), crm_str(id_rh));
 		return FALSE;
 	}
 
 	if(action == NULL) {
 		action = CRMD_ACTION_START;
 	}
 	if(action_rh == NULL) {
 		action_rh = action;
 	}
 	CRM_CHECK(action != NULL, return FALSE);
 	CRM_CHECK(action_rh != NULL, return FALSE);
 	
 	if(safe_str_eq(type, "before")) {
 		id_lh  = crm_element_value(xml_obj, XML_CONS_ATTR_TO);
 		id_rh  = crm_element_value(xml_obj, XML_CONS_ATTR_FROM);
 		action = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION);
 		action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION);
 		if(action_rh == NULL) {
 			action_rh = CRMD_ACTION_START;
 		}
 		if(action == NULL) {
 			action = action_rh;
 		}
 	}
 
 	CRM_CHECK(action != NULL, return FALSE);
 	CRM_CHECK(action_rh != NULL, return FALSE);
 	
 	rsc_lh   = pe_find_resource(data_set->resources, id_rh);
 	rsc_rh   = pe_find_resource(data_set->resources, id_lh);
 
 	if(rsc_lh == NULL) {
 		pe_config_err("Constraint %s: no resource found for LHS of %s", id, id_lh);
 		return FALSE;
 	
 	} else if(rsc_rh == NULL) {
 		pe_config_err("Constraint %s: no resource found for RHS of %s", id, id_rh);
 		return FALSE;
 	}
 
 	custom_action_order(
 		rsc_lh, generate_op_key(rsc_lh->graph_name, action, 0), NULL,
 		rsc_rh, generate_op_key(rsc_rh->graph_name, action_rh, 0), NULL,
 		pe_ordering_optional, data_set);
 
 	if(rsc_rh->restart_type == pe_restart_restart
 	   && safe_str_eq(action, action_rh)) {
 		if(safe_str_eq(action, CRMD_ACTION_START)) {
 			crm_debug_2("Recover start-start: %s-%s",
 				rsc_lh->id, rsc_rh->id);
   			order_start_start(rsc_lh, rsc_rh, pe_ordering_recover);
  		} else if(safe_str_eq(action, CRMD_ACTION_STOP)) {
 			crm_debug_2("Recover stop-stop: %s-%s",
 				rsc_rh->id, rsc_lh->id);
   			order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); 
 		}
 	}
 
 	cl_str_to_boolean(symmetrical, &symmetrical_bool);
 	if(symmetrical_bool == FALSE) {
 		return TRUE;
 	}
 	
 	action = invert_action(action);
 	action_rh = invert_action(action_rh);
 	
 	custom_action_order(
 		rsc_rh, generate_op_key(rsc_rh->graph_name, action_rh, 0), NULL,
 		rsc_lh, generate_op_key(rsc_lh->graph_name, action, 0), NULL,
 		pe_ordering_optional, data_set);
 
 	if(rsc_lh->restart_type == pe_restart_restart
 	   && safe_str_eq(action, action_rh)) {
 		if(safe_str_eq(action, CRMD_ACTION_START)) {
 			crm_debug_2("Recover start-start (2): %s-%s",
 				rsc_lh->id, rsc_rh->id);
   			order_start_start(rsc_lh, rsc_rh, pe_ordering_recover);
 		} else if(safe_str_eq(action, CRMD_ACTION_STOP)) { 
 			crm_debug_2("Recover stop-stop (2): %s-%s",
 				rsc_rh->id, rsc_lh->id);
   			order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); 
 		}
 	}
 	
 	return TRUE;
 }
 
 gboolean
 add_node_attrs(crm_data_t *xml_obj, node_t *node, pe_working_set_t *data_set)
 {
  	g_hash_table_insert(node->details->attrs,
 			    crm_strdup("#"XML_ATTR_UNAME),
 			    crm_strdup(node->details->uname));
  	g_hash_table_insert(node->details->attrs,
 			    crm_strdup("#"XML_ATTR_ID),
 			    crm_strdup(node->details->id));
 	if(safe_str_eq(node->details->id, data_set->dc_uuid)) {
 		data_set->dc_node = node;
 		node->details->is_dc = TRUE;
 		g_hash_table_insert(node->details->attrs,
 				    crm_strdup("#"XML_ATTR_DC),
 				    crm_strdup(XML_BOOLEAN_TRUE));
 	} else {
 		g_hash_table_insert(node->details->attrs,
 				    crm_strdup("#"XML_ATTR_DC),
 				    crm_strdup(XML_BOOLEAN_FALSE));
 	}
 	
 	unpack_instance_attributes(
 		xml_obj, XML_TAG_ATTR_SETS, node, node->details->attrs,
 		NULL, 0, data_set);
 
 	return TRUE;
 }
 
 gboolean
 unpack_rsc_location(crm_data_t * xml_obj, pe_working_set_t *data_set)
 {
 	const char *id_lh   = crm_element_value(xml_obj, "rsc");
 	const char *id      = crm_element_value(xml_obj, XML_ATTR_ID);
 	resource_t *rsc_lh  = pe_find_resource(data_set->resources, id_lh);
 	
 	if(rsc_lh == NULL) {
 		/* only a warn as BSC adds the constraint then the resource */
 		pe_config_warn("No resource (con=%s, rsc=%s)", id, id_lh);
 		return FALSE;
 
 	} else if(rsc_lh->is_managed == FALSE) {
 		crm_debug_2("Ignoring constraint %s: resource %s not managed",
 			    id, id_lh);
 		return FALSE;
 	}
 
 	xml_child_iter_filter(
 		xml_obj, rule_xml, XML_TAG_RULE,
 		crm_debug_2("Unpacking %s/%s", id, ID(rule_xml));
 		generate_location_rule(rsc_lh, rule_xml, data_set);
 		);
 	return TRUE;
 }
 
 rsc_to_node_t *
 generate_location_rule(
 	resource_t *rsc, crm_data_t *rule_xml, pe_working_set_t *data_set)
 {	
 	const char *rule_id = NULL;
 	const char *score   = NULL;
 	const char *boolean = NULL;
 	const char *role    = NULL;
 	const char *attr_score = NULL;
 
 	GListPtr match_L  = NULL;
 	
 	int score_f   = 0;
 	gboolean do_and = TRUE;
 	gboolean accept = TRUE;
 	gboolean raw_score = TRUE;
 	
 	rsc_to_node_t *location_rule = NULL;
 	
 	rule_id = crm_element_value(rule_xml, XML_ATTR_ID);
 	boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP);
 	role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE);
 
 	crm_debug_2("processing rule: %s", rule_id);
 
 	if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) {
 		pe_err("Bad role specified for %s: %s", rule_id, role);
 		return NULL;
 	}
 	
 	score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE);
 	if(score != NULL) {
 		score_f = char2score(score);
 
 	} else {
 		score = crm_element_value(
 			rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE);
 		if(score == NULL) {
 			score = crm_element_value(
 				rule_xml, XML_RULE_ATTR_SCORE_MANGLED);
 		}
 		if(score != NULL) {
 			raw_score = FALSE;
 		}
 	}
 	
 	if(safe_str_eq(boolean, "or")) {
 		do_and = FALSE;
 	}
 	
 	location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set);
 	
 	if(location_rule == NULL) {
 		return NULL;
 	}
 	if(role != NULL) {
 		crm_debug_2("Setting role filter: %s", role);
 		location_rule->role_filter = text2role(role);
 	}
 	if(do_and) {
 		match_L = node_list_dup(data_set->nodes, FALSE);
 		slist_iter(
 			node, node_t, match_L, lpc,
 			node->weight = score_f;
 			);
 	}
 
 	xml_child_iter(
 		rule_xml, expr, 		
 
 		enum expression_type type = find_expression_type(expr);
 		if(type == not_expr) {
 			pe_err("Expression <%s id=%s...> is not valid",
 			       crm_element_name(expr), crm_str(ID(expr)));
 			continue;
 			
 		}	
 		
 		slist_iter(
 			node, node_t, data_set->nodes, lpc,
 
 			if(type == nested_rule) {
 				accept = test_rule(expr, node, rsc, data_set);
 			} else {
 				accept = test_expression(
 					expr, node, rsc, data_set);
 			}
 			
 			if(raw_score == FALSE) {
 				attr_score = g_hash_table_lookup(
 					node->details->attrs, score);
 				if(attr_score == NULL) {
 					accept = FALSE;
 					pe_warn("node %s did not have a value"
 						" for %s",
 						node->details->uname, score);
 				} else {
 					score_f = char2score(score);
 				}
 			}
 			
 			if(!do_and && accept) {
 				node_t *local = pe_find_node_id(
 					match_L, node->details->id);
 				if(local == NULL) {
 					local = node_copy(node);
 					match_L = g_list_append(match_L, local);
 				}
 				local->weight = merge_weights(
 					local->weight, score_f);
 				crm_debug_5("node %s already matched",
 					    node->details->uname);
 				
 			} else if(do_and && !accept) {
 				/* remove it */
 				node_t *delete = pe_find_node_id(
 					match_L, node->details->id);
 				if(delete != NULL) {
 					match_L = g_list_remove(match_L,delete);
 					crm_debug_5("node %s did not match",
 						    node->details->uname);
 				}
 				crm_free(delete);
 			}
 			);
 		);
 	
 	location_rule->node_list_rh = match_L;
 	if(location_rule->node_list_rh == NULL) {
 		crm_debug_2("No matching nodes for rule %s", rule_id);
 		return NULL;
 	} 
 
 	crm_debug_2("%s: %d nodes matched",
 		    rule_id, g_list_length(location_rule->node_list_rh));
 	crm_action_debug_3(print_rsc_to_node("Added", location_rule, FALSE));
 	return location_rule;
 }