diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h
index b2c9177de5..a5e7239282 100644
--- a/crm/tengine/tengine.h
+++ b/crm/tengine/tengine.h
@@ -1,133 +1,134 @@
-/* $Id: tengine.h,v 1.20 2005/05/10 13:20:32 andrew Exp $ */
+/* $Id: tengine.h,v 1.21 2005/05/20 15:05:36 andrew 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
  */
 #ifndef TENGINE__H
 #define TENGINE__H
 
 #include <clplumbing/ipc.h>
 #include <fencing/stonithd_api.h>
 
 extern IPC_Channel *crm_ch;
 extern GListPtr graph;
 extern GMainLoop*  mainloop;
 extern gboolean in_transition;
 
 typedef enum {
 	action_type_pseudo,
 	action_type_rsc,
 	action_type_crm
 } action_type_e;
 
 typedef enum te_reason_e {
 	te_update,
 	te_done,
 	te_halt,
 	te_abort,
+	te_abort_confirmed,
 	te_failed,
 	te_timeout,
 	
 } te_reason_t;
 
 typedef struct synapse_s {
 		int id;
 		gboolean triggers_complete;
 		gboolean complete;
 		gboolean confirmed;
 		GListPtr actions; /* action_t* */
 		GListPtr inputs;  /* action_t* */
 } synapse_t;
 
 typedef struct te_timer_s te_timer_t;
 
 typedef struct action_s {
 		int id;
 		int timeout;
 		int interval;
 		te_timer_t *timer;
 
 		action_type_e type;
 
 		gboolean invoked;
 		gboolean complete;
 		gboolean can_fail;
 		
 		crm_data_t *xml;
 		
 } action_t;
 
 
 enum timer_reason {
 	timeout_action,
 	timeout_action_warn,
 	timeout_timeout,
 	timeout_fuzz
 };
 
 struct te_timer_s
 {
 	int source_id;
 	int timeout;
 	enum timer_reason reason;
 	action_t *action;
 
 };
 
 /* tengine */
 extern gboolean initialize_graph(void);
 extern gboolean process_graph_event(crm_data_t *event, const char *event_node);
 /*	const char *event_node,   const char *event_rsc, const char *rsc_state,
  *	const char *event_action, const char *event_rc, const char *op_status); */
 extern int match_graph_event(
 	action_t *action, crm_data_t *event, const char *event_node);
 extern int match_down_event(const char *target, const char *filter, int rc);
 
 extern gboolean initiate_transition(void);
 extern gboolean cib_action_update(action_t *action, int status);
 
 /* utils */
 extern void print_state(int log_level);
 extern void send_complete(const char *text,crm_data_t *msg,te_reason_t reason);
 extern gboolean stop_te_timer(te_timer_t *timer);
 extern gboolean start_te_timer(te_timer_t *timer);
 extern const char *get_rsc_state(const char *task, op_status_t status);
 
 /* unpack */
 extern gboolean unpack_graph(crm_data_t *xml_graph);
 extern gboolean extract_event(crm_data_t *msg);
 extern gboolean process_te_message(
 	HA_Message * msg, crm_data_t *xml_data, IPC_Channel *sender);
 
 extern uint transition_timeout;
 extern uint transition_fuzz_timeout;
 extern uint default_transition_timeout;
 
 extern te_timer_t *transition_timer;
 extern te_timer_t *transition_fuzz_timer;
 extern cib_t *te_cib_conn;
 
 extern const char *actiontype2text(action_type_e type);
 
 extern void tengine_stonith_callback(stonith_ops_t * op, void * private_data);
 extern void tengine_stonith_connection_destroy(gpointer user_data);
 extern gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data);
 extern void check_for_completion(void);
 void process_trigger(int action_id);
 
 #endif
 
 
diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c
index 8760c6b2ab..fde2b80130 100644
--- a/crm/tengine/utils.c
+++ b/crm/tengine/utils.c
@@ -1,385 +1,391 @@
-/* $Id: utils.c,v 1.29 2005/05/18 20:15:58 andrew Exp $ */
+/* $Id: utils.c,v 1.30 2005/05/20 15:05:36 andrew 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 <sys/param.h>
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/msg.h>
 #include <crm/common/xml.h>
 #include <tengine.h>
 #include <heartbeat.h>
 #include <clplumbing/Gmain_timeout.h>
 #include <lrm/lrm_api.h>
 
 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)
 {	
 	HA_Message *cmd = NULL;
 	const char *op = CRM_OP_TEABORT;
 
 	/* the transition is over... ignore all future callbacks
 	 * resulting from our CIB updates (usually for pending operations)
 	 */
 	remove_cib_op_callback(-1, TRUE);
 	
 	if(reason == te_done && in_transition == FALSE) {
 		crm_warn("Not in transition, not sending message");
 		return;
 
 	} else if(reason == te_timeout && in_transition == FALSE) {
 		crm_err("Not in transition, not sending message");
 		return;
 	}
 
 	switch(reason) {
 		case te_update:
 			crm_debug("Transition status: %s by CIB update: %s",
 				  in_transition?"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:
 			crm_info("Transition status: Stopped%s%s",
 				 text?": ":"", text?text:"");
 			print_state(LOG_DEBUG);
 			op = CRM_OP_TECOMPLETE;
 			break;
+		case te_abort_confirmed:
+			crm_info("Transition status: Confirmed Stopped%s%s",
+				 text?": ":"", text?text:"");
+			print_state(LOG_DEBUG);
+			op = CRM_OP_TEABORTED;
+			break;
 		case te_abort:
 			crm_info("Transition status: Stopped%s%s",
 				 text?": ":"", text?text:"");
 			print_state(LOG_DEBUG);
 			break;
 		case te_done:
 			crm_info("Transition status: Complete%s%s",
 				 text?": ":"", text?text:"");
 			print_state(LOG_DEBUG);
 			op = CRM_OP_TECOMPLETE;
 			break;
 		case te_timeout:
 			crm_err("Transition status: Timed out after %dms",
 				transition_timer->timeout);
 			print_state(LOG_WARNING);
 			op = CRM_OP_TETIMEOUT;
 			break;
 		case te_failed:
 			crm_err("Transition status: Aborted by failed action: %s",
 				 text);
 			crm_log_xml_debug(msg, "Cause");
 			print_state(LOG_WARNING);
 			break;
 	}
 	
 	in_transition = FALSE;
 	initialize_graph();
 
 	cmd = create_request(
 		op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL);
 
 	if(text != NULL) {
 		ha_msg_add(cmd, "message", text);
 	}
 	
 #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	
 }
 
 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__, "###########");
 		return;
 	}
 
 	do_crm_log(log_level, __FILE__, __FUNCTION__, "###########");
 
 	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");
 
 		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__, "###########");
 }
 
 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;
 	
 	if(timer->reason == timeout_fuzz) {
 		crm_warn("Transition timeout reached..."
 			 " marking transition complete.");
 		send_complete("success", NULL, te_done);
 		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);
 		
 		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 "<unknown>";
 }
 
 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;
 		}
 	}
 }