diff --git a/crm/cib/callbacks.c b/crm/cib/callbacks.c
index aa2aa8b300..c5dbb5279e 100644
--- a/crm/cib/callbacks.c
+++ b/crm/cib/callbacks.c
@@ -1,1441 +1,1442 @@
-/* $Id: callbacks.c,v 1.81 2005/09/21 13:57:16 andrew Exp $ */
+/* $Id: callbacks.c,v 1.82 2005/10/12 18:28:22 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 <portability.h>
 
 #include <sys/param.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 
 #include <hb_api.h>
 #include <clplumbing/uids.h>
 #include <clplumbing/cl_uuid.h>
 
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/ipc.h>
 #include <crm/common/ctrl.h>
 #include <crm/common/xml.h>
 #include <crm/common/msg.h>
 
 #include <cibio.h>
 #include <callbacks.h>
 #include <cibmessages.h>
 #include <cibprimatives.h>
 #include <notify.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 gint cib_GCompareFunc(gconstpointer a, gconstpointer b);
 gboolean cib_msg_timeout(gpointer data);
 void cib_GHFunc(gpointer key, gpointer value, gpointer user_data);
 gboolean can_write(int flags);
 HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data);
 gboolean ccm_manual_check(gpointer data);
 extern enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
 void send_cib_replace(const HA_Message *sync_request, const char *host);
 void cib_process_request(const HA_Message *request, gboolean privileged,
 			 gboolean from_peer, cib_client_t *cib_client);
 
 gboolean syncd_once = FALSE;
 
 GHashTable *peer_hash = NULL;
 int        next_client_id  = 0;
 gboolean   cib_is_master   = FALSE;
 gboolean   cib_have_quorum = FALSE;
 char *     ccm_transition_id = NULL;
 GHashTable *client_list    = NULL;
 GHashTable *ccm_membership = NULL;
 extern const char *cib_our_uname;
 extern ll_cluster_t *hb_conn;
 extern int set_connected_peers(crm_data_t *xml_obj);
 
 /*
 typedef struct cib_operation_s
 {
 	const char* 	operation;
 	gboolean	modifies_cib;
 	gboolean	needs_privileges;
 	gboolean	needs_quorum;
 	gboolean	needs_section;
 	gboolean	needs_data;
 	enum cib_errors (*fn)(
 		const char *, int, const char *,
 		crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**);
 } cib_operation_t;
 */
 /* technically bump does modify the cib...
  * but we want to split the "bump" from the "sync"
  */
 cib_operation_t cib_server_ops[] = {
 	{NULL,		   FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default},
 	{CRM_OP_NOOP,	   FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default},
 	{CIB_OP_APPLY_DIFF,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_diff},
 	{CIB_OP_SLAVE,     FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
 	{CIB_OP_SLAVEALL,  TRUE, TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
 	{CIB_OP_SYNC_ONE,  FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync_one},
 	{CIB_OP_MASTER,    FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
 	{CIB_OP_ISMASTER,  FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
 	{CIB_OP_BUMP,      TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_bump},
 	{CIB_OP_REPLACE,   TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_replace},
-	{CIB_OP_CREATE,    TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
-	{CIB_OP_UPDATE,    TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
+	{CIB_OP_CREATE,    TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_change},
+	{CIB_OP_MODIFY,    TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
+	{CIB_OP_UPDATE,    TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_change},
 	{CIB_OP_DELETE,    TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_delete},
-	{CIB_OP_DELETE_ALT,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
+	{CIB_OP_DELETE_ALT,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_change},
 	{CIB_OP_QUERY,     FALSE,FALSE,FALSE,TRUE, FALSE,cib_process_query},
 	{CIB_OP_SYNC,      FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync},
 	{CRM_OP_QUIT,	   FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_quit},
 	{CRM_OP_PING,	   FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_ping},
 	{CIB_OP_ERASE,     TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_erase}
 };
 
 int send_via_callback_channel(HA_Message *msg, const char *token);
 
 enum cib_errors cib_process_command(
 	const HA_Message *request, HA_Message **reply,
 	crm_data_t **cib_diff, gboolean privileged);
 
 gboolean cib_common_callback(
 	IPC_Channel *channel, gpointer user_data, gboolean privileged);
 
 enum cib_errors cib_get_operation_id(const HA_Message * msg, int *operation);
 
 gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client);
 
 gboolean
 cib_client_connect(IPC_Channel *channel, gpointer user_data)
 {
 	gboolean auth_failed = FALSE;
 	gboolean can_connect = TRUE;
 	gboolean (*client_callback)(IPC_Channel *channel, gpointer user_data) = NULL;
 
 	cib_client_t *new_client = NULL;
 	crm_debug_3("Connecting channel");
 
 	if (channel == NULL) {
 		crm_err("Channel was NULL");
 		can_connect = FALSE;
 		
 	} else if (channel->ch_status == IPC_DISCONNECT) {
 		crm_err("Channel was disconnected");
 		can_connect = FALSE;
 		
 	} else if(user_data == NULL) {
 		crm_err("user_data must contain channel name");
 		can_connect = FALSE;
 		
 	} else {
 		crm_malloc0(new_client, sizeof(cib_client_t));
 		new_client->id          = NULL;
 		new_client->callback_id = NULL;
 		new_client->source      = NULL;
 		new_client->channel     = channel;
 		new_client->channel_name = user_data;
 		new_client->delegated_calls = NULL;
 
 		crm_debug_3("Created channel %p for channel %s",
 			  new_client, new_client->channel_name);
 		
 		client_callback = NULL;
 		
 		/* choose callback and do auth based on channel_name */
 		if(safe_str_eq(new_client->channel_name, cib_channel_callback)) {
 			client_callback = cib_null_callback;
 
 		} else {
 			cl_uuid_t client_id;
 
 			cl_uuid_generate(&client_id);
 			crm_malloc0(new_client->id, sizeof(char)*36);
 			cl_uuid_unparse(&client_id, new_client->id);
 			new_client->id[35] = EOS;
 			
 			cl_uuid_generate(&client_id);
 			crm_malloc0(new_client->callback_id, sizeof(char)*36);
 			cl_uuid_unparse(&client_id, new_client->callback_id);
 			new_client->callback_id[35] = EOS;
 			
 			client_callback = cib_ro_callback;
 			if(safe_str_eq(new_client->channel_name, cib_channel_rw)) {
 				client_callback = cib_rw_callback;
 			} 
 		}
 	}
 
 	if(auth_failed) {
 		crm_err("Connection to %s channel failed authentication",
 			(char *)user_data);
 		can_connect = FALSE;
 	}
 
 	if(can_connect == FALSE) {
 		if(new_client) {
 			crm_free(new_client->id);
 			crm_free(new_client->callback_id);
 		}
 		crm_free(new_client);
 		return FALSE;
 	}
 
 	
 	channel->ops->set_recv_qlen(channel, 100);
 	if(safe_str_eq(new_client->channel_name, cib_channel_callback)) {
 		channel->ops->set_send_qlen(channel, 400);
 	} else {
 		channel->ops->set_send_qlen(channel, 100);
 	}
 		
 	if(client_callback != NULL) {
 		new_client->source = G_main_add_IPC_Channel(
 			G_PRIORITY_DEFAULT, channel, FALSE, client_callback,
 			new_client, default_ipc_connection_destroy);
 	}
 	if(client_callback != cib_null_callback) {
 		/* send msg to client with uuid to use when signing up for
 		 * callback channel
 		 */
 
 		HA_Message *reg_msg = ha_msg_new(3);
 		ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER);
 		ha_msg_add(reg_msg, F_CIB_CLIENTID,  new_client->id);
 		ha_msg_add(
 			reg_msg, F_CIB_CALLBACK_TOKEN, new_client->callback_id);
 		
 		send_ipc_message(channel, reg_msg);
 		
 		/* make sure we can find ourselves later for sync calls
 		 * redirected to the master instance
 		 */
 		g_hash_table_insert(client_list, new_client->id, new_client);
 	}
 
 	crm_debug_3("Channel %s connected for client %s",
 		  new_client->channel_name, new_client->id);
 	
 	return TRUE;
 }
 
 gboolean
 cib_rw_callback(IPC_Channel *channel, gpointer user_data)
 {
 	return cib_common_callback(channel, user_data, TRUE);
 }
 
 gboolean
 cib_ro_callback(IPC_Channel *channel, gpointer user_data)
 {
 	return cib_common_callback(channel, user_data, FALSE);
 }
 
 gboolean
 cib_null_callback(IPC_Channel *channel, gpointer user_data)
 {
 	gboolean did_disconnect = TRUE;
 	HA_Message *op_request = NULL;
 	cib_client_t *cib_client = user_data;
 	cib_client_t *hash_client = NULL;
 	const char *type = NULL;
 	const char *uuid_ticket = NULL;
 	const char *client_name = NULL;
 	gboolean register_failed = FALSE;
 
 	if(cib_client == NULL) {
 		crm_err("Discarding IPC message from unknown source"
 			" on callback channel.");
 		return FALSE;
 	}
 	
 	while(channel->ops->is_message_pending(channel)) {
 		if (channel->ch_status != IPC_CONNECT) {
 			/* The message which was pending for us is that
 			 * the channel is no longer fully connected.
 			 *
 			 * Dont read requests from disconnected clients
 			 */
 			break;
 		}
 		op_request = msgfromIPC_noauth(channel);
 
 		type = cl_get_string(op_request, F_CIB_OPERATION);
 		if(safe_str_eq(type, T_CIB_NOTIFY) ) {
 			/* Update the notify filters for this client */
 			int on_off = 0;
 			ha_msg_value_int(
 				op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);
 			type = cl_get_string(op_request, F_CIB_NOTIFY_TYPE);
 
 			crm_info("Setting %s callbacks for %s: %s",
 				 type, cib_client->name, on_off?"on":"off");
 			
 			if(safe_str_eq(type, T_CIB_POST_NOTIFY)) {
 				cib_client->post_notify = on_off;
 				
 			} else if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
 				cib_client->pre_notify = on_off;
 
 			} else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
 				cib_client->confirmations = on_off;
 
 			} else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
 				cib_client->diffs = on_off;
 
 			}
 			continue;
 			
 		} else if(safe_str_neq(type, CRM_OP_REGISTER) ) {
 			crm_warn("Discarding IPC message from %s on callback channel",
 				 cib_client->id);
 			crm_msg_del(op_request);
 			continue;
 		}
 
 		uuid_ticket = cl_get_string(op_request, F_CIB_CALLBACK_TOKEN);
 		client_name = cl_get_string(op_request, F_CIB_CLIENTNAME);
 
 		CRM_DEV_ASSERT(uuid_ticket != NULL);
 		if(crm_assert_failed) {
 			register_failed = crm_assert_failed;
 		}
 		
 		CRM_DEV_ASSERT(client_name != NULL);
 		if(crm_assert_failed) {
 			register_failed = crm_assert_failed;
 		}
 
 		if(register_failed == FALSE) {
 			hash_client = g_hash_table_lookup(client_list, uuid_ticket);
 			if(hash_client != NULL) {
 				crm_err("Duplicate registration request..."
 					" disconnecting");
 				register_failed = TRUE;
 			}
 		}
 		
 		if(register_failed) {
 			crm_err("Registration request failed... disconnecting");
 			crm_msg_del(op_request);
 			return FALSE;
 		}
 
 		cib_client->id   = crm_strdup(uuid_ticket);
 		cib_client->name = crm_strdup(client_name);
 
 		g_hash_table_insert(client_list, cib_client->id, cib_client);
 		crm_debug_2("Registered %s on %s channel",
 			    cib_client->id, cib_client->channel_name);
 
 		if(safe_str_eq(cib_client->name, CRM_SYSTEM_TENGINE)) {
 			/* The TE is _always_ interested in these
 			 * Enable now to avoid timing issues
 			 */
 			cib_client->diffs = TRUE;
 		}
 		
 		crm_msg_del(op_request);
 
 		op_request = ha_msg_new(2);
 		ha_msg_add(op_request, F_CIB_OPERATION, CRM_OP_REGISTER);
 		ha_msg_add(op_request, F_CIB_CLIENTID,  cib_client->id);
 		
 		send_ipc_message(channel, op_request);
 	}
 	did_disconnect = cib_process_disconnect(channel, cib_client);	
 	if(did_disconnect) {
 		crm_debug_2("Client disconnected");
 	}
 	
 	return did_disconnect;
 }
 
 gboolean
 cib_common_callback(
 	IPC_Channel *channel, gpointer user_data, gboolean privileged)
 {
 	int rc = cib_ok;
 	int lpc = 0;
 
 	const char *op = NULL;
 	HA_Message *op_request = NULL;
 	cib_client_t *cib_client = user_data;
 
 	if(cib_client == NULL) {
 		crm_err("Receieved call from unknown source. Discarding.");
 		return FALSE;
 	}
 	
 	crm_debug_2("Callback for %s on %s channel",
 		    cib_client->id, cib_client->channel_name);
 
 	while(channel->ops->is_message_pending(channel)) {
 		if (channel->ch_status != IPC_CONNECT) {
 			/* The message which was pending for us is that
 			 * the channel is no longer fully connected.
 			 *
 			 * Dont read requests from disconnected clients
 			 */
 			break;
 		}
 		op_request = msgfromIPC(channel, 0);
 		if (op_request == NULL) {
 			perror("Receive failure:");
 			break;
 		}
 
 
 		op = cl_get_string(op_request, F_CIB_OPERATION);
 		crm_info("Operation %s from client %s/%s",
 			 op, cib_client->id, cib_client->channel_name);
 		crm_log_message_adv(LOG_MSG, "Client[inbound]", op_request);
 		
 		lpc++;
 		rc = cib_ok;
 		
 		CRM_DEV_ASSERT(
 			ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id) == HA_OK);
 
 		if(crm_assert_failed == FALSE) {
 			cib_process_request(
 				op_request, privileged, FALSE, cib_client);
 		}
 		
 		crm_debug_3("Cleaning up request");
 		crm_msg_del(op_request);
 		op_request = NULL;
 	}
 
 	crm_debug_2("Processed %d messages", lpc);
 
 	return cib_process_disconnect(channel, cib_client);
 }
 
 void
 cib_process_request(const HA_Message *request, gboolean privileged,
 		    gboolean from_peer, cib_client_t *cib_client) 
 {
 	int call_type    = 0;
 	int call_options = 0;
 
 	gboolean process = TRUE;		
 	gboolean needs_reply = TRUE;
 	gboolean local_notify = FALSE;
 	gboolean needs_forward = FALSE;
 	crm_data_t *result_diff = NULL;
 	
 	enum cib_errors rc = cib_ok;
 	HA_Message *op_reply = NULL;
 	
 	const char *op         = cl_get_string(request, F_CIB_OPERATION);
 	const char *originator = cl_get_string(request, F_ORIG);
 	const char *host       = cl_get_string(request, F_CIB_HOST);
 	const char *reply_to   = cl_get_string(request, F_CIB_ISREPLY);
 	const char *update     = cl_get_string(request, F_CIB_GLOBAL_UPDATE);
 	const char *delegated  = cl_get_string(request, F_CIB_DELEGATED);
 	const char *client_id  = NULL;
 
 	crm_debug_4("%s Processing msg %s",
 		  cib_our_uname, cl_get_string(request, F_SEQ));
 
 	if(host != NULL && strlen(host) == 0) {
 		host = NULL;
 	}
 	
 	ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
 	crm_debug_4("Retrieved call options: %d", call_options);
 	
 	crm_debug_2("Processing %s message (%s) to %s...",
 		    from_peer?"peer":"local",originator, host?host:"master");
 
 	rc = cib_get_operation_id(request, &call_type);
 	
 	if(rc != cib_ok) {
 		/* TODO: construct error reply */
 		crm_err("Pre-processing of command failed: %s",
 			cib_error2string(rc));
 		
 	} else if(from_peer == FALSE) {
 
 		if(cib_server_ops[call_type].modifies_cib
 		   && !(call_options & cib_inhibit_bcast)) {
 			/* we need to send an update anyway */
 			needs_reply = TRUE;
 		} else {
 			needs_reply = FALSE;
 		}
 		
 		if(host == NULL && (call_options & cib_scope_local)) {
 			crm_debug("Processing locally scoped %s op from %s",
 				  op, cib_client->name);
 			local_notify = TRUE;
 
 		} else if(host == NULL && cib_is_master) {
 			crm_debug("Processing master %s op locally from %s",
 				  op, cib_client->name);
 			local_notify = TRUE;
 
 		} else if(safe_str_eq(host, cib_our_uname)) {
 			crm_debug("Processing locally addressed %s op from %s",
 				  op, cib_client->name);
 			local_notify = TRUE;
 		} else {
 			crm_debug("%s op from %s needs to be forwarded to %s",
 				  op, cib_client->name,
 				  host?host:"the master instance");
 			needs_forward = TRUE;
 			process = FALSE;
 		}
 		
 	} else if(crm_is_true(update) && safe_str_eq(reply_to, cib_our_uname)) {
 		crm_debug("Processing global/peer update from %s"
 			  " that originated from us", originator);
 		needs_reply = FALSE;
 		local_notify = TRUE;
 		
 	} else if(crm_is_true(update)) {
 		crm_debug("Processing global/peer update from %s", originator);
 		needs_reply = FALSE;
 
 	} else if(host != NULL && safe_str_eq(host, cib_our_uname)) {
 		crm_debug("Processing request sent to us from %s", originator);
 
 	} else if(delegated != NULL && cib_is_master == TRUE) {
 		crm_debug("Processing request sent to master instance from %s",
 			originator);
 
 	} else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) {
 		crm_debug("Forward reply sent from %s to local clients",
 			  originator);
 		process = FALSE;
 		needs_reply = FALSE;
 		local_notify = TRUE;
 
 	} else if(delegated != NULL) {
 		crm_debug("Ignoring msg for master instance");
 		return;
 
 	} else if(host != NULL) {
 		/* this is for a specific instance and we're not it */
 		crm_debug("Ignoring msg for instance on %s", crm_str(host));
 		return;
 		
 	} else if(reply_to == NULL && cib_is_master == FALSE) {
 		/* this is for the master instance and we're not it */
 		crm_debug("Ignoring reply to %s", crm_str(reply_to));
 		return;
 		
 	} else {
 		crm_err("Nothing for us to do?");
 		crm_log_message_adv(LOG_ERR, "Peer[inbound]", request);
 		return;
 	}
 	crm_debug_3("Finished determining processing actions");
 
 	if(call_options & cib_discard_reply) {
 		needs_reply = cib_server_ops[call_type].modifies_cib;
 		local_notify = FALSE;
 	}
 	
 	if(needs_forward) {
 		HA_Message *forward_msg = cib_msg_copy(request, TRUE);
 		ha_msg_add(forward_msg, F_CIB_DELEGATED, cib_our_uname);
 		
 		if(host != NULL) {
 			crm_debug("Forwarding %s op to %s", op, host);
 			send_ha_message(hb_conn, forward_msg, host, FALSE);
 			
 		} else {
 			crm_debug("Forwarding %s op to master instance", op);
 			send_ha_message(hb_conn, forward_msg, NULL, FALSE);
 		}
 		
 		if(call_options & cib_discard_reply) {
 			crm_debug_2("Client not interested in reply");
 			crm_msg_del(forward_msg);
 			
 		} else if(call_options & cib_sync_call) {
 			/* keep track of the request so we can time it
 			 * out if required
 			 */
 			crm_debug("Registering delegated call from %s",
 				  cib_client->id);
 			cib_client->delegated_calls = g_list_append(
 				cib_client->delegated_calls, forward_msg);
 		} else {
 			crm_msg_del(forward_msg);
 		}
 		return;
 	}
 
 	if(process) {
 		crm_debug_2("Performing local processing:"
 			    " op=%s origin=%s/%s,%s (update=%s)",
 			    cl_get_string(request, F_CIB_OPERATION), originator,
 			    cl_get_string(request, F_CIB_CLIENTID),
 			    cl_get_string(request, F_CIB_CALLID), update);
 		
 		rc = cib_process_command(request, &op_reply, &result_diff, TRUE);
 		crm_debug_2("Processing complete");
 
 		if(rc == cib_diff_resync || rc == cib_diff_failed
 		   || rc == cib_old_data) {
 			crm_warn("%s operation failed: %s",
 				crm_str(op), cib_error2string(rc));
 			
 		} else if(rc != cib_ok) {
 			crm_err("%s operation failed: %s",
 				crm_str(op), cib_error2string(rc));
 			crm_log_message_adv(LOG_DEBUG, "CIB[output]", op_reply);
 			crm_log_message_adv(LOG_INFO, "Input message", request);
 		}
 
 		if(op_reply == NULL && (needs_reply || local_notify)) {
 			crm_err("Unexpected NULL reply to message");
 			crm_log_message(LOG_ERR, request);
 			needs_reply = FALSE;
 			local_notify = FALSE;
 		}
 			
 	}
 
 	crm_debug_3("processing response cases");
 
 	if(local_notify) {
 		/* send callback to originating child */
 		cib_client_t *client_obj = NULL;
 		HA_Message *client_reply = NULL;
 		enum cib_errors local_rc = cib_ok;
 		crm_debug_2("Performing notification");
 
 		if(process == FALSE) {
 			client_reply = cib_msg_copy(request, TRUE);
 		} else {
 			client_reply = cib_msg_copy(op_reply, TRUE);
 		}
 		
 		client_id = cl_get_string(request, F_CIB_CLIENTID);
 		if(client_id != NULL) {
 			client_obj = g_hash_table_lookup(
 				client_list, client_id);
 		} else {
 			crm_debug("No client to sent the response to."
 				  "  F_CIB_CLIENTID not set.");
 		}
 		
 		crm_debug_3("Sending callback to request originator");
 		if(client_obj != NULL) {
 			crm_debug_2("Sending %ssync response to %s %s",
 				  (call_options & cib_sync_call)?"":"an a-",
 				  client_obj->id,
 				  from_peer?"(originator of delegated request)":"");
 
 			if(call_options & cib_sync_call) {
 				send_via_callback_channel(
 					client_reply, client_obj->id);
 
 			} else {
 				send_via_callback_channel(
 					client_reply, client_obj->callback_id);
 			}
 			
 		} else {
 			crm_warn("Client %s may have left us",
 				 crm_str(client_id));
 			crm_msg_del(client_reply);
 		}
 		if(local_rc != cib_ok) {
 			crm_warn("%sSync reply failed: %s",
 				 (call_options & cib_sync_call)?"":"A-",
 				 cib_error2string(local_rc));
 			crm_log_message(LOG_DEBUG, op_reply);
 		}
 	}
 
 	if(needs_reply == FALSE) {
 		/* nothing more to do...
 		 * this was a non-originating slave update
 		 */
 		crm_debug_2("Completed slave update");
 		crm_msg_del(op_reply);
 		free_xml(result_diff);
 		return;
 	}
 	
 	crm_debug_4("add the originator to message");
 
 	CRM_DEV_ASSERT(op_reply != NULL);
 	CRM_DEV_ASSERT(cib_server_ops[call_type].modifies_cib == FALSE
 		       || result_diff != NULL || rc != cib_ok);
 	
 	/* from now on we are the server */ 
 	if(rc == cib_ok
 	   && result_diff != NULL
 	   && cib_server_ops[call_type].modifies_cib
 	   && !(call_options & cib_inhibit_bcast)) {
 		/* this (successful) call modified the CIB _and_ the
 		 * change needs to be broadcast...
 		 *   send via HA to other nodes
 		 */
 		HA_Message *op_bcast = cib_msg_copy(request, FALSE);
 		int diff_add_updates = 0;
 		int diff_add_epoch  = 0;
 		int diff_add_admin_epoch = 0;
 		
 		int diff_del_updates = 0;
 		int diff_del_epoch  = 0;
 		int diff_del_admin_epoch = 0;
 		
 		cib_diff_version_details(
 			result_diff,
 			&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, 
 			&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
 
 		crm_debug("Sending update diff %d.%d.%d -> %d.%d.%d",
 			diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
 			diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
 
 		ha_msg_add(op_bcast, F_CIB_ISREPLY, originator);
 		ha_msg_add(op_bcast, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
 		ha_msg_mod(op_bcast, F_CIB_OPERATION, CIB_OP_APPLY_DIFF);
 
 		add_message_xml(op_bcast, F_CIB_UPDATE_DIFF, result_diff);
 		crm_log_message(LOG_DEBUG_3, op_bcast);
 		send_ha_message(hb_conn, op_bcast, NULL, TRUE);
 		crm_msg_del(op_bcast);
 		
 	} else if((call_options & cib_discard_reply) == 0) {
 		crm_debug_2("Sending replies");
 		if(from_peer && originator != NULL) {
 			/* send reply via HA to originating node */
 			crm_debug("Sending request result to originator only");
 			ha_msg_add(op_reply, F_CIB_ISREPLY, originator);
 			send_ha_message(hb_conn, op_reply, originator, FALSE);
 		}
 		if(call_options & cib_inhibit_bcast ) {
 			crm_debug("Request not broadcast: inhibited");
 		}
 		if(cib_server_ops[call_type].modifies_cib == FALSE) {
 			crm_debug_2("Request not broadcast: R/O call");
 		}
 		if(rc != cib_ok) {
 			crm_warn("Request not broadcast: call failed: %s",
 				 cib_error2string(rc));
 		}
 	}
 	
 	crm_msg_del(op_reply);
 	free_xml(result_diff);
 
 	return;	
 }
 
 enum cib_errors
 cib_process_command(const HA_Message *request, HA_Message **reply,
 		    crm_data_t **cib_diff, gboolean privileged)
 {
 	crm_data_t *output   = NULL;
 	crm_data_t *input    = NULL;
 	crm_data_t *input_fragment = NULL;
 
 	crm_data_t *current_cib = the_cib;
 	crm_data_t *result_cib  = NULL;
 	crm_data_t *local_diff  = NULL;
 	
 	int call_type      = 0;
 	int call_options   = 0;
 	enum cib_errors rc = cib_ok;
 
 	const char *op = NULL;
 	const char *call_id = NULL;
 	const char *section = NULL;
 	const char *tmp = NULL;
 	gboolean global_update = crm_is_true(
 		cl_get_string(request, F_CIB_GLOBAL_UPDATE));
 
 	CRM_DEV_ASSERT(reply != NULL);
 	if(reply) { *reply = NULL; }
 	
 	/* Start processing the request... */
 	op = cl_get_string(request, F_CIB_OPERATION);
 	call_id = cl_get_string(request, F_CIB_CALLID);
 	ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
 
 	crm_debug_4("Processing call id: %s", call_id);
 	
 	rc = cib_get_operation_id(request, &call_type);
 	
 	if(rc == cib_ok &&
 	   cib_server_ops[call_type].needs_privileges
 	   && privileged == FALSE) {
 		/* abort */
 		rc = cib_not_authorized;
 	}
 	
 	if(rc == cib_ok
 	   && global_update == FALSE
 	   && cib_server_ops[call_type].needs_quorum
 	   && can_write(call_options) == FALSE) {
 		rc = cib_no_quorum;
 	}
 
 	/* prevent NUMUPDATES from being incrimented - apply the change as-is */
 	if(global_update) {
 		call_options |= cib_inhibit_bcast;
 	}
 	
 	if(rc == cib_ok && cib_server_ops[call_type].needs_section) {
 		section = cl_get_string(request, F_CIB_SECTION);
 	}
 
 	if(rc == cib_ok && safe_str_eq(op, CIB_OP_APPLY_DIFF)) {
 		crm_debug_4("Unpacking diff data in %s", F_CIB_UPDATE_DIFF);
 		input_fragment = get_message_xml(request, F_CIB_UPDATE_DIFF);
 		if(global_update) {
 			call_options |= cib_force_diff;
 		} else {
 			do_id_check(input_fragment, NULL);
 		}
 		
 	} else if(rc == cib_ok && safe_str_eq(op, CIB_OP_SYNC)) {
  		input_fragment = ha_msg_copy(request);
 		
 	} else if(rc == cib_ok && safe_str_eq(op, CIB_OP_SYNC_ONE)) {
  		input_fragment = ha_msg_copy(request);
 		
 	} else if(rc == cib_ok && cib_server_ops[call_type].needs_data) {
 		crm_debug_4("Unpacking data in %s", F_CIB_CALLDATA);
 		input_fragment = get_message_xml(request, F_CIB_CALLDATA);
 	}
 
 	/* extract the CIB from the fragment */
 	if(input_fragment != NULL
 	   && safe_str_eq(crm_element_name(input_fragment), XML_TAG_FRAGMENT)) {
 		input = find_xml_node(input_fragment, XML_TAG_CIB, TRUE);
 		
 	} else {
 		input = input_fragment;
 	}
 
 	/* grab the section specified for the command */
 	if(input != NULL && safe_str_eq(crm_element_name(input), XML_TAG_CIB)){
 		rc = revision_check(input, current_cib, call_options);
 		if(rc == cib_ok) {
 			input = get_object_root(section, input);
 			do_id_check(input, NULL);
 		}
 	}
 	
 	if(cib_server_ops[call_type].modifies_cib) {
 		cib_pre_notify(
 			call_options, op,
 			get_object_root(section, current_cib), input);
 	}
 
 	if(rc == cib_ok) {
 		rc = cib_server_ops[call_type].fn(
 			op, call_options, section, input,
 			current_cib, &result_cib, &output);
 	}
 	
 	if(cib_server_ops[call_type].modifies_cib) {
 		if(safe_str_eq(op, CIB_OP_APPLY_DIFF)) {
 			local_diff = copy_xml(input);
 
 		} else if(result_cib != NULL && current_cib != result_cib) {
 			local_diff = diff_cib_object(
 				current_cib, result_cib, FALSE);
 		}
 		if(rc != cib_ok) {
 			free_xml(result_cib);
 
 		} else if(activateCibXml(result_cib,CIB_FILENAME) < 0){
 			crm_warn("Activation failed");
 			rc = cib_ACTIVATION;
 		}
 		cib_post_notify(call_options, op, input, rc, the_cib);
 		cib_diff_notify(call_options, op, input, rc, local_diff);
 
 	} else if(result_cib != NULL) {
 		crm_err("%s call modified the CIB", op);
 		free_xml(result_cib);
 	}
 	
 	
 	crm_debug_4("Processing reply cases");
 	if((call_options & cib_discard_reply)
 	   && cib_server_ops[call_type].modifies_cib == FALSE) {
 		crm_debug_3("No reply needed for call %s", call_id);
 		return rc;
 		
 	} else if(reply == NULL) {
 		crm_debug("No reply possible for call %s", call_id);
 		return rc;
 	}
 
 	crm_debug_4("Creating a basic reply");
 	*reply = ha_msg_new(8);
 	ha_msg_add(*reply, F_TYPE, T_CIB);
 	ha_msg_add(*reply, F_CIB_OPERATION, op);
 	ha_msg_add(*reply, F_CIB_CALLID, call_id);
 	ha_msg_add_int(*reply, F_CIB_RC, rc);
 
 	tmp = cl_get_string(request, F_CIB_CLIENTID);
 	ha_msg_add(*reply, F_CIB_CLIENTID, tmp);
 	
 	tmp = cl_get_string(request, F_CIB_CALLOPTS);
 	ha_msg_add(*reply, F_CIB_CALLOPTS, tmp);
 	
 	crm_debug_4("Attaching output if necessary");
 	if(output != NULL) {
 		add_message_xml(*reply, F_CIB_CALLDATA, output);
 	} else {
 		crm_debug_3("No output for call %s", call_id);
 	}
 	
 
 	crm_debug_4("Cleaning up");
 	if(cib_diff != NULL) {
 		*cib_diff = local_diff;
 	} else {
 		free_xml(local_diff);
 	}
 	free_xml(output);
 	free_xml(input_fragment);
 	return rc;
 }
 
 int
 send_via_callback_channel(HA_Message *msg, const char *token) 
 {
 	cib_client_t *hash_client = NULL;
 	GList *list_item = NULL;
 	enum cib_errors rc = cib_ok;
 	
 	crm_debug_3("Delivering msg %p to client %s", msg, token);
 
 	if(token == NULL) {
 		crm_err("No client id token, cant send message");
 		if(rc == cib_ok) {
 			rc = cib_missing;
 		}
 		
 	} else {
 		/* A client that left before we could reply is not really
 		 * _our_ error.  Warn instead.
 		 */
 		hash_client = g_hash_table_lookup(client_list, token);
 		if(hash_client == NULL) {
 			crm_warn("Cannot find client for token %s", token);
 			rc = cib_client_gone;
 			
 		} else if(hash_client->channel == NULL) {
 			crm_err("Cannot find channel for client %s", token);
 			rc = cib_client_corrupt;
 
 		} else if(hash_client->channel->ops->get_chan_status(
 				  hash_client->channel) != IPC_CONNECT) {
 			crm_warn("Client %s has disconnected", token);
 			rc = cib_client_gone;
 		}
 	}
 
 	/* this is a more important error so overwriting rc is warrented */
 	if(msg == NULL) {
 		crm_err("No message to send");
 		rc = cib_reply_failed;
 	}
 
 	if(rc == cib_ok) {
 		list_item = g_list_find_custom(
 			hash_client->delegated_calls, msg, cib_GCompareFunc);
 	}
 	
 	if(list_item != NULL) {
 		/* remove it - no need to time it out */
 		HA_Message *orig_msg = list_item->data;
 		crm_debug_3("Removing msg from delegated list");
 		hash_client->delegated_calls = g_list_remove(
 			hash_client->delegated_calls, orig_msg);
 		CRM_DEV_ASSERT(orig_msg != msg);
 		crm_msg_del(orig_msg);
 	}
 	
 	if(rc == cib_ok) {
 		crm_debug_3("Delivering reply to client %s", token);
 		if(send_ipc_message(hash_client->channel, msg) == FALSE) {
 			crm_warn("Delivery of reply to client %s/%s failed",
 				hash_client->name, token);
 			rc = cib_reply_failed;
 		}
 
 	} else {
 		/* be consistent...
 		 * send_ipc_message() will free the message, so we should do
 		 *  so manually if we dont try to send it.
 		 */
 		crm_msg_del(msg);
 	}
 	
 	return rc;
 }
 
 gint cib_GCompareFunc(gconstpointer a, gconstpointer b)
 {
 	const HA_Message *a_msg = a;
 	const HA_Message *b_msg = b;
 
 	int msg_a_id = 0;
 	int msg_b_id = 0;
 	
 	ha_msg_value_int(a_msg, F_CIB_CALLID, &msg_a_id);
 	ha_msg_value_int(b_msg, F_CIB_CALLID, &msg_b_id);
 	
 	if(msg_a_id == msg_b_id) {
 		return 0;
 	} else if(msg_a_id < msg_b_id) {
 		return -1;
 	}
 	return 1;
 }
 
 
 gboolean
 cib_msg_timeout(gpointer data)
 {
 	crm_debug_4("Checking if any clients have timed out messages");
 	g_hash_table_foreach(client_list, cib_GHFunc, NULL);
 	return TRUE;
 }
 
 
 void
 cib_GHFunc(gpointer key, gpointer value, gpointer user_data)
 {
 	cib_client_t *client = value;
 
 	GListPtr list = client->delegated_calls;
 	HA_Message *msg = NULL;
 
 
 	while(list != NULL) {
 		int seen = 0;
 		int timeout = 5; /* 1 iteration == 1 seconds */
 		HA_Message *reply = NULL;
 		const char *host_to = NULL;
 		
 		msg = list->data;
 		ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen);
 		ha_msg_value_int(msg, F_CIB_TIMEOUT, &timeout);
 		host_to = cl_get_string(msg, F_CIB_HOST);
 		
 		crm_debug_4("Timeout %d, seen %d", timeout, seen);
 		if(timeout > 0 && seen < timeout) {
 			int seen2 = 0;
 			crm_debug_4("Updating seen count for msg from client %s",
 				  client->id);
 			seen++;
 			ha_msg_mod_int(msg, F_CIB_SEENCOUNT, seen);
 			ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen2);
 			list = list->next;
 			continue;
 		}
 		
 		crm_warn("Sending operation timeout msg to client %s",
 			 client->id);
 		
 		reply = ha_msg_new(4);
 		ha_msg_add(reply, F_TYPE, T_CIB);
 		ha_msg_add(reply, F_CIB_OPERATION,
 			   cl_get_string(msg, F_CIB_OPERATION));
 		ha_msg_add(reply, F_CIB_CALLID,
 			   cl_get_string(msg, F_CIB_CALLID));
 		if(host_to == NULL) {
 			ha_msg_add_int(reply, F_CIB_RC, cib_master_timeout);
 		} else {
 			ha_msg_add_int(reply, F_CIB_RC, cib_remote_timeout);
 		}
 		
 		send_ipc_message(client->channel, reply);
 
 		list = list->next;
 		client->delegated_calls = g_list_remove(
 			client->delegated_calls, msg);
 
 		crm_msg_del(msg);
 	}
 }
 
 
 gboolean
 cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client)
 {
 	if (channel->ch_status != IPC_CONNECT && cib_client != NULL) {
 		crm_info("Cleaning up after %s channel disconnect from client (%p) %s/%s",
 			 cib_client->channel_name, cib_client,
 			 crm_str(cib_client->id), crm_str(cib_client->name));
 
 		if(cib_client->id != NULL) {
 			g_hash_table_remove(client_list, cib_client->id);
 		}
 		if(cib_client->source != NULL) {
 			crm_debug_3("deleting the IPC Channel");
  			G_main_del_IPC_Channel(cib_client->source);
 			cib_client->source = NULL;
 		}
 		
 		crm_debug_3("Freeing the cib client %s", crm_str(cib_client->id));
 #if 0
 		/* todo - put this back in once i recheck its safe */
  		crm_free(cib_client->callback_id);
   		crm_free(cib_client->name);
   		crm_free(cib_client->id);
 #endif
   		crm_free(cib_client);
 		crm_debug_3("Freed the cib client");
 
 		return FALSE;
 
 	} else if (channel->ch_status != IPC_CONNECT) {
 		crm_warn("Unknown client disconnected");
 		return FALSE;
 	}
 
 	return TRUE;
 }
 
 
 gboolean
 cib_ha_dispatch(IPC_Channel *channel, gpointer user_data)
 {
 	int lpc = 0;
 	ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data;
 
 	while(lpc < 2 && hb_cluster->llc_ops->msgready(hb_cluster)) {
  		lpc++; 
 		/* invoke the callbacks but dont block */
 		hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
 	}
 
 	crm_debug_4("%d HA messages dispatched", lpc);
 
 	if (channel && (channel->ch_status != IPC_CONNECT)) {
 		crm_crit("Lost connection to heartbeat service... exiting");
 		exit(100);
 		return FALSE;
 	}
 	return TRUE;
 }
 
 void
 cib_peer_callback(const HA_Message * msg, void* private_data)
 {
 	int call_type = 0;
 	const char *originator = cl_get_string(msg, F_ORIG);
 	const char *seq        = cl_get_string(msg, F_SEQ);
 	const char *op         = cl_get_string(msg, F_CIB_OPERATION);
 
 	crm_log_message_adv(LOG_MSG, "Peer[inbound]", msg);
 	
 	if(originator == NULL || safe_str_eq(originator, cib_our_uname)) {
  		crm_debug_3("Discarding %s message from ourselves", op);
 		return;
 
 	} else if(ccm_membership == NULL) {
  		crm_info("Discarding %s message (%s) from %s:"
 			 " membership not established", op, seq, originator);
 		return;
 		
 	} else if(g_hash_table_lookup(ccm_membership, originator) == NULL) {
  		crm_warn("Discarding %s message (%s) from %s:"
 			 " not in our membership", op, seq, originator);
 		return;
 
 	} else if(cib_get_operation_id(msg, &call_type) != cib_ok) {
  		crm_err("Discarding %s message (%s) from %s:"
 			" Invalid operation", op, seq, originator);
 		return;
 	}
 
 	crm_info("Processing %s msg (%s) from %s", op, seq, originator);
 
 	cib_process_request(msg, TRUE, TRUE, NULL);
 
 	return;
 }
 
 HA_Message *
 cib_msg_copy(const HA_Message *msg, gboolean with_data) 
 {
 	int lpc = 0;
 	const char *field = NULL;
 	const char *value = NULL;
 	const HA_Message *value_struct = NULL;
 
 	const char *field_list[] = {
 		F_TYPE		,
 		F_CIB_CLIENTID  ,
 		F_CIB_CALLOPTS  ,
 		F_CIB_CALLID    ,
 		F_CIB_OPERATION ,
 		F_CIB_ISREPLY   ,
 		F_CIB_SECTION   ,
 		F_CIB_HOST	,
 		F_CIB_RC	,
 		F_CIB_DELEGATED	,
 		F_CIB_OBJID	,
 		F_CIB_OBJTYPE	,
 		F_CIB_EXISTING	,
 		F_CIB_SEENCOUNT	,
 		F_CIB_TIMEOUT	,
 		F_CIB_CALLBACK_TOKEN	,
 		F_CIB_GLOBAL_UPDATE	,
 		F_CIB_CLIENTNAME	,
 		F_CIB_NOTIFY_TYPE	,
 		F_CIB_NOTIFY_ACTIVATE
 	};
 	
 	const char *data_list[] = {
 		F_CIB_CALLDATA  ,
 		F_CIB_UPDATE	,
 		F_CIB_UPDATE_RESULT
 	};
 
 	HA_Message *copy = ha_msg_new(10);
 
 	if(copy == NULL) {
 		return copy;
 	}
 	
 	for(lpc = 0; lpc < DIMOF(field_list); lpc++) {
 		field = field_list[lpc];
 		value = cl_get_string(msg, field);
 		if(value != NULL) {
 			ha_msg_add(copy, field, value);
 		}
 	}
 	for(lpc = 0; with_data && lpc < DIMOF(data_list); lpc++) {
 		field = data_list[lpc];
 		value_struct = cl_get_struct(msg, field);
 		if(value_struct != NULL) {
 			ha_msg_addstruct(copy, field, value_struct);
 		}
 	}
 	return copy;
 }
 
 
 enum cib_errors
 cib_get_operation_id(const HA_Message * msg, int *operation) 
 {
 	int lpc = 0;
 	int max_msg_types = DIMOF(cib_server_ops);
 	const char *op = cl_get_string(msg, F_CIB_OPERATION);
 
 	for (lpc = 0; lpc < max_msg_types; lpc++) {
 		if (safe_str_eq(op, cib_server_ops[lpc].operation)) {
 			*operation = lpc;
 			return cib_ok;
 		}
 	}
 	crm_err("Operation %s is not valid", op);
 	*operation = -1;
 	return cib_operation;
 }
 
 void
 cib_client_status_callback(const char * node, const char * client,
 			   const char * status, void * private)
 {
 	if(safe_str_eq(client, CRM_SYSTEM_CIB)) {
 		crm_info("Status update: Client %s/%s now has status [%s]",
 			 node, client, status);
 		g_hash_table_replace(peer_hash, crm_strdup(node), crm_strdup(status));
 		set_connected_peers(the_cib);
 	}
 	return;
 }
 
 extern oc_ev_t *cib_ev_token;
 
 gboolean
 ccm_manual_check(gpointer data)
 {
 	int rc = 0;
 	oc_ev_t *ccm_token = cib_ev_token;
 	
 	crm_debug("manual check");	
 	rc = oc_ev_handle_event(ccm_token);
 	if(0 == rc) {
 		return TRUE;
 
 	} else {
 		crm_err("CCM connection appears to have failed: rc=%d.", rc);
 		return FALSE;
 	}
 }
 
 gboolean cib_ccm_dispatch(int fd, gpointer user_data)
 {
 	int rc = 0;
 	oc_ev_t *ccm_token = (oc_ev_t*)user_data;
 	crm_debug("received callback");	
 	rc = oc_ev_handle_event(ccm_token);
 	if(0 == rc) {
 		return TRUE;
 
 	} else {
 		crm_err("CCM connection appears to have failed: rc=%d.", rc);
 		return FALSE;
 	}
 }
 
 static void crm_ghash_clfree(gpointer data)
 {
 	crm_free(data);
 }
 
 void 
 cib_ccm_msg_callback(
 	oc_ed_t event, void *cookie, size_t size, const void *data)
 {
 	int instance = -1;
 	gboolean update_id = FALSE;
 	gboolean update_quorum = FALSE;
 	
 	const oc_ev_membership_t *membership = data;
 
 	if(membership != NULL) {
 		instance = membership->m_instance;
 	}
 
 	crm_info("Process CCM event=%s (id=%d)", 
 		 ccm_event_name(event), instance);
 
 	switch(event) {
 		case OC_EV_MS_NEW_MEMBERSHIP:
 		case OC_EV_MS_INVALID:
 			update_id = TRUE;
 			update_quorum = TRUE;
 			break;
 		case OC_EV_MS_PRIMARY_RESTORED:
 			update_id = TRUE;
 			break;
 		case OC_EV_MS_NOT_PRIMARY:
 			crm_debug("Ignoring transitional CCM event: %s",
 				  ccm_event_name(event));
 			break;
 		case OC_EV_MS_EVICTED:
 			crm_err("Evicted from CCM: %s", ccm_event_name(event));
 			update_quorum = TRUE;
 			break;
 		default:
 			crm_err("Unknown CCM event: %d", event);
 	}
 	
 	if(update_id) {
 		CRM_DEV_ASSERT(membership != NULL);
 		if(crm_assert_failed) { return; }
 	
 		if(ccm_transition_id != NULL) {
 			crm_free(ccm_transition_id);
 			ccm_transition_id = NULL;
 		}
 		ccm_transition_id = crm_itoa(instance);
 		set_transition(the_cib);
 	}
 	
 	if(update_quorum) {
 		unsigned int members = 0;
 		int offset = 0;
 		unsigned int lpc = 0;
 
 		cib_have_quorum = ccm_have_quorum(event);
 
 		if(cib_have_quorum) {
  			crm_xml_add(
 				the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_TRUE);
 		} else {
  			crm_xml_add(
 				the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_FALSE);
 		}
 		
 		crm_info("Quorum %s after event=%s (id=%d)", 
 			 cib_have_quorum?"(re)attained":"lost",
 			 ccm_event_name(event), instance);
 		
 		if(ccm_membership == NULL) {
 			ccm_membership = g_hash_table_new_full(
 				g_str_hash, g_str_equal,
 				crm_ghash_clfree, NULL);
 		}
 
 		if(membership != NULL && membership->m_n_in != 0) {
 			members = membership->m_n_in;
 			offset = membership->m_in_idx;
 			for(lpc = 0; lpc < members; lpc++) {
 				oc_node_t a_node = membership->m_array[lpc+offset];
 				char *uname = crm_strdup(a_node.node_uname);
 				crm_info("Added: %s", uname);
 				g_hash_table_replace(
 					ccm_membership, uname, uname);	
 			}
 		}
 		if(membership != NULL && membership->m_n_out != 0) {
 			members = membership->m_n_out;
 			offset = membership->m_out_idx;
 			for(lpc = 0; lpc < members; lpc++) {
 				oc_node_t a_node = membership->m_array[lpc+offset];
 				crm_info("LOST: %s", a_node.node_uname);
 				g_hash_table_remove(
 					ccm_membership, a_node.node_uname);	
 			}
 		}
 	}
 	
 	oc_ev_callback_done(cookie);
 	set_connected_peers(the_cib);
 	
 	return;
 }
 
 
 gboolean
 can_write(int flags)
 {
 	const char *value = NULL;
 
 	if(cib_have_quorum) {
 		return TRUE;
 	}
 	value = get_crm_option(the_cib, "no_quorum_policy", TRUE);
 	if(safe_str_eq(value, "ignore")) {
 		return TRUE;		
 	}
 	if((flags & cib_quorum_override) != 0) {
 		crm_debug_2("Overriding \"no quorum\" condition");
 		return TRUE;
 	}
 	return FALSE;
 }
 
 
diff --git a/crm/cib/cibmessages.h b/crm/cib/cibmessages.h
index d219ca4ba8..83e654a9d5 100644
--- a/crm/cib/cibmessages.h
+++ b/crm/cib/cibmessages.h
@@ -1,79 +1,83 @@
-/* $Id: cibmessages.h,v 1.8 2005/06/17 11:07:16 andrew Exp $ */
+/* $Id: cibmessages.h,v 1.9 2005/10/12 18:28:22 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 CIB_MESSAGES__H
 #define CIB_MESSAGES__H
 
 
 extern crm_data_t *createCibRequest(
 	gboolean isLocal, const char *operation, const char *section,
 	const char *verbose, crm_data_t *data);
 
 extern enum cib_errors cib_process_default(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_quit(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_ping(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_query(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_erase(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_bump(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_replace(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_modify(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_readwrite(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_diff(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_sync(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_sync_one(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
 extern enum cib_errors cib_process_delete(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
 
+extern enum cib_errors cib_process_change(
+	const char *op, int options, const char *section, crm_data_t *input,
+	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer);
+
 #endif
diff --git a/crm/cib/messages.c b/crm/cib/messages.c
index 36e85e249c..050d5a677b 100644
--- a/crm/cib/messages.c
+++ b/crm/cib/messages.c
@@ -1,937 +1,962 @@
-/* $Id: messages.c,v 1.56 2005/09/27 13:18:45 andrew Exp $ */
+/* $Id: messages.c,v 1.57 2005/10/12 18:28:22 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 <portability.h>
 
 #include <sys/param.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 
 #include <heartbeat.h>
 #include <clplumbing/cl_log.h>
 
 #include <time.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 <cibio.h>
 #include <cibmessages.h>
 #include <cibprimatives.h>
 #include <callbacks.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 #define MAX_DIFF_RETRY 5
 
 extern const char *cib_our_uname;
 extern gboolean syncd_once;
 enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
 int get_revision(crm_data_t *xml_obj, int cur_revision);
 
 enum cib_errors updateList(
 	crm_data_t *local_cib, crm_data_t *update_command, crm_data_t *failed,
 	int operation, const char *section);
 
 crm_data_t *createCibFragmentAnswer(const char *section, crm_data_t *failed);
 
 enum cib_errors replace_section(
 	const char *section, crm_data_t *tmpCib, crm_data_t *command);
 
 gboolean check_generation(crm_data_t *newCib, crm_data_t *oldCib);
 
 gboolean update_results(
 	crm_data_t *failed, crm_data_t *target, int operation, int return_code);
 
 enum cib_errors cib_update_counter(
 	crm_data_t *xml_obj, const char *field, gboolean reset);
 
 enum cib_errors sync_our_cib(HA_Message *request, gboolean all);
 
 enum cib_errors 
 cib_process_default(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	enum cib_errors result = cib_ok;
 	crm_debug_2("Processing \"%s\" event", op);
 	if(answer != NULL) { *answer = NULL; }	
 
 	if(op == NULL) {
 		result = cib_operation;
 		crm_err("No operation specified");
 		
 	} else if(strcmp(CRM_OP_NOOP, op) == 0) {
 		;
 
 	} else {
 		result = cib_NOTSUPPORTED;
 		crm_err("Action [%s] is not supported by the CIB", op);
 	}
 	return result;
 }
 
 enum cib_errors 
 cib_process_quit(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	enum cib_errors result = cib_ok;
 	crm_debug_2("Processing \"%s\" event", op);
 
 	crm_warn("The CRMd has asked us to exit... complying");
 	exit(0);
 	return result;
 }
 
 
 enum cib_errors 
 cib_process_readwrite(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	enum cib_errors result = cib_ok;
 	crm_debug_2("Processing \"%s\" event", op);
 
 	if(safe_str_eq(op, CIB_OP_ISMASTER)) {
 		if(cib_is_master == TRUE) {
 			result = cib_ok;
 		} else {
 			result = cib_not_master;
 		}
 		return result;
 	}
 
 	if(safe_str_eq(op, CIB_OP_MASTER)) {
 		if(cib_is_master == FALSE) {
 			crm_info("We are now in R/W mode");
 			cib_is_master = TRUE;
 			syncd_once = TRUE;
 			
 		} else {
 			crm_debug("We are still in R/W mode");
 		}
 		
 	} else if(cib_is_master) {
 		crm_info("We are now in R/O mode");
 		cib_is_master = FALSE;
 	}
 
 	return result;
 }
 
 enum cib_errors 
 cib_process_ping(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	enum cib_errors result = cib_ok;
 	crm_debug_2("Processing \"%s\" event", op);
 	if(answer != NULL) {
 		*answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok");
 	}
 	return result;
 }
 
 
 enum cib_errors 
 cib_process_query(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	crm_data_t *obj_root = NULL;
 	enum cib_errors result = cib_ok;
 
 	crm_debug_2("Processing \"%s\" event for section=%s",
 		  op, crm_str(section));
 
 	if(answer != NULL) { *answer = NULL; }	
 	else { return cib_output_ptr; }
 	
 	if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
 		section = NULL;
 	}
 
 	*answer = create_xml_node(NULL, XML_TAG_FRAGMENT);
 /*  	crm_xml_add(*answer, XML_ATTR_SECTION, section); */
 
 	obj_root = get_object_root(section, existing_cib);
 	
 	if(obj_root == NULL) {
 		result = cib_NOTEXISTS;
 
 	} else if(obj_root == existing_cib) {
 		crm_xml_add(obj_root, "origin", cib_our_uname);
 		add_node_copy(*answer, obj_root);
 
 	} else {
 		crm_data_t *cib = createEmptyCib();
 		crm_data_t *query_obj_root = get_object_root(section, cib);
 		copy_in_properties(cib, existing_cib);
 		crm_xml_add(cib, "origin", cib_our_uname);
 
 		xml_child_iter(
 			obj_root, an_obj, NULL,
 			add_node_copy(query_obj_root, an_obj);
 			);
 
 		add_node_copy(*answer, cib);
 		free_xml(cib);
 	}
 
 	if(result == cib_ok && *answer == NULL) {
 		crm_err("Error creating query response");
 		result = cib_output_data;
 	}
 	
 	return result;
 }
 
 enum cib_errors 
 cib_process_erase(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	enum cib_errors result = cib_ok;
 
 	crm_debug_2("Processing \"%s\" event", op);
 	if(answer != NULL) { *answer = NULL; }	
 
 	*result_cib = createEmptyCib();
 
 	result = revision_check(existing_cib, *result_cib, options);
 	copy_in_properties(*result_cib, existing_cib);
 	
 	if(result == cib_ok && !(options & cib_inhibit_bcast)) {
 		cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
 	}
 	
 	if(answer != NULL) {
 		*answer = createCibFragmentAnswer(NULL, NULL);
 	}
 	
 	return result;
 }
 
 enum cib_errors 
 cib_process_bump(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	enum cib_errors result = cib_ok;
 
 	crm_debug_2("Processing \"%s\" event for epoch=%s",
 		  op, crm_str(crm_element_value(the_cib, XML_ATTR_GENERATION)));
 	
 	if(answer != NULL) { *answer = NULL; }	
 
 	*result_cib = copy_xml(the_cib);
 
 	cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
 	cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
 	
 	if(answer != NULL) {
 		*answer = createCibFragmentAnswer(NULL, NULL);
 	}
 	
 	return result;
 }
 
 extern ll_cluster_t *hb_conn;
 extern HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data);
 
 enum cib_errors 
 cib_process_sync(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	return sync_our_cib(input, TRUE);
 }
 
 enum cib_errors 
 cib_process_sync_one(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	return sync_our_cib(input, FALSE);
 }
 
 enum cib_errors 
 cib_update_counter(crm_data_t *xml_obj, const char *field, gboolean reset)
 {
 	char *new_value = NULL;
 	char *old_value = NULL;
 	int  int_value  = -1;
 
 	/* modify the timestamp */
 	set_node_tstamp(xml_obj);
 	if(reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
 		old_value = crm_element_value_copy(xml_obj, field);
 	}
 	if(old_value != NULL) {
 		crm_malloc0(new_value, 128*(sizeof(char)));
 		int_value = atoi(old_value);
 		sprintf(new_value, "%d", ++int_value);
 	} else {
 		new_value = crm_strdup("1");
 	}
 
 	crm_debug_4("%s %d(%s)->%s",
 		  field, int_value, crm_str(old_value), crm_str(new_value));
 	crm_xml_add(xml_obj, field, new_value);
 	crm_free(new_value);
 
 	crm_free(old_value);
 	return cib_ok;
 }
 
 int sync_in_progress = 0;
 
 enum cib_errors 
 cib_process_diff(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	unsigned int log_level = LOG_DEBUG;
 	const char *value = NULL;
 	const char *reason = NULL;
 	gboolean apply_diff = TRUE;
 	gboolean do_resync = FALSE;
 	enum cib_errors result = cib_ok;
 
 	int this_updates = 0;
 	int this_epoch  = 0;
 	int this_admin_epoch = 0;
 
 	int diff_add_updates = 0;
 	int diff_add_epoch  = 0;
 	int diff_add_admin_epoch = 0;
 
 	int diff_del_updates = 0;
 	int diff_del_epoch  = 0;
 	int diff_del_admin_epoch = 0;
 
 	crm_debug_2("Processing \"%s\" event", op);
 
 	if(cib_is_master) {
 		/* the master is never waiting for a resync */
 		sync_in_progress = 0;
 	}
 	
 	cib_diff_version_details(
 		input,
 		&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, 
 		&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
 
 	if(sync_in_progress > MAX_DIFF_RETRY) {
 		/* request another full-sync,
 		 * the last request may have been lost
 		 */
 		sync_in_progress = 0;
 	} 
 	if(sync_in_progress) {
 		sync_in_progress++;
 		crm_warn("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
 			diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
 			diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
 		return cib_diff_resync;
 	}
 	
 	value = crm_element_value(existing_cib, XML_ATTR_GENERATION);
 	this_epoch = atoi(value?value:"0");
 	
 	value = crm_element_value(existing_cib, XML_ATTR_NUMUPDATES);
 	this_updates = atoi(value?value:"0");
 	
 	value = crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN);
 	this_admin_epoch = atoi(value?value:"0");
 	
 	if(diff_del_admin_epoch == diff_add_admin_epoch
 	   && diff_del_epoch == diff_add_epoch
 	   && diff_del_updates == diff_add_updates) {
 		apply_diff = FALSE;
 		log_level = LOG_ERR;
 		reason = "+ and - versions in the diff did not change";
 		log_cib_diff(LOG_ERR, input, __FUNCTION__);
 	}
 
 	if(apply_diff && diff_del_admin_epoch > this_admin_epoch) {
 		do_resync = TRUE;
 		apply_diff = FALSE;
 		log_level = LOG_INFO;
 		reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is less than required";
 		
 	} else if(apply_diff && diff_del_admin_epoch < this_admin_epoch) {
 		apply_diff = FALSE;
 		log_level = LOG_WARNING;
 		reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required";
 	}
 
 	if(apply_diff && diff_del_epoch > this_epoch) {
 		do_resync = TRUE;
 		apply_diff = FALSE;
 		log_level = LOG_INFO;
 		reason = "current \""XML_ATTR_GENERATION"\" is less than required";
 		
 	} else if(apply_diff && diff_del_epoch < this_epoch) {
 		apply_diff = FALSE;
 		log_level = LOG_WARNING;
 		reason = "current \""XML_ATTR_GENERATION"\" is greater than required";
 	}
 
 	if(apply_diff && diff_del_updates > this_updates) {
 		do_resync = TRUE;
 		apply_diff = FALSE;
 		log_level = LOG_INFO;
 		reason = "current \""XML_ATTR_NUMUPDATES"\" is less than required";
 		
 	} else if(apply_diff && diff_del_updates < this_updates) {
 		apply_diff = FALSE;
 		log_level = LOG_WARNING;
 		reason = "current \""XML_ATTR_NUMUPDATES"\" is greater than required";
 	}
 
 	if(apply_diff
 	   && apply_cib_diff(existing_cib, input, result_cib) == FALSE) {
 		log_level = LOG_WARNING;
 		reason = "Failed application of an update diff";
 		if(options & cib_force_diff && cib_is_master == FALSE) {
   			log_level = LOG_INFO;
 			reason = "Failed application of a global update.  Requesting full refresh.";
 			do_resync = TRUE;
 		} else if(options & cib_force_diff) {
 			reason = "Failed application of a global update.  Not requesting full refresh.";
 		}
 	}
 	
 
 	if(reason != NULL) {
 		crm_log_maybe(
 			log_level,
 			"Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s",
 			diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
 			diff_add_admin_epoch,diff_add_epoch,diff_add_updates,
 			this_admin_epoch,this_epoch,this_updates, reason);
 		
 		result = cib_diff_failed;
 
 	} else if(apply_diff) {
 		crm_debug("Diff %d.%d.%d -> %d.%d.%d was applied",
 			diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
 			diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
 	}
 
 	if(do_resync && cib_is_master == FALSE) {
 		HA_Message *sync_me = ha_msg_new(3);
 		free_xml(*result_cib);
 		*result_cib = NULL;
 		result = cib_diff_resync;
 		crm_info("Requesting re-sync from peer: %s", reason);
 		sync_in_progress++;
 		
 		ha_msg_add(sync_me, F_TYPE, "cib");
 		ha_msg_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
 		ha_msg_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
 
 		if(send_ha_message(hb_conn, sync_me, NULL, FALSE) == FALSE) {
 			result = cib_not_connected;
 		}
 		ha_msg_del(sync_me);
 		
 	} else if(do_resync) {
 		crm_err("Not resyncing in master mode");
 	}
 	
 	
 	return result;
 }
 
 enum cib_errors 
 cib_process_replace(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	gboolean verbose       = FALSE;
 	enum cib_errors result = cib_ok;
 	
 	crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
 	if(answer != NULL) { *answer = NULL; }	
 
 	if (options & cib_verbose) {
 		verbose = TRUE;
 	}
 	if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
 		section = NULL;
 	}
 	
 	if (input == NULL) {
 		result = cib_NOOBJECT;
 		
 	} else if(section == NULL) {
 		int updates = 0;
 		int epoch  = 0;
 		int admin_epoch = 0;
 		
 		int replace_updates = 0;
 		int replace_epoch  = 0;
 		int replace_admin_epoch = 0;
 		const char *reason = NULL;
 		
 		cib_version_details(
 			existing_cib, &admin_epoch, &epoch, &updates);
 		cib_version_details(input, &replace_admin_epoch,
 				    &replace_epoch, &replace_updates);
 
 		if(replace_admin_epoch < admin_epoch) {
 			reason = XML_ATTR_GENERATION_ADMIN;
 
 		} else if(replace_admin_epoch > admin_epoch) {
 			/* no more checks */
 		} else if(replace_epoch < epoch) {
 			reason = XML_ATTR_GENERATION;
 
 		} else if(replace_epoch > epoch) {
 			/* no more checks */
 
 		} else if(replace_updates < updates) {
 			reason = XML_ATTR_NUMUPDATES;
 		}
 
 		if(reason != NULL) {
 			crm_warn("Replacement %d.%d.%d not applied to %d.%d.%d:"
 				 " current %s is greater than the replacement",
 				 replace_admin_epoch, replace_epoch,
 				 replace_updates, admin_epoch, epoch, updates,
 				 reason);
 			result = cib_old_data;
 		}
 		sync_in_progress = 0;
 		*result_cib = copy_xml(input);
 		
 	} else {
 		*result_cib = copy_xml(existing_cib);
 		result = replace_section(section, *result_cib, input);
 	}
 
 	if(result == cib_ok && section != NULL) {
 		cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
 	}
 	
 	if (answer != NULL && (verbose || result != cib_ok)) {
 		*answer = createCibFragmentAnswer(section, NULL);
 	}
 
 	return result;
 }
 
 enum cib_errors 
 cib_process_delete(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	crm_debug_2("Processing \"%s\" event", op);
 
 	if(input == NULL) {
 		crm_err("Cannot perform modification with no data");
 		return cib_NOOBJECT;
 	}
 	
 	*result_cib = copy_xml(existing_cib);
 	
 	crm_validate_data(input);
 	crm_validate_data(*result_cib);
 
 	if(delete_xml_child(NULL, *result_cib, input) == FALSE) {
 		return cib_NOTEXISTS;		
 	}
 	
 	cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
 	return cib_ok;
 }
 
 
 enum cib_errors 
 cib_process_modify(
 	const char *op, int options, const char *section, crm_data_t *input,
 	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
+{
+	crm_debug_2("Processing \"%s\" event", op);
+
+	if(input == NULL) {
+		crm_err("Cannot perform modification with no data");
+		return cib_NOOBJECT;
+	}
+	
+	*result_cib = copy_xml(existing_cib);
+	
+	crm_validate_data(input);
+	crm_validate_data(*result_cib);
+
+	if(update_xml_child(*result_cib, input) == FALSE) {
+		return cib_NOTEXISTS;		
+	}
+	
+	cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
+	return cib_ok;
+}
+
+enum cib_errors 
+cib_process_change(
+	const char *op, int options, const char *section, crm_data_t *input,
+	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
 {
 	gboolean verbose = FALSE;
 	crm_data_t *failed = NULL;
 	enum cib_errors result = cib_ok;
 	int cib_update_op = CIB_UPDATE_OP_NONE;
 
 	crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
 
 	failed = create_xml_node(NULL, XML_TAG_FAILED);
 
 	if (strcmp(CIB_OP_CREATE, op) == 0) {
 		cib_update_op = CIB_UPDATE_OP_ADD;
 		
 	} else if (strcmp(CIB_OP_UPDATE, op) == 0) {
 		cib_update_op = CIB_UPDATE_OP_MODIFY;
 		
 	} else if (strcmp(CIB_OP_DELETE_ALT, op) == 0) {
 		cib_update_op = CIB_UPDATE_OP_DELETE;
 		
 	} else {
 		crm_err("Incorrect request handler invoked for \"%s\" op",
 			crm_str(op));
 		return cib_operation;
 	}
 
 	result = cib_ok;
 	if (options & cib_verbose) {
 		verbose = TRUE;
 	}
 	
 	if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
 		section = NULL;
 	}
 
 	if(input == NULL) {
 		crm_err("Cannot perform modification with no data");
 		return cib_NOOBJECT;
 	}
 	
 	*result_cib = copy_xml(existing_cib);
 	
 	crm_validate_data(input);
 	crm_validate_data(*result_cib);
 	
 	/* make changes to a temp copy then activate */
 	if(section == NULL) {
 		crm_data_t *sub_input = NULL;
 		copy_in_properties(*result_cib, input);
 		/* order is no longer important here */
 		if(result == cib_ok) {
 			sub_input = get_object_root(XML_CIB_TAG_NODES, input);
 			result = updateList(
 				*result_cib, sub_input, failed, cib_update_op,
 				XML_CIB_TAG_NODES);
 		}
 		
 		if(result == cib_ok) {
 			sub_input = get_object_root(XML_CIB_TAG_NODES, input);
 			result = updateList(
 				*result_cib, sub_input, failed, cib_update_op,
 				XML_CIB_TAG_RESOURCES);
 		}
 		if(result == cib_ok) {
 			sub_input = get_object_root(XML_CIB_TAG_NODES, input);
 			result = updateList(
 				*result_cib, sub_input, failed, cib_update_op,
 				XML_CIB_TAG_CONSTRAINTS);
 		}
 		if(result == cib_ok) {
 			sub_input = get_object_root(XML_CIB_TAG_NODES, input);
 			result = updateList(
 				*result_cib, sub_input, failed, cib_update_op,
 				XML_CIB_TAG_STATUS);
 		}
 
 	} else {
 		result = updateList(
 			*result_cib, input, failed, cib_update_op, section);
 	}
 
 	if(result == cib_ok && !(options & cib_inhibit_bcast)) {
 		cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
 	}
 	
 	if (result != cib_ok || xml_has_children(failed)) {
 		if(result == cib_ok) {
 			result = cib_unknown;
 		}
 		crm_log_xml_err(failed, "CIB Update failures");
 	}
 
 	if (verbose || xml_has_children(failed) || result != cib_ok) {
 		*answer = createCibFragmentAnswer(section, failed);
 	}
 
 	free_xml(failed);
 
 	return result;
 }
 
 
 enum cib_errors
 replace_section(
 	const char *section, crm_data_t *tmpCib, crm_data_t *new_section)
 {
 	crm_data_t *old_section = NULL;
 
 	/* find the old and new versions of the section */
 	old_section = get_object_root(section, tmpCib);
 	
 	if(old_section == NULL) {
 		crm_err("The CIB is corrupt, cannot replace missing section %s",
 		       section);
 		return cib_NOSECTION;
 
 	} else if(new_section == NULL) {
 		crm_err("The CIB is corrupt, cannot set section %s to nothing",
 		       section);
 		return cib_NOSECTION;
 	}
 
 	xml_child_iter(
 		old_section, a_child, NULL,
 		free_xml_from_parent(old_section, a_child);
 		);
 
 	copy_in_properties(old_section, new_section);
 
 	xml_child_iter(
 		new_section, a_child, NULL,
 		add_node_copy(old_section, a_child);
 		);
 
 	return cib_ok;
 }
 
 
 
 enum cib_errors
 updateList(crm_data_t *local_cib, crm_data_t *xml_section, crm_data_t *failed,
 	   int operation, const char *section)
 {
 	int rc = cib_ok;
 	crm_data_t *this_section = get_object_root(section, local_cib);
 	
 	if (section == NULL || xml_section == NULL) {
 		crm_err("Section %s not found in message."
 			"  CIB update is corrupt, ignoring.",
 			crm_str(section));
 		return cib_NOSECTION;
 	}
 
 	if((CIB_UPDATE_OP_NONE > operation) || (operation > CIB_UPDATE_OP_MAX)){
 		crm_err("Invalid operation on section %s", crm_str(section));
 		return cib_operation;
 	}
 
 	set_node_tstamp(this_section);
 
 	xml_child_iter(
 		xml_section, a_child, NULL,
 
 		rc = cib_ok;
 		if(operation == CIB_UPDATE_OP_DELETE) {
 			rc = delete_cib_object(this_section, a_child);
 			update_results(failed, a_child, operation, rc);
 
 		} else if(operation == CIB_UPDATE_OP_MODIFY) {
 			rc = update_cib_object(this_section, a_child);
 			update_results(failed, a_child, operation, rc);
 				       
 		} else {
 			rc = add_cib_object(this_section, a_child);
 			update_results(failed, a_child, operation, rc);
 		} 
 		);
 
 	if(rc == cib_ok && xml_has_children(failed)) {
 		rc = cib_unknown;
 	}
 	return rc;
 }
 
 crm_data_t*
 createCibFragmentAnswer(const char *section, crm_data_t *failed)
 {
 	crm_data_t *cib = NULL;
 	crm_data_t *fragment = NULL;
 	
 	fragment = create_xml_node(NULL, XML_TAG_FRAGMENT);
 
 	if (section == NULL
 	    || strlen(section) == 0
 	    || strcmp(XML_CIB_TAG_SECTION_ALL, section) == 0) {
 		
 		cib = get_the_CIB();
 		if(cib != NULL) {
 			add_node_copy(fragment, get_the_CIB());
 		}
 		
 	} else {
 		crm_data_t *obj_root = get_object_root(section, get_the_CIB());
 
 		if(obj_root != NULL) {
 			cib = create_xml_node(fragment, XML_TAG_CIB);
 
 			add_node_copy(cib, obj_root);
 			copy_in_properties(cib, get_the_CIB());
 		} 
 	}
 
 	if (failed != NULL && xml_has_children(failed)) {
 		add_node_copy(fragment, failed);
 	}
 		
 	crm_xml_add(fragment, XML_ATTR_SECTION, section);
 	crm_xml_add(fragment, "generated_on", cib_our_uname);
 	return fragment;
 }
 
 gboolean
 check_generation(crm_data_t *newCib, crm_data_t *oldCib)
 {
 	if(cib_compare_generation(newCib, oldCib) >= 0) {
 		return TRUE;
 	}
 
 	crm_warn("Generation from update is older than the existing one");
 	return FALSE;
 }
  
 gboolean
 update_results(
 	crm_data_t *failed, crm_data_t *target, int operation, int return_code)
 {
 	gboolean   was_error      = FALSE;
 	const char *error_msg     = NULL;
 	const char *operation_msg = NULL;
 	crm_data_t *xml_node       = NULL;
 	
 	operation_msg = cib_op2string(operation);
     
 	if (return_code != cib_ok) {
 		error_msg = cib_error2string(return_code);
 
 		xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
 
 		was_error = TRUE;
 
 		add_node_copy(xml_node, target);
 		
 		crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
 		crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
 		crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation_msg);
 		crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
 
 		crm_warn("Action %s failed: %s (cde=%d)",
 			  operation_msg, error_msg, return_code);
 	
 	} else {
 		crm_debug_3("CIB %s passed", operation_msg);
 	}
 
 	return was_error;
 }
 
 enum cib_errors
 revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags)
 {
 	int cmp = 0;
 	enum cib_errors rc = cib_ok;
 	char *new_revision = NULL;
 	const char *cur_revision = crm_element_value(
 		cib_copy, XML_ATTR_CIB_REVISION);
 
 	crm_validate_data(cib_update);
 	crm_validate_data(cib_copy);
 	
 	if(crm_element_value(cib_update, XML_ATTR_CIB_REVISION) == NULL) {
 		return cib_ok;
 	}
 
 	new_revision = crm_element_value_copy(cib_update,XML_ATTR_CIB_REVISION);
 	
 	cmp = compare_version(new_revision, CIB_FEATURE_SET);
 	if(cmp > 0) {
 		CRM_DEV_ASSERT(cib_is_master == FALSE);
 		CRM_DEV_ASSERT((flags & cib_scope_local) == 0);
 
 		if(cib_is_master) {
 			crm_err("Update uses an unsupported tag/feature:"
 				" %s vs %s", new_revision,CIB_FEATURE_SET);
 			rc = cib_revision_unsupported;
 
 		} else if(flags & cib_scope_local) {
 			 /* an admin has forced a local change using a tag we
 			  * dont understand... ERROR
 			  */
 			crm_err("Local update uses an unsupported tag/feature:"
 				" %s vs %s", new_revision,CIB_FEATURE_SET);
 			rc = cib_revision_unsupported;
 		}
 
 	} else if(cur_revision == NULL) {
 		crm_info("Updating CIB revision to %s", new_revision);
 		crm_xml_add(cib_copy, XML_ATTR_CIB_REVISION, new_revision);
 
 	} else {
 		/* make sure we end up with the right value in the end */
 		crm_xml_add(cib_update, XML_ATTR_CIB_REVISION, cur_revision);
 	} 
 	
 	crm_free(new_revision);
 	return rc;
 }
 
 
 enum cib_errors
 sync_our_cib(HA_Message *request, gboolean all) 
 {
 	enum cib_errors result      = cib_ok;
 	const char *host            = cl_get_string(request, F_ORIG);
 	const char *op              = cl_get_string(request, F_CIB_OPERATION);
 
 	crm_data_t *sync_data       = create_cib_fragment(the_cib,XML_TAG_CIB);
 	HA_Message *replace_request = cib_msg_copy(request, FALSE);
 	
 	CRM_DEV_ASSERT(sync_data != NULL);
 	CRM_DEV_ASSERT(replace_request != NULL);
 	
 	crm_info("Syncing CIB to %s", all?"all peers":host);
 	if(all == FALSE && host == NULL) {
 		crm_log_message(LOG_ERR, request);
 	}
 	
 	/* remove the all == FALSE condition
 	 *
 	 * sync_from was failing, the local client wasnt being notified
 	 *    because it didnt know it was a reply
 	 * setting this does not prevent the other nodes from applying it
 	 *    if all == TRUE
 	 */
 	if(host != NULL) {
 		ha_msg_add(replace_request, F_CIB_ISREPLY, host);
 	}
 	ha_msg_mod(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE);
 	ha_msg_add(replace_request, "original_"F_CIB_OPERATION, op);
 	ha_msg_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
 	ha_msg_addstruct(replace_request, F_CIB_CALLDATA, sync_data);
 	
 	if(send_ha_message(hb_conn, replace_request, all?NULL:host, FALSE) == FALSE) {
 		result = cib_not_connected;
 	}
 	ha_msg_del(replace_request);
 	free_xml(sync_data);
 	return result;
 }
diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c
index 97815f3687..23f8c38734 100644
--- a/crm/crmd/callbacks.c
+++ b/crm/crmd/callbacks.c
@@ -1,619 +1,619 @@
 /* 
  * 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 <sys/param.h>
 #include <crm/crm.h>
 #include <string.h>
 #include <crmd_fsa.h>
 
 #include <heartbeat.h>
 
 #include <hb_api.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/msg.h>
 #include <crm/cib.h>
 
 #include <crmd.h>
 #include <crmd_messages.h>
 #include <crmd_callbacks.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 GHashTable *crmd_peer_state = NULL;
 
 crm_data_t *find_xml_in_hamessage(const HA_Message * msg);
 void crmd_ha_connection_destroy(gpointer user_data);
 
 /* From join_dc... */
 extern gboolean check_join_state(
 	enum crmd_fsa_state cur_state, const char *source);
 
 
 /* #define MAX_EMPTY_CALLBACKS 20 */
 /* int empty_callbacks = 0; */
 
 gboolean
 crmd_ha_msg_dispatch(IPC_Channel *channel, gpointer user_data)
 {
 	int lpc = 0;
 	ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data;
 
 	while(lpc < 2 && hb_cluster->llc_ops->msgready(hb_cluster)) {
 		if(channel->ch_status != IPC_CONNECT) {
 			/* there really is no point continuing */
 			break;
 		}
  		lpc++; 
 		/* invoke the callbacks but dont block */
 		hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
 	}
 
 	crm_debug_3("%d HA messages dispatched", lpc);
 	G_main_set_trigger(fsa_source);
 	
 	if (channel && (channel->ch_status != IPC_CONNECT)) {
 		crm_crit("Lost connection to heartbeat service.");
 		return FALSE;
 	}
     
 	return TRUE;
 }
 
 
 void
 crmd_ha_msg_callback(const HA_Message * msg, void* private_data)
 {
 	ha_msg_input_t *new_input = NULL;
 	oc_node_t *from_node = NULL;
 	
 	const char *from = ha_msg_value(msg, F_ORIG);
 	const char *seq  = ha_msg_value(msg, F_SEQ);
 	const char *op   = ha_msg_value(msg, F_CRM_TASK);
 
 	const char *sys_to   = ha_msg_value(msg, F_CRM_SYS_TO);
 	const char *sys_from = ha_msg_value(msg, F_CRM_SYS_FROM);
 
 	CRM_DEV_ASSERT(from != NULL);
 
 	if(fsa_membership_copy == NULL) {
 		crm_debug("Ignoring HA messages until we are"
 			  " connected to the CCM (%s op from %s)", op, from);
 		crm_log_message_adv(
 			LOG_MSG, "HA[inbound]: Ignore (No CCM)", msg);
 		return;
 	}
 	
 	from_node = g_hash_table_lookup(fsa_membership_copy->members, from);
 
 	if(from_node == NULL) {
 		int level = LOG_DEBUG;
 		if(safe_str_eq(op, CRM_OP_VOTE)) {
 			level = LOG_WARNING;
 
 		} else if(AM_I_DC && safe_str_eq(op, CRM_OP_JOIN_ANNOUNCE)) {
 			level = LOG_WARNING;
 
 		} else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) {
 			level = LOG_WARNING;
 		}
 		do_crm_log(level, __FILE__, __FUNCTION__, 
 			   "Ignoring HA message (op=%s) from %s: not in our"
 			   " membership list (size=%d)", op, from,
 			   g_hash_table_size(fsa_membership_copy->members));
 		
 		crm_log_message_adv(LOG_MSG, "HA[inbound]: CCM Discard", msg);
 
 	} else if(AM_I_DC
 	   && safe_str_eq(sys_from, CRM_SYSTEM_DC)
 	   && safe_str_neq(from, fsa_our_uname)) {
 		crm_err("Another DC detected: %s (op=%s)", from, op);
 		crm_log_message_adv(
 			LOG_WARNING, "HA[inbound]: Duplicate DC", msg);
 		new_input = new_ha_msg_input(msg);
 
 		/* make sure the election happens NOW */
 		register_fsa_error_adv(C_FSA_INTERNAL, I_ELECTION, NULL,
 				       new_input, __FUNCTION__);
 		
 #if 0
 		/* still thinking about this one...
 		 * could create a timing issue if we dont notice the
 		 * election before a new DC is elected.
 		 */
 	} else if(fsa_our_dc != NULL
 		  && safe_str_eq(sys_from, CRM_SYSTEM_DC)
 		  && safe_str_neq(from, fsa_our_dc)) {
 		crm_warn("Ignoring message from wrong DC: %s vs. %s ",
 			 from, fsa_our_dc);
 		crm_log_message_adv(LOG_WARNING, "HA[inbound]: wrong DC", msg);
 #endif
 	} else if(safe_str_eq(sys_to, CRM_SYSTEM_DC) && AM_I_DC == FALSE) {
 		crm_debug_2("Ignoring message for the DC [F_SEQ=%s]", seq);
 		crm_log_message_adv(LOG_DEBUG_4, "HA[inbound]: ignore", msg);
 		return;
 
 	} else if(safe_str_eq(from, fsa_our_uname)
 		  && safe_str_eq(op, CRM_OP_VOTE)) {
 		crm_log_message_adv(LOG_DEBUG_4, "HA[inbound]", msg);
 		crm_debug_2("Ignoring our own vote [F_SEQ=%s]: own vote", seq);
 		return;
 		
 	} else if(AM_I_DC && safe_str_eq(op, CRM_OP_HBEAT)) {
 		crm_debug_2("Ignoring our own heartbeat [F_SEQ=%s]", seq);
 		crm_log_message_adv(LOG_DEBUG_4, "HA[inbound]: own heartbeat", msg);
 		return;
 
 	} else {
 		crm_debug_3("Processing message");
 		crm_log_message_adv(LOG_MSG, "HA[inbound]", msg);
 		new_input = new_ha_msg_input(msg);
 		register_fsa_input(C_HA_MESSAGE, I_ROUTER, new_input);
 	}
 
 	
 #if 0
 	if(ha_msg_value(msg, XML_ATTR_REFERENCE) == NULL) {
 		ha_msg_add(new_input->msg, XML_ATTR_REFERENCE, seq);
 	}
 #endif
 
 	delete_ha_msg_input(new_input);
 
 	return;
 }
 
 /*
  * Apparently returning TRUE means "stay connected, keep doing stuff".
  * Returning FALSE means "we're all done, close the connection"
  */
 gboolean
 crmd_ipc_msg_callback(IPC_Channel *client, gpointer user_data)
 {
 	int lpc = 0;
 	IPC_Message *msg = NULL;
 	ha_msg_input_t *new_input = NULL;
 	crmd_client_t *curr_client = (crmd_client_t*)user_data;
 	gboolean stay_connected = TRUE;
 	
 	crm_debug_2("Processing IPC message from %s",
 		   curr_client->table_key);
 
 	while(lpc == 0 && client->ops->is_message_pending(client)) {
 		if (client->ch_status == IPC_DISCONNECT) {
 			/* The message which was pending for us is that
 			 * the IPC status is now IPC_DISCONNECT */
 			break;
 		}
 		if (client->ops->recv(client, &msg) != IPC_OK) {
 			perror("Receive failure:");
 			crm_err("[%s] [receive failure]",
 				curr_client->table_key);
 			stay_connected = FALSE;
 			break;
 			
 		} else if (msg == NULL) {
 			crm_err("[%s] [no message this time]",
 				curr_client->table_key);
 			continue;
 		}
 
 		lpc++;
 		new_input = new_ipc_msg_input(msg);
 		msg->msg_done(msg);
 		
 		crm_debug_2("Processing msg from %s", curr_client->table_key);
 		crm_log_message_adv(LOG_MSG, "CRMd[inbound]", new_input->msg);
 		if(crmd_authorize_message(new_input, curr_client)) {
 			register_fsa_input(C_IPC_MESSAGE, I_ROUTER, new_input);
 		}
 		delete_ha_msg_input(new_input);
 		
 		msg = NULL;
 		new_input = NULL;
 	}
 	
 	crm_debug_2("Processed %d messages", lpc);
     
 	if (client->ch_status == IPC_DISCONNECT) {
 		stay_connected = FALSE;
 		process_client_disconnect(curr_client);
 	}
 
 	G_main_set_trigger(fsa_source);
 	return stay_connected;
 }
 
 
 
 gboolean
 lrm_dispatch(IPC_Channel*src_not_used, gpointer user_data)
 {
 	int num_msgs = 0;
 	ll_lrm_t *lrm = (ll_lrm_t*)user_data;
 	crm_debug_3("received callback");
 	num_msgs = lrm->lrm_ops->rcvmsg(lrm, FALSE);
 	if(num_msgs < 1) {
 		crm_err("lrm->lrm_ops->rcvmsg() failed, connection lost?");
 		clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED);
 		register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
 		return FALSE;
 	}
 	return TRUE;
 }
 
 void
 lrm_op_callback(lrm_op_t* op)
 {
 	CRM_DEV_ASSERT(op != NULL);
 	if(crm_assert_failed) {
 		return;
 	}
 	
 	crm_debug("received callback: %s/%s (%s)",
 		  op->op_type, op->rsc_id, op_status2text(op->op_status));
 
 	/* Make sure the LRM events are received in order */
 	register_fsa_input_later(C_LRM_OP_CALLBACK, I_LRM_EVENT, op);
 }
 
 void
 crmd_ha_status_callback(
 	const char *node, const char * status,	void* private_data)
 {
 	crm_data_t *update = NULL;
 
 	crm_debug_3("received callback");
 	crm_notice("Status update: Node %s now has status [%s]",node,status);
 
 	if(safe_str_neq(status, DEADSTATUS)) {
 		crm_debug_3("nstatus callback was not for a dead node");
 		return;
 	}
 
 	/* this node is taost */
 	update = create_node_state(
 		node, node, status, NULL, NULL, NULL, NULL, __FUNCTION__);
 	
 	crm_xml_add(update, XML_CIB_ATTR_CLEAR_SHUTDOWN, XML_BOOLEAN_TRUE);
 	crm_xml_add(update, XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS);
 
 	/* this change should not be broadcast */
 	update_local_cib(create_cib_fragment(update, XML_CIB_TAG_STATUS));
 	G_main_set_trigger(fsa_source);
 	free_xml(update);
 }
 
 
 void
 crmd_client_status_callback(const char * node, const char * client,
 		 const char * status, void * private)
 {
 	const char    *join = NULL;
 	const char   *extra = NULL;
 	crm_data_t *  update = NULL;
 
 	crm_debug_3("received callback");
 	if(safe_str_neq(client, CRM_SYSTEM_CRMD)) {
 		return;
 	}
 
 	if(safe_str_eq(status, JOINSTATUS)){
 		status = ONLINESTATUS;
 /* 		extra  = XML_CIB_ATTR_CLEAR_SHUTDOWN; */
 
 	} else if(safe_str_eq(status, LEAVESTATUS)){
 		status = OFFLINESTATUS;
 		join   = CRMD_STATE_INACTIVE;
 		extra  = XML_CIB_ATTR_CLEAR_SHUTDOWN;
 	}
 	
 	set_bit_inplace(fsa_input_register, R_PEER_DATA);
 	g_hash_table_replace(
 		crmd_peer_state, crm_strdup(node), crm_strdup(status));
 
 	if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
 		return;
 	} else if(fsa_state == S_STOPPING) {
 		return;
 	}
 
 	crm_notice("Status update: Client %s/%s now has status [%s]",
 		   node, client, status);
 
 	if(safe_str_eq(node, fsa_our_dc)
 	   && safe_str_eq(status, OFFLINESTATUS)) {
 		/* did our DC leave us */
 		crm_info("Got client status callback - our DC is dead");
 		register_fsa_input(C_CRMD_STATUS_CALLBACK, I_ELECTION, NULL);
 		
 	} else {
 		crm_data_t *fragment = NULL;
 		crm_debug_3("Got client status callback");
 		update = create_node_state(
 			node, node, NULL, NULL, status, join, NULL,
 			__FUNCTION__);
 		
 		crm_xml_add(update, extra, XML_BOOLEAN_TRUE);
 		if(safe_str_eq(extra, XML_CIB_ATTR_CLEAR_SHUTDOWN)) {
 			crm_xml_add(update, XML_CIB_ATTR_REPLACE,
 				    XML_TAG_TRANSIENT_NODEATTRS);
 		}
 		
 		fragment = create_cib_fragment(update, XML_CIB_TAG_STATUS);
 
 		/* it is safe to keep these updates on the local node
 		 * each node updates their own CIB
 		 */
-		fsa_cib_conn->cmds->modify(
+		fsa_cib_conn->cmds->update(
 			fsa_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL,
 			cib_inhibit_bcast|cib_scope_local|cib_quorum_override);
 
 		free_xml(fragment);
 		free_xml(update);
 
 		if(AM_I_DC && safe_str_eq(status, OFFLINESTATUS)) {
 
 			g_hash_table_remove(confirmed_nodes,  node);
 			g_hash_table_remove(finalized_nodes,  node);
 			g_hash_table_remove(integrated_nodes, node);
 			g_hash_table_remove(welcomed_nodes,   node);
 			
 			check_join_state(fsa_state, __FUNCTION__);
 		}
 	}
 	
 	G_main_set_trigger(fsa_source);
 }
 
 void
 crmd_ha_connection_destroy(gpointer user_data)
 {
 	if(is_set(fsa_input_register, R_HA_DISCONNECTED)) {
 		/* we signed out, so this is expected */
 		return;
 	}
 
 	crm_crit("Heartbeat has left us");
 	/* this is always an error */
 	/* feed this back into the FSA */
 	register_fsa_input(C_HA_DISCONNECT, I_ERROR, NULL);
 }
 
 
 gboolean
 crmd_client_connect(IPC_Channel *client_channel, gpointer user_data)
 {
 	if (client_channel == NULL) {
 		crm_err("Channel was NULL");
 
 	} else if (client_channel->ch_status == IPC_DISCONNECT) {
 		crm_err("Channel was disconnected");
 
 	} else {
 		crmd_client_t *blank_client = NULL;
 		crm_debug_3("Channel connected");
 		crm_malloc0(blank_client, sizeof(crmd_client_t));
 	
 		if (blank_client == NULL) {
 			return FALSE;
 		}
 		
 		client_channel->ops->set_recv_qlen(client_channel, 100);
 		client_channel->ops->set_send_qlen(client_channel, 100);
 	
 		blank_client->client_channel = client_channel;
 		blank_client->sub_sys   = NULL;
 		blank_client->uuid      = NULL;
 		blank_client->table_key = NULL;
 	
 		blank_client->client_source =
 			G_main_add_IPC_Channel(
 				G_PRIORITY_LOW, client_channel,
 				FALSE,  crmd_ipc_msg_callback,
 				blank_client, default_ipc_connection_destroy);
 	}
     
 	return TRUE;
 }
 
 
 gboolean ccm_dispatch(int fd, gpointer user_data)
 {
 	int rc = 0;
 	oc_ev_t *ccm_token = (oc_ev_t*)user_data;
 	gboolean was_error = FALSE;
 	
 	crm_debug_3("received callback");	
 	rc = oc_ev_handle_event(ccm_token);
 
 	if(rc != 0) {
 		if(is_set(fsa_input_register, R_CCM_DISCONNECTED) == FALSE) {
 			/* we signed out, so this is expected */
 			register_fsa_input(C_CCM_CALLBACK, I_ERROR, NULL);
 			crm_err("CCM connection appears to have failed: rc=%d.",
 				rc);
 		}
 		was_error = TRUE;
 	}
 
 	G_main_set_trigger(fsa_source);
 	return !was_error;
 }
 
 static gboolean fsa_have_quorum = FALSE;
 
 void 
 crmd_ccm_msg_callback(
 	oc_ed_t event, void *cookie, size_t size, const void *data)
 {
 	int instance = -1;
 	gboolean update_cache = FALSE;
 	struct crmd_ccm_data_s *event_data = NULL;
 	const oc_ev_membership_t *membership = data;
 
 	gboolean update_quorum = FALSE;
 	gboolean trigger_transition = FALSE;
 
 	crm_debug_3("received callback");
 
 	if(data != NULL) {
 		instance = membership->m_instance;
 	}
 	
 	crm_info("Quorum %s after event=%s (id=%d)", 
 		 ccm_have_quorum(event)?"(re)attained":"lost",
 		 ccm_event_name(event), instance);
 	
 	switch(event) {
 		case OC_EV_MS_NEW_MEMBERSHIP:
 		case OC_EV_MS_INVALID:/* fall through */
 			update_cache = TRUE;
 			update_quorum = TRUE;
 			break;
 		case OC_EV_MS_NOT_PRIMARY:
 #if UNTESTED
 			if(AM_I_DC == FALSE) {
 				break;
 			}
 			/* tell the TE to pretend it had completed and stop */
 			/* side effect: we'll end up in S_IDLE */
 			register_fsa_action(A_TE_HALT, TRUE);
 #endif
 			break;
 		case OC_EV_MS_PRIMARY_RESTORED:
 			fsa_membership_copy->id = instance;
 			if(AM_I_DC && need_transition(fsa_state)) {
 				trigger_transition = TRUE;
 			}
 			break;
 		case OC_EV_MS_EVICTED:
 			update_quorum = TRUE;
 			register_fsa_input(C_FSA_INTERNAL, I_STOP, NULL);
 			break;
 		default:
 			crm_err("Unknown CCM event: %d", event);
 	}
 
 	if(update_quorum && ccm_have_quorum(event) == FALSE) {
 		/* did we just loose quorum? */
 		if(fsa_have_quorum && need_transition(fsa_state)) {
 			crm_info("Quorum lost: triggering transition (%s)",
 				 ccm_event_name(event));
 			trigger_transition = TRUE;
 		}
 		fsa_have_quorum = FALSE;
 			
 	} else if(update_quorum)  {
 		crm_debug_2("Updating quorum after event %s",
 			    ccm_event_name(event));
 		fsa_have_quorum = TRUE;
 	}
 
 	if(trigger_transition) {
 		crm_debug_2("Scheduling transition after event %s",
 			    ccm_event_name(event));
 		/* make sure that when we query the CIB that it has
 		 * the changes that triggered the transition
 		 */
 		switch(event) {
 			case OC_EV_MS_NEW_MEMBERSHIP:
 			case OC_EV_MS_INVALID:
 			case OC_EV_MS_PRIMARY_RESTORED:
 				fsa_membership_copy->id = instance;
 				break;
 			default:
 				break;
 		}
 		if(update_cache == FALSE) {
 			/* a stand-alone transition */
 			register_fsa_action(A_TE_CANCEL);
 		}
 	}
 	if(update_cache) {
 		crm_debug_2("Updating cache after event %s",
 			    ccm_event_name(event));
 
 		crm_malloc0(event_data, sizeof(struct crmd_ccm_data_s));
 		if(event_data == NULL) { return; }
 		
 		event_data->event = event;
 		if(data != NULL) {
 			event_data->oc = copy_ccm_oc_data(data);
 		}
 		register_fsa_input_adv(
 			C_CCM_CALLBACK, I_CCM_EVENT, event_data,
 			trigger_transition?A_TE_CANCEL:A_NOTHING,
 			FALSE, __FUNCTION__);
 		
 		if (event_data->oc) {
 			crm_free(event_data->oc);
 			event_data->oc = NULL;
 		}
 		crm_free(event_data);
 	} 
 	
 	oc_ev_callback_done(cookie);
 	return;
 }
 
 void
 crmd_cib_connection_destroy(gpointer user_data)
 {
 	if(is_set(fsa_input_register, R_SHUTDOWN)
 	   || is_set(fsa_input_register, R_CIB_CONNECTED)) {
 		crm_info("Connection to the CIB terminated...");
 		return;
 	}
 
 	/* eventually this will trigger a reconnect, not a shutdown */ 
 	crm_err("Connection to the CIB terminated...");
 	register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
 	clear_bit_inplace(fsa_input_register, R_CIB_CONNECTED);
 	
 	return;
 }
 
 longclock_t fsa_start = 0;
 longclock_t fsa_stop = 0;
 longclock_t fsa_diff = 0;
 
 gboolean
 crm_fsa_trigger(gpointer user_data) 
 {
 	unsigned int fsa_diff_ms = 0;
 	if(fsa_diff_max_ms > 0) {
 		fsa_start = time_longclock();
 	}
 	s_crmd_fsa(C_FSA_INTERNAL);
 	if(fsa_diff_max_ms > 0) {
 		fsa_stop = time_longclock();
 		fsa_diff = sub_longclock(fsa_stop, fsa_start);
 		fsa_diff_ms = longclockto_ms(fsa_diff);
 		if(fsa_diff_ms > fsa_diff_max_ms) {
 			crm_warn("FSA took %dms to complete", fsa_diff_ms);
 
 		} else if(fsa_diff_ms > fsa_diff_warn_ms) {
 			crm_warn("FSA took %dms to complete", fsa_diff_ms);
 		}
 		
 	}
 	return TRUE;	
 }
diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c
index 72e335c8c7..85d346c28e 100644
--- a/crm/crmd/ccm.c
+++ b/crm/crmd/ccm.c
@@ -1,658 +1,658 @@
-/* $Id: ccm.c,v 1.89 2005/09/28 07:42:58 andrew Exp $ */
+/* $Id: ccm.c,v 1.90 2005/10/12 18:28:22 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
  */
 
 /* put these first so that uuid_t is defined without conflicts */
 #include <portability.h>
 #include <ocf/oc_event.h>
 #include <ocf/oc_membership.h>
 
 #include <clplumbing/GSource.h>
 #include <string.h>
 
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crmd_messages.h>
 #include <crmd_fsa.h>
 #include <fsa_proto.h>
 #include <crmd_callbacks.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
 
 int register_with_ccm(ll_cluster_t *hb_cluster);
 
 void msg_ccm_join(const HA_Message *msg, void *foo);
 
 void crmd_ccm_msg_callback(oc_ed_t event,
 			     void *cookie,
 			     size_t size,
 			     const void *data);
 
 gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data);
 void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data);
 
 #define CCM_EVENT_DETAIL 0
 #define CCM_EVENT_DETAIL_PARTIAL 1
 
 oc_ev_t *fsa_ev_token;
 int num_ccm_register_fails = 0;
 int max_ccm_register_fails = 30;
 
 /*	 A_CCM_CONNECT	*/
 enum crmd_fsa_input
 do_ccm_control(long long action,
 		enum crmd_fsa_cause cause,
 		enum crmd_fsa_state cur_state,
 		enum crmd_fsa_input current_input,
 		fsa_data_t *msg_data)
 {
 	int      ret;
  	int	 fsa_ev_fd; 
 	gboolean did_fail = FALSE;
 	
 	if(action & A_CCM_DISCONNECT){
 		set_bit_inplace(fsa_input_register, R_CCM_DISCONNECTED);
 		oc_ev_unregister(fsa_ev_token);
 	}
 
 	if(action & A_CCM_CONNECT) {
 		crm_debug_3("Registering with CCM");
 		clear_bit_inplace(fsa_input_register, R_CCM_DISCONNECTED);
 		ret = oc_ev_register(&fsa_ev_token);
 		if (ret != 0) {
 			crm_warn("CCM registration failed");
 			did_fail = TRUE;
 		}
 
 		if(did_fail == FALSE) {
 			crm_debug_3("Setting up CCM callbacks");
 			ret = oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS,
 						 crmd_ccm_msg_callback, NULL);
 			if (ret != 0) {
 				crm_warn("CCM callback not set");
 				did_fail = TRUE;
 			}
 		}
 		if(did_fail == FALSE) {
 			oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/);
 			
 			crm_debug_3("Activating CCM token");
 			ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd);
 			if (ret != 0){
 				crm_warn("CCM Activation failed");
 				did_fail = TRUE;
 			}
 		}
 
 		if(did_fail) {
 			num_ccm_register_fails++;
 			oc_ev_unregister(fsa_ev_token);
 			
 			if(num_ccm_register_fails < max_ccm_register_fails) {
 				crm_warn("CCM Connection failed"
 					 " %d times (%d max)",
 					 num_ccm_register_fails,
 					 max_ccm_register_fails);
 				
 				crm_timer_start(wait_timer);
 				crmd_fsa_stall(NULL);
 				return I_NULL;
 				
 			} else {
 				crm_err("CCM Activation failed %d (max) times",
 					num_ccm_register_fails);
 				register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
 				return I_NULL;
 			}
 		}
 		
 
 		crm_info("CCM Activation passed... all set to go!");
 
 		G_main_add_fd(G_PRIORITY_HIGH, fsa_ev_fd, FALSE, ccm_dispatch,
 			      fsa_ev_token, default_ipc_connection_destroy);
 		
 	}
 
 	if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) {
 		crm_err("Unexpected action %s in %s",
 		       fsa_action2string(action), __FUNCTION__);
 	}
 	
 	return I_NULL;
 }
 
 
 /*	 A_CCM_EVENT	*/
 enum crmd_fsa_input
 do_ccm_event(long long action,
 	     enum crmd_fsa_cause cause,
 	     enum crmd_fsa_state cur_state,
 	     enum crmd_fsa_input current_input,
 	     fsa_data_t *msg_data)
 {
 	enum crmd_fsa_input return_input = I_NULL;
 	oc_ed_t event;
 	const oc_ev_membership_t *oc = NULL;
 	struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
 	
 	if(ccm_data == NULL) {
 		crm_err("No data provided to FSA function");
 		register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
 		return I_NULL;
 
 	} else if(msg_data->fsa_cause != C_CCM_CALLBACK) {
 		crm_err("FSA function called in response to incorect input");
 		register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
 		return I_NULL;
 	}
 
 	event = ccm_data->event;
 	oc = ccm_data->oc;
 	
 	ccm_event_detail(oc, event);
 
 	if (OC_EV_MS_EVICTED == event) {
 		/* todo: drop back to S_PENDING instead */
 		/* get out... NOW!
 		 *
 		 * go via the error recovery process so that HA will
 		 *    restart us if required
 		 */
 		register_fsa_error(cause, I_ERROR, msg_data->data);
 		return I_NULL;
 	}
 	
 	CRM_DEV_ASSERT(oc->m_n_in != 0 || oc->m_n_out != 0);
 	
 	if(AM_I_DC) {
 		/* Membership changed, remind everyone we're here.
 		 * This will aid detection of duplicate DCs
 		 */
 		HA_Message *no_op = create_request(
 			CRM_OP_NOOP, NULL, NULL,
 			CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL);
 	
 		send_msg_via_ha(fsa_cluster_conn, no_op);
 
 	} else if(oc->m_n_out != 0) {
 		/* Possibly move this logic to ghash_update_cib_node() */
 		unsigned lpc = 0;
 		int offset = oc->m_out_idx;
 		for(lpc=0; lpc < oc->m_n_out; lpc++) {
 			const char *uname = oc->m_array[offset+lpc].node_uname;
 			if(uname == NULL) {
 				crm_err("CCM node had no name");
 				continue;
 				
 			} else if(safe_str_eq(uname, fsa_our_dc)) {
 				crm_warn("Our DC node (%s) left the cluster",
 					 uname);
 				register_fsa_input(cause, I_ELECTION, NULL);
 			}
 		}
 	}
 	
 	return return_input;
 }
 
 /*	 A_CCM_UPDATE_CACHE	*/
 /*
  * Take the opportunity to update the node status in the CIB as well
  */
 
 enum crmd_fsa_input
 do_ccm_update_cache(long long action,
 		    enum crmd_fsa_cause cause,
 		    enum crmd_fsa_state cur_state,
 		    enum crmd_fsa_input current_input,
 		    fsa_data_t *msg_data)
 {
 	enum crmd_fsa_input next_input = I_NULL;
 	unsigned int	lpc;
 	int		offset;
 	GHashTable *members = NULL;
 	oc_ed_t event;
 	const oc_ev_membership_t *oc = NULL;
 	oc_node_list_t *tmp = NULL, *membership_copy = NULL;
 	struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
 
 	if(ccm_data == NULL) {
 		crm_err("No data provided to FSA function");
 		register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
 		return I_NULL;
 	}
 
 	event = ccm_data->event;
 	oc = ccm_data->oc;
 
 	crm_debug_2("Updating CCM cache after a \"%s\" event.", 
 		 ccm_event_name(event));
 
 	crm_debug_2("instance=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
 		  "new_idx=%d, old_idx=%d",
 		  oc->m_instance,
 		  oc->m_n_member,
 		  oc->m_n_in,
 		  oc->m_n_out,
 		  oc->m_memb_idx,
 		  oc->m_in_idx,
 		  oc->m_out_idx);
 #define ALAN_DEBUG 1
 #ifdef ALAN_DEBUG
 	{
 		/*
 		 *	Size	(Size + 2) / 2
 		 *
 		 *	3	(3+2)/2	= 5 / 2 = 2
 		 *	4	(4+2)/2	= 6 / 2 = 3
 		 *	5	(5+2)/2	= 7 / 2 = 3
 		 *	6	(6+2)/2	= 8 / 2 = 4
 		 *	7	(7+2)/2	= 9 / 2 = 4
 		 */
 		unsigned int		clsize = (oc->m_out_idx - oc->m_n_member);
 		unsigned int		plsize = (clsize + 2)/2;
 		gboolean	plurality = (oc->m_n_member >= plsize);
 		gboolean	Q = ccm_have_quorum(event);
 
 		if(clsize == 2) {
 			if (!Q) {
 				crm_err("2 nodes w/o quorum");
 			}
 			
 		} else if(Q && !plurality) {
 			crm_err("Quorum w/o plurality (%d/%d nodes)",
 				oc->m_n_member, clsize);
 		} else if(plurality && !Q) {
 			crm_err("Plurality w/o Quorum (%d/%d nodes)",
 				oc->m_n_member, clsize);
 		} else {
 			crm_debug_2("Quorum(%s) and plurality (%d/%d) agree.",
 				    Q?"true":"false", oc->m_n_member, clsize);
 		}
 		
 	}
 #endif
 		
 
 	crm_malloc0(membership_copy, sizeof(oc_node_list_t));
 
 	if(membership_copy == NULL) {
 		crm_crit("Couldnt create membership copy - out of memory");
 		register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 		return I_NULL;
 	}
 
 	membership_copy->id = oc->m_instance;
 	membership_copy->last_event = event;
 
 	crm_debug_3("Copying members");
 
 	/*--*-- All Member Nodes --*--*/
 	offset = oc->m_memb_idx;
 	membership_copy->members_size = oc->m_n_member;
 
 	if(membership_copy->members_size > 0) {
 		membership_copy->members =
 			g_hash_table_new(g_str_hash, g_str_equal);
 		members = membership_copy->members;
 		
 		for(lpc=0; lpc < membership_copy->members_size; lpc++) {
 			oc_node_t *member = NULL;
 			crm_debug_3("Copying member %d", lpc);
 			crm_malloc0(member, sizeof(oc_node_t));
 			
 			if(member == NULL) {
 				continue;
 			}
 
 			member->node_id =
 				oc->m_array[offset+lpc].node_id;
 			
 			member->node_born_on =
 				oc->m_array[offset+lpc].node_born_on;
 			
 			member->node_uname = NULL;
 			if(oc->m_array[offset+lpc].node_uname != NULL) {
 				member->node_uname =
 					crm_strdup(oc->m_array[offset+lpc].node_uname);
 			} else {
 				crm_err("Node %d had a NULL uname",
 					member->node_id);
 			}
 			g_hash_table_insert(
 				members, member->node_uname, member);	
 		}
 		
 	} else {
 		membership_copy->members = NULL;
 	}
 	
 	crm_debug_3("Copying new members");
 
 	/*--*-- New Member Nodes --*--*/
 	offset = oc->m_in_idx;
 	membership_copy->new_members_size = oc->m_n_in;
 
 	if(membership_copy->new_members_size > 0) {
 		membership_copy->new_members =
 			g_hash_table_new(g_str_hash, g_str_equal);
 		members = membership_copy->new_members;
 		
 		for(lpc=0; lpc < membership_copy->new_members_size; lpc++) {
 			oc_node_t *member = NULL;
 			crm_malloc0(member, sizeof(oc_node_t));
 
 			if(member == NULL) {
 				continue;
 			}
 			
 			member->node_uname = NULL;
 			member->node_id = oc->m_array[offset+lpc].node_id;
 			member->node_born_on =
 				oc->m_array[offset+lpc].node_born_on;
 
 			if(oc->m_array[offset+lpc].node_uname != NULL) {
 				member->node_uname =
 					crm_strdup(oc->m_array[offset+lpc].node_uname);
 			} else {
 				crm_err("Node %d had a NULL uname",
 					member->node_id);
 			}
 			g_hash_table_insert(
 				members, member->node_uname, member);	
 
 			g_hash_table_insert(members, member->node_uname, member);
 		}
 
 	} else {
 		membership_copy->new_members = NULL;
 	}
 	
 	crm_debug_3("Copying dead members");
 
 	/*--*-- Recently Dead Member Nodes --*--*/
 	offset = oc->m_out_idx;
 	membership_copy->dead_members_size = oc->m_n_out;
 	if(membership_copy->dead_members_size > 0) {
 		membership_copy->dead_members =
 			g_hash_table_new(g_str_hash, g_str_equal);
 
 		members = membership_copy->dead_members;
 
 		for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) {
 			oc_node_t *member = NULL;
 			crm_malloc0(member, sizeof(oc_node_t));
 
 			if(member == NULL) {
 				continue;
 			}
 			
 			member->node_id =
 				oc->m_array[offset+lpc].node_id;
 			
 			member->node_born_on =
 				oc->m_array[offset+lpc].node_born_on;
 			
 			member->node_uname = NULL;
 			CRM_DEV_ASSERT(oc->m_array[offset+lpc].node_uname != NULL);
 			
 			if(oc->m_array[offset+lpc].node_uname == NULL) {
 				continue;
 			}
 			
 			member->node_uname =
 				crm_strdup(oc->m_array[offset+lpc].node_uname);
 
 			g_hash_table_insert(
 				members, member->node_uname, member);	
 
 			g_hash_table_insert(members, member->node_uname, member);
 		}
 
 	} else {
 		membership_copy->dead_members = NULL;
 	}
 
 	tmp = fsa_membership_copy;
 	fsa_membership_copy = membership_copy;
 	crm_debug_2("Updated membership cache with %d (%d new, %d lost) members",
 		    g_hash_table_size(fsa_membership_copy->members),
 		    g_hash_table_size(fsa_membership_copy->new_members),
 		    g_hash_table_size(fsa_membership_copy->dead_members));
 	
 	/* Free the old copy */
 	if(tmp != NULL) {
 		if(tmp->members != NULL)
 			g_hash_table_foreach_remove(
 				tmp->members, ghash_node_clfree, NULL);
 		if(tmp->new_members != NULL)
 			g_hash_table_foreach_remove(
 				tmp->new_members, ghash_node_clfree, NULL);
 		if(tmp->dead_members != NULL)
 			g_hash_table_foreach_remove(
 				tmp->dead_members, ghash_node_clfree, NULL);
 		crm_free(tmp);
 	}
 	crm_debug_3("Free'd old copies");
 
 	set_bit_inplace(fsa_input_register, R_CCM_DATA);
 
 	if(cur_state != S_STOPPING) {
 		crm_debug_3("Updating the CIB from CCM cache");
 		do_update_cib_nodes(NULL, FALSE);
 	}
 
 	
 	return next_input;
 }
 
 void
 ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event)
 {
 	int lpc;
 	gboolean member = FALSE;
 	member = FALSE;
 
 	crm_debug_2("-----------------------");
 	crm_info("%s: trans=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
 		 "new_idx=%d, old_idx=%d",
 		 ccm_event_name(event),
 		 oc->m_instance,
 		 oc->m_n_member,
 		 oc->m_n_in,
 		 oc->m_n_out,
 		 oc->m_memb_idx,
 		 oc->m_in_idx,
 		 oc->m_out_idx);
 	
 #if !CCM_EVENT_DETAIL_PARTIAL
 	for(lpc=0; lpc < oc->m_n_member; lpc++) {
 		crm_info("\tCURRENT: %s [nodeid=%d, born=%d]",
 		       oc->m_array[oc->m_memb_idx+lpc].node_uname,
 		       oc->m_array[oc->m_memb_idx+lpc].node_id,
 		       oc->m_array[oc->m_memb_idx+lpc].node_born_on);
 
 		if(safe_str_eq(fsa_our_uname,
 			       oc->m_array[oc->m_memb_idx+lpc].node_uname)) {
 			member = TRUE;
 		}
 	}
 	if (member == FALSE) {
 		crm_warn("MY NODE IS NOT IN CCM THE MEMBERSHIP LIST");
 	}
 #endif
 	for(lpc=0; lpc<(int)oc->m_n_in; lpc++) {
 		crm_info("\tNEW:     %s [nodeid=%d, born=%d]",
 		       oc->m_array[oc->m_in_idx+lpc].node_uname,
 		       oc->m_array[oc->m_in_idx+lpc].node_id,
 		       oc->m_array[oc->m_in_idx+lpc].node_born_on);
 	}
 	
 	for(lpc=0; lpc<(int)oc->m_n_out; lpc++) {
 		crm_info("\tLOST:    %s [nodeid=%d, born=%d]",
 		       oc->m_array[oc->m_out_idx+lpc].node_uname,
 		       oc->m_array[oc->m_out_idx+lpc].node_id,
 		       oc->m_array[oc->m_out_idx+lpc].node_born_on);
 		if(fsa_our_uname != NULL
 		   && 0 == strcmp(fsa_our_uname,
 			     oc->m_array[oc->m_out_idx+lpc].node_uname)) {
 			crm_err("We're not part of the cluster anymore");
 		}
 	}
 	
 	crm_debug_2("-----------------------");
 	
 }
 
 int
 register_with_ccm(ll_cluster_t *hb_cluster)
 {
 	return 0;
 }
 
 void 
 msg_ccm_join(const HA_Message *msg, void *foo)
 {
 	
 	crm_debug_2("###### Received ccm_join message...");
 	if (msg != NULL)
 	{
 		crm_debug_2("[type=%s]",
 			    ha_msg_value(msg, F_TYPE));
 		crm_debug_2("[orig=%s]",
 			    ha_msg_value(msg, F_ORIG));
 		crm_debug_2("[to=%s]",
 			    ha_msg_value(msg, F_TO));
 		crm_debug_2("[status=%s]",
 			    ha_msg_value(msg, F_STATUS));
 		crm_debug_2("[info=%s]",
 			    ha_msg_value(msg, F_COMMENT));
 		crm_debug_2("[rsc_hold=%s]",
 			    ha_msg_value(msg, F_RESOURCES));
 		crm_debug_2("[stable=%s]",
 			    ha_msg_value(msg, F_ISSTABLE));
 		crm_debug_2("[rtype=%s]",
 			    ha_msg_value(msg, F_RTYPE));
 		crm_debug_2("[ts=%s]",
 			    ha_msg_value(msg, F_TIME));
 		crm_debug_2("[seq=%s]",
 			    ha_msg_value(msg, F_SEQ));
 		crm_debug_2("[generation=%s]",
 			    ha_msg_value(msg, F_HBGENERATION));
 		/*      crm_debug_2("[=%s]", ha_msg_value(msg, F_)); */
 	}
 	return;
 }
 
 struct update_data_s
 {
 		crm_data_t *updates;
 		const char *state;
 		const char *join;
 };
 
 crm_data_t*
 do_update_cib_nodes(crm_data_t *updates, gboolean overwrite)
 {
 	int call_options = cib_scope_local|cib_quorum_override;
 	struct update_data_s update_data;
 	crm_data_t *fragment = updates;
 	crm_data_t *tmp = NULL;
 	
 	if(updates == NULL) {
 		fragment = create_cib_fragment(NULL, NULL);
 		crm_xml_add(fragment, XML_ATTR_SECTION, XML_CIB_TAG_STATUS);
 	}
 
 	tmp = find_xml_node(fragment, XML_TAG_CIB, TRUE);
 	tmp = get_object_root(XML_CIB_TAG_STATUS, tmp);
 	CRM_DEV_ASSERT(tmp != NULL);
 	
 	update_data.updates = tmp;
 
 	update_data.state = XML_BOOLEAN_YES;
 	update_data.join  = NULL;
 	if(overwrite) {
 		crm_debug_2("Performing a join update based on CCM data");
 		update_data.join = CRMD_JOINSTATE_PENDING;
 		if(fsa_membership_copy->members != NULL) {
 			g_hash_table_foreach(fsa_membership_copy->members,
 					     ghash_update_cib_node, &update_data);
 		}
 		
 	} else {
 		call_options = call_options|cib_inhibit_bcast;
 		crm_debug_2("Inhibiting bcast for CCM updates");
 
 		if(fsa_membership_copy->members != NULL) {
 			g_hash_table_foreach(fsa_membership_copy->new_members,
 					     ghash_update_cib_node, &update_data);
 		}
 
 		update_data.state = XML_BOOLEAN_NO;
 		update_data.join  = CRMD_STATE_INACTIVE;
 		if(fsa_membership_copy->dead_members != NULL) {
 			g_hash_table_foreach(fsa_membership_copy->dead_members,
 					     ghash_update_cib_node, &update_data);
 		}		
 	}
 	
 	if(update_data.updates != NULL) {
-		fsa_cib_conn->cmds->modify(fsa_cib_conn, XML_CIB_TAG_STATUS,
+		fsa_cib_conn->cmds->update(fsa_cib_conn, XML_CIB_TAG_STATUS,
 					   fragment, NULL, call_options);
 		free_xml(fragment);
 	}
 
 	return NULL;
 }
 
 void
 ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data)
 {
 	crm_data_t *tmp1 = NULL;
 	const char *node_uname = (const char*)key;
 	struct update_data_s* data = (struct update_data_s*)user_data;
 
 	crm_debug_2("%s processing %s (%s)",
 		    __FUNCTION__, node_uname, data->state);
 
 	tmp1 = create_node_state(node_uname, node_uname,
 				 NULL, data->state, NULL, data->join,
 				 NULL, __FUNCTION__);
 
 	add_node_copy(data->updates, tmp1);
 	free_xml(tmp1);
 }
 
 gboolean
 ghash_node_clfree(gpointer key, gpointer value, gpointer user_data)
 {
 	/* value->node_uname is free'd as "key" */
 	if(key != NULL) {
 		crm_free(key);
 	}
 	if(value != NULL) {
 		crm_free(value);
 	}
 	return TRUE;
 }
diff --git a/crm/crmd/election.c b/crm/crmd/election.c
index 823d4eced8..d0c36bb014 100644
--- a/crm/crmd/election.c
+++ b/crm/crmd/election.c
@@ -1,358 +1,358 @@
 /* 
  * 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 <heartbeat.h>
 
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/crm.h>
 #include <crmd_fsa.h>
 #include <crmd_messages.h>
 #include <crmd_callbacks.h>
 #include <clplumbing/Gmain_timeout.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 uint highest_born_on = -1;
 
 /*	A_ELECTION_VOTE	*/
 enum crmd_fsa_input
 do_election_vote(long long action,
 		 enum crmd_fsa_cause cause,
 		 enum crmd_fsa_state cur_state,
 		 enum crmd_fsa_input current_input,
 		 fsa_data_t *msg_data)
 {
 	gboolean not_voting = FALSE;
 	HA_Message *vote = NULL;
 	
 	/* dont vote if we're in one of these states or wanting to shut down */
 	switch(cur_state) {
 		case S_RECOVERY:
 		case S_STOPPING:
 		case S_TERMINATE:
 			crm_warn("Not voting in election, we're in state %s",
 				 fsa_state2string(cur_state));
 			not_voting = TRUE;
 			break;
 		default:
 			break;
 	}
 
 	if(not_voting == FALSE) {
 		if(is_set(fsa_input_register, R_STARTING)) {
 			not_voting = TRUE;
 		}
 	}	
 
 	if(not_voting) {
 		if(AM_I_DC) {
 			register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL);
 
 		} else {
 			register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL);
 		}
 		return I_NULL;
 	}
 	
 	vote = create_request(
 		CRM_OP_VOTE, NULL, NULL,
 		CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
 
 	if(is_set(fsa_input_register, R_SHUTDOWN)) {
 		crm_warn("Not voting in election, we're shutting down");
 		cl_msg_remove(vote, F_CRM_VERSION);
 	}
 
 	send_request(vote, NULL);
 	if(cur_state == S_ELECTION || cur_state == S_RELEASE_DC) {
 		crm_timer_start(election_timeout);		
 
 	} else if(cur_state != S_INTEGRATION) {
 		crm_err("Broken? Voting in state %s",
 			fsa_state2string(cur_state));
 	}
 	
 	
 	return I_NULL;
 }
 
 char *dc_hb_msg = NULL;
 int beat_num = 0;
 
 gboolean
 do_dc_heartbeat(gpointer data)
 {
 #if 0
 	fsa_timer_t *timer = (fsa_timer_t *)data;
 
 	crm_debug_3("Sending DC Heartbeat %d", beat_num);
 	HA_Message *msg = ha_msg_new(5); 
 	ha_msg_add(msg, F_TYPE,		T_CRM);
 	ha_msg_add(msg, F_SUBTYPE,	XML_ATTR_REQUEST);
 	ha_msg_add(msg, F_CRM_SYS_TO,   CRM_SYSTEM_CRMD);
 	ha_msg_add(msg, F_CRM_SYS_FROM, CRM_SYSTEM_DC);
 	ha_msg_add(msg, F_CRM_TASK,	CRM_OP_HBEAT);
 	ha_msg_add_int(msg, "dc_beat_seq", beat_num);
 	beat_num++;
 
 	if(send_msg_via_ha(fsa_cluster_conn, msg) == FALSE) {
 		/* this is bad */
 		crm_timer_stop(timer); /* make it not go off again */
 
 		register_fsa_input(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL);
 		return FALSE;
 	}
 #endif
 	return TRUE;
 }
 
 struct election_data_s 
 {
 		const char *winning_uname;
 		unsigned int winning_bornon;
 };
 
 /*	A_ELECTION_COUNT	*/
 enum crmd_fsa_input
 do_election_count_vote(long long action,
 		       enum crmd_fsa_cause cause,
 		       enum crmd_fsa_state cur_state,
 		       enum crmd_fsa_input current_input,
 		       fsa_data_t *msg_data)
 {
 	gboolean we_loose = FALSE;
 	ha_msg_input_t *vote = fsa_typed_data(fsa_dt_ha_msg);
 	enum crmd_fsa_input election_result = I_NULL;
 	const char *vote_from    = cl_get_string(vote->msg, F_CRM_HOST_FROM);
 	const char *your_version = cl_get_string(vote->msg, F_CRM_VERSION);
 	oc_node_t *our_node = NULL, * your_node = NULL;
 
 	if(vote_from == NULL || strcmp(vote_from, fsa_our_uname) == 0) {
 		/* dont count our own vote */
 		return election_result;
 	}
 
 	if(fsa_membership_copy == NULL) {
 		/* if the membership copy is NULL we REALLY shouldnt be voting
 		 * the question is how we managed to get here.
 		 */
 		crm_err("Membership copy was NULL");
 		return I_NULL;
 		
 	} else if(fsa_membership_copy->members != NULL) {
 		our_node = (oc_node_t*)
 			g_hash_table_lookup(fsa_membership_copy->members,fsa_our_uname);
 
 		your_node = (oc_node_t*)
 			g_hash_table_lookup(fsa_membership_copy->members,vote_from);
 	}
 	
 	if(your_node == NULL) {
 		crm_debug("Election ignore: The other side doesnt exist in CCM.");
 		return I_NULL;
 		
 		/* if your_version == 0, then they're shutting down too */
 	} else if(is_set(fsa_input_register, R_SHUTDOWN)) {
 		if(your_version != NULL) {
 			crm_info("Election fail: we are shutting down");
 			we_loose = TRUE;
 			
 		} else {
 			/* pretend nothing happened, they want to shutdown too*/
 			crm_info("Election ignore: they are shutting down too");
 			return I_NULL;
 		}
 		
 	} else if(our_node == NULL
 		|| fsa_membership_copy->last_event == OC_EV_MS_EVICTED) {
 		crm_info("Election fail: we dont exist in CCM");
 		we_loose = TRUE;
 		
 	} else if(your_version == NULL) {
 		crm_info("Election pass: they are shutting down");
 
 	} else if(compare_version(your_version, CRM_FEATURE_SET) < 0) {
 		crm_debug("Election fail: version");
 		we_loose = TRUE;
 		
 	} else if(compare_version(your_version, CRM_FEATURE_SET) > 0) {
 		crm_debug("Election pass: version");
 		
 	} else if(your_node->node_born_on < our_node->node_born_on) {
 		crm_debug("Election fail: born_on");
 		we_loose = TRUE;
 
 	} else if(your_node->node_born_on > our_node->node_born_on) {
 		crm_debug("Election pass: born_on");
 		
 	} else if(strcmp(fsa_our_uname, vote_from) > 0) {
 		crm_debug("Election fail: uname");
 		we_loose = TRUE;
 /* cant happen...
  *	} else if(strcmp(fsa_our_uname, vote_from) == 0) {
  *
  * default...
  *	} else { // strcmp(fsa_our_uname, vote_from) < 0
  *		we win
  */
 	}
 
 	if(we_loose) {
 		crm_timer_stop(election_timeout);
 		crm_debug("Election lost to %s", vote_from);
 		if(fsa_input_register & R_THE_DC) {
 			crm_debug_3("Give up the DC to %s", vote_from);
 			election_result = I_RELEASE_DC;
 			
 		} else {
 			crm_debug_3("We werent the DC anyway");
 			election_result = I_PENDING;
 			
 		}
 
 	} else {
 		if(cur_state == S_PENDING) {
 			crm_debug("Election ignore: We already lost the election");
 			return I_NULL;
 			
 		} else {
 			crm_info("Election won over %s", vote_from);
 			election_result = I_ELECTION;
 		}
 	}
 	
 
 	register_fsa_input(C_FSA_INTERNAL, election_result, NULL);
 	return I_NULL;
 }
 
 /*	A_ELECT_TIMER_START, A_ELECTION_TIMEOUT 	*/
 /* we won */
 enum crmd_fsa_input
 do_election_timer_ctrl(long long action,
 		    enum crmd_fsa_cause cause,
 		    enum crmd_fsa_state cur_state,
 		    enum crmd_fsa_input current_input,
 		    fsa_data_t *msg_data)
 {
 	return I_NULL;
 }
 
 
 static void
 feature_update_callback(const HA_Message *msg, int call_id, int rc,
 			crm_data_t *output, void *user_data)
 {
 	if(rc != cib_ok) {
 		fsa_data_t *msg_data = NULL;
 		register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 	}
 }
 
 /*	 A_DC_TAKEOVER	*/
 enum crmd_fsa_input
 do_dc_takeover(long long action,
 	       enum crmd_fsa_cause cause,
 	       enum crmd_fsa_state cur_state,
 	       enum crmd_fsa_input current_input,
 	       fsa_data_t *msg_data)
 {
 	int rc = cib_ok;
 	crm_data_t *cib = NULL;
 	crm_data_t *fragment = NULL;
 	
 	crm_info("Taking over DC status for this partition");
 	set_bit_inplace(fsa_input_register, R_THE_DC);
 
 	crm_free(fsa_our_dc);
 	fsa_our_dc = crm_strdup(fsa_our_uname);
 
 	set_bit_inplace(fsa_input_register, R_JOIN_OK);
 	set_bit_inplace(fsa_input_register, R_INVOKE_PE);
 	
 	if(dc_heartbeat->source_id == (guint)-1
 	   || dc_heartbeat->source_id == (guint)-2) {
 		crm_debug_3("Starting DC Heartbeat timer");
 		dc_heartbeat->source_id = Gmain_timeout_add_full(
 			G_PRIORITY_HIGH, dc_heartbeat->period_ms,
 			dc_heartbeat->callback, dc_heartbeat, NULL);
 	} else {
 		crm_debug_3("DC Heartbeat timer already active");
 	}
 	
 /* 	fsa_cib_conn->cmds->set_slave_all(fsa_cib_conn, cib_none); */
 	fsa_cib_conn->cmds->set_master(fsa_cib_conn, cib_none);
 	
 	cib = createEmptyCib();
 	crm_xml_add(cib, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 	crm_xml_add(cib, XML_ATTR_CIB_REVISION, CIB_FEATURE_SET);
 	fragment = create_cib_fragment(cib, XML_TAG_CIB);
-	fsa_cib_conn->cmds->modify(
+	fsa_cib_conn->cmds->update(
 		fsa_cib_conn, NULL, fragment, NULL, cib_quorum_override);
 	add_cib_op_callback(rc, FALSE, NULL, feature_update_callback);
 
 	free_xml(cib);
 	free_xml(fragment);
 	
 	crm_debug_3("Requesting an initial dump of CRMD client_status");
 	fsa_cluster_conn->llc_ops->client_status(
 		fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1);
 	
 	return I_NULL;
 }
 
 
 /*	 A_DC_RELEASE	*/
 enum crmd_fsa_input
 do_dc_release(long long action,
 	      enum crmd_fsa_cause cause,
 	      enum crmd_fsa_state cur_state,
 	      enum crmd_fsa_input current_input,
 	      fsa_data_t *msg_data)
 {
 	enum crmd_fsa_input result = I_NULL;
 	
 	crm_timer_stop(dc_heartbeat);
 	if(action & A_DC_RELEASE) {
 		crm_debug("Releasing the role of DC");
 		clear_bit_inplace(fsa_input_register, R_THE_DC);
 		fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local);
 		
 	} else if (action & A_DC_RELEASED) {
 		crm_info("DC role released");
 #if 0
 		if( are there errors ) {
 			/* we cant stay up if not healthy */
 			/* or perhaps I_ERROR and go to S_RECOVER? */
 			result = I_SHUTDOWN;
 		}
 #endif
 		register_fsa_input(C_FSA_INTERNAL, I_RELEASE_SUCCESS, NULL);
 		
 	} else {
 		crm_err("Unknown action %s", fsa_action2string(action));
 	}
 
 	crm_debug_2("Am I still the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO);
 
 	return result;
 }
 
diff --git a/crm/crmd/join_dc.c b/crm/crmd/join_dc.c
index 1184554f51..d450840eac 100644
--- a/crm/crmd/join_dc.c
+++ b/crm/crmd/join_dc.c
@@ -1,621 +1,621 @@
 /* 
  * 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 <heartbeat.h>
 
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 
 #include <crmd_fsa.h>
 #include <crmd_messages.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 GHashTable *welcomed_nodes   = NULL;
 GHashTable *integrated_nodes = NULL;
 GHashTable *finalized_nodes  = NULL;
 GHashTable *confirmed_nodes  = NULL;
 char *max_epoch = NULL;
 char *max_generation_from = NULL;
 crm_data_t *max_generation_xml = NULL;
 
 void initialize_join(gboolean before);
 gboolean finalize_join_for(gpointer key, gpointer value, gpointer user_data);
 void join_send_offer(gpointer key, gpointer value, gpointer user_data);
 void finalize_sync_callback(const HA_Message *msg, int call_id, int rc,
 			    crm_data_t *output, void *user_data);
 gboolean process_join_ack_msg(
 	const char *join_from, crm_data_t *lrm_update, int join_id);
 gboolean check_join_state(enum crmd_fsa_state cur_state, const char *source);
 void join_update_complete_callback(const HA_Message *msg, int call_id, int rc,
 				   crm_data_t *output, void *user_data);
 
 void finalize_join(const char *caller);
 
 static int current_join_id = 0;
 
 /*	 A_DC_JOIN_OFFER_ALL	*/
 enum crmd_fsa_input
 do_dc_join_offer_all(long long action,
 		     enum crmd_fsa_cause cause,
 		     enum crmd_fsa_state cur_state,
 		     enum crmd_fsa_input current_input,
 		     fsa_data_t *msg_data)
 {
 	/* reset everyones status back to down or in_ccm in the CIB
 	 *
 	 * any nodes that are active in the CIB but not in the CCM list
 	 *   will be seen as offline by the PE anyway
 	 */
 	do_update_cib_nodes(NULL, TRUE);
 	
 	crm_info("0) Offering membership to %d clients",
 		  fsa_membership_copy->members_size);
 	
 	initialize_join(TRUE);
 	current_join_id++;
 	
 	g_hash_table_foreach(
 		fsa_membership_copy->members, join_send_offer, NULL);
 	
 	/* dont waste time by invoking the PE yet; */
 	crm_debug("1) Waiting on %d outstanding join acks",
 		  g_hash_table_size(welcomed_nodes));
 
 	return I_NULL;
 }
 
 /*	 A_DC_JOIN_OFFER_ONE	*/
 enum crmd_fsa_input
 do_dc_join_offer_one(long long action,
 		     enum crmd_fsa_cause cause,
 		     enum crmd_fsa_state cur_state,
 		     enum crmd_fsa_input current_input,
 		     fsa_data_t *msg_data)
 {
 	oc_node_t member;
 	gpointer a_node = NULL;
 	ha_msg_input_t *welcome = fsa_typed_data(fsa_dt_ha_msg);
 	const char *join_to = NULL;
 
 	if(welcome == NULL) {
 		crm_err("Attempt to send welcome message "
 			"without a message to reply to!");
 		return I_NULL;
 	}
 	
 	join_to = cl_get_string(welcome->msg, F_CRM_HOST_FROM);
 	if(a_node != NULL
 	   && (cur_state == S_INTEGRATION || cur_state == S_FINALIZE_JOIN)) {
 		/* note: it _is_ possible that a node will have been
 		 *  sick or starting up when the original offer was made.
 		 *  however, it will either re-announce itself in due course
 		 *  _or_ we can re-store the original offer on the client.
 		 */
 		crm_debug("Re-offering membership to %s...", join_to);
 	}
 
 	crm_info("Processing annouce request from %s in state %s",
 		 join_to, fsa_state2string(cur_state));
 
 	/* always offer to the DC (ourselves)
 	 * this ensures the correct value for max_generation_from
 	 */
 	member.node_uname = crm_strdup(fsa_our_uname);
 	join_send_offer(NULL, &member, NULL);
 	crm_free(member.node_uname);
 	
 	member.node_uname = crm_strdup(join_to);
 	join_send_offer(NULL, &member, NULL);
 	crm_free(member.node_uname);
 	
 	/* this was a genuine join request, cancel any existing
 	 * transition and invoke the PE
 	 */
 	if(need_transition(fsa_state)) {
 		register_fsa_action(A_TE_CANCEL);
 	}
 	
 	/* dont waste time by invoking the pe yet; */
 	crm_debug("1) Waiting on %d outstanding join acks",
 		  g_hash_table_size(welcomed_nodes));
 	
 	return I_NULL;
 }
 
 /*	 A_DC_JOIN_PROCESS_REQ	*/
 enum crmd_fsa_input
 do_dc_join_req(long long action,
 	       enum crmd_fsa_cause cause,
 	       enum crmd_fsa_state cur_state,
 	       enum crmd_fsa_input current_input,
 	       fsa_data_t *msg_data)
 {
 	crm_data_t *generation = NULL;
 
 	int join_id = -1;
 	gboolean ack_nack_bool = TRUE;
 	const char *ack_nack = CRMD_JOINSTATE_MEMBER;
 	ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg);
 
 	const char *join_from = cl_get_string(join_ack->msg,F_CRM_HOST_FROM);
 	const char *ref       = cl_get_string(join_ack->msg,XML_ATTR_REFERENCE);
 	
 	gpointer join_node =
 		g_hash_table_lookup(fsa_membership_copy->members, join_from);
 
 	crm_debug_3("2) Processing req from %s", join_from);
 	
 	generation = join_ack->xml;
 	ha_msg_value_int(join_ack->msg, F_CRM_JOIN_ID, &join_id);
 	crm_log_xml_debug_2(max_generation_xml, "Max generation");
 	crm_log_xml_debug_2(generation, "Their generation");
 
 	if(join_node == NULL) {
 		crm_err("Node %s is not a member", join_from);
 		ack_nack_bool = FALSE;
 		
 	} else if(generation == NULL) {
 		crm_err("Generation was NULL");
 		ack_nack_bool = FALSE;
 
 	} else if(join_id != current_join_id) {
 		crm_debug("Response from %s was for invalid join: %d vs. %d",
 			  join_from, join_id, current_join_id);
 		check_join_state(cur_state, __FUNCTION__);
 		return I_NULL;
 		
 	} else if(max_generation_xml == NULL) {
 		max_generation_xml = copy_xml(generation);
 		max_generation_from = crm_strdup(join_from);
 
 	} else if(cib_compare_generation(max_generation_xml, generation) < 0) {
 		crm_debug("%s has a better generation number than"
 			  " the current max %s",
 			  join_from, max_generation_from);
 		crm_free(max_generation_from);
 		free_xml(max_generation_xml);
 		
 		max_generation_from = crm_strdup(join_from);
 		max_generation_xml = copy_xml(join_ack->xml);
 	}
 
 	if(ack_nack_bool == FALSE) {
 		/* NACK this client */
 		ack_nack = CRMD_STATE_INACTIVE;
 		crm_err("2) NACK'ing node %s (ref %s)", join_from, ref);
 	} else {
 		crm_debug("2) Welcoming node %s after ACK (ref %s)",
 			  join_from, ref);
 	}
 	
 	/* add them to our list of CRMD_STATE_ACTIVE nodes */
 	g_hash_table_insert(
 		integrated_nodes, crm_strdup(join_from), crm_strdup(ack_nack));
 
 	crm_debug_2("%u nodes have been integrated",
 		    g_hash_table_size(integrated_nodes));
 	
 	g_hash_table_remove(welcomed_nodes, join_from);
 
 	if(check_join_state(cur_state, __FUNCTION__) == FALSE) {
 		/* dont waste time by invoking the PE yet; */
 		crm_debug_2("Still waiting on %d outstanding join acks",
 			    g_hash_table_size(welcomed_nodes));
 	}
 	return I_NULL;
 }
 
 
 #define JOIN_AFTER_SYNC 1
 
 /*	A_DC_JOIN_FINALIZE	*/
 enum crmd_fsa_input
 do_dc_join_finalize(long long action,
 		    enum crmd_fsa_cause cause,
 		    enum crmd_fsa_state cur_state,
 		    enum crmd_fsa_input current_input,
 		    fsa_data_t *msg_data)
 {
 	enum cib_errors rc = cib_ok;
 
 	/* This we can do straight away and avoid clients timing us out
 	 *  while we compute the latest CIB
 	 */
 #if JOIN_AFTER_SYNC
 	crm_debug("Finializing join for %d clients",
 		  g_hash_table_size(integrated_nodes));
 #else
 	crm_debug("Notifying %d clients of join results",
 		  g_hash_table_size(integrated_nodes));
 	g_hash_table_foreach_remove(
 		integrated_nodes, finalize_join_for, NULL);
 #endif
 	clear_bit_inplace(fsa_input_register, R_HAVE_CIB);
 	if(max_generation_from == NULL
 	   || safe_str_eq(max_generation_from, fsa_our_uname)){
 		set_bit_inplace(fsa_input_register, R_HAVE_CIB);
 	}
 	
 	if(is_set(fsa_input_register, R_HAVE_CIB) == FALSE) {
 		/* ask for the agreed best CIB */
 		crm_info("Asking %s for its copy of the CIB",
 			 crm_str(max_generation_from));
 		crm_log_xml_debug(max_generation_xml, "Requesting version");
 		
 		set_bit_inplace(fsa_input_register, R_CIB_ASKED);
 
 		fsa_cib_conn->call_timeout = 10;
 		rc = fsa_cib_conn->cmds->sync_from(
 			fsa_cib_conn, max_generation_from, NULL,
 			cib_quorum_override);
 		fsa_cib_conn->call_timeout = 0; /* back to the default */
 		add_cib_op_callback(rc, FALSE, crm_strdup(max_generation_from),
 				    finalize_sync_callback);
 		return I_NULL;
 	}
 
 	finalize_join(__FUNCTION__);
 
 	return I_NULL;
 }
 
 void
 finalize_sync_callback(const HA_Message *msg, int call_id, int rc,
 		       crm_data_t *output, void *user_data) 
 {
 	CRM_DEV_ASSERT(cib_not_master != rc);
 	clear_bit_inplace(fsa_input_register, R_CIB_ASKED);
 	if(rc != cib_ok) {
 		crm_log_maybe((rc==cib_old_data?LOG_WARNING:LOG_ERR),
 			      "Sync from %s resulted in an error: %s",
 			      (char*)user_data, cib_error2string(rc));
 
 		/* restart the whole join process */
 		register_fsa_error_adv(C_FSA_INTERNAL, I_ELECTION_DC,
 				       NULL, NULL, __FUNCTION__);
 
 	} else if(AM_I_DC && fsa_state == S_FINALIZE_JOIN) {
 		finalize_join(__FUNCTION__);
 
 	} else {
 		crm_debug("No longer the DC in S_FINALIZE_JOIN: %s/%s",
 			  AM_I_DC?"DC":"CRMd", fsa_state2string(fsa_state));
 	}
 	
 	crm_free(user_data);
 }
 
 void
 finalize_join(const char *caller)
 {
 	crm_data_t *cib = createEmptyCib();
 	crm_data_t *cib_update = NULL;
 	
 	set_bit_inplace(fsa_input_register, R_HAVE_CIB);
 	clear_bit_inplace(fsa_input_register, R_CIB_ASKED);
 
 	set_uuid(fsa_cluster_conn, cib, XML_ATTR_DC_UUID, fsa_our_uname);
 	crm_debug_3("Update %s in the CIB to our uuid: %s",
 		    XML_ATTR_DC_UUID, crm_element_value(cib, XML_ATTR_DC_UUID));
 	
 	cib_update = create_cib_fragment(cib, XML_TAG_CIB);
-	fsa_cib_conn->cmds->modify(
+	fsa_cib_conn->cmds->update(
 		fsa_cib_conn, NULL, cib_update, NULL, cib_quorum_override);
 
 	free_xml(cib_update);
 	free_xml(cib);
 	
 	crm_debug_3("Bumping the epoch and syncing to %d clients",
 		  g_hash_table_size(finalized_nodes));
 	fsa_cib_conn->cmds->bump_epoch(
 		fsa_cib_conn, cib_scope_local|cib_quorum_override);
 	
 #if JOIN_AFTER_SYNC
 	/* make sure dc_uuid is re-set to us */
 	
 	if(check_join_state(fsa_state, caller) == FALSE) {
 		crm_debug("Notifying %d clients of join results",
 			  g_hash_table_size(integrated_nodes));
 		g_hash_table_foreach_remove(
 			integrated_nodes, finalize_join_for, NULL);
 	}
 #else
 	check_join_state(cur_state, caller);
 	rc = fsa_cib_conn->cmds->sync(fsa_cib_conn, NULL, cib_quorum_override);
 #endif
 }
 
 
 /*	A_DC_JOIN_PROCESS_ACK	*/
 enum crmd_fsa_input
 do_dc_join_ack(long long action,
 	       enum crmd_fsa_cause cause,
 	       enum crmd_fsa_state cur_state,
 	       enum crmd_fsa_input current_input,
 	       fsa_data_t *msg_data)
 {
 	ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg);
 	const char *join_from  = cl_get_string(join_ack->msg, F_CRM_HOST_FROM);
 	const char *op         = cl_get_string(join_ack->msg, F_CRM_TASK);
 
 	if(safe_str_neq(op, CRM_OP_JOIN_CONFIRM)) {
 		crm_debug("Ignoring op=%s message", op);
 
 	} else {
 		int join_id = -1;
 		ha_msg_value_int(join_ack->msg, F_CRM_JOIN_ID, &join_id);
 		process_join_ack_msg(join_from, join_ack->xml, join_id);
 	}
 	return I_NULL;
 }
 
 gboolean
 process_join_ack_msg(const char *join_from, crm_data_t *lrm_update, int join_id)
 {
 	/* now update them to "member" */
 	int call_id = 0;
 	crm_data_t *update = NULL;
 	crm_data_t *fragment = NULL;
 	const char *join_state = NULL;
 	
 	crm_debug_2("Processing ack from %s", join_from);
 
 	join_state = (const char *)
 		g_hash_table_lookup(finalized_nodes, join_from);
 	
 	if(join_state == NULL) {
 		crm_err("Join not in progress: ignoring join from %s",
 			join_from);
 		return FALSE;
 		
 	} else if(safe_str_neq(join_state, CRMD_JOINSTATE_MEMBER)) {
 		crm_err("Node %s wasnt invited to join the cluster",join_from);
 		g_hash_table_remove(finalized_nodes, join_from);
 		return FALSE;
 		
 	} else if(join_id != current_join_id) {
 		crm_err("Node %s responded to an invalid join: %d vs. %d",
 			join_from, join_id, current_join_id);
 		g_hash_table_remove(finalized_nodes, join_from);
 		return FALSE;
 	}
 
 	g_hash_table_remove(finalized_nodes, join_from);
 	
 	if(g_hash_table_lookup(confirmed_nodes, join_from) != NULL) {
 		crm_err("hash already contains confirmation from %s",join_from);
 	}
 	
 	g_hash_table_insert(confirmed_nodes, crm_strdup(join_from),
 			    crm_strdup(CRMD_JOINSTATE_MEMBER));
 
  	crm_info("4) Updating node state to %s for %s",
  		 CRMD_JOINSTATE_MEMBER, join_from);
 
 #if 0
 	???dig into the fragment and clear shutdown??
 	/* the slave will re-ask if it wants to be shutdown */
 	crm_xml_add(lrm_update, XML_CIB_ATTR_CLEAR_SHUTDOWN, XML_BOOLEAN_TRUE);
 #endif
 	/* update CIB with the current LRM status from the node
 	 * We dont need to notify the TE of these updates, a transition will
 	 *   be started in due time
 	 */
-	call_id = fsa_cib_conn->cmds->modify(
+	call_id = fsa_cib_conn->cmds->update(
 		fsa_cib_conn, XML_CIB_TAG_STATUS, lrm_update, NULL,
 		cib_scope_local|cib_quorum_override);
 
 	add_cib_op_callback(call_id, TRUE,NULL, join_update_complete_callback);
 
 	free_xml(fragment);
 	free_xml(update);
 	
 	return TRUE;
 }
 
 gboolean
 finalize_join_for(gpointer key, gpointer value, gpointer user_data)
 {
 	const char *join_to = NULL;
 	const char *join_state = NULL;
 	HA_Message *acknak = NULL;
 	
 	if(key == NULL || value == NULL) {
 		return TRUE;
 	}
 
 	join_to    = (const char *)key;
 	join_state = (const char *)value;
 
 	/* make sure the node exists in the config section */
 	create_node_entry(join_to, join_to, CRMD_JOINSTATE_MEMBER);
 
 	/* send the ack/nack to the node */
 	acknak = create_request(
 		CRM_OP_JOIN_ACKNAK, NULL, join_to,
 		CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL);
 	ha_msg_add_int(acknak, F_CRM_JOIN_ID, current_join_id);
 	
 	/* set the ack/nack */
 	if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
 		crm_debug("3) ACK'ing join request from %s, state %s",
 			  join_to, join_state);
 		ha_msg_add(acknak, CRM_OP_JOIN_ACKNAK, XML_BOOLEAN_TRUE);
 		g_hash_table_insert(
 			finalized_nodes,
 			crm_strdup(join_to), crm_strdup(CRMD_JOINSTATE_MEMBER));
 	} else {
 		crm_warn("3) NACK'ing join request from %s, state %s",
 			 join_to, join_state);
 		
 		ha_msg_add(acknak, CRM_OP_JOIN_ACKNAK, XML_BOOLEAN_FALSE);
 	}
 	
 	send_msg_via_ha(fsa_cluster_conn, acknak);
 	return TRUE;
 }
 
 void
 initialize_join(gboolean before)
 {
 	/* clear out/reset a bunch of stuff */
 	crm_debug("Initializing join data");
 	
 	g_hash_table_destroy(welcomed_nodes);
 	g_hash_table_destroy(integrated_nodes);
 	g_hash_table_destroy(finalized_nodes);
 	g_hash_table_destroy(confirmed_nodes);
 
 	if(before) {
 		if(max_generation_from != NULL) {
 			crm_free(max_generation_from);
 			max_generation_from = NULL;
 		}
 		if(max_generation_xml != NULL) {
 			free_xml(max_generation_xml);
 			max_generation_xml = NULL;
 		}
 		clear_bit_inplace(fsa_input_register, R_HAVE_CIB);
 		clear_bit_inplace(fsa_input_register, R_CIB_ASKED);
 	}
 	
 	welcomed_nodes = g_hash_table_new_full(
 		g_str_hash, g_str_equal,
 		g_hash_destroy_str, g_hash_destroy_str);
 	integrated_nodes = g_hash_table_new_full(
 		g_str_hash, g_str_equal,
 		g_hash_destroy_str, g_hash_destroy_str);
 	finalized_nodes = g_hash_table_new_full(
 		g_str_hash, g_str_equal,
 		g_hash_destroy_str, g_hash_destroy_str);
 	confirmed_nodes = g_hash_table_new_full(
 		g_str_hash, g_str_equal,
 		g_hash_destroy_str, g_hash_destroy_str);
 }
 
 
 void
 join_send_offer(gpointer key, gpointer value, gpointer user_data)
 {
 	const char *join_to = NULL;
 	const char *crm_online = NULL;
 	const oc_node_t *member = (const oc_node_t*)value;
 
 	if(member != NULL) {
 		join_to = member->node_uname;
 	}
 
 	if(join_to == NULL) {
 		crm_err("No recipient for welcome message");
 		return;
 		
 	}
 
 	g_hash_table_remove(confirmed_nodes,  join_to);
 	g_hash_table_remove(finalized_nodes,  join_to);
 	g_hash_table_remove(integrated_nodes, join_to);
 	g_hash_table_remove(welcomed_nodes,   join_to);
 
 	crm_online = g_hash_table_lookup(crmd_peer_state, join_to);
 	
 	if(safe_str_eq(crm_online, ONLINESTATUS)) {
 		HA_Message *offer = create_request(
 			CRM_OP_JOIN_OFFER, NULL, join_to,
 			CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL);
 
 		ha_msg_add_int(offer, F_CRM_JOIN_ID, current_join_id);
 		/* send the welcome */
 		crm_debug("Sending %s(%d) to %s",
 			  CRM_OP_JOIN_OFFER, current_join_id, join_to);
 
 		send_msg_via_ha(fsa_cluster_conn, offer);
 
 		g_hash_table_insert(welcomed_nodes, crm_strdup(join_to),
 				    crm_strdup(CRMD_JOINSTATE_PENDING));
 	} else {
 		crm_debug("Peer process on %s is not active", join_to);
 	}
 	
 }
 
 gboolean
 check_join_state(enum crmd_fsa_state cur_state, const char *source)
 {
 	crm_debug_2("Invoked by %s in state: %s",
 		  source, fsa_state2string(cur_state));
 
 	if(cur_state == S_INTEGRATION) {
 		if(g_hash_table_size(welcomed_nodes) == 0) {
 			crm_debug("Integration of %d peers complete: %s",
 				 g_hash_table_size(integrated_nodes), source);
 			register_fsa_input_before(
 				C_FSA_INTERNAL, I_INTEGRATED, NULL);
 			return TRUE;
 		}
 
 	} else if(cur_state == S_FINALIZE_JOIN) {
 		if(is_set(fsa_input_register, R_HAVE_CIB) == FALSE) {
 			crm_debug("Delaying I_FINALIZED until we have the CIB");
 			return TRUE;
 			
 		} else if(g_hash_table_size(integrated_nodes) == 0
 		   && g_hash_table_size(finalized_nodes) == 0) {
 			crm_debug("Join process complete: %s", source);
 			register_fsa_input_later(
 				C_FSA_INTERNAL, I_FINALIZED, NULL);
 			
 		} else if(g_hash_table_size(integrated_nodes) != 0
 			  && g_hash_table_size(finalized_nodes) != 0) {
 			crm_err("Waiting on %d integrated nodes"
 				" AND %d confirmations",
 				g_hash_table_size(integrated_nodes),
 				g_hash_table_size(finalized_nodes));
 
 		} else if(g_hash_table_size(integrated_nodes) != 0) {
 			crm_debug("Still waiting on %d integrated nodes",
 				  g_hash_table_size(integrated_nodes));
 			
 		} else if(g_hash_table_size(finalized_nodes) != 0) {
 			crm_debug_2("Still waiting on %d confirmations",
 				  g_hash_table_size(finalized_nodes));
 		}
 		
 	}
 	
 	return FALSE;
 }
 
 void
 join_update_complete_callback(const HA_Message *msg, int call_id, int rc,
 			      crm_data_t *output, void *user_data)
 {
 	fsa_data_t *msg_data = NULL;
 	
 	if(rc == cib_ok) {
 		check_join_state(fsa_state, __FUNCTION__);
 
 	} else {
 		crm_err("Join update failed");
 		crm_log_message(LOG_DEBUG, msg);
 		register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 	}
 }
diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c
index 6046d567ce..eee9a0eba7 100644
--- a/crm/tengine/tengine.c
+++ b/crm/tengine/tengine.c
@@ -1,1051 +1,1049 @@
-/* $Id: tengine.c,v 1.102 2005/09/27 14:21:06 andrew Exp $ */
+/* $Id: tengine.c,v 1.103 2005/10/12 18:28:22 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 <portability.h>
 
 #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>
 
 gboolean graph_complete = FALSE;
 GListPtr graph = NULL;
 IPC_Channel *crm_ch = NULL;
 uint transition_idle_timeout = 30*1000; /* 30 seconds */
 
 void fire_synapse(synapse_t *synapse);
 gboolean initiate_action(action_t *action);
 gboolean confirm_synapse(synapse_t *synapse, int action_id);
 void check_synapse_triggers(synapse_t *synapse, int action_id);
 void cib_action_updated(
 	const HA_Message *msg, int call_id, int rc,
 	crm_data_t *output, void *user_data);
 
 te_timer_t *transition_timer = NULL;
 te_timer_t *abort_timer = NULL;
 int transition_counter = 1;
 char *te_uuid = NULL;
 
 const te_fsa_state_t te_state_matrix[i_invalid][s_invalid] = 
 {
 			/*  s_idle,          s_in_transition, s_abort_pending,   s_updates_pending */
 /* Got an i_transition  */{ s_in_transition, s_abort_pending, s_abort_pending,   s_updates_pending },
 /* Got an i_cancel      */{ s_idle,          s_abort_pending, s_abort_pending,   s_updates_pending },
 /* Got an i_complete    */{ s_idle,          s_idle,          s_abort_pending,   s_updates_pending },
 /* Got an i_cmd_complete*/{ s_idle,          s_in_transition, s_updates_pending, s_updates_pending },
 /* Got an i_cib_complete*/{ s_idle,          s_in_transition, s_abort_pending,   s_idle },
 /* Got an i_cib_confirm */{ s_idle,          s_in_transition, s_abort_pending,   s_updates_pending },
 /* Got an i_cib_notify  */{ s_idle,          s_in_transition, s_abort_pending,   s_updates_pending }
 };
 
 
 
 te_fsa_state_t te_fsa_state = s_idle;
 
 
 gboolean
 initialize_graph(void)
 {
 	remove_cib_op_callback(-1, TRUE);
 
 	if(transition_timer == NULL) {
 		crm_malloc0(transition_timer, sizeof(te_timer_t));
 	    
 		transition_timer->timeout   = 10;
 		transition_timer->source_id = -1;
 		transition_timer->reason    = timeout_timeout;
 		transition_timer->action    = NULL;
 	} else {
 		stop_te_timer(transition_timer);
 	}
 
 	if(abort_timer == NULL) {
 		crm_malloc0(abort_timer, sizeof(te_timer_t));
 	    
 		abort_timer->timeout   = 10;
 		abort_timer->source_id = -1;
 		abort_timer->reason    = timeout_abort;
 		abort_timer->action    = NULL;
 	} else {
 		stop_te_timer(abort_timer);
 	}
 	
 	if(te_uuid == NULL) {
 		cl_uuid_t new_uuid;
 		crm_malloc0(te_uuid, sizeof(char)*38);
 		cl_uuid_generate(&new_uuid);
 		cl_uuid_unparse(&new_uuid, te_uuid);
 		crm_info("Registering TE UUID: %s", te_uuid);
 	}
 	
 	while(g_list_length(graph) > 0) {
 		synapse_t *synapse = g_list_nth_data(graph, 0);
 
 		while(g_list_length(synapse->actions) > 0) {
 			action_t *action = g_list_nth_data(synapse->actions,0);
 			synapse->actions = g_list_remove(
 				synapse->actions, action);
 
 			if(action->timer->source_id > 0) {
 				crm_debug_3("Removing timer for action: %d",
 					    action->id);
 				
 				Gmain_timeout_remove(action->timer->source_id);
 			}
 			g_hash_table_destroy(action->params);
 			free_xml(action->xml);
 			crm_free(action->timer);
 			crm_free(action);
 		}
 
 		while(g_list_length(synapse->inputs) > 0) {
 			action_t *action = g_list_nth_data(synapse->inputs, 0);
 			synapse->inputs =
 				g_list_remove(synapse->inputs, action);
 
 			g_hash_table_destroy(action->params);
 			free_xml(action->xml);
 			crm_free(action->timer);
 			crm_free(action);
 			
 		}
 		graph = g_list_remove(graph, synapse);
 		crm_free(synapse);
 	}
 
 	graph = NULL;
 	return TRUE;
 }
 
 /*
  * returns the ID of the action if a match is found
  * returns -1 if a match was not found
  * returns -2 if a match was found but the action failed (and was
  *            not allowed to)
  */
 int
 match_graph_event(action_t *action, crm_data_t *event, const char *event_node)
 {
 	const char *target_rc_s = NULL;
 	const char *allow_fail  = NULL;
 	const char *this_action = NULL;
 	const char *this_node   = NULL;
 	const char *this_uname  = NULL;
 	const char *this_rsc    = NULL;
 	const char *magic       = NULL;
 
 	const char *this_event;
 	char *update_te_uuid = NULL;
 	const char *update_event;
 	
 	action_t *match = NULL;
 	int op_status_i = -3;
 	int op_rc_i = -3;
 	int transition_i = -1;
 
 	if(event == NULL) {
 		crm_debug_4("Ignoring NULL event");
 		return -1;
 	}
 	
 	this_rsc = crm_element_value(action->xml, XML_LRM_ATTR_RSCID);
 	
 	if(this_rsc == NULL) {
 		crm_debug_4("Skipping non-resource event");
 		return -1;
 	}
 
 	crm_debug_3("Processing \"%s\" change", crm_element_name(event));
 	update_event = crm_element_value(event, XML_ATTR_ID);
 	magic        = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC);
 
 	if(magic == NULL) {
 /* 		crm_debug("Skipping \"non-change\""); */
 		crm_log_xml_debug(event, "Skipping \"non-change\"");
 		return -3;
 	}
 	
 	this_action = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 	this_node   = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
 	this_uname  = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 
 	this_event = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
 	CRM_DEV_ASSERT(this_event != NULL);
 	
 	if(safe_str_neq(this_event, update_event)) {
 		crm_debug_2("Action %d : Event mismatch %s vs. %s",
 			    action->id, this_event, update_event);
 
 	} else if(safe_str_neq(this_node, event_node)) {
 		crm_debug_2("Action %d : Node mismatch %s (%s) vs. %s",
 			    action->id, this_node, this_uname, event_node);
 	} else {
 		match = action;
 	}
 	
 	if(match == NULL) {
 		return -1;
 	}
 	
 	crm_debug("Matched action (%d) %s", action->id, this_event);
 
 	CRM_DEV_ASSERT(decode_transition_magic(
 			       magic, &update_te_uuid,
 			       &transition_i, &op_status_i, &op_rc_i));
 
 	if(event == NULL) {
 		crm_err("No event");
 
 	} else if(transition_i == -1) {
 		/* we never expect these - recompute */
 		crm_err("Detected an action initiated outside of a transition");
 		crm_log_message(LOG_ERR, event);
 		return -5;
 		
 	} else if(safe_str_neq(update_te_uuid, te_uuid)) {
 		crm_err("Detected an action from a different transitioner:"
 			" %s vs. %s", update_te_uuid, te_uuid);
 		crm_log_message(LOG_ERR, event);
 		return -6;
 		
 	} else if(transition_counter != transition_i) {
 		crm_warn("Detected an action from a different transition:"
 			 " %d vs. %d", transition_i, transition_counter);
 		crm_log_message(LOG_WARNING, event);
 		return -3;
 	}
 	
 	/* stop this event's timer if it had one */
 	stop_te_timer(match->timer);
 	match->complete = TRUE;
 
 	target_rc_s = g_hash_table_lookup(match->params,XML_ATTR_TE_TARGET_RC);
 	if(target_rc_s != NULL) {
 		int target_rc = atoi(target_rc_s);
-		
-		crm_info("Target rc = %d (%s)", target_rc, target_rc_s);
 		if(target_rc == op_rc_i) {
 			crm_info("Target rc: == %d", op_rc_i);
 			if(op_status_i != LRM_OP_DONE) {
 				crm_debug("Re-mapping op status to"
 					  " LRM_OP_DONE for %s", update_event);
 				op_status_i = LRM_OP_DONE;
 			}
 		} else {
 			crm_info("Target rc: != %d", op_rc_i);
 			if(op_status_i != LRM_OP_ERROR) {
 				crm_info("Re-mapping op status to"
 					 " LRM_OP_ERROR for %s", update_event);
 				op_status_i = LRM_OP_ERROR;
 			}
 		}
 	}
 	
 	/* Process OP status */
 	allow_fail = g_hash_table_lookup(match->params, XML_ATTR_TE_ALLOWFAIL);
 	switch(op_status_i) {
 		case -3:
 			crm_err("Action returned the same as last time..."
 				" whatever that was!");
 			crm_log_message(LOG_ERR, event);
 			break;
 		case LRM_OP_PENDING:
 			crm_debug("Ignoring pending operation");
 			return -4;
 			break;
 		case LRM_OP_DONE:
 			break;
 		case LRM_OP_ERROR:
 		case LRM_OP_TIMEOUT:
 		case LRM_OP_NOTSUPPORTED:
 			match->failed = TRUE;
 			crm_warn("Action %s on %s failed: %s",
 				 update_event, event_node,
 				 op_status2text(op_status_i));
 			if(FALSE == crm_is_true(allow_fail)) {
 				send_complete("Action failed", event,
 					      te_failed, i_cancel);
 				return -2;
 			}
 			break;
 		case LRM_OP_CANCELLED:
 			/* do nothing?? */
 			crm_err("Dont know what to do for cancelled ops yet");
 			break;
 		default:
 			crm_err("Unsupported action result: %d", op_status_i);
 			send_complete("Unsupport action result",
 				      event, te_failed, i_cancel);
 			return -2;
 	}
 	
 	te_log_action(LOG_INFO, "Action %d confirmed", match->id);
 	process_trigger(match->id);
 
 	if(te_fsa_state != s_in_transition) {
 		return -3;
 	}
 	return match->id;
 }
 
 int
 match_down_event(const char *target, const char *filter, int rc)
 {
 	const char *allow_fail  = NULL;
 	const char *this_action = NULL;
 	const char *this_node   = NULL;
 	action_t *match = NULL;
 
 	slist_iter(
 		synapse, synapse_t, graph, lpc,
 
 		/* lookup event */
 		slist_iter(
 			action, action_t, synapse->actions, lpc2,
 
 			this_action = crm_element_value(
 				action->xml, XML_LRM_ATTR_TASK);
 
 			if(action->type != action_type_crm) {
 				continue;
 
 			} else if(filter != NULL
 				  && safe_str_neq(this_action, filter)) {
 				continue;
 			}
 			
 			if(safe_str_eq(this_action, CRM_OP_FENCE)) {
 				this_node = crm_element_value(
 					action->xml, XML_LRM_ATTR_TARGET_UUID);
 
 			} else if(safe_str_eq(this_action, CRM_OP_SHUTDOWN)) {
 				this_node = crm_element_value(
 					action->xml, XML_LRM_ATTR_TARGET_UUID);
 			} else {
 				crm_err("Action %d : Bad action %s",
 					action->id, this_action);
 				continue;
 			}
 
 			if(this_node == NULL) {
 				crm_log_xml_err(action->xml, "No node uuid");
 			}
 			
 			if(safe_str_neq(this_node, target)) {
 				crm_debug("Action %d : Node mismatch: %s",
 					 action->id, this_node);
 				continue;
 			}
 
 			match = action;
 			);
 		if(match != NULL) {
 			break;
 		}
 		);
 	
 	if(match == NULL) {
 		crm_debug_3("didnt match current action");
 		return -1;
 	}
 
 	crm_debug_3("matched");
 
 	/* stop this event's timer if it had one */
 	stop_te_timer(match->timer);
 	match->complete = TRUE;
 	
 	/* Process OP status */
 	switch(rc) {
 		case STONITH_SUCCEEDED:
 			break;
 		case STONITH_CANNOT:
 		case STONITH_TIMEOUT:
 		case STONITH_GENERIC:
 			match->failed = TRUE;
 			allow_fail = g_hash_table_lookup(
 				match->params, XML_ATTR_TE_ALLOWFAIL);
 
 			if(FALSE == crm_is_true(allow_fail)) {
 				crm_err("Stonith of %s failed (%d)..."
 					" aborting transition.", target, rc);
 				send_complete("Stonith failed",
 					      match->xml, te_failed, i_cancel);
 				return -2;
 			}
 			break;
 		default:
 			crm_err("Unsupported action result: %d", rc);
 			send_complete("Unsupport Stonith result",
 				      match->xml, te_failed, i_cancel);
 			return -3;
 	}
 	
 	crm_debug_3("Action %d was successful, looking for next action",
 		match->id);
 
 	return match->id;
 }
 
 gboolean
 process_graph_event(crm_data_t *event, const char *event_node)
 {
 	int rc                = -1;
 	int action_id         = -1;
 	int op_status_i       = 0;
 	const char *magic     = NULL;
 	const char *rsc_id    = NULL;
 	const char *op_status = NULL;
 
 	if(event == NULL) {
 		crm_debug("a transition is starting");
 
 		process_trigger(action_id);
 		check_for_completion();
 		
 		return TRUE;
 	}
 	rsc_id    = crm_element_value(event, XML_ATTR_ID);
 	op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS);
 	magic     = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC);
 
 	if(op_status != NULL) {
 		op_status_i = atoi(op_status);
 		if(op_status_i == -1) {
 			/* just information that the action was sent */
 			crm_debug("Ignoring TE initiated updates");
 			return TRUE;
 		}
 	}
 	
 	if(magic == NULL) {
 		crm_log_xml_debug(event, "Skipping \"non-change\"");
 		action_id = -3;
 	} else {
 		crm_debug("Processing CIB update: %s on %s: %s",
 			  rsc_id, event_node, magic);
 	}
 	
 	slist_iter(
 		synapse, synapse_t, graph, lpc,
 
 		/* lookup event */
 		slist_iter(
 			action, action_t, synapse->actions, lpc2,
 
 			rc = match_graph_event(action, event, event_node);
 			if(action_id >= 0 && rc >= 0) {
 				crm_err("Additional match found: %d [%d]",
 					rc, action_id);
 			} else if(rc != -1) {
 				action_id = rc;
 			}
 			);
 		if(action_id != -1) {
 			crm_debug("Terminating search: %d", action_id);
 			break;
 		}
 		);
 
 	if(action_id == -1) {
 		/* didnt find a match...
 		 * now try any dangling inputs
 		 */
 		slist_iter(
 			synapse, synapse_t, graph, lpc,
 			
 			slist_iter(
 				action, action_t, synapse->inputs, lpc2,
 				
 				rc = match_graph_event(action,event,event_node);
 				if(action_id >=0 && rc >=0 && rc != action_id) {
 					crm_err("Additional match found:"
 						" %d [%d]", rc, action_id);
 				} else if(rc != -1) {
 					action_id = rc;
 				}
 				);
 			if(action_id != -1) {
 				break;
 			}
 			);
 	}
 
 	if(action_id > -1) {
 		crm_log_xml_debug_3(event, "Event found");
 		
 	} else if(action_id == -2) {
 		crm_log_xml_info(event, "Event failed");
 		
 	} else if(action_id == -3) {
 		crm_log_xml_info(event, "Old event found");
 		
 	} else if(action_id == -4) {
 		crm_log_xml_debug(event, "Pending event found");
 		
 	} else {
 		/* unexpected event, trigger a pe-recompute */
 		/* possibly do this only for certain types of actions */
 		crm_debug("Search terminated: %d", action_id);
 		send_complete("Event not matched", event, te_update, i_cancel);
 		return FALSE;
 	}
 
 	check_for_completion();
 
 	return TRUE;
 }
 
 void
 check_for_completion(void)
 {
 	if(graph_complete) {
 		/* allow some slack until we are pretty sure nothing
 		 * else is happening
 		 */
 		crm_info("Transition complete");
 		send_complete("complete", NULL, te_done, i_complete);
 		
 	} else {
 		/* restart the transition timer again */
 		crm_debug_3("Transition not yet complete");
 		start_te_timer(transition_timer);
 	}
 }
 
 
 gboolean
 initiate_action(action_t *action) 
 {
 	gboolean ret = FALSE;
 	gboolean send_command = FALSE;
 
 	const char *on_node   = NULL;
 	const char *id        = NULL;
 	const char *task      = NULL;
 	const char *timeout   = NULL;
 	const char *msg_task    = XML_GRAPH_TAG_RSC_OP;
 
 	on_node  = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 	id       = crm_element_value(action->xml, XML_ATTR_ID);
 	task     = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 	timeout  = crm_element_value(action->xml, XML_ATTR_TIMEOUT);
 
 	if(id == NULL || strlen(id) == 0
 	   || task == NULL || strlen(task) == 0) {
 		/* error */
 		te_log_action(LOG_ERR, "Failed on corrupted command: %s (id=%s) %s",
 			crm_element_name(action->xml),
 			crm_str(id), crm_str(task));
 
 	} else if(action->type == action_type_pseudo){
 		te_log_action(LOG_INFO, "Executing pseudo-event (%d): "
 			 "%s on %s", action->id, task, on_node);
 		
 		action->complete = TRUE;
 		process_trigger(action->id);
 		ret = TRUE;
 
 	} else if(action->type == action_type_crm
 		  && safe_str_eq(task, CRM_OP_FENCE)){
 		
 		const char *uuid = NULL;
 		const char *target = NULL;
 		stonith_ops_t * st_op = NULL;
 
 		target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 		uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
 		CRM_DEV_ASSERT(target != NULL);
 		CRM_DEV_ASSERT(uuid != NULL);
 
 		te_log_action(LOG_INFO,"Executing fencing operation (%s) on %s",
 			      id, target);
 #ifdef TESTING
 		ret = TRUE;
 		action->complete = TRUE;
 		process_trigger(action->id);
 		return TRUE;
 #endif
 		crm_malloc0(st_op, sizeof(stonith_ops_t));
 		st_op->optype = RESET;
 		st_op->timeout = transition_idle_timeout / 2;
 		st_op->node_name = crm_strdup(target);
 		st_op->node_uuid = crm_strdup(uuid);
 
 		if(stonithd_input_IPC_channel() == NULL) {
 			crm_err("Cannot fence %s - stonith not available",
 				target);
 			
 		} else if (ST_OK == stonithd_node_fence( st_op )) {
 			ret = TRUE;
 		}
 		
 	} else if(on_node == NULL || strlen(on_node) == 0) {
 		/* error */
 		te_log_action(LOG_ERR,
 			      "Failed on corrupted command: %s (id=%s) %s on %s",
 			      crm_element_name(action->xml), crm_str(id),
 			      crm_str(task), crm_str(on_node));
 			
 	} else if(action->type == action_type_crm){
 		te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s",
 			      id, task, on_node);
 
 #ifdef TESTING
 		action->complete = TRUE;
 		process_trigger(action->id);
 		return TRUE;
 #endif
 /* 		action->complete = TRUE; */
 		msg_task = task;
 		send_command = TRUE;
 
 	} else if(action->type == action_type_rsc){
 		/* never overwrite stop actions in the CIB with
 		 *   anything other than completed results
 		 *
 		 * Writing pending stops makes it look like the
 		 *   resource is running again
 		 */
 #ifdef TESTING
 		action->invoked = FALSE;
 		cib_action_update(action, LRM_OP_DONE);
 		return TRUE;
 #endif
 		action->invoked = FALSE;
 		if(safe_str_eq(task, CRMD_ACTION_START)
 		   || safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
 			cib_action_update(action, LRM_OP_PENDING);
 		} else {
 			cib_action_updated(NULL, 0, cib_ok, NULL, action);
 		}
 		ret = TRUE;
 
 	} else {
 		te_log_action(LOG_ERR,
 			      "Failed on unsupported command type: "
 			      "%s, %s (id=%s) on %s",
 			      crm_element_name(action->xml), task, id, on_node);
 	}
 
 	if(send_command) {
 		HA_Message *cmd = NULL;
 		char *counter = crm_itoa(transition_counter);
 
 		cmd = create_request(msg_task, NULL, on_node, CRM_SYSTEM_CRMD,
 				     CRM_SYSTEM_TENGINE, NULL);
 
 		counter = generate_transition_key(transition_counter, te_uuid);
 		crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter);
 		ret = send_ipc_message(crm_ch, cmd);
 		crm_free(counter);
 
 		if(ret && action->timeout > 0) {
 			crm_debug_3("Setting timer for action %d",action->id);
 			action->timer->reason = timeout_action_warn;
 			start_te_timer(action->timer);
 		}
 	}
 	return ret;
 }
 
 gboolean
 cib_action_update(action_t *action, int status)
 {
 	char *code = NULL;
 	crm_data_t *fragment = NULL;
 	crm_data_t *state    = NULL;
 	crm_data_t *rsc      = NULL;
 	crm_data_t *xml_op   = NULL;
 	char *op_id = NULL;
 
 	enum cib_errors rc = cib_ok;
 	const char *task   = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 	const char *rsc_id = crm_element_value(action->xml, XML_LRM_ATTR_RSCID);
 	const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 	const char *target_uuid =
 		crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
 
 	int call_options = cib_quorum_override;
 
 	if(status == LRM_OP_TIMEOUT) {
 		if(crm_element_value(action->xml, XML_LRM_ATTR_RSCID) != NULL) {
 			crm_warn("%s: %s %s on %s timed out",
 				 crm_element_name(action->xml), task, rsc_id, target);
 		} else {
 			crm_warn("%s: %s on %s timed out",
 				 crm_element_name(action->xml), task, target);
 		}
 	}
 	code = crm_itoa(status);
 	
 /*
   update the CIB
 
 <node_state id="hadev">
       <lrm>
         <lrm_resources>
           <lrm_resource id="rsc2" last_op="start" op_code="0" target="hadev"/>
 */
 
 	fragment = NULL;
 	state    = create_xml_node(NULL, XML_CIB_TAG_STATE);
 
 	crm_xml_add(state, XML_ATTR_UUID,  target_uuid);
 	crm_xml_add(state, XML_ATTR_UNAME, target);
 	
 	rsc = create_xml_node(state, XML_CIB_TAG_LRM);
 	rsc = create_xml_node(rsc,   XML_LRM_TAG_RESOURCES);
 	rsc = create_xml_node(rsc,   XML_LRM_TAG_RESOURCE);
 
 	xml_op = create_xml_node(rsc,XML_LRM_TAG_RSC_OP);
 	
 	crm_xml_add(rsc,    XML_ATTR_ID, rsc_id);
 	crm_xml_add(xml_op, XML_ATTR_ID, task);
 	
 	op_id = generate_op_key(rsc_id, task, action->interval);
 	crm_xml_add(xml_op, XML_ATTR_ID, op_id);
 	crm_free(op_id);
 	
 	crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
 	crm_xml_add(rsc, XML_LRM_ATTR_RSCSTATE,
 			      get_rsc_state(task, status));
 	
 	crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, code);
 	crm_xml_add(xml_op, XML_LRM_ATTR_CALLID, "-1");
 	crm_xml_add(xml_op, XML_LRM_ATTR_RC, code);
 	crm_xml_add(xml_op, "origin", __FUNCTION__);
 
 	crm_free(code);
 
 	code = generate_transition_key(transition_counter, te_uuid);
 	crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, code);
 	crm_free(code);
 
 	code = generate_transition_magic(
 		crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY), status, status);
 	crm_xml_add(xml_op,  XML_ATTR_TRANSITION_MAGIC, code);
 	crm_free(code);
 	
 	set_node_tstamp(xml_op);
 
 	fragment = create_cib_fragment(state, XML_CIB_TAG_STATUS);
 	
 	crm_debug_3("Updating CIB with \"%s\" (%s): %s %s on %s",
 		  status<0?"new action":XML_ATTR_TIMEOUT,
 		  crm_element_name(action->xml), crm_str(task), rsc_id, target);
 	
 #ifndef TESTING
-	rc = te_cib_conn->cmds->modify(
+	rc = te_cib_conn->cmds->update(
 		te_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, call_options);
 
 	crm_debug("Updating CIB with %s action %d: %s %s on %s (call_id=%d)",
 		  op_status2text(status), action->id, task, rsc_id, target, rc);
 
 	if(status == LRM_OP_PENDING) {
 		crm_debug_2("Waiting for callback id: %d", rc);
 		add_cib_op_callback(rc, FALSE, action, cib_action_updated);
 	}
 #else
 	te_log_action(LOG_INFO, "Initiating action %d: %s %s on %s",
 		      action->id, task, rsc_id, target);
 	call_options = 0;
 	{
 		HA_Message *cmd = ha_msg_new(11);
 		ha_msg_add(cmd, F_TYPE,		T_CRM);
 		ha_msg_add(cmd, F_CRM_VERSION,	CRM_FEATURE_SET);
 		ha_msg_add(cmd, F_CRM_MSG_TYPE, XML_ATTR_REQUEST);
 		ha_msg_add(cmd, F_CRM_TASK,	CRM_OP_EVENTCC);
 		ha_msg_add(cmd, F_CRM_SYS_TO,   CRM_SYSTEM_TENGINE);
 		ha_msg_add(cmd, F_CRM_SYS_FROM, CRM_SYSTEM_TENGINE);
 		ha_msg_addstruct(cmd, crm_element_name(state), state);
 		send_ipc_message(crm_ch, cmd);
 	}
 #endif
 	free_xml(fragment);
 	free_xml(state);
 
 	action->sent_update = TRUE;
 	
 	if(rc < cib_ok) {
 		return FALSE;
 	}
 
 	return TRUE;
 }
 
 
 void
 cib_action_updated(
 	const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data)
 {
 	HA_Message *cmd = NULL;
 	crm_data_t *rsc_op  = NULL;
 	const char *task    = NULL;
 	const char *rsc_id  = NULL;
 	const char *on_node = NULL;
 	const char *value = NULL;
 
 	action_t *action = user_data;
 	char *counter = crm_itoa(transition_counter);
 
 	CRM_DEV_ASSERT(action != NULL);      if(crm_assert_failed) { return; }
 	CRM_DEV_ASSERT(action->xml != NULL); if(crm_assert_failed) { return; }
 
 	rsc_op  = action->xml;
 	task    = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
 	rsc_id  = crm_element_value(rsc_op, XML_LRM_ATTR_RSCID);
 	on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET);
 	counter = generate_transition_key(transition_counter, te_uuid);
 	crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter);
 	crm_free(counter);
 	
 	if(rc < cib_ok) {
 		crm_err("Update for action %d: %s %s on %s FAILED",
 			action->id, task, rsc_id, on_node);
 		send_complete(cib_error2string(rc), output, te_failed, i_cancel);
 		return;
 	}
 
 	if(te_fsa_state != s_in_transition) {
 		int pending_updates = num_cib_op_callbacks();
 		if(pending_updates == 0) {
 			send_complete("CIB update queue empty", output,
 				      te_done, i_cib_complete);
 		} else {
 			crm_debug("Still waiting on %d callbacks",
 				pending_updates);
 		}
 		crm_debug("Not executing action: Not in a transition: %d",
 			  te_fsa_state);
 		return;
 	}
 	
 	crm_info("Initiating action %d: %s %s on %s",
 		 action->id, task, rsc_id, on_node);
 	
 	if(rsc_op != NULL) {
 		crm_log_xml_debug_2(rsc_op, "Performing");
 	}
 	cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node,
 			     CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL);
 	
 
 #ifndef TESTING
 	send_ipc_message(crm_ch, cmd);
 #else
 	crm_log_message(LOG_INFO, cmd);
 #endif
 	
 	action->invoked = TRUE;
 	value = g_hash_table_lookup(action->params, XML_ATTR_TE_NOWAIT);
 	if(crm_is_true(value)) {
 		crm_info("Skipping wait for %d", action->id);
 		action->complete = TRUE;
 		process_trigger(action->id);
 
 	} else if(action->timeout > 0) {
 		crm_debug_3("Setting timer for action %d",action->id);
 		action->timer->reason = timeout_action_warn;
 		start_te_timer(action->timer);
 	}
 }
 
 gboolean
 initiate_transition(void)
 {
 	crm_info("Initating transition");
 
 	process_graph_event(NULL, NULL);
 
 	return TRUE;
 }
 
 void
 check_synapse_triggers(synapse_t *synapse, int action_id)
 {
 	synapse->triggers_complete = TRUE;
 			
 	if(synapse->confirmed) {
 		crm_debug_3("Skipping confirmed synapse %d", synapse->id);
 		return;
 			
 	} else if(synapse->complete == FALSE) {
 		crm_debug_3("Checking pre-reqs for %d", synapse->id);
 		/* lookup prereqs */
 		slist_iter(
 			prereq, action_t, synapse->inputs, lpc,
 				
 			crm_debug_3("Processing input %d", prereq->id);
 				
 			if(prereq->id == action_id) {
 				crm_debug_3("Marking input %d complete",
 					  action_id);
 				prereq->complete = TRUE;
 					
 			} else if(prereq->complete == FALSE) {
 				crm_debug_3("Inputs for synapse %d not satisfied",
 					  synapse->id);
 				synapse->triggers_complete = FALSE;
 			}
 				
 			);
 	}
 }
 
 void
 fire_synapse(synapse_t *synapse) 
 {
 	if(synapse == NULL) {
 		crm_err("Synapse was NULL!");
 		return;
 	}
 	
 	crm_debug_3("Checking if synapse %d needs to be fired", synapse->id);
 	if(synapse->complete) {
 		crm_debug_3("Skipping complete synapse %d", synapse->id);
 		return;
 		
 	} else if(synapse->triggers_complete == FALSE) {
 		crm_debug_3("Synapse %d not yet satisfied", synapse->id);
 		return;
 	}
 	
 	crm_debug("All inputs for synapse %d satisfied... invoking actions",
 		  synapse->id);
 
 	synapse->complete = TRUE;
 	slist_iter(
 		action, action_t, synapse->actions, lpc,
 
 		/* allow some leeway */
 		int tmp_time = 2 * action->timeout;
 		gboolean passed = FALSE;
 		action->invoked = TRUE;
 
 		/* Invoke the action and start the timer */
 		passed = initiate_action(action);
 
 		if(passed == FALSE) {
 			crm_err("Failed initiating <%s id=%d> in synapse %d",
 				crm_element_name(action->xml),
 				action->id, synapse->id);
 
 			send_complete("Action init failed", action->xml,
 				      te_failed, i_cancel);
 			return;
 		} 
 		if(tmp_time > transition_timer->timeout) {
 			crm_debug("Action %d: Increasing IDLE timer to %d",
 				  action->id, tmp_time);
 			transition_timer->timeout = tmp_time;
 		}
 			
 		);
 	
 	crm_debug("Synapse %d complete", synapse->id);
 }
 
 gboolean
 confirm_synapse(synapse_t *synapse, int action_id) 
 {
 	gboolean complete = TRUE;
 	synapse->confirmed = TRUE;
 	slist_iter(
 		action, action_t, synapse->actions, lpc,
 		
 		if(action->complete == FALSE) {
 			complete = FALSE;
 			synapse->confirmed = FALSE;
 			crm_debug_3("Found an incomplete action"
 				  " - transition not complete");
 			break;
 		}
 		);
 
 	if(complete) {
 		crm_debug("Synapse %d complete (action=%d)",
 			  synapse->id, action_id);
 	}
 
 	return complete;
 }
 
 void
 process_trigger(int action_id) 
 {
 	if(te_fsa_state != s_in_transition) {
 		int unconfirmed = unconfirmed_actions();
 		crm_info("Trigger from action %d (%d more) discarded:"
 			 " Not in transition", action_id, unconfirmed);
 		if(unconfirmed == 0) {
 			send_complete("Last pending action confirmed", NULL,
 				      te_abort_confirmed, i_cmd_complete);
 		}
 		return;
 	}
 	
 	graph_complete = TRUE;
 	
 	crm_debug_3("Processing trigger from action %d", action_id);
 
 	/* something happened, stop the timer and start it again at the end */
 	stop_te_timer(transition_timer);
 	
 	slist_iter(
 		synapse, synapse_t, graph, lpc,
 		
 		if(synapse->confirmed) {
 			crm_debug_3("Skipping confirmed synapse %d", synapse->id);
 			continue;
 		}
 		
 		check_synapse_triggers(synapse, action_id);
 		
 		fire_synapse(synapse);
 
 		if(graph == NULL) {
 			crm_err("Trigger processing aborted after failed synapse");
 			break;
 		}
 		
 		crm_debug_3("Checking if %d is confirmed", synapse->id);
 		if(synapse->complete == FALSE) {
 			crm_debug_3("Found an incomplete synapse"
 				  " - transition not complete");
 			/* indicate that the transition is not yet complete */
 			graph_complete = FALSE;
 			
 		} else if(synapse->confirmed == FALSE) {
 			gboolean confirmed = confirm_synapse(synapse,action_id);
 			graph_complete = graph_complete && confirmed;
 		}
 
 		crm_debug_3("%d is %s", synapse->id,
 			  synapse->confirmed?"confirmed":synapse->complete?"complete":"pending");
 		
 		);
 }
 	
diff --git a/include/crm/cib.h b/include/crm/cib.h
index bf68962956..f9ec52aa6e 100644
--- a/include/crm/cib.h
+++ b/include/crm/cib.h
@@ -1,381 +1,384 @@
-/* $Id: cib.h,v 1.33 2005/09/27 14:20:19 andrew Exp $ */
+/* $Id: cib.h,v 1.34 2005/10/12 18:28:21 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 CIB__H
 #define CIB__H
 
 #include <portability.h>
 
 #include <clplumbing/ipc.h>
 #include <crm/common/ipc.h>
 #include <crm/common/xml.h>
 #include <ha_msg.h>
 
 #define CIB_FEATURE_SET "1.2"
 /* use compare_version() for doing comparisons */
 
 enum cib_variant {
 	cib_native,
 	cib_database,
 	cib_edir
 };
 
 enum cib_state {
 	cib_connected_command,
 	cib_connected_query,
 	cib_disconnected
 };
 
 enum cib_conn_type {
 	cib_command,
 	cib_query,
 	cib_no_connection
 };
 
 enum cib_call_options {
 	cib_none            = 0x00000000,
 	cib_verbose         = 0x00000001,
 	cib_discard_reply   = 0x00000010,
 	cib_scope_local     = 0x00000100,
 	cib_sync_call       = 0x00001000,
 	cib_inhibit_notify  = 0x00010000,
  	cib_quorum_override = 0x00100000,
 	cib_inhibit_bcast   = 0x01000000,
 	cib_force_diff	    = 0x10000000
 };
 
 #define cib_default_options = cib_none
 
 enum cib_errors {
 	cib_ok			=  0,
 	cib_operation		= -1,
 	cib_create_msg		= -2,
 	cib_not_connected	= -3,
 	cib_not_authorized	= -4,
 	cib_send_failed		= -5,
 	cib_reply_failed	= -6,
 	cib_return_code		= -7,
 	cib_output_ptr		= -8,
 	cib_output_data		= -9,
 	cib_connection		= -10,
 	cib_authentication	= -11,
 	cib_missing		= -12,
 	cib_variant		= -28,
 	CIBRES_MISSING_ID	= -13,
 	CIBRES_MISSING_TYPE	= -14,
 	CIBRES_MISSING_FIELD	= -15,
 	CIBRES_OBJTYPE_MISMATCH	= -16,
 	CIBRES_CORRUPT		= -17,	
 	CIBRES_OTHER		= -18,
 	cib_unknown		= -19,
 	cib_STALE		= -20,
 	cib_EXISTS		= -21,
 	cib_NOTEXISTS		= -22,
 	cib_ACTIVATION		= -23,
 	cib_NOSECTION		= -24,
 	cib_NOOBJECT		= -25,
 	cib_NOPARENT		= -26,
 	cib_NODECOPY		= -27,
 	cib_NOTSUPPORTED	= -29,
 	cib_registration_msg	= -30,
 	cib_callback_token	= -31,
 	cib_callback_register	= -32,
 	cib_msg_field_add	= -33,
 	cib_client_gone		= -34,
 	cib_not_master		= -35,
 	cib_client_corrupt	= -36,
 	cib_master_timeout	= -37,
 	cib_revision_unsupported= -38,
 	cib_revision_unknown	= -39,
 	cib_missing_data	= -40,
 	cib_remote_timeout	= -41,
 	cib_no_quorum		= -42,
 	cib_diff_failed		= -43,
 	cib_diff_resync		= -44,
 	cib_old_data		= -45
 };
 
 enum cib_update_op {
 	CIB_UPDATE_OP_NONE = 0,
 	CIB_UPDATE_OP_ADD,
 	CIB_UPDATE_OP_MODIFY,
 	CIB_UPDATE_OP_DELETE,
 	CIB_UPDATE_OP_MAX
 };
 
 enum cib_section {
 	cib_section_none,
 	cib_section_all,
 	cib_section_nodes,
 	cib_section_constraints,
 	cib_section_resources,
 	cib_section_crmconfig,
 	cib_section_status
 };
 
 #define CIB_OP_SLAVE	"cib_slave"
 #define CIB_OP_SLAVEALL	"cib_slave_all"
 #define CIB_OP_MASTER	"cib_master"
 #define CIB_OP_SYNC	"cib_sync"
 #define CIB_OP_SYNC_ONE	"cib_sync_one"
 #define CIB_OP_ISMASTER	"cib_ismaster"
 #define CIB_OP_BUMP	"cib_bump"
 #define CIB_OP_QUERY	"cib_query"
 #define CIB_OP_CREATE	"cib_create"
 #define CIB_OP_UPDATE	"cib_update"
+#define CIB_OP_MODIFY	"cib_modify"
 #define CIB_OP_DELETE	"cib_delete"
 #define CIB_OP_DELETE_ALT	"cib_delete_alt"
 #define CIB_OP_ERASE	"cib_erase"
 #define CIB_OP_REPLACE	"cib_replace"
 #define CIB_OP_NOTIFY	"cib_notify"
 #define CIB_OP_APPLY_DIFF "cib_apply_diff"
 
 #define F_CIB_CLIENTID  "cib_clientid"
 #define F_CIB_CALLOPTS  "cib_callopt"
 #define F_CIB_CALLID    "cib_callid"
 #define F_CIB_CALLDATA  "cib_calldata"
 #define F_CIB_OPERATION "cib_op"
 #define F_CIB_ISREPLY   "cib_isreplyto"
 #define F_CIB_SECTION   "cib_section"
 #define F_CIB_HOST	"cib_host"
 #define F_CIB_RC	"cib_rc"
 #define F_CIB_DELEGATED	"cib_delegated_from"
 #define F_CIB_OBJID	"cib_object"
 #define F_CIB_OBJTYPE	"cib_object_type"
 #define F_CIB_EXISTING	"cib_existing_object"
 #define F_CIB_SEENCOUNT	"cib_seen"
 #define F_CIB_TIMEOUT	"cib_timeout"
 #define F_CIB_UPDATE	"cib_update"
 #define F_CIB_CALLBACK_TOKEN	"cib_callback_token"
 #define F_CIB_GLOBAL_UPDATE	"cib_update"
 #define F_CIB_UPDATE_RESULT	"cib_update_result"
 #define F_CIB_CLIENTNAME	"cib_clientname"
 #define F_CIB_NOTIFY_TYPE	"cib_notify_type"
 #define F_CIB_NOTIFY_ACTIVATE	"cib_notify_activate"
 #define F_CIB_UPDATE_DIFF	"cib_update_diff"
 
 #define T_CIB			"cib"
 #define T_CIB_NOTIFY		"cib_notify"
 /* notify sub-types */
 #define T_CIB_PRE_NOTIFY	"cib_pre_notify"
 #define T_CIB_POST_NOTIFY	"cib_post_notify"
 #define T_CIB_UPDATE_CONFIRM	"cib_update_confirmation"
 #define T_CIB_DIFF_NOTIFY	"cib_diff_notify"
 
 #define cib_channel_ro		"cib_ro"
 #define cib_channel_rw		"cib_rw"
 #define cib_channel_callback	"cib_callback"
 
 typedef struct cib_s cib_t;
 
 typedef struct cib_api_operations_s
 {
 		int (*variant_op)(
 			cib_t *cib, const char *op, const char *host,
 			const char *section, crm_data_t *data,
 			crm_data_t **output_data, int call_options);
 		
 		int (*signon) (
 			cib_t *cib, const char *name, enum cib_conn_type type);
 		int (*signoff)(cib_t *cib);
 		int (*free) (cib_t *cib);
 
 		int (*set_op_callback)(
 			cib_t *cib, void (*callback)(
 				const HA_Message *msg, int callid ,
 				int rc, crm_data_t *output));
 
 		int (*add_notify_callback)(
 			cib_t *cib, const char *event, void (*callback)(
 				const char *event, HA_Message *msg));
 
 		int (*del_notify_callback)(
 			cib_t *cib, const char *event, void (*callback)(
 				const char *event, HA_Message *msg));
 
 		int (*set_connection_dnotify)(
 			cib_t *cib, void (*dnotify)(gpointer user_data));
 		
 		IPC_Channel *(*channel)(cib_t* cib);
 		int (*inputfd)(cib_t* cib);
 
 		int (*noop)(cib_t *cib, int call_options);
 		int (*ping)(
 			cib_t *cib, crm_data_t **output_data, int call_options);
 
 		int (*query)(cib_t *cib, const char *section,
 			     crm_data_t **output_data, int call_options);
 		int (*query_from)(
 			cib_t *cib, const char *host, const char *section,
 			crm_data_t **output_data, int call_options);
 
 		int (*is_master) (cib_t *cib);
 		int (*set_master)(cib_t *cib, int call_options);
 		int (*set_slave) (cib_t *cib, int call_options);
 		int (*set_slave_all)(cib_t *cib, int call_options);
 		
 		int (*sync)(cib_t *cib, const char *section, int call_options);
 		int (*sync_from)(
 			cib_t *cib, const char *host, const char *section,
 			int call_options);
 
 		int (*bump_epoch)(cib_t *cib, int call_options);
 		
 		int (*create)(cib_t *cib, const char *section, crm_data_t *data,
 			   crm_data_t **output_data, int call_options);
 		int (*modify)(cib_t *cib, const char *section, crm_data_t *data,
 			   crm_data_t **output_data, int call_options);
+		int (*update)(cib_t *cib, const char *section, crm_data_t *data,
+			   crm_data_t **output_data, int call_options);
 		int (*replace)(cib_t *cib, const char *section, crm_data_t *data,
 			   crm_data_t **output_data, int call_options);
 		int (*delete)(cib_t *cib, const char *section, crm_data_t *data,
 			   crm_data_t **output_data, int call_options);
 		int (*delete_absolute)(
 			cib_t *cib, const char *section, crm_data_t *data,
 			crm_data_t **output_data, int call_options);
 		int (*erase)(
 			cib_t *cib, crm_data_t **output_data, int call_options);
 
 		int (*quit)(cib_t *cib,   int call_options);
 		
 		gboolean (*msgready)(cib_t* cib);
 		int (*rcvmsg)(cib_t* cib, int blocking);
 		gboolean (*dispatch)(IPC_Channel *channel, gpointer user_data);
 
 		int (*register_callback)(
 			cib_t* cib, const char *callback, int enabled);
 
 } cib_api_operations_t;
 
 struct cib_s
 {
 		enum cib_state	   state;
 		enum cib_conn_type type;
 
 		int   call_id;
 		int   call_timeout;
 		void  *variant_opaque;
 
 		GList *notify_list;
 		void (*op_callback)(const HA_Message *msg, int call_id,
 				    int rc, crm_data_t *output);
 
 		cib_api_operations_t *cmds;
 };
 
 typedef struct cib_notify_client_s 
 {
 	const char *event;
 	const char *obj_id;   /* implement one day */
 	const char *obj_type; /* implement one day */
 	void (*callback)(
 		const char *event, HA_Message *msg);
 	
 } cib_notify_client_t;
 
 typedef struct cib_callback_client_s 
 {
 		void (*callback)(
 			const HA_Message*, int, int, crm_data_t*, void*);
 		void *user_data;
 		gboolean only_success;
 		
 } cib_callback_client_t;
 
 /* Core functions */
 extern cib_t *cib_new(void);
 
 extern gboolean   startCib(const char *filename);
 extern crm_data_t *get_cib_copy(cib_t *cib);
 extern crm_data_t *cib_get_generation(cib_t *cib);
 extern int cib_compare_generation(crm_data_t *left, crm_data_t *right);
 extern 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*));
 extern void remove_cib_op_callback(int call_id, gboolean all_callbacks);
 extern int num_cib_op_callbacks(void);
 
 /* Utility functions */
 extern crm_data_t *get_object_root(const char *object_type,crm_data_t *the_root);
 extern crm_data_t *create_cib_fragment_adv(
 			crm_data_t *update, const char *section, const char *source);
 extern char *cib_pluralSection(const char *a_section);
 extern const char *get_crm_option(
 	crm_data_t *cib, const char *name, gboolean do_warn);
 
 /* Error Interpretation*/
 extern const char *cib_error2string(enum cib_errors);
 extern const char *cib_op2string(enum cib_update_op);
 
 extern crm_data_t *createEmptyCib(void);
 extern gboolean verifyCibXml(crm_data_t *cib);
 extern int cib_section2enum(const char *a_section);
 
 #define create_cib_fragment(update,cib_section) create_cib_fragment_adv(update, cib_section, __FUNCTION__)
 
 extern crm_data_t *diff_cib_object(
 	crm_data_t *old, crm_data_t *new,gboolean suppress);
 
 extern gboolean apply_cib_diff(
 	crm_data_t *old, crm_data_t *diff, crm_data_t **new);
 
 extern void log_cib_diff(int log_level, crm_data_t *diff, const char *function);
 
 extern gboolean cib_diff_version_details(
 	crm_data_t *diff, int *admin_epoch, int *epoch, int *updates, 
 	int *_admin_epoch, int *_epoch, int *_updates);
 
 extern gboolean cib_version_details(
 	crm_data_t *cib, int *admin_epoch, int *epoch, int *updates);
 
 extern enum cib_errors update_attr(
 	cib_t *the_cib,
 	const char *section, const char *node_uuid, const char *set_name,
 	const char *attr_id, const char *attr_name, const char *attr_value);
 
 extern enum cib_errors read_attr(
 	cib_t *the_cib,
 	const char *section, const char *node_uuid, const char *set_name,
 	const char *attr_id, const char *attr_name, char **attr_value);
 
 extern enum cib_errors delete_attr(
 	cib_t *the_cib,
 	const char *section, const char *node_uuid, const char *set_name,
 	const char *attr_id, const char *attr_name, const char *attr_value);
 
 extern enum cib_errors query_node_uuid(
 	cib_t *the_cib, const char *uname, char **uuid);
 
 extern enum cib_errors query_node_uname(
 	cib_t *the_cib, const char *uuid, char **uname);
 
 extern enum cib_errors query_standby(
 	cib_t *the_cib,
 	const char *uuid, const char *scope, char **standby_value);
 
 extern enum cib_errors set_standby(
 	cib_t *the_cib,
 	const char *uuid, const char *scope, const char *standby_value);
 
 enum cib_errors delete_standby(
 	cib_t *the_cib,
 	const char *uuid, const char *scope, const char *standby_value);
 
 extern const char *feature_set(crm_data_t *xml_obj);
 
 #endif
 
diff --git a/lib/crm/cib/cib_attrs.c b/lib/crm/cib/cib_attrs.c
index ad33f93ddd..de5ed13bed 100644
--- a/lib/crm/cib/cib_attrs.c
+++ b/lib/crm/cib/cib_attrs.c
@@ -1,438 +1,438 @@
-/* $Id: cib_attrs.c,v 1.4 2005/09/27 13:15:39 andrew Exp $ */
+/* $Id: cib_attrs.c,v 1.5 2005/10/12 18:28:21 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 <portability.h>
 
 #include <sys/param.h>
 
 #include <crm/crm.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/cib.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 
 enum cib_errors 
 update_attr(cib_t *the_cib,
 	    const char *section, const char *node_uuid, const char *set_name,
 	    const char *attr_id, const char *attr_name, const char *attr_value)
 {
 	const char *tag = NULL;
 	
 	enum cib_errors rc = cib_ok;
 	crm_data_t *xml_top = NULL;
 	crm_data_t *xml_obj = NULL;
 	crm_data_t *fragment = NULL;
 
 	if(attr_id == NULL) {
 		attr_id = attr_name;
 	}
 	if(attr_name == NULL) {
 		attr_name = attr_id;
 	}
 
 	CRM_ASSERT(attr_id != NULL);
 	CRM_ASSERT(attr_name != NULL);
 	
 	if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) {
 		tag = NULL;
 		
 	} else if(safe_str_eq(section, XML_CIB_TAG_NODES)) {
 		tag = XML_CIB_TAG_NODE;
 		
 	} else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) {
 		xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_STATE);
 		crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid);
 		if(xml_top == NULL) {
 			xml_top = xml_obj;
 		}
 		tag = XML_TAG_TRANSIENT_NODEATTRS;
 
 	} else {
 		return cib_NOSECTION;
 	}
 	
 	crm_debug("Creating %s/%s", section, tag);
 	if(tag != NULL) {
 		xml_obj = create_xml_node(xml_obj, tag);
 		crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid);
 		if(xml_top == NULL) {
 			xml_top = xml_obj;
 		}
 	}
 
 	if(set_name != NULL) {
 		xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS);
 		if(xml_top == NULL) {
 			xml_top = xml_obj;
 		}
 		crm_xml_add(xml_obj, XML_ATTR_ID, set_name);
 		xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS);
 	}
 	xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
 	if(xml_top == NULL) {
 		xml_top = xml_obj;
 	}
 	crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
 	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
 	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value);
 	
 	fragment = create_cib_fragment(xml_top, section);
 	crm_log_xml_debug_2(xml_top, "Update");
 	crm_log_xml_debug(fragment, "Update Fragment");
 	
 	free_xml(xml_top);
 	
-	rc = the_cib->cmds->modify(the_cib, section, fragment, NULL,
+	rc = the_cib->cmds->update(the_cib, section, fragment, NULL,
 				   cib_sync_call|cib_quorum_override);
 	if(rc != cib_ok) {
 		crm_err("Error setting %s=%s (section=%s, set=%s): %s",
 			attr_name, attr_value, section, crm_str(set_name),
 			cib_error2string(rc));
 	}
 	
 	free_xml(fragment);
 	return rc;
 }
 
 enum cib_errors 
 read_attr(cib_t *the_cib,
 	  const char *section, const char *node_uuid, const char *set_name,
 	  const char *attr_id, const char *attr_name, char **attr_value)
 {
 	const char *tag = NULL;
 	enum cib_errors rc = cib_ok;
 	crm_data_t *a_node = NULL;
 	crm_data_t *xml_obj = NULL;
 	crm_data_t *xml_next = NULL;
 	crm_data_t *fragment = NULL;
 
 	CRM_ASSERT(attr_value != NULL);
 	*attr_value = NULL;
 
 	crm_debug("Searching for attribute %s (section=%s, node=%s, set=%s)",
 		  attr_name, section, crm_str(node_uuid), crm_str(set_name));
 
 	rc = the_cib->cmds->query(
 		the_cib, section, &fragment, cib_sync_call);
 
 	if(rc != cib_ok) {
 		crm_err("Query failed for attribute %s (section=%s, node=%s, set=%s): %s",
 			attr_name, section, crm_str(set_name), crm_str(node_uuid),
 			cib_error2string(rc));
 		return rc;
 	}
 	
 	a_node = find_xml_node(fragment, XML_TAG_CIB, TRUE);
 	xml_obj = get_object_root(section, a_node);
 	CRM_ASSERT(xml_obj != NULL);
 	crm_log_xml_debug_2(xml_obj, "Result section");
 
 
 	if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) {
 		tag = NULL;
 		
 	} else if(safe_str_eq(section, XML_CIB_TAG_NODES)) {
 		tag = XML_CIB_TAG_NODE;
 		
 	} else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) {
 		xml_next = find_entity(xml_obj, XML_CIB_TAG_STATE, node_uuid);
 		tag = XML_TAG_TRANSIENT_NODEATTRS;
 
 	} else {
 		return cib_NOSECTION;
 	}
 	
 	
 	if(tag != NULL) {
 		xml_next = find_entity(xml_obj, tag, node_uuid);
 		if(xml_next == NULL) {
 			crm_debug("%s=%s not found in %s", tag, node_uuid,
 				  crm_element_name(xml_obj));
 			return cib_NOTEXISTS;
 		}
 		xml_obj = xml_next;
 	}
 	if(set_name != NULL) {
 		xml_next = find_entity(xml_obj, XML_TAG_ATTR_SETS, set_name);
 		if(xml_next == NULL) {
 			crm_debug("%s=%s object not found in %s",
 				  XML_TAG_ATTR_SETS, set_name,
 				  crm_element_name(xml_obj));
 			return cib_NOTEXISTS;
 		}
 		xml_obj = xml_next;
 
 		xml_next = find_xml_node(xml_obj, XML_TAG_ATTRS, TRUE);
 		if(xml_next == NULL) {
 			crm_debug("%s object not found in %s",
 				  XML_TAG_ATTRS, crm_element_name(xml_obj));
 			return cib_NOTEXISTS;
 		}
 		xml_obj = xml_next;
 	}
 
 	xml_next = NULL;
 	xml_child_iter(
 		xml_obj, a_child, XML_CIB_TAG_NVPAIR,
 		const char *name = crm_element_value(
 			a_child, XML_NVPAIR_ATTR_NAME);
 
 		if(attr_id != NULL
 		   && safe_str_neq(attr_id, ID(a_child))) {
 			continue;
 			
 		} else if(attr_name != NULL
 			  && safe_str_neq(attr_name, name)) {
 			continue;
 		}
 		xml_next = a_child;
 		break;
 		);
 	
 	if(xml_next == NULL) {
 		crm_debug("<%s id=%s name=%s/> not found in %s",
 			  XML_CIB_TAG_NVPAIR, attr_id, attr_name,
 			  crm_element_name(xml_obj));
 		return cib_NOTEXISTS;
 	}
 	xml_obj = xml_next;
 	
 	if(crm_element_value(xml_obj, XML_NVPAIR_ATTR_VALUE) != NULL) {
 		*attr_value = crm_element_value_copy(
 			xml_obj, XML_NVPAIR_ATTR_VALUE);
 	}
 	
 	free_xml(fragment);
 	return cib_ok;
 }
 
 
 enum cib_errors 
 delete_attr(cib_t *the_cib,
 	    const char *section, const char *node_uuid, const char *set_name,
 	    const char *attr_id, const char *attr_name, const char *attr_value)
 {
 	char *tmp = NULL;
 	enum cib_errors rc = cib_ok;
 	crm_data_t *xml_obj = NULL;
 
 	rc = read_attr(the_cib, section, node_uuid, set_name,
 		       attr_id, attr_name, &tmp);
 
 	if(rc != cib_ok) {
 		return rc;
 
 	} else if(attr_value != NULL
 		  && safe_str_neq(attr_value, tmp)) {
 		crm_free(tmp);
 		return cib_NOTEXISTS;
 	}
 	crm_free(tmp);
 
 	xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR);
 	crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
 	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
 	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value);
 	
 	rc = the_cib->cmds->delete(
 		the_cib, section, xml_obj, NULL,
 		cib_sync_call|cib_quorum_override);
 
 	free_xml(xml_obj);
 	return rc;
 }
 
 enum cib_errors 
 query_node_uuid(cib_t *the_cib, const char *uname, char **uuid)
 {
 	enum cib_errors rc = cib_ok;
 	crm_data_t *xml_obj = NULL;
 	crm_data_t *fragment = NULL;
 	const char *child_name = NULL;
 
 	CRM_ASSERT(uname != NULL);
 	CRM_ASSERT(uuid != NULL);
 	
 	rc = the_cib->cmds->query(
 		the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call);
 	if(rc != cib_ok) {
 		return rc;
 	}
 
 	xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE);
 	xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj);
 	CRM_ASSERT(xml_obj != NULL);
 	crm_log_xml_debug(xml_obj, "Result section");
 
 	rc = cib_NOTEXISTS;
 	*uuid = NULL;
 	
 	xml_child_iter(
 		xml_obj, a_child, XML_CIB_TAG_NODE,
 		child_name = crm_element_value(a_child, XML_ATTR_UNAME);
 
 		if(safe_str_eq(uname, child_name)) {
 			child_name = ID(a_child);
 			if(child_name != NULL) {
 				*uuid = crm_strdup(child_name);
 				rc = cib_ok;
 			}
 			break;
 		}
 		);
 	free_xml(fragment);
 	return rc;
 }
 
 enum cib_errors 
 query_node_uname(cib_t *the_cib, const char *uuid, char **uname)
 {
 	enum cib_errors rc = cib_ok;
 	crm_data_t *xml_obj = NULL;
 	crm_data_t *fragment = NULL;
 	const char *child_name = NULL;
 
 	CRM_ASSERT(uname != NULL);
 	CRM_ASSERT(uuid != NULL);
 	
 	rc = the_cib->cmds->query(
 		the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call);
 	if(rc != cib_ok) {
 		return rc;
 	}
 
 	xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE);
 	xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj);
 	CRM_ASSERT(xml_obj != NULL);
 	crm_log_xml_debug_2(xml_obj, "Result section");
 
 	rc = cib_NOTEXISTS;
 	*uname = NULL;
 	
 	xml_child_iter(
 		xml_obj, a_child, XML_CIB_TAG_NODE,
 		child_name = ID(a_child);
 
 		if(safe_str_eq(uuid, child_name)) {
 			child_name = crm_element_value(a_child, XML_ATTR_UNAME);
 			if(child_name != NULL) {
 				*uname = crm_strdup(child_name);
 				rc = cib_ok;
 			}
 			break;
 		}
 		);
 	free_xml(fragment);
 	return rc;
 }
 
 /* 	if(safe_str_eq(scope, "reboot")				\ */
 /* 	   || safe_str_eq(scope, XML_CIB_TAG_STATUS)) {		\ */
 /* 		type = XML_CIB_TAG_STATUS;			\ */
 /* 	}							\ */
 /* 								\ */
 #define standby_common 	char *attr_id  = NULL;	\
 	char *set_name = NULL;			\
 	const char *attr_name  = "standby";	\
 	const char *type = XML_CIB_TAG_NODES;	\
 						\
 	CRM_DEV_ASSERT(uuid != NULL);					\
 	CRM_DEV_ASSERT(standby_value != NULL);				\
 									\
 	crm_malloc0(attr_id, 2 + strlen(attr_name) + strlen(uuid));	\
 	sprintf(attr_id, "%s-%s", attr_name, uuid);			\
 									\
 	crm_malloc0(set_name, 2 + strlen(attr_name) + strlen(uuid));	\
 	sprintf(set_name, "%s-%s", attr_name, uuid);			\
 	
 
 enum cib_errors 
 query_standby(cib_t *the_cib, const char *uuid, const char *scope,
 	char **standby_value)
 {
 	enum cib_errors rc = cib_ok;
 	standby_common;
 
 	if(scope != NULL) {
 		rc = read_attr(the_cib, type, uuid, set_name,
 			       attr_id, attr_name, standby_value);
 	} else {
 		rc = read_attr(the_cib, XML_CIB_TAG_NODES, uuid, set_name,
 			       attr_id, attr_name, standby_value);
 #if 0
 		if(rc == cib_NOTEXISTS) {
 			crm_info("No standby value found with lifetime=forever,"
 				 " checking lifetime=reboot.");
 			rc = read_attr(the_cib, XML_CIB_TAG_STATUS, uuid, set_name,
 				       attr_id, attr_name, standby_value);
 		}
 #endif
 	}
 	
 	crm_free(attr_id);
 	crm_free(set_name);
 	return rc;
 }
 
 enum cib_errors 
 set_standby(cib_t *the_cib, const char *uuid, const char *scope,
 	    const char *standby_value)
 {
 	enum cib_errors rc = cib_ok;
 	standby_common;
 
 	rc = update_attr(the_cib, type, uuid, set_name,
 			 attr_id, attr_name, standby_value);
 
 	crm_free(attr_id);
 	crm_free(set_name);
 
 	return rc;
 }
 
 enum cib_errors 
 delete_standby(cib_t *the_cib, const char *uuid, const char *scope,
 	       const char *standby_value)
 {
 	enum cib_errors rc = cib_ok;
 	
 	standby_common;	
 	
 	rc = delete_attr(the_cib, type, uuid, set_name,
 			 attr_id, attr_name, standby_value);
 	
 	crm_free(attr_id);
 	crm_free(set_name);
 
 	return rc;
 }
 
diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c
index 2c33260024..a5e29f030c 100755
--- a/lib/crm/cib/cib_client.c
+++ b/lib/crm/cib/cib_client.c
@@ -1,1470 +1,1488 @@
 /*
  * 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 <portability.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
 
 #include <glib.h>
 #include <heartbeat.h>
 #include <clplumbing/ipc.h>
 
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <cib_private.h>
 
 /* 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);
+		      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);
+		      crm_data_t **output_data, int call_options);
+int cib_client_update(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);
+		       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);
+		      crm_data_t **output_data, int call_options);
 int cib_client_delete_absolute(
 	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->update  = cib_client_update;
 	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;
 
 	new_cib->cmds->delete_absolute  = cib_client_delete_absolute;
 	
 	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_MODIFY, NULL, section,
+				     data, output_data, call_options);
+}
+
+int cib_client_update(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_delete_absolute(
 	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_ALT, 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, "resource") == 0) {
 		a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
 
 	} 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_GROUP) == 0) {
 		a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
 
 	} else if(strcmp(a_section, XML_CIB_TAG_INCARNATION) == 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 if(strcmp(a_section, XML_TAG_ATTR_SETS) == 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 = "<unknown error>";
 	}
 	
 	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 = "<unknown operation>";
 	}
 	
 	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_epoch  = 0;
 	int this_admin_epoch = 0;
 
 	int diff_add_updates = 0;
 	int diff_add_epoch  = 0;
 	int diff_add_admin_epoch = 0;
 
 	int diff_del_updates = 0;
 	int diff_del_epoch  = 0;
 	int diff_del_admin_epoch = 0;
 
 	CRM_DEV_ASSERT(diff != NULL);
 	CRM_DEV_ASSERT(old != NULL);
 	
 	value = crm_element_value(old, XML_ATTR_GENERATION_ADMIN);
 	this_admin_epoch = atoi(value?value:"0");
 	crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION_ADMIN,
 		  this_admin_epoch, value);
 	
 	value = crm_element_value(old, XML_ATTR_GENERATION);
 	this_epoch = atoi(value?value:"0");
 	crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION, this_epoch, 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_epoch, &diff_add_epoch, &diff_add_updates, 
 		&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
 
 	value = NULL;
 	if(result && diff_del_admin_epoch != this_admin_epoch) {
 		value = XML_ATTR_GENERATION_ADMIN;
 		result = FALSE;
 		crm_debug_3("%s=%d", value, diff_del_admin_epoch);
 
 	} else if(result && diff_del_epoch != this_epoch) {
 		value = XML_ATTR_GENERATION;
 		result = FALSE;
 		crm_debug_3("%s=%d", value, diff_del_epoch);
 
 	} 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";
 		}
 		crm_xml_add(dest, name, value);
 
 		name = XML_ATTR_GENERATION;
 		value = crm_element_value(src, name);
 		if(value == NULL) {
 			value = "0";
 		}
 		crm_xml_add(dest, name, value);
 
 		name = XML_ATTR_NUMUPDATES;
 		value = crm_element_value(src, name);
 		if(value == NULL) {
 			value = "0";
 		}
 		crm_xml_add(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";
 		}
 		crm_xml_add(dest, name, value);
 
 		name = XML_ATTR_GENERATION;
 		value = crm_element_value(src, name);
 		if(value == NULL) {
 			value = "0";
 		}
 		crm_xml_add(dest, name, value);
 
 		name = XML_ATTR_NUMUPDATES;
 		value = crm_element_value(src, name);
 		if(value == NULL) {
 			value = "0";
 		}
 		crm_xml_add(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_epoch  = 0;
 	int add_admin_epoch = 0;
 
 	int del_updates = 0;
 	int del_epoch  = 0;
 	int del_admin_epoch = 0;
 
 	if(diff == NULL) {
 		return;
 	}
 	
 	cib_diff_version_details(
 		diff, &add_admin_epoch, &add_epoch, &add_updates, 
 		&del_admin_epoch, &del_epoch, &del_updates);
 
 	if(add_updates != del_updates) {
 		do_crm_log(log_level, NULL, function, "Diff: --- %d.%d.%d",
 			   del_admin_epoch, del_epoch, del_updates);
 		do_crm_log(log_level, NULL, function, "Diff: +++ %d.%d.%d",
 			   add_admin_epoch, add_epoch, add_updates);
 	} else if(diff != NULL) {
 		do_crm_log(log_level, NULL, function,
 			   "Local-only Change: %d.%d.%d",
 			   add_admin_epoch, add_epoch, add_updates);
 	}
 	
 	log_xml_diff(log_level, diff, function);
 }
 
 gboolean
 cib_version_details(
 	crm_data_t *cib, int *admin_epoch, int *epoch, int *updates)
 {
 	const char *value = NULL;
 	if(cib == NULL) {
 		*admin_epoch = -1;
 		*epoch  = -1;
 		*updates = -1;
 		return FALSE;
 		
 	} else {
 		value = crm_element_value(cib, XML_ATTR_GENERATION_ADMIN);
 		*admin_epoch = atoi(value?value:"-1");
 
 		value  = crm_element_value(cib, XML_ATTR_GENERATION);
 		*epoch = 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_epoch, int *epoch, int *updates, 
 	int *_admin_epoch, int *_epoch, int *_updates)
 {
 	crm_data_t *tmp = NULL;
 
 	tmp = find_xml_node(diff, "diff-added", FALSE);
 	cib_version_details(tmp, admin_epoch, epoch, updates);
 
 	tmp = find_xml_node(diff, "diff-removed", FALSE);
 	cib_version_details(tmp, _admin_epoch, _epoch, _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, FALSE);
 
 		node_stack[0] = object_type;
 		node_stack[1] = NULL;
 
 	} else {
 		tmp_node = find_xml_node_nested(the_root, node_stack, 2);
 	}
 
 	if (tmp_node == NULL) {
 		crm_debug_2("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 *update_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;
 	const char *update_name = NULL;
 
 /* 	crm_debug("Creating a blank fragment: %s", update_section); */
 	
 	if(update == NULL && update_section == NULL) {
 		crm_debug_3("Creating a blank fragment");
 		update = createEmptyCib();
 		whole_cib = TRUE;
 
 	} else if(update == NULL) {
 		crm_err("No update to create a fragment for");
 		return NULL;
 		
 	} else if(update_section == NULL) {
 		update_section = cib_pluralSection(update_name);
 	}
 
 	if(safe_str_eq(crm_element_name(update), XML_TAG_CIB)) {
 		whole_cib = TRUE;
 	}
 	
 	crm_xml_add(fragment, XML_ATTR_SECTION, update_section);
 
 	if(whole_cib == FALSE) {
 		cib = createEmptyCib();
 		crm_xml_add(cib, "debug_source", source);
 		object_root = get_object_root(update_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);
 		crm_xml_add(cib, "debug_source", source);
 	}
 	
 	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);
 	
 /* 	crm_xml_add(cib_root, "version", "1"); */
 	crm_xml_add(cib_root, "generated", XML_BOOLEAN_TRUE);
 
 	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;
 }