diff --git a/crmd/election.c b/crmd/election.c
index dac1527d15..02e3c28de5 100644
--- a/crmd/election.c
+++ b/crmd/election.c
@@ -1,477 +1,477 @@
 /* 
  * 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 <crm_internal.h>
 
 #include <heartbeat.h>
 
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/cluster.h>
 #include <crm/crm.h>
 #include <crmd_fsa.h>
 #include <crmd_messages.h>
 #include <crmd_callbacks.h>
 #include <clplumbing/Gmain_timeout.h>
 #include <clplumbing/cl_uuid.h>
 #include <ha_version.h>
 
 GHashTable *voted = NULL;
 uint highest_born_on = -1;
 static int current_election_id = 1;
 const char *get_hg_version(void);
 const char *get_hg_version(void) 
 {
     /* limit this #define's use to a single file to avoid rebuilding more than necessary */
-    return HA_HG_VERSION;
+    return BUILD_VERSION;
 }
 
 /*	A_ELECTION_VOTE	*/
 void
 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;
 	xmlNode *vote = NULL;
 	
 	/* don't vote if we're in one of these states or wanting to shut down */
 	switch(cur_state) {
 		case S_STARTING:
 		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;
 	}
 	
 	vote = create_request(
 		CRM_OP_VOTE, NULL, NULL,
 		CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
 
 	current_election_id++;
 	crm_xml_add(vote, F_CRM_ELECTION_OWNER, fsa_our_uuid);
 	crm_xml_add_int(vote, F_CRM_ELECTION_ID, current_election_id);
 
 	send_request(vote, NULL);
 	crm_debug("Destroying voted hash");
 	if(voted) {
 	    g_hash_table_destroy(voted);	    
 	}
 	free_xml(vote);
 	voted = 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;
 }
 
 char *dc_hb_msg = NULL;
 int beat_num = 0;
 
 gboolean
 do_dc_heartbeat(gpointer data)
 {
 	return TRUE;
 }
 
 struct election_data_s 
 {
 		const char *winning_uname;
 		unsigned int winning_bornon;
 };
 
 static void
 log_member_uname(gpointer key, gpointer value, gpointer user_data)
 {
     if(crm_is_member_active(value)) {
 	crm_err("%s: %s", (char*)user_data, (char*)key);
     }
 }
 
 static void
 log_node(gpointer key, gpointer value, gpointer user_data)
 {
 	crm_err("%s: %s", (char*)user_data, (char*)key);
 }
 
 void
 do_election_check(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 voted_size = 0;
 	int num_members = crm_active_members();
 
 	if(voted) {
 	    voted_size = g_hash_table_size(voted);
 	}
 	/* in the case of #voted > #members, it is better to
 	 *   wait for the timeout and give the cluster time to
 	 *   stabilize
 	 */
 	if(fsa_state != S_ELECTION) {
 		crm_debug("Ignore election check: we not in an election");
 
 	} else if(voted_size >= num_members) {
 		/* we won and everyone has voted */
 		crm_timer_stop(election_timeout);
 		register_fsa_input(C_FSA_INTERNAL, I_ELECTION_DC, NULL);
 		if(voted_size > num_members) {
 			char *data = NULL;
 			
 			data = crm_strdup("member");
 			g_hash_table_foreach(crm_peer_cache, log_member_uname, data);
 			crm_free(data);
 			
 			data = crm_strdup("voted");
 			g_hash_table_foreach(voted, log_node, data);
 			crm_free(data);
 			
 		}
 		crm_debug("Destroying voted hash");
 		g_hash_table_destroy(voted);
 		voted = NULL;
 		
 	} else {
 		crm_info("Still waiting on %d non-votes (%d total)",
 			 num_members - voted_size, num_members);
 	}
 
 	return;
 }
 
 /*	A_ELECTION_COUNT	*/
 void
 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)
 {
 	int election_id = -1;
 	gboolean we_loose = FALSE;
 	const char *op             = NULL;	
 	const char *vote_from      = NULL;
 	const char *your_version   = NULL;
 	const char *election_owner = NULL;
 	const char *reason	   = "unknown";
 	crm_node_t *our_node = NULL, *your_node = NULL;
 	ha_msg_input_t *vote = fsa_typed_data(fsa_dt_ha_msg);
 
 	static int win_dampen = 1;  /* in seconds */
 	static int loss_dampen = 2; /* in seconds */
 	static time_t last_election_win = 0;
 	static time_t last_election_loss = 0;
 	
 	/* if the membership copy is NULL we REALLY shouldnt be voting
 	 * the question is how we managed to get here.
 	 */
 	
 	CRM_CHECK(msg_data != NULL, return);
 	CRM_CHECK(crm_peer_cache != NULL, return);
 	CRM_CHECK(vote != NULL, crm_err("Bogus data from %s", msg_data->origin); return);
 	CRM_CHECK(vote->msg != NULL, crm_err("Bogus data from %s", msg_data->origin); return);
 	
 	vote_from = crm_element_value(vote->msg, F_CRM_HOST_FROM);
 	CRM_CHECK(vote_from != NULL, vote_from = fsa_our_uname);
 	
 	your_node = crm_get_peer(0, vote_from);
 	if(your_node == NULL || crm_is_member_active(your_node) == FALSE) {
 	    crm_debug("Election ignore: The other side doesn't exist in CCM: %s", vote_from);
 	    return;
 	}	
 	
  	if(voted == NULL) {
 		crm_debug("Created voted hash");
  		voted = g_hash_table_new_full(
 			g_str_hash, g_str_equal,
 			g_hash_destroy_str, g_hash_destroy_str);
  	}
 
 	op             = crm_element_value(vote->msg, F_CRM_TASK);
 	election_owner = crm_element_value(vote->msg, F_CRM_ELECTION_OWNER);
 
 	crm_element_value_int(vote->msg, F_CRM_ELECTION_ID, &election_id);
 	
 	our_node = crm_get_peer(0, fsa_our_uname);
 	CRM_ASSERT(our_node != NULL && crm_is_member_active(our_node));
 	crm_debug("Election %d, owner: %s", election_id, election_owner);
 
 	/* update the list of nodes that have voted */
 	if(crm_str_eq(fsa_our_uuid, election_owner, TRUE)
 	   || crm_str_eq(fsa_our_uname, election_owner, TRUE)) {
 		if(election_id == current_election_id) {
 			char *uname_copy = NULL;
 			char *op_copy = crm_strdup(op);
 			uname_copy = crm_strdup(your_node->uname);
 			g_hash_table_replace(voted, uname_copy, op_copy);
 			crm_info("Updated voted hash for %s to %s",
 				 your_node->uname, op);
 		} else {
 			crm_debug("Ignore old '%s' from %s: %d vs. %d",
 				  op, your_node->uname,
 				  election_id, current_election_id);
 			return;
 		}
 			
 	} else {
 		CRM_CHECK(safe_str_neq(op, CRM_OP_NOVOTE), return);
 	}
 	
 	if(vote_from == NULL || crm_str_eq(vote_from, fsa_our_uname, TRUE)) {
 		/* don't count our own vote */
 		crm_info("Election ignore: our %s (%s)", op,crm_str(vote_from));
 		return;
 
 	} else if(crm_str_eq(op, CRM_OP_NOVOTE, TRUE)) {
 		crm_info("Election ignore: no-vote from %s", vote_from);
 		return;
 	}
 
 	crm_info("Election check: %s from %s", op, vote_from);
 	your_version   = crm_element_value(vote->msg, F_CRM_VERSION);
 
 	if(cur_state == S_STARTING) {
 		reason = "still starting";
 		we_loose = TRUE;
 	
 	} else if(our_node == NULL || safe_str_neq(our_node->state, CRM_NODE_MEMBER)) {
 		reason = "we don't exist in CCM";
 		we_loose = TRUE;
 
 	} else if(compare_version(your_version, CRM_FEATURE_SET) < 0) {
 		reason = "version";
 		we_loose = TRUE;
 		
 	} else if(compare_version(your_version, CRM_FEATURE_SET) > 0) {
 		reason = "version";
 		
 	} else if(your_node->born < our_node->born) {
 		reason = "born_on";
 		we_loose = TRUE;
 		
 	} else if(your_node->born > our_node->born) {
 		reason = "born_on";
 
 	} else if(fsa_our_uname == NULL
 		  || strcasecmp(fsa_our_uname, vote_from) > 0) {
 		reason = "uname";
 		we_loose = TRUE;
 
 	} else {
 		CRM_CHECK(strcmp(fsa_our_uname, vote_from) != 0, ;);
 		crm_debug("Them: %s (born="U64T")  Us: %s (born="U64T")",
 			  vote_from, your_node->born,
 			  fsa_our_uname, our_node->born);
 /* cant happen...
  *	} else if(strcasecmp(fsa_our_uname, vote_from) == 0) {
  *
  * default...
  *	} else { // strcasecmp(fsa_our_uname, vote_from) < 0
  *		we win
  */
 	}
 
 	if(we_loose) {
 		xmlNode *novote = create_request(
 			CRM_OP_NOVOTE, NULL, vote_from,
 			CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
 
 		update_dc(NULL, FALSE);
 		
 		crm_timer_stop(election_timeout);
 		crm_debug("Election %d lost to %s: %s", election_id, vote_from, reason);
 		if(fsa_input_register & R_THE_DC) {
 			crm_debug_3("Give up the DC to %s", vote_from);
 			register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL);
 			
 		} else if(cur_state != S_STARTING) {
 			crm_debug_3("We werent the DC anyway");
 			register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL);
 		}
 
 		crm_xml_add(novote, F_CRM_ELECTION_OWNER, election_owner);
 		crm_xml_add_int(novote, F_CRM_ELECTION_ID, election_id);
 		
 		CRM_CHECK(send_request(novote, NULL),;);
 		free_xml(novote);
 
 		fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local);
 
 		last_election_loss = time(NULL);
 		last_election_win = 0;
 
 	} else {
 	    if(last_election_loss) {
 		time_t tm_now = time(NULL);
 		if(tm_now - last_election_loss < (time_t)loss_dampen) {
 		    crm_info("Election %d ignore: We already lost an election less than %ds ago",
 			      election_id, loss_dampen);
 		    return;
 		}
 		last_election_loss = 0;
 	    }
 
 	    if(last_election_win) {
 		time_t tm_now = time(NULL);
 		if(tm_now - last_election_win < (time_t)win_dampen) {
 		    crm_info("Election %d ignore: We already won an election less than %ds ago",
 			      election_id, win_dampen);
 		    return;
 		}
 	    }
 
 #if 0
 	    /* Enabling this code can lead to multiple DCs during SimulStart.
 	     * Specifically when a node comes up after our last 'win' vote.
 	     *
 	     * Fixing and enabling this functionality might become important when
 	     * we start running realy big clusters, but for now leave it disabled.
 	     */
 	    last_election_win = time(NULL);
 #endif
 	    register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
 	    crm_info("Election %d won over %s: %s", election_id, vote_from, reason);
 	    g_hash_table_destroy(voted);
 	    voted = NULL;
 	}
 	
 }
 
 /*	A_ELECT_TIMER_START, A_ELECTION_TIMEOUT 	*/
 /* we won */
 void
 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)
 {
 }
 
 
 static void
 feature_update_callback(xmlNode *msg, int call_id, int rc,
 			xmlNode *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	*/
 void
 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;
 	xmlNode *cib = NULL;
 	
 	crm_info("Taking over DC status for this partition");
 	set_bit_inplace(fsa_input_register, R_THE_DC);
 
 	if(voted != NULL) {
 		crm_debug_2("Destroying voted hash");
 		g_hash_table_destroy(voted);
 		voted = NULL;
 	}
 	
 	set_bit_inplace(fsa_input_register, R_JOIN_OK);
 	set_bit_inplace(fsa_input_register, R_INVOKE_PE);
 	
  	fsa_cib_conn->cmds->set_slave_all(fsa_cib_conn, cib_none);
 	fsa_cib_conn->cmds->set_master(fsa_cib_conn, cib_none);
 	
 	cib = create_xml_node(NULL, XML_TAG_CIB);
 	crm_xml_add(cib, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 	fsa_cib_update(XML_TAG_CIB, cib, cib_quorum_override, rc);
 	add_cib_op_callback(fsa_cib_conn, rc, FALSE, NULL, feature_update_callback);
 
 	update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_CRMCONFIG,
-		    NULL, NULL, NULL, "dc-version", VERSION"-"HA_HG_VERSION, FALSE);
+		    NULL, NULL, NULL, "dc-version", VERSION"-"BUILD_VERSION, FALSE);
 
 	free_xml(cib);
 }
 
 
 /*	 A_DC_RELEASE	*/
 void
 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)
 {
 	if(action & A_DC_RELEASE) {
 		crm_debug("Releasing the role of DC");
 		clear_bit_inplace(fsa_input_register, R_THE_DC);
 		
 	} 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);
 
 }
 
diff --git a/include/Makefile.am b/include/Makefile.am
index c9914fb97f..e2914ee35e 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,64 +1,64 @@
 #
 # linux-ha: Linux-HA heartbeat code
 #
 # Copyright (C) 2001 Michael Moerz
 #                    This instance created by Horms
 #
 # 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
 # of the License, or (at your option) any later version.
 # 
 # This program 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 program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #
 
 MAINTAINERCLEANFILES    = Makefile.in ha_version.h config.h.in
 
 EXTRA_DIST = ha_version.h crm_internal.h
 
 headerdir=$(pkgincludedir)
 
 
 noinst_HEADERS	        = portability.h config.h ha_version.h
 header_HEADERS	        = crm_config.h
  
 
 SUBDIRS                 =  crm fencing
 
 ## The backtick commands are not executed here,
 ## but rather as macro-expansions at use within the rules.
 HG_LIVE_VERSION := `$(HG) -R "$(top_srcdir)" id -itb`
 ARCHIVE_VERSION := "$(top_srcdir)/.hg_archival.txt"
 HG_TAR_VERSION  := `cat "$(ARCHIVE_VERSION)" | awk '/node:/ { print $2 }'`
 
 ha_version.h: $(ARCHIVE_VERSION)
 	if [ -r ha_version.h -a ! -w ha_version.h ]; then	\
 		hgv="";						\
 		echo "Saved Version";	 			\
 	elif [ -f $(ARCHIVE_VERSION) ]; then			\
 		hgv="$(HG_TAR_VERSION)";			\
 		echo "Hg Archived Version: $${hgv}";		\
 	elif [ -x $(HG) -a -d $(top_srcdir)/.hg ]; then		\
 		hgv="$(HG_LIVE_VERSION)";			\
 		echo "Hg Live Version: $${hgv}";	 	\
 	elif [ -r ha_version.h ]; then				\
 		hgv="";						\
 		echo "Hg Saved Live Version"; 			\
 		cat ha_version.h; 				\
 	else							\
 		hgv="Unknown";					\
 		echo "Unknown Hg Version";			\
 	fi ;							\
 	if [ X"$${hgv}" != "X" ]; then					\
 	  echo "/* $${hgv} */" > ha_version.h; 				\
-	  echo "#define HA_HG_VERSION \"$${hgv}\"" >> ha_version.h; 	\
+	  echo "#define BUILD_VERSION \"$${hgv}\"" >> ha_version.h; 	\
 	fi
 
 .PHONY: $(ARCHIVE_VERSION)
diff --git a/include/crm/common/util.h b/include/crm/common/util.h
index b409b26092..7190e7df0f 100644
--- a/include/crm/common/util.h
+++ b/include/crm/common/util.h
@@ -1,212 +1,213 @@
 /* 
  * 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 CRM_COMMON_UTIL__H
 #define CRM_COMMON_UTIL__H
 
 #include <signal.h>
 
 #if SUPPORT_HEARTBEAT
 #  include <hb_api.h>
 #  include <ocf/oc_event.h>
 #endif
 
 #include <lrm/lrm_api.h>
 
 #include <sys/types.h>
 #include <stdlib.h>
 #include <limits.h>
 
 #define DEBUG_INC SIGUSR1
 #define DEBUG_DEC SIGUSR2
 
 extern unsigned int crm_log_level;
 extern gboolean crm_config_error;
 extern gboolean crm_config_warning;
 
 #define crm_config_err(fmt...) { crm_config_error = TRUE; crm_err(fmt); }
 #define crm_config_warn(fmt...) { crm_config_warning = TRUE; crm_warn(fmt); }
 
 extern void crm_log_deinit(void);
 extern gboolean crm_log_init(
     const char *entity, int level, gboolean coredir, gboolean to_stderr,
     int argc, char **argv);
 
 /* returns the old value */
 extern unsigned int set_crm_log_level(unsigned int level);
 
 extern unsigned int get_crm_log_level(void);
 
 extern char *crm_itoa(int an_int);
 
 extern char *crm_strdup_fn(const char *a, const char *file, const char *fn, int line);
 
 extern char *generate_hash_key(const char *crm_msg_reference, const char *sys);
 
 extern char *generate_hash_value(const char *src_node, const char *src_subsys);
 
 extern gboolean decodeNVpair(const char *srcstring,
 			     char separator, char **name, char **value);
 
 extern int compare_version(const char *version1, const char *version2);
 
 
 extern char *generateReference(const char *custom1, const char *custom2);
 
 extern void alter_debug(int nsig);
 
 extern void g_hash_destroy_str(gpointer data);
 
 extern gboolean crm_is_true(const char * s);
 
 extern int crm_str_to_boolean(const char * s, int * ret);
 
 extern long long crm_get_msec(const char * input);
 extern unsigned long long crm_get_interval(const char * input);
 
 extern const char *op_status2text(op_status_t status);
 
 extern char *generate_op_key(
 	const char *rsc_id, const char *op_type, int interval);
 
 extern gboolean parse_op_key(
 	const char *key, char **rsc_id, char **op_type, int *interval);
 
 extern char *generate_notify_key(
 	const char *rsc_id, const char *notify_type, const char *op_type);
 
 extern char *generate_transition_magic_v202(
 	const char *transition_key, int op_status);
 
 extern char *generate_transition_magic(
 	const char *transition_key, int op_status, int op_rc);
 
 extern gboolean decode_transition_magic(
 	const char *magic, char **uuid,
 	int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc);
 
 extern char *generate_transition_key(int action, int transition_id, int target_rc, const char *node);
 
 extern gboolean decode_transition_key(
     const char *key, char **uuid, int *action, int *transition_id, int *target_rc);
 
 extern char *crm_concat(const char *prefix, const char *suffix, char join);
 
 extern gboolean decode_op_key(
 	const char *key, char **rsc_id, char **op_type, int *interval);
 
 extern void filter_action_parameters(xmlNode *param_set, const char *version);
 extern void filter_reload_parameters(xmlNode *param_set, const char *restart_string);
 
 #define safe_str_eq(a, b) crm_str_eq(a, b, FALSE)
 
 extern gboolean crm_str_eq(const char *a, const char *b, gboolean use_case);
 
 extern gboolean safe_str_neq(const char *a, const char *b);
 extern int crm_parse_int(const char *text, const char *default_text);
 extern long long crm_int_helper(const char *text, char **end_text);
 #define crm_atoi(text, default_text) crm_parse_int(text, default_text)
 
 extern void crm_abort(const char *file, const char *function, int line,
 		      const char *condition, gboolean do_core, gboolean do_fork);
 
 extern char *generate_series_filename(
 	const char *directory, const char *series, int sequence, gboolean bzip);
 
 extern int get_last_sequence(const char *directory, const char *series);
 
 extern void write_last_sequence(
 	const char *directory, const char *series, int sequence, int max);
 
 extern void crm_make_daemon(
 	const char *name, gboolean daemonize, const char *pidfile);
 
 typedef struct pe_cluster_option_s {
 	const char *name;
 	const char *alt_name;
 	const char *type;
 	const char *values;
 	const char *default_value;
 
 	gboolean (*is_valid)(const char *);
 
 	const char *description_short;
 	const char *description_long;
 	
 } pe_cluster_option;
 
 extern const char *cluster_option(
 	GHashTable* options, gboolean(*validate)(const char*),
 	const char *name, const char *old_name, const char *def_value);
 
 extern const char *get_cluster_pref(
 	GHashTable *options, pe_cluster_option *option_list, int len, const char *name);
 
 extern void config_metadata(
 	const char *name, const char *version, const char *desc_short, const char *desc_long,
 	pe_cluster_option *option_list, int len);
 
 extern void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len);
 extern gboolean check_time(const char *value);
 extern gboolean check_timer(const char *value);
 extern gboolean check_boolean(const char *value);
 extern gboolean check_number(const char *value);
 
 extern int char2score(const char *score);
 extern char *score2char(int score);
 
 extern gboolean crm_is_writable(
 	const char *dir, const char *file,
 	const char *user, const char *group, gboolean need_both);
 
 extern long long crm_set_bit(const char *function, long long word, long long bit);
 extern long long crm_clear_bit(const char *function, long long word, long long bit);
 
 
 #define set_bit(word, bit) word = crm_set_bit(__PRETTY_FUNCTION__, word, bit) 
 #define clear_bit(word, bit) word = crm_clear_bit(__PRETTY_FUNCTION__, word, bit) 
 
 #define set_bit_inplace(word, bit) word |= bit 
 #define clear_bit_inplace(word, bit) word &= ~bit 
 
 static inline gboolean
 is_not_set(long long word, long long bit)
 {
 	return ((word & bit) == 0);
 }
 
 static inline gboolean
 is_set(long long word, long long bit)
 {
 	return ((word & bit) == bit);
 }
 
 static inline gboolean
 is_set_any(long long word, long long bit)
 {
 	return ((word & bit) != 0);
 }
 
 extern gboolean is_openais_cluster(void);
 extern gboolean is_heartbeat_cluster(void);
 
 extern xmlNode *cib_recv_remote_msg(void *session);
 extern void cib_send_remote_msg(void *session, xmlNode *msg);
 extern char *crm_meta_name(const char *field);
 extern const char *crm_meta_value(GHashTable *hash, const char *field);
+extern void crm_show_version(int exit_code);
 
 #endif
diff --git a/lib/common/utils.c b/lib/common/utils.c
index 270f36bd5c..ae7a7076a6 100644
--- a/lib/common/utils.c
+++ b/lib/common/utils.c
@@ -1,1712 +1,1720 @@
 /* 
  * 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 <crm_internal.h>
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 
 #include <stdlib.h>
 #include <limits.h>
 #include <ctype.h>
 #include <pwd.h>
 #include <grp.h>
 
 #include <ha_msg.h>
 #include <clplumbing/cl_log.h>
 #include <clplumbing/cl_signal.h>
 #include <clplumbing/cl_syslog.h>
 #include <clplumbing/cl_misc.h>
 #include <clplumbing/coredumps.h>
 #include <clplumbing/lsb_exitcodes.h>
 #include <clplumbing/cl_pidfile.h>
 
 #include <time.h> 
 
 #include <clplumbing/Gmain_timeout.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/util.h>
 #include <crm/common/iso8601.h>
 
 #ifndef MAXLINE
 #    define MAXLINE 512
 #endif
 
 static uint ref_counter = 0;
 unsigned int crm_log_level = LOG_INFO;
 gboolean crm_config_error = FALSE;
 gboolean crm_config_warning = FALSE;
 const char *crm_system_name = "unknown";
 
 void crm_set_env_options(void);
 
 gboolean
 check_time(const char *value) 
 {
 	if(crm_get_msec(value) < 5000) {
 		return FALSE;
 	}
 	return TRUE;
 }
 
 gboolean
 check_timer(const char *value) 
 {
 	if(crm_get_msec(value) < 0) {
 		return FALSE;
 	}
 	return TRUE;
 }
 
 gboolean
 check_boolean(const char *value) 
 {
 	int tmp = FALSE;
 	if(crm_str_to_boolean(value, &tmp) != 1) {
 		return FALSE;
 	}
 	return TRUE;
 }
 
 gboolean
 check_number(const char *value) 
 {
 	errno = 0;
 	if(value == NULL) {
 		return FALSE;
 		
 	} else if(safe_str_eq(value, MINUS_INFINITY_S)) {
 		
 	} else if(safe_str_eq(value, INFINITY_S)) {
 
 	} else {
 		crm_int_helper(value, NULL);
 	}
 
 	if(errno != 0) {
 		return FALSE;
 	}
 	return TRUE;
 }
 
 int
 char2score(const char *score) 
 {
 	int score_f = 0;
 	
 	if(score == NULL) {
 		
 	} else if(safe_str_eq(score, MINUS_INFINITY_S)) {
 		score_f = -INFINITY;
 		
 	} else if(safe_str_eq(score, INFINITY_S)) {
 		score_f = INFINITY;
 		
 	} else if(safe_str_eq(score, "+"INFINITY_S)) {
 		score_f = INFINITY;
 		
 	} else {
 		score_f = crm_parse_int(score, NULL);
 		if(score_f > 0 && score_f > INFINITY) {
 			score_f = INFINITY;
 			
 		} else if(score_f < 0 && score_f < -INFINITY) {
 			score_f = -INFINITY;
 		}
 	}
 	
 	return score_f;
 }
 
 
 char *
 score2char(int score) 
 {
 
 	if(score >= INFINITY) {
 		return crm_strdup("+"INFINITY_S);
 
 	} else if(score <= -INFINITY) {
 		return crm_strdup("-"INFINITY_S);
 	} 
 	return crm_itoa(score);
 }
 
 
 const char *
 cluster_option(GHashTable* options, gboolean(*validate)(const char*),
 	       const char *name, const char *old_name, const char *def_value)
 {
 	const char *value = NULL;
 	CRM_ASSERT(name != NULL);
 
 	if(options != NULL) {
 		value = g_hash_table_lookup(options, name);
 	}
 
 	if(value == NULL && old_name && options != NULL) {
 		value = g_hash_table_lookup(options, old_name);
 		if(value != NULL) {
 			crm_config_warn("Using deprecated name '%s' for"
 				       " cluster option '%s'", old_name, name);
 			g_hash_table_insert(
 				options, crm_strdup(name), crm_strdup(value));
 			value = g_hash_table_lookup(options, old_name);
 		}
 	}
 
 	if(value == NULL) {
 		crm_debug("Using default value '%s' for cluster option '%s'",
 			  def_value, name);
 
 		if(options == NULL) {
 			return def_value;
 		}
 		
 		g_hash_table_insert(
 			options, crm_strdup(name), crm_strdup(def_value));
 		value = g_hash_table_lookup(options, name);
 	}
 	
 	if(validate && validate(value) == FALSE) {
 		crm_config_err("Value '%s' for cluster option '%s' is invalid."
 			      "  Defaulting to %s", value, name, def_value);
 		g_hash_table_replace(options, crm_strdup(name),
 				     crm_strdup(def_value));
 		value = g_hash_table_lookup(options, name);
 	}
 	
 	return value;
 }
 
 
 const char *
 get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name)
 {
 	int lpc = 0;
 	const char *value = NULL;
 	gboolean found = FALSE;
 	for(lpc = 0; lpc < len; lpc++) {
 		if(safe_str_eq(name, option_list[lpc].name)) {
 			found = TRUE;
 			value = cluster_option(options, 
 					       option_list[lpc].is_valid,
 					       option_list[lpc].name,
 					       option_list[lpc].alt_name,
 					       option_list[lpc].default_value);
 		}
 	}
 	CRM_CHECK(found, crm_err("No option named: %s", name));
 	CRM_ASSERT(value != NULL);
 	return value;
 }
 
 void
 config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long,
 		pe_cluster_option *option_list, int len)
 {
 	int lpc = 0;
 
 	fprintf(stdout, "<?xml version=\"1.0\"?>"
 		"<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
 		"<resource-agent name=\"%s\">\n"
 		"  <version>%s</version>\n"
 		"  <longdesc lang=\"en\">%s</longdesc>\n"
 		"  <shortdesc lang=\"en\">%s</shortdesc>\n"
 		"  <parameters>\n", name, version, desc_long, desc_short);
 	
 	for(lpc = 0; lpc < len; lpc++) {
 		if(option_list[lpc].description_long == NULL
 			&& option_list[lpc].description_short == NULL) {
 			continue;
 		}
 		fprintf(stdout, "    <parameter name=\"%s\" unique=\"0\">\n"
 			"      <shortdesc lang=\"en\">%s</shortdesc>\n"
 			"      <content type=\"%s\" default=\"%s\"/>\n"
 			"      <longdesc lang=\"en\">%s%s%s</longdesc>\n"
 			"    </parameter>\n",
 			option_list[lpc].name,
 			option_list[lpc].description_short,
 			option_list[lpc].type,
 			option_list[lpc].default_value,
 			option_list[lpc].description_long?option_list[lpc].description_long:option_list[lpc].description_short,
 			option_list[lpc].values?"  Allowed values: ":"",
 			option_list[lpc].values?option_list[lpc].values:"");
 	}
 	fprintf(stdout, "  </parameters>\n</resource-agent>\n");
 }
 
 void
 verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len)
 {
 	int lpc = 0;
 	for(lpc = 0; lpc < len; lpc++) {
 		cluster_option(options, 
 			       option_list[lpc].is_valid,
 			       option_list[lpc].name,
 			       option_list[lpc].alt_name,
 			       option_list[lpc].default_value);
 	}
 }
 
 char *
 generateReference(const char *custom1, const char *custom2)
 {
 
 	const char *local_cust1 = custom1;
 	const char *local_cust2 = custom2;
 	int reference_len = 4;
 	char *since_epoch = NULL;
 
 	reference_len += 20; /* too big */
 	reference_len += 40; /* too big */
 	
 	if(local_cust1 == NULL) { local_cust1 = "_empty_"; }
 	reference_len += strlen(local_cust1);
 	
 	if(local_cust2 == NULL) { local_cust2 = "_empty_"; }
 	reference_len += strlen(local_cust2);
 	
 	crm_malloc0(since_epoch, reference_len);
 
 	if(since_epoch != NULL) {
 		sprintf(since_epoch, "%s-%s-%ld-%u",
 			local_cust1, local_cust2,
 			(unsigned long)time(NULL), ref_counter++);
 	}
 
 	return since_epoch;
 }
 
 gboolean
 decodeNVpair(const char *srcstring, char separator, char **name, char **value)
 {
 	int lpc = 0;
 	int len = 0;
 	const char *temp = NULL;
 
 	CRM_ASSERT(name != NULL && value != NULL);
 	*name = NULL;
 	*value = NULL;
 
 	crm_debug_4("Attempting to decode: [%s]", srcstring);
 	if (srcstring != NULL) {
 		len = strlen(srcstring);
 		while(lpc <= len) {
 			if (srcstring[lpc] == separator) {
 				crm_malloc0(*name, lpc+1);
 				if(*name == NULL) {
 					break; /* and return FALSE */
 				}
 				strncpy(*name, srcstring, lpc);
 				(*name)[lpc] = '\0';
 
 /* this sucks but as the strtok manpage says..
  * it *is* a bug
  */
 				len = len-lpc; len--;
 				if(len <= 0) {
 					*value = NULL;
 				} else {
 
 					crm_malloc0(*value, len+1);
 					if(*value == NULL) {
 						crm_free(*name);
 						break; /* and return FALSE */
 					}
 					temp = srcstring+lpc+1;
 					strncpy(*value, temp, len);
 					(*value)[len] = '\0';
 				}
 				return TRUE;
 			}
 			lpc++;
 		}
 	}
 
 	if(*name != NULL) {
 		crm_free(*name);
 	}
 	*name = NULL;
 	*value = NULL;
     
 	return FALSE;
 }
 
 char *
 crm_concat(const char *prefix, const char *suffix, char join) 
 {
 	int len = 0;
 	char *new_str = NULL;
 	CRM_ASSERT(prefix != NULL);
 	CRM_ASSERT(suffix != NULL);
 	len = strlen(prefix) + strlen(suffix) + 2;
 
 	crm_malloc0(new_str, (len));
 	sprintf(new_str, "%s%c%s", prefix, join, suffix);
 	new_str[len-1] = 0;
 	return new_str;
 }
 
 
 char *
 generate_hash_key(const char *crm_msg_reference, const char *sys)
 {
 	char *hash_key = crm_concat(sys?sys:"none", crm_msg_reference, '_');
 	crm_debug_3("created hash key: (%s)", hash_key);
 	return hash_key;
 }
 
 char *
 generate_hash_value(const char *src_node, const char *src_subsys)
 {
 	char *hash_value = NULL;
 	
 	if (src_node == NULL || src_subsys == NULL) {
 		return NULL;
 	}
     
 	if (strcasecmp(CRM_SYSTEM_DC, src_subsys) == 0) {
 		hash_value = crm_strdup(src_subsys);
 		if (!hash_value) {
 			crm_err("memory allocation failed in "
 			       "generate_hash_value()");
 		}
 		return hash_value;
 	}
 
 	hash_value = crm_concat(src_node, src_subsys, '_');
 	crm_info("created hash value: (%s)", hash_value);
 	return hash_value;
 }
 
 char *
 crm_itoa(int an_int)
 {
 	int len = 32;
 	char *buffer = NULL;
 	
 	crm_malloc0(buffer, (len+1));
 	if(buffer != NULL) {
 		snprintf(buffer, len, "%d", an_int);
 	}
 	
 	return buffer;
 }
 
 extern int LogToLoggingDaemon(int priority, const char * buf, int bstrlen, gboolean use_pri_str);
 
 #ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER
 GLogFunc glib_log_default;
 
 static void
 crm_glib_handler(const gchar *log_domain, GLogLevelFlags flags, const gchar *message, gpointer user_data)
 {
 	int log_level = LOG_WARNING;
 	GLogLevelFlags msg_level = (flags & G_LOG_LEVEL_MASK);
 
 	switch(msg_level) {
 	    case G_LOG_LEVEL_CRITICAL:
 		/* log and record how we got here */
 		crm_abort(__FILE__,__PRETTY_FUNCTION__,__LINE__, message, TRUE, TRUE);
 		return;
 
 	    case G_LOG_LEVEL_ERROR:	log_level = LOG_ERR;    break;
 	    case G_LOG_LEVEL_MESSAGE:	log_level = LOG_NOTICE; break;
 	    case G_LOG_LEVEL_INFO:	log_level = LOG_INFO;   break;
 	    case G_LOG_LEVEL_DEBUG:	log_level = LOG_DEBUG;  break;
 		
 	    case G_LOG_LEVEL_WARNING:
 	    case G_LOG_FLAG_RECURSION:
 	    case G_LOG_FLAG_FATAL:
 	    case G_LOG_LEVEL_MASK:
 		log_level = LOG_WARNING;
 		break;
 	}
 
 	do_crm_log(log_level, "%s: %s", log_domain, message);
 }
 #endif
 
 void crm_log_deinit(void) {
 #ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER
     g_log_set_default_handler(glib_log_default, NULL);
 #endif
 }
 
 gboolean
 crm_log_init(
     const char *entity, int level, gboolean coredir, gboolean to_stderr,
     int argc, char **argv)
 {
 	/* Redirect messages from glib functions to our handler */
 /*  	cl_malloc_forced_for_glib(); */
 #ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER
 	glib_log_default = g_log_set_default_handler(crm_glib_handler, NULL);
 #endif
 	
 	/* and for good measure... - this enum is a bit field (!) */
 	g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/
 	
 	crm_system_name = entity;
 	cl_log_set_entity(entity);
 	cl_log_set_facility(HA_LOG_FACILITY);
 
 	if(coredir) {
 		cl_set_corerootdir(HA_COREDIR);
 		cl_cdtocoredir();
 	}
 	
 	set_crm_log_level(level);
 	crm_set_env_options();
 
 	cl_log_args(argc, argv);
 	cl_log_enable_stderr(to_stderr);
 
 	CL_SIGNAL(DEBUG_INC, alter_debug);
 	CL_SIGNAL(DEBUG_DEC, alter_debug);
 
 	return TRUE;
 }
 
 /* returns the old value */
 unsigned int
 set_crm_log_level(unsigned int level)
 {
 	unsigned int old = crm_log_level;
 
 	while(crm_log_level < 100 && crm_log_level < level) {
 		alter_debug(DEBUG_INC);
 	}
 	while(crm_log_level > 0 && crm_log_level > level) {
 		alter_debug(DEBUG_DEC);
 	}
 	
 	return old;
 }
 
 unsigned int
 get_crm_log_level(void)
 {
 	return crm_log_level;
 }
 
 static int
 crm_version_helper(const char *text, char **end_text)
 {
 	int atoi_result = -1;
 	CRM_ASSERT(end_text != NULL);
 
 	errno = 0;
 	
 	if(text != NULL && text[0] != 0) {
 	    atoi_result = (int)strtol(text, end_text, 10);
 		
 	    if(errno == EINVAL) {
 		crm_err("Conversion of '%s' %c failed", text, text[0]);
 		atoi_result = -1;
 	    }
 	}
 	return atoi_result;
 }
 
 
 /*
  * version1 < version2 : -1
  * version1 = version2 :  0
  * version1 > version2 :  1
  */
 int
 compare_version(const char *version1, const char *version2)
 {
 	int rc = 0;
 	int lpc = 0;
 	char *ver1_copy = NULL, *ver2_copy = NULL;
 	char *rest1 = NULL, *rest2 = NULL;
 
 	if(version1 == NULL && version2 == NULL) {
 		return 0;
 	} else if(version1 == NULL) {
 		return -1;
 	} else if(version2 == NULL) {
 		return 1;
 	}
 	
 	ver1_copy = crm_strdup(version1);
 	ver2_copy = crm_strdup(version2);
 	rest1 = ver1_copy;
 	rest2 = ver2_copy;
 
 	while(1) {
 		int digit1 = 0;
 		int digit2 = 0;
 
 		lpc++;
 
 		if(rest1 == rest2) {
 		    break;
 		}
 		
 		if(rest1 != NULL) {
 		    digit1 = crm_version_helper(rest1, &rest1);
 		}
 
 		if(rest2 != NULL) {
 		    digit2 = crm_version_helper(rest2, &rest2);
 		}
 
 		if(digit1 < digit2){
 			rc = -1;
 			crm_debug_5("%d < %d", digit1, digit2);
 			break;
 			
 		} else if (digit1 > digit2){
 			rc = 1;
 			crm_debug_5("%d > %d", digit1, digit2);
 			break;
 		}
 
 		if(rest1 != NULL && rest1[0] == '.') {
 		    rest1++;
 		}
 		if(rest1 != NULL && rest1[0] == 0) {
 		    rest1 = NULL;
 		}
 
 		if(rest2 != NULL && rest2[0] == '.') {
 		    rest2++;
 		}
 		if(rest2 != NULL && rest2[0] == 0) {
 		    rest2 = NULL;
 		}
 	}
 	
 	crm_free(ver1_copy);
 	crm_free(ver2_copy);
 
 	if(rc == 0) {
 	    crm_debug_3("%s == %s (%d)", version1, version2, lpc);
 	} else if(rc < 0) {
 	    crm_debug_3("%s < %s (%d)", version1, version2, lpc);
 	} else if(rc > 0) {
 	    crm_debug_3("%s > %s (%d)", version1, version2, lpc);
 	}
 
 	return rc;
 }
 
 gboolean do_stderr = FALSE;
 
 void
 alter_debug(int nsig) 
 {
 	CL_SIGNAL(DEBUG_INC, alter_debug);
 	CL_SIGNAL(DEBUG_DEC, alter_debug);
 	
 	switch(nsig) {
 		case DEBUG_INC:
 			if (crm_log_level < 100) {
 				crm_log_level++;
 			}
 			break;
 
 		case DEBUG_DEC:
 			if (crm_log_level > 0) {
 				crm_log_level--;
 			}
 			break;	
 
 		default:
 			fprintf(stderr, "Unknown signal %d\n", nsig);
 			cl_log(LOG_ERR, "Unknown signal %d", nsig);
 			break;	
 	}
 }
 
 
 void g_hash_destroy_str(gpointer data)
 {
 	crm_free(data);
 }
 
 #include <sys/types.h>
 /* #include <stdlib.h> */
 /* #include <limits.h> */
 
 long long
 crm_int_helper(const char *text, char **end_text)
 {
     long long result = -1;
     char *local_end_text = NULL;
     
     errno = 0;
     
     if(text != NULL) {
 #ifdef ANSI_ONLY
 	if(end_text != NULL) {
 	    result = strtol(text, end_text, 10);
 	} else {
 	    result = strtol(text, &local_end_text, 10);
 	}
 #else
 	if(end_text != NULL) {
 	    result = strtoll(text, end_text, 10);
 	} else {
 	    result = strtoll(text, &local_end_text, 10);
 	}
 #endif
 /* 		CRM_CHECK(errno != EINVAL); */
 	if(errno == EINVAL) {
 	    crm_err("Conversion of %s failed", text);
 	    result = -1;
 	    
 	} else if(errno == ERANGE) {
 	    crm_err("Conversion of %s was clipped: %lld", text, result);
 
 	} else if(errno != 0) {
 	    crm_perror(LOG_ERR,"Conversion of %s failed:", text);
 	}
 			
 	if(local_end_text != NULL && local_end_text[0] != '\0') {
 	    crm_err("Characters left over after parsing '%s': '%s'", text, local_end_text);
 	}
     }
     return result;
 }
 
 int
 crm_parse_int(const char *text, const char *default_text)
 {
 	int atoi_result = -1;
 	if(text != NULL) {
 		atoi_result = crm_int_helper(text, NULL);
 		if(errno == 0) {
 			return atoi_result;
 		}
 	}
 	
 	if(default_text != NULL) {
 		atoi_result = crm_int_helper(default_text, NULL);
 		if(errno == 0) {
 			return atoi_result;
 		}
 
 	} else {
 		crm_err("No default conversion value supplied");
 	}
 
 	return -1;
 }
 
 gboolean
 safe_str_neq(const char *a, const char *b)
 {
 	if(a == b) {
 		return FALSE;
 
 	} else if(a==NULL || b==NULL) {
 		return TRUE;
 
 	} else if(strcasecmp(a, b) == 0) {
 		return FALSE;
 	}
 	return TRUE;
 }
 
 char *
 crm_strdup_fn(const char *src, const char *file, const char *fn, int line)
 {
 	char *dup = NULL;
 	CRM_CHECK(src != NULL, return NULL);
 	crm_malloc0(dup, strlen(src) + 1);
 	return strcpy(dup, src);
 }
 
 
 
 #define ENV_PREFIX "HA_"
 void
 crm_set_env_options(void) 
 {
 	cl_inherit_logging_environment(500);
 	cl_log_set_logd_channel_source(NULL, NULL);
 
 	if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) {
 	    set_crm_log_level(LOG_INFO + debug_level);
 	}
 }
 
 gboolean
 crm_is_true(const char * s)
 {
 	gboolean ret = FALSE;
 	if(s != NULL) {
 		crm_str_to_boolean(s, &ret);
 	}
 	return ret;
 }
 
 int
 crm_str_to_boolean(const char * s, int * ret)
 {
 	if(s == NULL) {
 		return -1;
 
 	} else if (strcasecmp(s, "true") == 0
 		   ||	strcasecmp(s, "on") == 0
 		   ||	strcasecmp(s, "yes") == 0
 		   ||	strcasecmp(s, "y") == 0
 		   ||	strcasecmp(s, "1") == 0){
 		*ret = TRUE;
 		return 1;
 
 	} else if (strcasecmp(s, "false") == 0
 		   ||	strcasecmp(s, "off") == 0
 		   ||	strcasecmp(s, "no") == 0
 		   ||	strcasecmp(s, "n") == 0
 		   ||	strcasecmp(s, "0") == 0){
 		*ret = FALSE;
 		return 1;
 	}
 	return -1;
 }
 
 #ifndef NUMCHARS
 #    define	NUMCHARS	"0123456789."
 #endif
 
 #ifndef WHITESPACE
 #    define	WHITESPACE	" \t\n\r\f"
 #endif
 
 unsigned long long
 crm_get_interval(const char * input)
 {
     ha_time_t *interval = NULL;
     char *input_copy = crm_strdup(input);
     char *input_copy_mutable = input_copy;
     unsigned long long msec = 0;
     
     if(input == NULL) {
 	return 0;
 
     } else if(input[0] != 'P') {
 	crm_free(input_copy);
 	return crm_get_msec(input);
     }
     
     interval = parse_time_duration(&input_copy_mutable);
     msec = date_in_seconds(interval);
     free_ha_date(interval);
     crm_free(input_copy);
     return msec * 1000;
 }
 
 long long
 crm_get_msec(const char * input)
 {
 	const char *cp = input;
 	const char *units;
 	long long multiplier = 1000;
 	long long divisor = 1;
 	long long msec = -1;
 	char *end_text = NULL;
 	/* double dret; */
 
 	if(input == NULL) {
 		return msec;
 	}
 	
 	cp += strspn(cp, WHITESPACE);
 	units = cp + strspn(cp, NUMCHARS);
 	units += strspn(units, WHITESPACE);
 
 	if (strchr(NUMCHARS, *cp) == NULL) {
 		return msec;
 	}
 
 	if (strncasecmp(units, "ms", 2) == 0
 	    || strncasecmp(units, "msec", 4) == 0) {
 		multiplier = 1;
 		divisor = 1;
 	} else if (strncasecmp(units, "us", 2) == 0
 		  || strncasecmp(units, "usec", 4) == 0) {
 		multiplier = 1;
 		divisor = 1000;
 	} else if (strncasecmp(units, "s", 1) == 0
 		  || strncasecmp(units, "sec", 3) == 0) {
 		multiplier = 1000;
 		divisor = 1;
 	} else if (strncasecmp(units, "m", 1) == 0
 		  || strncasecmp(units, "min", 3) == 0) {
 		multiplier = 60*1000;
 		divisor = 1;
 	} else if (strncasecmp(units, "h", 1) == 0
 		  || strncasecmp(units, "hr", 2) == 0) {
 		multiplier = 60*60*1000;
 		divisor = 1;
 	} else if (*units != EOS && *units != '\n' && *units != '\r') {
 		return msec;
 	}
 	
 	msec = crm_int_helper(cp, &end_text);
 	msec *= multiplier;
 	msec /= divisor;
 	/* dret += 0.5; */
 	/* msec = (long long)dret; */
 	return msec;
 }
 
 const char *
 op_status2text(op_status_t status)
 {
 	switch(status) {
 		case LRM_OP_PENDING:
 			return "pending";
 			break;
 		case LRM_OP_DONE:
 			return "complete";
 			break;
 		case LRM_OP_ERROR:
 			return "Error";
 			break;
 		case LRM_OP_TIMEOUT:
 			return "Timed Out";
 			break;
 		case LRM_OP_NOTSUPPORTED:
 			return "NOT SUPPORTED";
 			break;
 		case LRM_OP_CANCELLED:
 			return "Cancelled";
 			break;
 	}
 	crm_err("Unknown status: %d", status);
 	return "UNKNOWN!";
 }
 
 char *
 generate_op_key(const char *rsc_id, const char *op_type, int interval)
 {
 	int len = 35;
 	char *op_id = NULL;
 
 	CRM_CHECK(rsc_id  != NULL, return NULL);
 	CRM_CHECK(op_type != NULL, return NULL);
 	
 	len += strlen(op_type);
 	len += strlen(rsc_id);
 	crm_malloc0(op_id, len);
 	CRM_CHECK(op_id != NULL, return NULL);
 	sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval);
 	return op_id;
 }
 
 gboolean
 parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
 {
 	char *mutable_key = NULL;
 	char *mutable_key_ptr = NULL;
 	int len = 0, offset = 0, ch = 0;
 
 	CRM_CHECK(key != NULL, return FALSE);
 	
 	*interval = 0;
 	len = strlen(key);
 	offset = len-1;
 
 	crm_debug_3("Source: %s", key);
 	
 	while(offset > 0 && isdigit(key[offset])) {
 		int digits = len-offset;
 		ch = key[offset] - '0';
 		CRM_CHECK(ch < 10, return FALSE);
 		CRM_CHECK(ch >= 0, return FALSE);
 		while(digits > 1) {
 			digits--;
 			ch = ch * 10;
 		}
 		*interval +=  ch;
 		offset--;
 	}
 
 	crm_debug_3("  Interval: %d", *interval);
 	CRM_CHECK(key[offset] == '_', return FALSE);
 
 	mutable_key = crm_strdup(key);
 	mutable_key_ptr = mutable_key_ptr;
 	mutable_key[offset] = 0;
 	offset--;
 
 	while(offset > 0 && key[offset] != '_') {
 		offset--;
 	}
 
 	CRM_CHECK(key[offset] == '_',
 		  crm_free(mutable_key); return FALSE);
 
 	mutable_key_ptr = mutable_key+offset+1;
 
 	crm_debug_3("  Action: %s", mutable_key_ptr);
 	
 	*op_type = crm_strdup(mutable_key_ptr);
 
 	mutable_key[offset] = 0;
 	offset--;
 
 	CRM_CHECK(mutable_key != mutable_key_ptr,
 		  crm_free(mutable_key); return FALSE);
 	
 	crm_debug_3("  Resource: %s", mutable_key);
 	*rsc_id = crm_strdup(mutable_key);
 
 	crm_free(mutable_key);
 	return TRUE;
 }
 
 char *
 generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
 {
 	int len = 12;
 	char *op_id = NULL;
 
 	CRM_CHECK(rsc_id  != NULL, return NULL);
 	CRM_CHECK(op_type != NULL, return NULL);
 	CRM_CHECK(notify_type != NULL, return NULL);
 	
 	len += strlen(op_type);
 	len += strlen(rsc_id);
 	len += strlen(notify_type);
 	crm_malloc0(op_id, len);
 	if(op_id != NULL) {
 		sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
 	}
 	return op_id;
 }
 
 char *
 generate_transition_magic_v202(const char *transition_key, int op_status)
 {
 	int len = 80;
 	char *fail_state = NULL;
 
 	CRM_CHECK(transition_key != NULL, return NULL);
 	
 	len += strlen(transition_key);
 	
 	crm_malloc0(fail_state, len);
 	if(fail_state != NULL) {
 		snprintf(fail_state, len, "%d:%s", op_status,transition_key);
 	}
 	return fail_state;
 }
 
 char *
 generate_transition_magic(const char *transition_key, int op_status, int op_rc)
 {
 	int len = 80;
 	char *fail_state = NULL;
 
 	CRM_CHECK(transition_key != NULL, return NULL);
 	
 	len += strlen(transition_key);
 	
 	crm_malloc0(fail_state, len);
 	if(fail_state != NULL) {
 		snprintf(fail_state, len, "%d:%d;%s",
 			 op_status, op_rc, transition_key);
 	}
 	return fail_state;
 }
 
 gboolean
 decode_transition_magic(
 	const char *magic, char **uuid, int *transition_id, int *action_id,
 	int *op_status, int *op_rc, int *target_rc)
 {
     int res = 0;
     char *key = NULL;
     gboolean result = TRUE;
 
     CRM_CHECK(magic != NULL, return FALSE);
     CRM_CHECK(op_rc != NULL, return FALSE);
     CRM_CHECK(op_status != NULL, return FALSE);
     
     crm_malloc0(key, strlen(magic));
     res = sscanf(magic, "%d:%d;%s", op_status, op_rc, key);
     if(res != 3) {
 	crm_crit("Only found %d items in: %s", res, magic);
 	result = FALSE;
 	goto bail;
     }
     
     CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id, target_rc),
 	      result = FALSE;
 	      goto bail;
 	);
     
   bail:
     crm_free(key);
     return result;
 }
 
 char *
 generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
 {
 	int len = 40;
 	char *fail_state = NULL;
 
 	CRM_CHECK(node != NULL, return NULL);
 	
 	len += strlen(node);
 	
 	crm_malloc0(fail_state, len);
 	if(fail_state != NULL) {
 		snprintf(fail_state, len, "%d:%d:%d:%s",
 			 action_id, transition_id, target_rc, node);
 	}
 	return fail_state;
 }
 
 
 gboolean
 decode_transition_key(
 	const char *key, char **uuid, int *transition_id, int *action_id, int *target_rc)
 {
 	int res = 0;
 	gboolean done = FALSE;
 
 	CRM_CHECK(uuid != NULL, return FALSE);
 	CRM_CHECK(target_rc != NULL, return FALSE);
 	CRM_CHECK(action_id != NULL, return FALSE);
 	CRM_CHECK(transition_id != NULL, return FALSE);
 	
 	crm_malloc0(*uuid, strlen(key));
 	res = sscanf(key, "%d:%d:%d:%s", action_id, transition_id, target_rc, *uuid);
 	switch(res) {
 	    case 4:
 		/* Post Pacemaker 0.6 */
 		done = TRUE;
 		break;
 	    case 3:
 	    case 2:
 		/* this can be tricky - the UUID might start with an integer */
 
 		/* Until Pacemaker 0.6 */
 		done = TRUE;
 		*target_rc = -1;
 		res = sscanf(key, "%d:%d:%s", action_id, transition_id, *uuid);
 		if(res == 2) {
 		    *action_id = -1;
 		    res = sscanf(key, "%d:%s", transition_id, *uuid);
 		    CRM_CHECK(res == 2, done = FALSE);
 
 		} else if(res != 3) {
 		    CRM_CHECK(res == 3, done = FALSE);
 		}
 		break;
 		
 	    case 1:
 		/* Prior to Heartbeat 2.0.8 */
 		done = TRUE;
 		*action_id = -1;
 		*target_rc = -1;
 		res = sscanf(key, "%d:%s", transition_id, *uuid);
 		CRM_CHECK(res == 2, done = FALSE);
 		break;
 	    default:
 		crm_crit("Unhandled sscanf result (%d) for %s", res, key);
 		
 	}
 
 	if(strlen(*uuid) != 36) {
 	    crm_warn("Bad UUID (%s) in sscanf result (%d) for %s", *uuid, res, key);		    
 	}
 	
 	if(done == FALSE) {
 	    crm_err("Cannot decode '%s' rc=%d", key, res);
 	    
 	    crm_free(*uuid);
 	    *uuid = NULL;
 	    *target_rc = -1;
 	    *action_id = -1;
 	    *transition_id = -1;
 	}
 	
 	return done;
 }
 
 void
 filter_action_parameters(xmlNode *param_set, const char *version) 
 {
 	char *key = NULL;
 	char *timeout = NULL;
 	char *interval = NULL;
 #if CRM_DEPRECATED_SINCE_2_0_5
 	const char *filter_205[] = {
 		XML_ATTR_TE_TARGET_RC,
 		XML_ATTR_LRM_PROBE,
 		XML_RSC_ATTR_START,
 		XML_RSC_ATTR_NOTIFY,
 		XML_RSC_ATTR_UNIQUE,
 		XML_RSC_ATTR_MANAGED,
 		XML_RSC_ATTR_PRIORITY,
 		XML_RSC_ATTR_MULTIPLE,
 		XML_RSC_ATTR_STICKINESS,
 		XML_RSC_ATTR_FAIL_STICKINESS,
 		XML_RSC_ATTR_TARGET_ROLE,
 
 /* ignore clone fields */
 		XML_RSC_ATTR_INCARNATION, 
 		XML_RSC_ATTR_INCARNATION_MAX, 
 		XML_RSC_ATTR_INCARNATION_NODEMAX,
 		XML_RSC_ATTR_MASTER_MAX,
 		XML_RSC_ATTR_MASTER_NODEMAX,
 		
 /* old field names */
 		"role",
 		"crm_role",
 		"te-target-rc",
 		
 /* ignore notify fields */
  		"notify_stop_resource",
  		"notify_stop_uname",
  		"notify_start_resource",
  		"notify_start_uname",
  		"notify_active_resource",
  		"notify_active_uname",
  		"notify_inactive_resource",
  		"notify_inactive_uname",
  		"notify_promote_resource",
  		"notify_promote_uname",
  		"notify_demote_resource",
  		"notify_demote_uname",
  		"notify_master_resource",
  		"notify_master_uname",
  		"notify_slave_resource",
  		"notify_slave_uname"		
 	};
 #endif
 	
 	const char *attr_filter[] = {
 		XML_ATTR_ID,
 		XML_ATTR_CRM_VERSION,
 		XML_LRM_ATTR_OP_DIGEST,
 	};
 
 	gboolean do_delete = FALSE;
 	int lpc = 0;
 	static int meta_len = 0;
 	if(meta_len == 0) {
 		meta_len  = strlen(CRM_META);
 	}	
 	
 	if(param_set == NULL) {
 		return;
 	}
 
 #if CRM_DEPRECATED_SINCE_2_0_5
  	if(version == NULL || compare_version("1.0.5", version) > 0) {
 		for(lpc = 0; lpc < DIMOF(filter_205); lpc++) {
 			xml_remove_prop(param_set, filter_205[lpc]); 
 		}
 	}
 #endif
 
 	for(lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
 		xml_remove_prop(param_set, attr_filter[lpc]); 
 	}
 
 	key = crm_meta_name(XML_LRM_ATTR_INTERVAL);
 	interval = crm_element_value_copy(param_set, key);
 	crm_free(key);
 
 	key = crm_meta_name(XML_ATTR_TIMEOUT);
 	timeout = crm_element_value_copy(param_set, key);
 	
 	xml_prop_iter(param_set, prop_name, prop_value,      
 		      do_delete = FALSE;
 		      if(strncasecmp(prop_name, CRM_META, meta_len) == 0) {
 			      do_delete = TRUE;
 		      }
 
 		      if(do_delete) {
 			      xml_remove_prop(param_set, prop_name);
 		      }
 		);
 
 	if(crm_get_msec(interval) > 0 && compare_version(version, "1.0.8") > 0) {
 		/* Re-instate the operation's timeout value */
 		if(timeout != NULL) {
 			crm_xml_add(param_set, key, timeout);
 		}
 	}
 
 	crm_free(interval);
 	crm_free(timeout);
 	crm_free(key);
 }
 
 void
 filter_reload_parameters(xmlNode *param_set, const char *restart_string) 
 {
 	int len = 0;
 	char *name = NULL;
 	char *match = NULL;
 	
 	if(param_set == NULL) {
 		return;
 	}
 
 	xml_prop_iter(param_set, prop_name, prop_value,      
 		      name = NULL;
 		      len = strlen(prop_name) + 3;
 
 		      crm_malloc0(name, len);
 		      sprintf(name, " %s ", prop_name);
 		      name[len-1] = 0;
 		      
 		      match = strstr(restart_string, name);
 		      if(match == NULL) {
 			      crm_debug_3("%s not found in %s",
 					  prop_name, restart_string);
 			      xml_remove_prop(param_set, prop_name);
 		      }
 		      crm_free(name);
 		);
 }
 
 void
 crm_abort(const char *file, const char *function, int line,
 	  const char *assert_condition, gboolean do_core, gboolean do_fork)
 {
 	int rc = 0;
 	int pid = 0;
 	int status = 0;
 
 	if(do_core == FALSE) {
 	    do_crm_log(LOG_ERR, "%s: Triggered assert at %s:%d : %s",
 		       function, file, line, assert_condition);
 	    return;
 
 	} else if(do_fork) {
 	    pid=fork();
 
 	} else {
 	    do_crm_log(LOG_ERR, "%s: Triggered fatal assert at %s:%d : %s",
 		       function, file, line, assert_condition);
 	}
 	
 	switch(pid) {
 		case -1:
 			do_crm_log(LOG_CRIT, "%s: Cannot create core for non-fatal assert at %s:%d : %s",
 				   function, file, line, assert_condition);
 			return;
 
 		default:	/* Parent */
 			do_crm_log(LOG_ERR, 
 				   "%s: Forked child %d to record non-fatal assert at %s:%d : %s",
 				   function, pid, file, line, assert_condition);
 			do {
 			    rc = waitpid(pid, &status, 0);
 			    if(rc < 0 && errno != EINTR) {
 				crm_perror(LOG_ERR,"%s: Cannot wait on forked child %d", function, pid);
 			    }
 			    
 			} while(rc < 0 && errno == EINTR);
 			    
 			return;
 
 		case 0:	/* Child */
 			abort();
 			break;
 	}
 }
 
 char *
 generate_series_filename(
 	const char *directory, const char *series, int sequence, gboolean bzip)
 {
 	int len = 40;
 	char *filename = NULL;
 	const char *ext = "raw";
 
 	CRM_CHECK(directory  != NULL, return NULL);
 	CRM_CHECK(series != NULL, return NULL);
 	
 	len += strlen(directory);
 	len += strlen(series);
 	crm_malloc0(filename, len);
 	CRM_CHECK(filename != NULL, return NULL);
 
 	if(bzip) {
 		ext = "bz2";
 	}
 	sprintf(filename, "%s/%s-%d.%s", directory, series, sequence, ext);
 	
 	return filename;
 }
 
 int
 get_last_sequence(const char *directory, const char *series)
 {
 	FILE *file_strm = NULL;
 	int start = 0, length = 0, read_len = 0;
 	char *series_file = NULL;
 	char *buffer = NULL;
 	int seq = 0;
 	int len = 36;
 
 	CRM_CHECK(directory  != NULL, return 0);
 	CRM_CHECK(series != NULL, return 0);
 	
 	len += strlen(directory);
 	len += strlen(series);
 	crm_malloc0(series_file, len);
 	CRM_CHECK(series_file != NULL, return 0);
 	sprintf(series_file, "%s/%s.last", directory, series);
 	
 	file_strm = fopen(series_file, "r");
 	if(file_strm == NULL) {
 		crm_debug("Series file %s does not exist", series_file);
 		crm_free(series_file);
 		return 0;
 	}
 	
 	/* see how big the file is */
 	start  = ftell(file_strm);
 	fseek(file_strm, 0L, SEEK_END);
 	length = ftell(file_strm);
 	fseek(file_strm, 0L, start);
 	
 	CRM_ASSERT(start == ftell(file_strm));
 
 	crm_debug_3("Reading %d bytes from file", length);
 	crm_malloc0(buffer, (length+1));
 	read_len = fread(buffer, 1, length, file_strm);
 
 	if(read_len != length) {
 		crm_err("Calculated and read bytes differ: %d vs. %d",
 			length, read_len);
 		crm_free(buffer);
 		buffer = NULL;
 		
 	} else  if(length <= 0) {
 		crm_info("%s was not valid", series_file);
 		crm_free(buffer);
 		buffer = NULL;
 	}
 	
 	crm_free(series_file);
 	seq = crm_parse_int(buffer, "0");
 	crm_free(buffer);
 	fclose(file_strm);
 	return seq;
 }
 
 void
 write_last_sequence(
 	const char *directory, const char *series, int sequence, int max)
 {
 	int rc = 0;
 	int len = 36;
 	char *buffer = NULL;
 	FILE *file_strm = NULL;
 	char *series_file = NULL;
 
 	CRM_CHECK(directory  != NULL, return);
 	CRM_CHECK(series != NULL, return);
 
 	if(max == 0) {
 		return;
 	}
 	while(max > 0 && sequence > max) {
 		sequence -= max;
 	}
 	buffer = crm_itoa(sequence);
 	
 	len += strlen(directory);
 	len += strlen(series);
 	crm_malloc0(series_file, len);
 	sprintf(series_file, "%s/%s.last", directory, series);
 	
 	file_strm = fopen(series_file, "w");
 	if(file_strm == NULL) {
 		crm_err("Cannout open series file %s for writing", series_file);
 		goto bail;
 	}
 
 	rc = fprintf(file_strm, "%s", buffer);
 	if(rc < 0) {
 		crm_perror(LOG_ERR,"Cannot write to series file %s", series_file);
 	}
 
   bail:
 	if(file_strm != NULL) {
 		fflush(file_strm);
 		fclose(file_strm);
 	}
 	
 	crm_free(series_file);
 	crm_free(buffer);
 }
 
 void
 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
 {
 	long pid;
 	const char *devnull = "/dev/null";
 
 	if(daemonize == FALSE) {
 		return;
 	}
 	
 	pid = fork();
 	if (pid < 0) {
 		fprintf(stderr, "%s: could not start daemon\n", name);
 		crm_perror(LOG_ERR,"fork");
 		exit(LSB_EXIT_GENERIC);
 
 	} else if (pid > 0) {
 		exit(LSB_EXIT_OK);
 	}
 	
 	if (cl_lock_pidfile(pidfile) < 0 ) {
 		pid = cl_read_pidfile_no_checking(pidfile);
 		crm_warn("%s: already running [pid %ld] (%s).\n",
 			 name, pid, pidfile);
 		exit(LSB_EXIT_OK);
 	}
 	
 	umask(022);
 	close(STDIN_FILENO);
 	(void)open(devnull, O_RDONLY);		/* Stdin:  fd 0 */
 	close(STDOUT_FILENO);
 	(void)open(devnull, O_WRONLY);		/* Stdout: fd 1 */
 	close(STDERR_FILENO);
 	(void)open(devnull, O_WRONLY);		/* Stderr: fd 2 */
 }
 
 gboolean
 crm_is_writable(const char *dir, const char *file,
 		const char *user, const char *group, gboolean need_both)
 {
 	int s_res = -1;
 	struct stat buf;
 	char *full_file = NULL;
 	const char *target = NULL;
 	
 	gboolean pass = TRUE;
 	gboolean readwritable = FALSE;
 
 	CRM_ASSERT(dir != NULL);
 	if(file != NULL) {
 		full_file = crm_concat(dir, file, '/');
 		target = full_file;
 		s_res = stat(full_file, &buf);
 		if( s_res == 0 && S_ISREG(buf.st_mode) == FALSE ) {
 			crm_err("%s must be a regular file", target);
 			pass = FALSE;
 			goto out;
 		}
 	}
 	
 	if (s_res != 0) {
 		target = dir;
 		s_res = stat(dir, &buf);
 		if(s_res != 0) {
 			crm_err("%s must exist and be a directory", dir);
 			pass = FALSE;
 			goto out;
 
 		} else if( S_ISDIR(buf.st_mode) == FALSE ) {
 			crm_err("%s must be a directory", dir);
 			pass = FALSE;
 		}
 	}
 
 	if(user) {
 		struct passwd *sys_user = NULL;
 		sys_user = getpwnam(user);
 		readwritable = (sys_user != NULL
 				&& buf.st_uid == sys_user->pw_uid
 				&& (buf.st_mode & (S_IRUSR|S_IWUSR)));
 		if(readwritable == FALSE) {
 			crm_err("%s must be owned and r/w by user %s",
 				target, user);
 			if(need_both) {
 				pass = FALSE;
 			}
 		}
 	}	
 
 	if(group) {
 		struct group *sys_grp = getgrnam(group);
 		readwritable = (
 			sys_grp != NULL
 			&& buf.st_gid == sys_grp->gr_gid
 			&& (buf.st_mode & (S_IRGRP|S_IWGRP)));		
 		if(readwritable == FALSE) {
 			if(need_both || user == NULL) {
 				pass = FALSE;
 				crm_err("%s must be owned and r/w by group %s",
 					target, group);
 			} else {
 				crm_warn("%s should be owned and r/w by group %s",
 					 target, group);
 			}
 		}
 	}
 
   out:
 	crm_free(full_file);
 	return pass;
 }
 
 static unsigned long long crm_bit_filter = 0; /* 0x00000002ULL; */
 static unsigned int bit_log_level = LOG_DEBUG_5;
 
 long long
 crm_clear_bit(const char *function, long long word, long long bit)
 {
 	unsigned int level = bit_log_level;
 	if(bit & crm_bit_filter) {
 	    level = LOG_ERR;
 	}
 
 	do_crm_log_unlikely(level, "Bit 0x%.16llx cleared by %s", bit, function);
 	word &= ~bit;
 
 	return word;
 }
 
 long long
 crm_set_bit(const char *function, long long word, long long bit)
 {
 	unsigned int level = bit_log_level;
 	if(bit & crm_bit_filter) {
 	    level = LOG_ERR;
 	}
 
 	do_crm_log_unlikely(level, "Bit 0x%.16llx set by %s", bit, function);
 	word |= bit;
 	return word;
 }
 
 static const char *cluster_type = NULL;
 
 gboolean is_openais_cluster(void)
 {
     if(cluster_type == NULL) {
 	cluster_type = getenv("HA_cluster_type");
 	if(cluster_type == NULL) {
 	    cluster_type = "Heartbeat";
 	}
     }
     
     if(safe_str_eq("openais", cluster_type)) {
 #if SUPPORT_AIS
 	return TRUE;
 #else
 	crm_crit("The installation of Pacemaker only supports Heartbeat"
 		 " but you're trying to run it on %s.  Terminating.",
 		 cluster_type);
 	exit(100);
 #endif
     }
     return FALSE;
 }
 
 gboolean is_heartbeat_cluster(void)
 {
 #if SUPPORT_HEARTBEAT
     return !is_openais_cluster();
 #else
     if(is_openais_cluster() == FALSE) {
 	crm_crit("The installation of Pacemaker only supports OpenAIS"
 		 " but you're trying to run it on %s.  Terminating.",
 		 cluster_type);
 	exit(100);
     }
     return FALSE;
 #endif
 }
 
 gboolean crm_str_eq(const char *a, const char *b, gboolean use_case) 
 {
     if(a == b) {
 	return TRUE;
 	
     } else if(a == NULL || b == NULL) {
 	/* shouldn't be comparing NULLs */
 	return FALSE;
 	    
     } else if(use_case && a[0] != b[0]) {
 	return FALSE;		
 	
     } else if(strcasecmp(a, b) == 0) {
 	return TRUE;
     }
     return FALSE;
 }
 
 char *crm_meta_name(const char *field) 
 {
     int lpc = 0;
     int max = 0;
     char *crm_name = NULL;
 
     CRM_CHECK(field != NULL, return NULL);
     crm_name = crm_concat(CRM_META, field, '_');
 
     /* Massage the names so they can be used as shell variables */ 
     max = strlen(crm_name);
     for(; lpc < max; lpc++) {
 	switch(crm_name[lpc]) {
 	    case '-':
 		crm_name[lpc] = '_';
 		break;
 	}
     }
     return crm_name;
 }
 
 const char *crm_meta_value(GHashTable *hash, const char *field) 
 {
     char *key = NULL;
     const char *value = NULL;
 
     key = crm_meta_name(field);
     if(key) {
 	value = g_hash_table_lookup(hash, key);
 	crm_free(key);
     }
     
     return value;
 }
+
+void crm_show_version(int exit_code)
+{
+    fprintf(stderr, "%s %s\n", crm_system_name, VERSION);
+    if(exit_code >= 0) {
+	exit(exit_code);
+    }
+}
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
index a241f6c23f..695f02b78d 100644
--- a/tools/crm_mon.c
+++ b/tools/crm_mon.c
@@ -1,1653 +1,1657 @@
 
 /* 
  * 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 <crm_internal.h>
 
 #include <sys/param.h>
 
 #include <crm/crm.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
 
 #include <clplumbing/uids.h>
 #include <clplumbing/cl_pidfile.h>
 #include <clplumbing/Gmain_timeout.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/util.h>
 #include <crm/common/xml.h>
 #include <crm/common/ctrl.h>
 #include <crm/common/ipc.h>
 
 #include <crm/cib.h>
 #include <crm/pengine/status.h>
 #include <../lib/pengine/unpack.h>
 
 #ifdef HAVE_GETOPT_H
 #  include <getopt.h>
 #endif
 
 
 /* GMainLoop *mainloop = NULL; */
 
 void usage(const char *cmd, int exit_status);
 void wait_for_refresh(int offset, const char *prefix, int msec);
 void clean_up(int rc);
 void crm_diff_update(const char *event, xmlNode *msg);
 gboolean mon_refresh_display(gpointer user_data);
 int cib_connect(gboolean full);
 
 char *xml_file = NULL;
 char *as_html_file = NULL;
 char *pid_file = NULL;
 char *snmp_target = NULL;
 
 gboolean as_console = TRUE;;
 gboolean simple_status = FALSE;
 gboolean group_by_node = FALSE;
 gboolean inactive_resources = FALSE;
 gboolean web_cgi = FALSE;
 int reconnect_msec = 5000;
 gboolean daemonize = FALSE;
 GMainLoop *mainloop = NULL;
 guint timer_id = 0;
 
 const char *crm_mail_host = NULL;
 const char *crm_mail_prefix = NULL;
 const char *crm_mail_from = NULL;
 const char *crm_mail_to = NULL;
 
 cib_t *cib = NULL;
 xmlNode *current_cib = NULL;
 
 gboolean one_shot = FALSE;
 gboolean has_warnings = FALSE;
 gboolean print_failcount = FALSE;
 gboolean print_operations = FALSE;
 gboolean print_timing = FALSE;
 
 gboolean log_diffs = FALSE;
 gboolean log_updates = FALSE;
 
 long last_refresh = 0;
 GTRIGSource *refresh_trigger = NULL;
 
 /*
  * 1.3.6.1.4.1.32723 has been assigned to the project by IANA
  * http://www.iana.org/assignments/enterprise-numbers
  */
 #define PACEMAKER_PREFIX "1.3.6.1.4.1.32723"
 #define PACEMAKER_TRAP_PREFIX PACEMAKER_PREFIX ".1"
 
 #define snmp_crm_trap_oid   PACEMAKER_TRAP_PREFIX
 #define snmp_crm_oid_node   PACEMAKER_TRAP_PREFIX ".1"
 #define snmp_crm_oid_rsc    PACEMAKER_TRAP_PREFIX ".2"
 #define snmp_crm_oid_task   PACEMAKER_TRAP_PREFIX ".3"
 #define snmp_crm_oid_desc   PACEMAKER_TRAP_PREFIX ".4"
 #define snmp_crm_oid_status PACEMAKER_TRAP_PREFIX ".5"
 #define snmp_crm_oid_rc     PACEMAKER_TRAP_PREFIX ".6"
 #define snmp_crm_oid_trc    PACEMAKER_TRAP_PREFIX ".7"
 
 #if CURSES_ENABLED
 #  define print_dot() if(as_console) {			\
 	printw(".");					\
 	clrtoeol();					\
 	refresh();					\
     } else {						\
 	fprintf(stdout, ".");				\
     }
 #else
 #  define print_dot() fprintf(stdout, ".");
 #endif
 
 #if CURSES_ENABLED
 #  define print_as(fmt, args...) if(as_console) {	\
 	printw(fmt, ##args);				\
 	clrtoeol();					\
 	refresh();					\
     } else {						\
 	fprintf(stdout, fmt, ##args);		\
     }
 #else
 #  define print_as(fmt, args...) fprintf(stdout, fmt, ##args);
 #endif
 
 static void
 blank_screen(void) 
 {
 #if CURSES_ENABLED
     int lpc = 0;
     for(lpc = 0; lpc < LINES; lpc++) {
 	move(lpc, 0);
 	clrtoeol();
     }
     move(0, 0);
     refresh();
 #endif
 }
 
 static gboolean
 mon_timer_popped(gpointer data)
 {
     int rc = cib_ok;
     if(timer_id > 0) {
 	Gmain_timeout_remove(timer_id);
     }
 
     rc = cib_connect(TRUE);
     
     if(rc != cib_ok) {
 	print_dot();
 	timer_id = Gmain_timeout_add(reconnect_msec, mon_timer_popped, NULL);
     }
     return FALSE;
 }
 
 static void mon_cib_connection_destroy(gpointer user_data)
 {
     print_as("Connection to the CIB terminated\n");
     print_as("Reconnecting...");
     cib->cmds->signoff(cib);
     timer_id = Gmain_timeout_add(reconnect_msec, mon_timer_popped, NULL);
     return;
 }
 
 /*
  * Mainloop signal handler.
  */
 static gboolean
 mon_shutdown(int nsig, gpointer unused)
 {
     clean_up(-1);
     if (mainloop && g_main_is_running(mainloop)) {
 	g_main_quit(mainloop);
 	
     } else {
 	clean_up(LSB_EXIT_OK);
     }
     return FALSE;
 }
 
 int cib_connect(gboolean full) 
 {
     int rc = cib_ok;
     static gboolean need_pass = TRUE;
     CRM_CHECK(cib != NULL, return cib_missing);
 
     if(cib->state != cib_connected_query
        && cib->state != cib_connected_command) {
 	crm_debug_4("Connecting to the CIB");		
 	if(need_pass && cib->variant == cib_remote) {
 	    need_pass = FALSE;
 	    print_as("Password:");
 	}
 
 	rc = cib->cmds->signon(cib, crm_system_name, cib_query);
 
 	if(rc != cib_ok) {
 	    return rc;
 	}
 
 	current_cib = get_cib_copy(cib);
 	mon_refresh_display(NULL);
 	
 	if(full) {
 	    if(rc == cib_ok) {
 		rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy);
 	    }
 
 	    
 	    if(rc == cib_ok) {
 		cib->cmds->del_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
 		rc = cib->cmds->add_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
 	    }
 	    
 	    if(rc != cib_ok) {
 		print_as("Notification setup failed, could not monitor CIB actions");
 		if(as_console) { sleep(2); }
 		clean_up(-rc);
 	    }
 	}
     }
     return rc;
 }
 
-#define OPTARGS	"V?i:nrh:dp:s1wx:oftNS:T:F:H:P:"
+#define OPTARGS	"V?i:nrh:dp:s1wx:oftNS:T:F:H:P:v"
 
 int
 main(int argc, char **argv)
 {
     int flag;
     int argerr = 0;
     int exit_code = 0;
 
 #ifdef HAVE_GETOPT_H
     int option_index = 0;
 	
     static struct option long_options[] = {
 	/* Top-level Options */
 	{"verbose",        0, 0, 'V'},
+	{"version",        0, 0, 'v'},
 	{"help",           0, 0, '?'},
 	{"interval",       1, 0, 'i'},
 	{"group-by-node",  0, 0, 'n'},
 	{"inactive",       0, 0, 'r'},
 	{"failcounts",     0, 0, 'f'},		
 	{"operations",     0, 0, 'o'},		
 	{"timing-details", 0, 0, 't'},		
 	{"as-html",        1, 0, 'h'},		
 	{"web-cgi",        0, 0, 'w'},
 	{"simple-status",  0, 0, 's'},
 	{"snmp-traps",     0, 0, 'S'},
 
 	{"mail-to",        1, 0, 'T'},
 	{"mail-from",      1, 0, 'F'},
 	{"mail-host",      1, 0, 'H'},
 	{"mail-prefix",    1, 0, 'P'},
 
 	{"one-shot",       0, 0, '1'},		
 	{"daemonize",      0, 0, 'd'},		
 	{"disable-ncurses",0, 0, 'N'},		
 	{"pid-file",       0, 0, 'p'},		
 	{"xml-file",       1, 0, 'x'},
 
 	{0, 0, 0, 0}
     };
 #endif
     pid_file = crm_strdup("/tmp/ClusterMon.pid");
     crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, 0, NULL);
 
     if (strcmp(crm_system_name, "crm_mon.cgi")==0) {
 	web_cgi = TRUE;
 	one_shot = TRUE;
     }
 	
     while (1) {
 #ifdef HAVE_GETOPT_H
 	flag = getopt_long(argc, argv, OPTARGS,
 			   long_options, &option_index);
 #else
 	flag = getopt(argc, argv, OPTARGS);
 #endif
 	if (flag == -1)
 	    break;
 
 	switch(flag) {
 	    case 'V':
 		cl_log_enable_stderr(TRUE);
 		alter_debug(DEBUG_INC);
 		break;
 	    case 'i':
 		reconnect_msec = crm_get_msec(optarg);
 		break;
 	    case 'n':
 		group_by_node = TRUE;
 		break;
 	    case 'r':
 		inactive_resources = TRUE;
 		break;
 	    case 'd':
 		daemonize = TRUE;
 		break;
 	    case 't':
 		print_timing = TRUE;
 		print_operations = TRUE;
 		break;
 	    case 'o':
 		print_operations = TRUE;
 		break;
 	    case 'f':
 		print_failcount = TRUE;
 		break;
 	    case 'p':
 		crm_free(pid_file);
 		pid_file = crm_strdup(optarg);
 		break;
 	    case 'x':
 		xml_file = crm_strdup(optarg);
 		one_shot = TRUE;
 		break;
 	    case 'h':
 		as_html_file = crm_strdup(optarg);
 		break;
 	    case 'w':
 		web_cgi = TRUE;
 		one_shot = TRUE;
 		break;
 	    case 's':
 		simple_status = TRUE;
 		one_shot = TRUE;
 		break;
 	    case 'S':
 		snmp_target = optarg;
 		break;
 	    case 'T':
 		crm_mail_to = optarg;
 		break;
 	    case 'F':
 		crm_mail_from = optarg;
 		break;
 	    case 'H':
 		crm_mail_host = optarg;
 		break;
 	    case 'P':
 		crm_mail_prefix = optarg;
 		break;
 	    case '1':
 		one_shot = TRUE;
 		break;
 	    case 'N':
 		as_console = FALSE;
 		break;
+	    case 'v':
+		crm_show_version(0);
+		break;
 	    case '?':
 		usage(crm_system_name, LSB_EXIT_OK);
 		break;
 	    default:
 		printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
 		++argerr;
 		break;
 	}
     }
 
     if (optind < argc) {
 	printf("non-option ARGV-elements: ");
 	while (optind < argc)
 	    printf("%s ", argv[optind++]);
 	printf("\n");
     }
     if (argerr) {
 	usage(crm_system_name, LSB_EXIT_GENERIC);
     }
     
     if(one_shot) {
 	as_console = FALSE;
 
     } else if(daemonize) {
 	long pid;
 	const char *devnull = "/dev/null";
 
 	as_console = FALSE;
 	cl_log_enable_stderr(FALSE);
 	
 	if(!as_html_file && !snmp_target && !crm_mail_to) {
 	    printf("Looks like you forgot to specify one or more of: --as-html, --mail-to, --snmp-target\n");
 	    usage(crm_system_name, LSB_EXIT_GENERIC);
 	}
 
 	pid = fork();
 	if (pid < 0) {
 	    crm_perror(LOG_ERR, "%s: could not start daemon", crm_system_name);
 	    clean_up(LSB_EXIT_GENERIC);
 	    
 	} else if (pid > 0) {
 	    clean_up(LSB_EXIT_OK);
 	}
 	
 	if (cl_lock_pidfile(pid_file) < 0 ){
 	    pid = cl_read_pidfile(pid_file);
 	    fprintf(stderr, "%s: already running [pid %ld].\n", crm_system_name, pid);
 	    clean_up(LSB_EXIT_OK);
 	}
 	
 	umask(022);
 	close(0); close(1); close(2);
 	(void)open(devnull, O_RDONLY);		/* Stdin:  fd 0 */
 	(void)open(devnull, O_WRONLY);		/* Stdout: fd 1 */
 	(void)open(devnull, O_WRONLY);		/* Stderr: fd 2 */
 
     } else if(as_console) {
 #if CURSES_ENABLED
 	initscr();
 	cbreak();
 	noecho();
 	cl_log_enable_stderr(FALSE);
 #else
 	one_shot = TRUE;
 	as_console = FALSE;
 	printf("Defaulting to one-shot mode\n");
 	printf("You need to have curses available at compile time to enable console mode\n");
 #endif
     }
 
     crm_info("Starting %s", crm_system_name);
     if(xml_file != NULL) {
 	current_cib = filename2xml(xml_file);
 	mon_refresh_display(NULL);
 	return exit_code;
     }
     
     if(current_cib == NULL) {
 	cib = cib_new();
 	if(!one_shot) {
 	    print_as("Attempting connection to the cluster...");
 	}
 	
 	do {
 	    exit_code = cib_connect(!one_shot);
 
 	    if(one_shot) {
 		break;
 
 	    } else if(exit_code != cib_ok) {
 		print_dot();
 		sleep(reconnect_msec/1000);
 	    }
 	    
 	} while(exit_code == cib_connection);
 	    
 	if(exit_code != cib_ok) {
 	    print_as("\nConnection to cluster failed: %s", cib_error2string(exit_code));
 	    if(as_console) { sleep(2); }
 	    clean_up(-exit_code);
 	}
     }
 
     if(one_shot) {
 	return exit_code;
     }
 
     mainloop = g_main_new(FALSE);
 
     G_main_add_SignalHandler(G_PRIORITY_HIGH, SIGTERM, mon_shutdown, NULL, NULL);
     G_main_add_SignalHandler(G_PRIORITY_HIGH, SIGINT, mon_shutdown, NULL, NULL);
     refresh_trigger = G_main_add_TriggerHandler(G_PRIORITY_LOW, mon_refresh_display, NULL, NULL);
 	
     g_main_run(mainloop);
     g_main_destroy(mainloop);
     return_to_orig_privs();
 	
     crm_info("Exiting %s", crm_system_name);	
 
     clean_up(0);
     return 0; /* never reached */
 }
 
 void
 wait_for_refresh(int offset, const char *prefix, int msec) 
 {
     int lpc = msec / 1000;
     struct timespec sleept = {1 , 0};
 
     if(as_console == FALSE) {
 	timer_id = Gmain_timeout_add(msec, mon_timer_popped, NULL);
 	return;
     }
 	
     crm_notice("%sRefresh in %ds...", prefix?prefix:"", lpc);
     while(lpc > 0) {
 #if CURSES_ENABLED
 	move(offset, 0);
 /* 		printw("%sRefresh in \033[01;32m%ds\033[00m...", prefix?prefix:"", lpc); */
 	printw("%sRefresh in %ds...\n", prefix?prefix:"", lpc);
 	clrtoeol();
 	refresh();
 #endif
 	lpc--;
 	if(lpc == 0) {
 	    timer_id = Gmain_timeout_add(
 		1000, mon_timer_popped, NULL);
 	} else {
 	    if (nanosleep(&sleept, NULL) != 0) {
 		return;
 	    }
 	}
     }
 }
 
 #define mon_warn(fmt...) do {			\
 	if (!has_warnings) {			\
 	    print_as("Warning:");		\
 	} else {				\
 	    print_as(",");			\
 	}					\
 	print_as(fmt);				\
 	has_warnings = TRUE;			\
     } while(0)
 
 static int
 print_simple_status(pe_working_set_t *data_set) 
 {
     node_t *dc = NULL;
     int nodes_online = 0;
     int nodes_standby = 0;
 
     dc = data_set->dc_node;
 
     if(dc == NULL) {
 	mon_warn("No DC ");
     }
 
     slist_iter(node, node_t, data_set->nodes, lpc2,
 	       if(node->details->standby && node->details->online) {
 		   nodes_standby++;
 	       } else if(node->details->online) {
 		   nodes_online++;
 	       } else {
 		   mon_warn("offline node: %s", node->details->uname);
 	       }
 	);
 	
     if (!has_warnings) {
 	print_as("Ok: %d nodes online", nodes_online);
 	if (nodes_standby > 0) {
 	    print_as(", %d standby nodes", nodes_standby);
 	}
 	print_as(", %d resources configured",
 		 g_list_length(data_set->resources));
     }
 	
     print_as("\n");
     return 0;
 }
 
 extern int get_failcount(node_t *node, resource_t *rsc, int *last_failure, pe_working_set_t *data_set);
 
 static void get_ping_score(node_t *node, pe_working_set_t *data_set) 
 {
     const char *attr = "pingd";
     const char *value = NULL;
     value = g_hash_table_lookup(node->details->attrs, attr);
     
     if(value != NULL) {
 	print_as(" %s=%s", attr, value);
     }
 }
 
 static void print_date(time_t time) 
 {
     int lpc = 0;
     char date_str[26];
     asctime_r(localtime(&time), date_str);
     for(; lpc < 26; lpc++) {
 	if(date_str[lpc] == '\n') {
 	    date_str[lpc] = 0;
 	}
     }
     print_as("'%s'", date_str);
 }
 
 static void print_rsc_summary(pe_working_set_t *data_set, node_t *node, resource_t *rsc, gboolean all)
 {
     gboolean printed = FALSE;
     time_t last_failure = 0;
     int failcount = get_failcount(node, rsc, (int*)&last_failure, data_set);	
 
     if(all || failcount || last_failure > 0) {
 	printed = TRUE;
 	print_as("   %s: migration-threshold=%d",
 		 rsc->id, rsc->migration_threshold);
     }
     
     if(failcount > 0) {
 	printed = TRUE;
 	print_as(" fail-count=%d", failcount);
     }
     
     if(last_failure > 0) {
 	printed = TRUE;
 	print_as(" last-failure=");
 	print_date(last_failure);
     }
 
     if(printed) {
 	print_as("\n");
     }
 }
 
 
 static void print_rsc_history(pe_working_set_t *data_set, node_t *node, xmlNode *rsc_entry)
 {
     GListPtr op_list = NULL;
     gboolean print_name = TRUE;
     GListPtr sorted_op_list = NULL;
     const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
     resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
 
     xml_child_iter_filter(
 	rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP,
 	op_list = g_list_append(op_list, rsc_op);
 	);
     
     sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
     
     slist_iter(xml_op, xmlNode, sorted_op_list, lpc,
 	       const char *value = NULL;
 	       const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
 	       const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
 	       const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
 	       const char *interval = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
 	       int rc = crm_parse_int(op_rc, "0");
 	       
 	       if(safe_str_eq(task, CRMD_ACTION_STATUS)
 		  && safe_str_eq(interval, "0")) {
 		   task = "probe";
 	       }
 	       
 	       if(rc == 7 && safe_str_eq(task, "probe")) {
 		   continue;
 		   
 	       } else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) {
 		   continue;
 	       }
 	       
 	       if(print_name) {
 		   print_name = FALSE;
 		   if(rsc == NULL) {
 		       print_as("Orphan resource: %s", rsc_id);
 		   } else {
 		       print_rsc_summary(data_set, node, rsc, TRUE);
 		   }
 	       }
 	       
 	       print_as("    + (%s) %s:", call, task);
 	       if(safe_str_neq(interval, "0")) {
 		   print_as(" interval=%sms", interval);
 	       }
 
 	       if(print_timing) {
 		   int int_value;
 		   const char *attr = "last-rc-change";
 		   value = crm_element_value(xml_op, attr);
 		   if(value) {
 		       int_value = crm_parse_int(value, NULL);
 		       print_as(" %s=", attr);
 		       print_date(int_value);
 		   }
 
 		   attr = "last-run";
 		   value = crm_element_value(xml_op, attr);
 		   if(value) {
 		       int_value = crm_parse_int(value, NULL);
 		       print_as(" %s=", attr);
 		       print_date(int_value);
 		   }
 		   
 		   attr = "exec-time";
 		   value = crm_element_value(xml_op, attr);
 		   if(value) {
 		       int_value = crm_parse_int(value, NULL);
 		       print_as(" %s=%dms", attr, int_value);
 		   }
 		   
 		   attr = "queue-time";
 		   value = crm_element_value(xml_op, attr);
 		   if(value) {
 		       int_value = crm_parse_int(value, NULL);
 		       print_as(" %s=%dms", attr, int_value);
 		   }
 	       }
 	       
 	       print_as(" rc=%s (%s)\n", op_rc, execra_code2string(rc));
 	       
 	);
     
     /* no need to free the contents */
     g_list_free(sorted_op_list);
 }
 
 static void print_node_summary(pe_working_set_t *data_set, gboolean operations)
 {
     xmlNode *lrm_rsc = NULL;
     xmlNode *cib_status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
 
     if(operations) {
 	print_as("\nOperations:\n");
     } else {
 	print_as("\nMigration summary:\n");
     }
     
     xml_child_iter_filter(
 	cib_status, node_state, XML_CIB_TAG_STATE,
 	node_t *node = pe_find_node_id(data_set->nodes, ID(node_state));
 	if(node == NULL || node->details->online == FALSE){
 	    continue;
 	}
 	
 	print_as("* Node %s: ", crm_element_value(node_state, XML_ATTR_UNAME));
 	get_ping_score(node, data_set); 
 	print_as("\n");
 	
 	lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
 	lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
 	
 	xml_child_iter_filter(
 	    lrm_rsc, rsc_entry, XML_LRM_TAG_RESOURCE,
 
 	    if(operations) {
 		print_rsc_history(data_set, node, rsc_entry);
 
 	    } else {
 		const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
 		resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
 		print_rsc_summary(data_set, node, rsc, FALSE);
 	    }
 	    );
 	);
 }
 
 static int
 print_status(pe_working_set_t *data_set) 
 {
     static int updates = 0;
 
     node_t *dc = NULL;
     char *since_epoch = NULL;
     xmlNode *dc_version = NULL;
     time_t a_time = time(NULL);
 
     int configured_resources = 0;
     int print_opts = pe_print_ncurses;
 
     if(as_console) {
 	blank_screen();
     } else {
 	print_opts = pe_print_printf;
     }
 
     updates++;
     dc = data_set->dc_node;
 
     print_as("\n\n============\n");
 
     if(a_time == (time_t)-1) {
 	crm_perror(LOG_ERR,"set_node_tstamp(): Invalid time returned");
 	return 1;
     }
 	
     since_epoch = ctime(&a_time);
     if(since_epoch != NULL) {
 	print_as("Last updated: %s", since_epoch);
     }
 
     dc_version = get_xpath_object("//nvpair[@name='dc-version']", data_set->input, LOG_DEBUG);
 
     if(dc == NULL) {
 	print_as("Current DC: NONE\n");
     } else {
 	print_as("Current DC: %s (%s)\n",
 		 dc->details->uname, dc->details->id);
 	if(dc_version) {
 	    print_as("Version: %s\n", crm_element_value(dc_version, XML_NVPAIR_ATTR_VALUE));
 	}
     }
 
     slist_iter(rsc, resource_t, data_set->resources, lpc,
 	       if(is_not_set(rsc->flags, pe_rsc_orphan)) {
 		   configured_resources++;
 	       }
 	);
 	
     print_as("%d Nodes configured.\n", g_list_length(data_set->nodes));
     print_as("%d Resources configured.\n", configured_resources);
     print_as("============\n\n");
 
     slist_iter(node, node_t, data_set->nodes, lpc2,
 	       const char *node_mode = "OFFLINE";
 	       if(node->details->pending) {
 		   node_mode = "pending";
 
 	       } else if(node->details->standby_onfail && node->details->online) {
 		   node_mode = "standby (on-fail)";
 
 	       } else if(node->details->standby && node->details->online) {
 		   node_mode = "standby";
 
 	       } else if(node->details->standby) {
 		   node_mode = "OFFLINE (standby)";
 
 	       } else if(node->details->online) {
 		   node_mode = "online";
 	       }
 		   
 	       print_as("Node: %s (%s): %s\n",
 			node->details->uname, node->details->id,
 			node_mode);
 	       if(group_by_node) {
 		   slist_iter(rsc, resource_t,
 			      node->details->running_rsc, lpc2,
 			      rsc->fns->print(
 				  rsc, "\t", print_opts|pe_print_rsconly, stdout);
 		       );
 	       }
 	);
 
     if(group_by_node == FALSE && inactive_resources) {
 	print_as("\nFull list of resources:\n");
 
     } else if(inactive_resources) {
 	print_as("\nInactive resources:\n");
     }
 	
     if(group_by_node == FALSE || inactive_resources) {
 	print_as("\n");
 	slist_iter(rsc, resource_t, data_set->resources, lpc2,
 		   gboolean is_active = rsc->fns->active(rsc, TRUE);
 		   gboolean partially_active = rsc->fns->active(rsc, FALSE);
 		   if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) {
 		       continue;
 				   
 		   } else if(group_by_node == FALSE) {
 		       if(partially_active || inactive_resources) {
 			   rsc->fns->print(rsc, NULL, print_opts, stdout);
 		       }
 				   
 		   } else if(is_active == FALSE && inactive_resources) {
 		       rsc->fns->print(rsc, NULL, print_opts, stdout);
 		   }
 	    );
     }
 
     if(print_operations || print_failcount) {
 	print_node_summary(data_set, print_operations);
     }
 	
     if(xml_has_children(data_set->failed)) {
 	print_as("\nFailed actions:\n");
 	xml_child_iter(data_set->failed, xml_op, 
 		       int val = 0;
 		       const char *id = ID(xml_op);
 		       const char *last = crm_element_value(xml_op, "last_run");
 		       const char *node = crm_element_value(xml_op, XML_ATTR_UNAME);
 		       const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
 		       const char *rc   = crm_element_value(xml_op, XML_LRM_ATTR_RC);
 		       const char *status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS);
 			       
 		       val = crm_parse_int(status, "0");
 		       print_as("    %s (node=%s, call=%s, rc=%s, status=%s",
 				id, node, call, rc, op_status2text(val));
 
 		       if(last) {
 			   time_t run_at = crm_parse_int(last, "0");
 			   print_as(", last-run=%s, queued=%sms, exec=%sms\n",
 				    ctime(&run_at),
 				    crm_element_value(xml_op, "exec_time"),
 				    crm_element_value(xml_op, "queue_time"));
 		       }
 
 		       val = crm_parse_int(rc, "0");
 		       print_as("): %s\n", execra_code2string(val));
 	    );
     }
 	
 #if CURSES_ENABLED
     if(as_console) {
 	refresh();
     }
 #endif
     return 0;
 }
 
 static int
 print_html_status(pe_working_set_t *data_set, const char *filename, gboolean web_cgi) 
 {
     FILE *stream;
     node_t *dc = NULL;
     static int updates = 0;
     char *filename_tmp = NULL;
 
     if (web_cgi) {
 	stream=stdout;
 	fprintf(stream, "Content-type: text/html\n\n");
 
     } else {
 	filename_tmp = crm_concat(filename, "tmp", '.');
 	stream = fopen(filename_tmp, "w");
 	if(stream == NULL) {
 	    crm_perror(LOG_ERR,"Cannot open %s for writing", filename_tmp);
 	    crm_free(filename_tmp);
 	    return -1;
 	}	
     }
 
     updates++;
     dc = data_set->dc_node;
 
     fprintf(stream, "<html>");
     fprintf(stream, "<head>");
     fprintf(stream, "<title>Cluster status</title>");
 /* content="%d;url=http://webdesign.about.com" */
     fprintf(stream,
 	    "<meta http-equiv=\"refresh\" content=\"%d\">", reconnect_msec);
     fprintf(stream, "</head>");
 
     /*** SUMMARY ***/
 
     fprintf(stream, "<h2>Cluster summary</h2>");
     {
 	char *now_str = NULL;
 	time_t now = time(NULL);
 	now_str = ctime(&now);
 	now_str[24] = EOS; /* replace the newline */
 	fprintf(stream, "Last updated: <b>%s</b><br/>\n", now_str);
     }
 	
     if(dc == NULL) {
 	fprintf(stream, "Current DC: <font color=\"red\"><b>NONE</b></font><br/>");
     } else {
 	fprintf(stream, "Current DC: %s (%s)<br/>",
 		dc->details->uname, dc->details->id);
     }
     fprintf(stream, "%d Nodes configured.<br/>",
 	    g_list_length(data_set->nodes));
     fprintf(stream, "%d Resources configured.<br/>",
 	    g_list_length(data_set->resources));
 
     /*** CONFIG ***/
 	
     fprintf(stream, "<h3>Config Options</h3>\n");
 
     fprintf(stream, "<table>\n");
     fprintf(stream, "<tr><td>Default resource stickiness</td><td>:</td><td>%d</td></tr>\n",
 	    data_set->default_resource_stickiness);
 	
     fprintf(stream, "<tr><td>STONITH of failed nodes</td><td>:</td><td>%s</td></t, pe_flag_\n",
 	    is_set(data_set->flags, pe_flag_stonith_enabled)?"enabled":"disabled");
 
     fprintf(stream, "<tr><td>Cluster is</td><td>:</td><td>%ssymmetric</td></tr>\n",
 	    is_set(data_set->flags, pe_flag_symmetric_cluster)?"":"a-");
 	
     fprintf(stream, "<tr><td>No Quorum Policy</td><td>:</td><td>");
     switch (data_set->no_quorum_policy) {
 	case no_quorum_freeze:
 	    fprintf(stream, "Freeze resources");
 	    break;
 	case no_quorum_stop:
 	    fprintf(stream, "Stop ALL resources");
 	    break;
 	case no_quorum_ignore:
 	    fprintf(stream, "Ignore");
 	    break;
 	case no_quorum_suicide:
 	    fprintf(stream, "Suicide");
 	    break;
     }
     fprintf(stream, "\n</td></tr>\n</table>\n");
 
     /*** NODE LIST ***/
 	
     fprintf(stream, "<h2>Node List</h2>\n");
     fprintf(stream, "<ul>\n");
     slist_iter(node, node_t, data_set->nodes, lpc2,
 	       fprintf(stream, "<li>");
 	       if(node->details->standby_onfail && node->details->online) {
 		   fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"<font color=\"orange\">standby (on-fail)</font>\n");
 	       } else if(node->details->standby && node->details->online) {
 		   fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"<font color=\"orange\">standby</font>\n");
 	       } else if(node->details->standby) {
 		   fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"<font color=\"red\">OFFLINE (standby)</font>\n");
 	       } else if(node->details->online) {
 		   fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"<font color=\"green\">online</font>\n");
 	       } else {
 		   fprintf(stream, "Node: %s (%s): %s",node->details->uname, node->details->id,"<font color=\"red\">OFFLINE</font>\n");
 	       }
 	       if(group_by_node) {
 		   fprintf(stream, "<ul>\n");
 		   slist_iter(rsc, resource_t,
 			      node->details->running_rsc, lpc2,
 			      fprintf(stream, "<li>");
 			      rsc->fns->print(rsc, NULL,
 					      pe_print_html|pe_print_rsconly, stream);
 			      fprintf(stream, "</li>\n");
 		       );
 		   fprintf(stream, "</ul>\n");
 	       }
 	       fprintf(stream, "</li>\n");
 	);
     fprintf(stream, "</ul>\n");
 	
     if(group_by_node && inactive_resources) {
 	fprintf(stream, "<h2>(Partially) Inactive Resources</h2>\n");
 
     } else if(group_by_node == FALSE)  {
 	fprintf(stream, "<h2>Resource List</h2>\n");
     }
 	
     if(group_by_node == FALSE || inactive_resources) {
 	slist_iter(rsc, resource_t, data_set->resources, lpc2,
 		   if(group_by_node && rsc->fns->active(rsc, TRUE)) {
 		       continue;
 		   }
 		   rsc->fns->print(rsc, NULL, pe_print_html, stream);
 	    );
     }
 
     fprintf(stream, "</html>");
     fflush(stream);
     fclose(stream);
 
     if (!web_cgi) {
 	if(rename(filename_tmp, filename) != 0) {
 	    crm_perror(LOG_ERR,"Unable to rename %s->%s", filename_tmp, filename);
 	}
 	crm_free(filename_tmp);
     }
     return 0;
 }
 
 #if ENABLE_SNMP
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/snmpv3_api.h>
 #include <net-snmp/agent/agent_trap.h>
 #include <net-snmp/library/snmp_client.h>
 #include <net-snmp/library/mib.h>
 #include <net-snmp/library/snmp_debug.h>
 
 #define add_snmp_field(list, oid_string, value) do {			\
 	oid name[MAX_OID_LEN];						\
         size_t name_length = MAX_OID_LEN;				\
 	if (snmp_parse_oid(oid_string, name, &name_length)) {		\
 	    int s_rc = snmp_add_var(list, name, name_length, 's', (value)); \
 	    if(s_rc != 0) {						\
 		crm_err("Could not add %s=%s rc=%d", oid_string, value, s_rc); \
 	    } else {							\
 		crm_debug_2("Added %s=%s", oid_string, value);		\
 	    }								\
 	} else {							\
 	    crm_err("Could not parse OID: %s", oid_string);		\
 	}								\
     } while(0)								\
 
 #define add_snmp_field_int(list, oid_string, value) do {		\
 	oid name[MAX_OID_LEN];						\
         size_t name_length = MAX_OID_LEN;				\
 	if (snmp_parse_oid(oid_string, name, &name_length)) {		\
 	    if(NULL == snmp_pdu_add_variable(				\
 		   list, name, name_length, ASN_INTEGER,		\
 		   (u_char *) & value, sizeof(value))) {		\
 		crm_err("Could not add %s=%d", oid_string, value); \
 	    } else {							\
 		crm_debug_2("Added %s=%d", oid_string, value);		\
 	    }								\
 	} else {							\
 	    crm_err("Could not parse OID: %s", oid_string);		\
 	}								\
     } while(0)								\
     
 static int snmp_input(int operation, netsnmp_session *session,
 		      int reqid, netsnmp_pdu *pdu, void *magic)
 {
     return 1;
 }
 
 static netsnmp_session *crm_snmp_init(const char *target) 
 {
     static netsnmp_session *session = NULL;
 
     if(session) {
 	return session;
     }
 
     if(target == NULL) {
 	return NULL;
     }
     
     if(crm_log_level > LOG_INFO) {
 	char *debug_tokens = crm_strdup("run:shell,snmptrap,tdomain");
 	debug_register_tokens(debug_tokens);
 	snmp_set_do_debugging(1);
     }
 
     crm_malloc0(session, sizeof(netsnmp_session));
     snmp_sess_init(session);
     session->version = SNMP_VERSION_2c;
     session->callback = snmp_input;
     session->callback_magic = NULL;
 
     session = snmp_add(session,
                   netsnmp_transport_open_client("snmptrap", target),
                   NULL, NULL);
 
     if (session == NULL) {
         snmp_sess_perror("Could not create snmp transport", session);
     }
     return session;
 }
 
 
 #endif
 
 static int
 send_snmp_trap(const char *node, const char *rsc, const char *task, int target_rc, int rc, int status, const char *desc)
 {
     int ret = 1;
 #if ENABLE_SNMP
     static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
     static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
 
     netsnmp_pdu *trap_pdu;
     netsnmp_session *session = crm_snmp_init(snmp_target);
 
     trap_pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
     if ( !trap_pdu ) {
 	crm_err("Failed to create SNMP notification");
 	return SNMPERR_GENERR;
     }
 
     if(1) {
 	/* send uptime */
         char csysuptime[20];
 	time_t now = time(NULL);
 	sprintf(csysuptime, "%ld", now);
 	snmp_add_var(trap_pdu, sysuptime_oid, sizeof(sysuptime_oid) / sizeof(oid), 't', csysuptime);
     }
     
     /* Indicate what the trap is by setting snmpTrapOid.0 */
     ret = snmp_add_var(trap_pdu, snmptrap_oid, sizeof(snmptrap_oid) / sizeof(oid), 'o', snmp_crm_trap_oid);
     if (ret != 0) {
 	crm_err("Failed set snmpTrapOid.0=%s", snmp_crm_trap_oid);
 	return ret;
     }
 
     /* Add extries to the trap */
     add_snmp_field(trap_pdu, snmp_crm_oid_rsc,  rsc);
     add_snmp_field(trap_pdu, snmp_crm_oid_node, node);
     add_snmp_field(trap_pdu, snmp_crm_oid_task, task);
     add_snmp_field(trap_pdu, snmp_crm_oid_desc, desc);
 
     add_snmp_field_int(trap_pdu, snmp_crm_oid_rc,  rc);
     add_snmp_field_int(trap_pdu, snmp_crm_oid_trc, target_rc);
     add_snmp_field_int(trap_pdu, snmp_crm_oid_status, status);
 
     /* Send and cleanup */
     ret = snmp_send(session, trap_pdu);
     if(ret == 0) {
 	/* error */
 	snmp_sess_perror("Could not send SNMP trap", session);
 	snmp_free_pdu(trap_pdu);
 	ret = SNMPERR_GENERR;
     } else {
 	ret = SNMPERR_SUCCESS;
     }
 #else
     crm_err("Sending SNMP traps is not supported by this installation");
 #endif
     return ret;
 }
 
 #if ENABLE_ESMTP
 #include <auth-client.h>
 #include <libesmtp.h>
 
 static void print_recipient_status(
     smtp_recipient_t recipient, const char *mailbox, void *arg)
 {
     const smtp_status_t *status;
 
     status = smtp_recipient_status (recipient);
     printf ("%s: %d %s", mailbox, status->code, status->text);
 }
 
 static void event_cb (smtp_session_t session, int event_no, void *arg, ...)
 {
     int *ok;
     va_list alist;
 
     va_start(alist, arg);
     switch(event_no) {
 	case SMTP_EV_CONNECT: 
 	case SMTP_EV_MAILSTATUS:
 	case SMTP_EV_RCPTSTATUS:
 	case SMTP_EV_MESSAGEDATA:
 	case SMTP_EV_MESSAGESENT:
 	case SMTP_EV_DISCONNECT:
 	    break;
 
 	case SMTP_EV_WEAK_CIPHER: {
 	    int bits = va_arg(alist, long);
 	    ok = va_arg(alist, int*);
 	    crm_debug("SMTP_EV_WEAK_CIPHER, bits=%d - accepted.", bits);
 	    *ok = 1; break;
 	}
 	case SMTP_EV_STARTTLS_OK:
 	    crm_debug("SMTP_EV_STARTTLS_OK - TLS started here.");
 	    break;
 
 	case SMTP_EV_INVALID_PEER_CERTIFICATE: {
 	    long vfy_result = va_arg(alist, long);
 	    ok = va_arg(alist, int*);
 	    
 	    /* There is a table in handle_invalid_peer_certificate() of mail-file.c */
 	    crm_err("SMTP_EV_INVALID_PEER_CERTIFICATE: %ld", vfy_result);
 	    *ok = 1; break;
 	}
 	case SMTP_EV_NO_PEER_CERTIFICATE:
 	    ok = va_arg(alist, int*); 
 	    crm_debug("SMTP_EV_NO_PEER_CERTIFICATE - accepted.");
 	    *ok = 1;
 	    break;
 	case SMTP_EV_WRONG_PEER_CERTIFICATE:
 	    ok = va_arg(alist, int*);
 	    crm_debug("SMTP_EV_WRONG_PEER_CERTIFICATE - accepted.");
 	    *ok = 1;
 	    break;
 	case SMTP_EV_NO_CLIENT_CERTIFICATE:
 	    ok = va_arg(alist, int*); 
 	    crm_debug("SMTP_EV_NO_CLIENT_CERTIFICATE - accepted.");
 	    *ok = 1;
 	    break;
 	default:
 	    crm_debug("Got event: %d - ignored.\n", event_no);
     }
     va_end(alist);
 }
 #endif
 
 #define BODY_MAX 2048
 
 static int
 send_smtp_trap(const char *node, const char *rsc, const char *task, int target_rc, int rc, int status, const char *desc)
 {
 #if ENABLE_ESMTP
     smtp_session_t session;
     smtp_message_t message;
     auth_context_t authctx;
     struct sigaction sa;
     
     int len = 10;
     int noauth = 1;
     char crm_mail_body[BODY_MAX];
     char *crm_mail_subject = NULL;
     
     if(node == NULL) {
 	node = "-";
     }
     if(rsc) {
 	rsc = "-";
     }
     if(desc == NULL) {
 	desc = "-";
     }
     
     if(crm_mail_to == NULL) {
 	return 1;
     }
     
     if(crm_mail_host == NULL) {
 	crm_mail_host = "localhost:25";
     }
 
     if(crm_mail_prefix == NULL) {
 	crm_mail_prefix = "Cluster notification";
     }
     
     crm_debug("Sending '%s' mail to %s via %s", crm_mail_prefix, crm_mail_to, crm_mail_host);
 
     len += strlen(crm_mail_prefix);
     len += strlen(node);
     len += strlen(rsc);
     len += strlen(desc);
     
     crm_malloc0(crm_mail_subject, len);
     snprintf(crm_mail_subject, len, "%s: %s event for %s on %s: %s", crm_mail_prefix, task, rsc, node, desc);
 
     len = 0;
     len += snprintf(crm_mail_body, BODY_MAX-len, "%s\n", crm_mail_prefix);
     len += snprintf(crm_mail_body, BODY_MAX-len, "====\n\n");
     if(rc==target_rc) {
 	len += snprintf(crm_mail_body, BODY_MAX-len,
 			"Completed operation %s for resource %s on %s\n", task, rsc, node);
     } else {
 	len += snprintf(crm_mail_body, BODY_MAX-len,
 			"Operation %s for resource %s on %s failed: %s\n", task, rsc, node, desc);
     }
 
     len += snprintf(crm_mail_body, BODY_MAX-len, "\nDetails:\n");
     len += snprintf(crm_mail_body, BODY_MAX-len,
 		    "\toperation status: (%d) %s\n", status, op_status2text(status));
     if(status == LRM_OP_DONE) {
 	len += snprintf(crm_mail_body, BODY_MAX-len,
 			"\tscript returned: (%d) %s\n", rc, execra_code2string(rc));
 	len += snprintf(crm_mail_body, BODY_MAX-len,
 			"\texpected return value: (%d) %s\n", target_rc, execra_code2string(target_rc));			    
     }
     
     auth_client_init();
     session = smtp_create_session();
     message = smtp_add_message(session);
 
     smtp_starttls_enable (session, Starttls_ENABLED);
     
     sa.sa_handler = SIG_IGN;
     sigemptyset (&sa.sa_mask);
     sa.sa_flags = 0;
     sigaction (SIGPIPE, &sa, NULL); 
 
     smtp_set_server (session, crm_mail_host);
 
     authctx = auth_create_context ();
     auth_set_mechanism_flags (authctx, AUTH_PLUGIN_PLAIN, 0);
 
     smtp_set_eventcb(session, event_cb, NULL);
 
     /* Now tell libESMTP it can use the SMTP AUTH extension.
      */
     if (!noauth) {
 	smtp_auth_set_context (session, authctx);
     }
     
     /* NULL is ok */
     smtp_set_reverse_path (message, crm_mail_from);
 
 #if 1
     /* In thoery, the last arg can be NULL if we then call smtp_add_recipient() */
     smtp_set_header (message, "To", NULL/*phrase*/, crm_mail_to); /* "Phrase" <crm_mail_to> */ 
 #else
     smtp_add_recipient (message, crm_mail_to);
 #endif
     
     /* Set the Subject: header and override any subject line in the message headers. */
     smtp_set_header (message, "Subject", crm_mail_subject);
     smtp_set_header_option (message, "Subject", Hdr_OVERRIDE, 1);
 
     smtp_set_message_str(message, crm_mail_body);
 
     if (!smtp_start_session (session)) {
 	char buf[128];
 	crm_err("SMTP server problem: %s\n", smtp_strerror (smtp_errno (), buf, sizeof buf));
 
     } else {
 	const smtp_status_t *smtp_status = smtp_message_transfer_status(message);
 	crm_info("Send status: %d %s", smtp_status->code, crm_str(smtp_status->text));
 	smtp_enumerate_recipients (message, print_recipient_status, NULL);
     }
 
     smtp_destroy_session(session);
     auth_destroy_context(authctx);
     auth_client_exit();
 #endif
     return 0;
 }
 
 static void handle_rsc_op(xmlNode *rsc_op) 
 {
     int rc = -1;
     int status = -1;
     int action = -1;
     int interval = 0;
     int target_rc = -1;
     int transition_num = -1;
     gboolean send_trap = TRUE;
     gboolean send_email = TRUE;
     
     char *rsc = NULL;
     char *task = NULL;
     const char *desc = NULL;
     const char *node = NULL;			     
     const char *magic = NULL;			     
     const char *id = ID(rsc_op);
     char *update_te_uuid = NULL;
 
     xmlNode *n = rsc_op;
     
     magic = crm_element_value(rsc_op, XML_ATTR_TRANSITION_MAGIC);
     if(magic == NULL) {
 	/* non-change */
 	return;
     }
 			
     if(FALSE == decode_transition_magic(
 	   magic, &update_te_uuid, &transition_num, &action,
 	   &status, &rc, &target_rc)) {
 	crm_err("Invalid event %s detected for %s", magic, id);
 	return;
     }
 			
     if(parse_op_key(id, &rsc, &task, &interval) == FALSE) {
 	crm_err("Invalid event detected for %s", id);
 	return;
     }
 
     while(n != NULL && safe_str_neq(XML_CIB_TAG_STATE, TYPE(n))) {
 	n = n->parent;
     }
 
     node = ID(n);
     if(node == NULL) {
 	crm_err("No node detected for event %s (%s)", magic, id);
 	return;
     }
 
     /* look up where we expected it to be? */
     desc = cib_error2string(cib_ok);
     if(status == LRM_OP_DONE && target_rc == rc) {
 	crm_notice("%s of %s on %s completed: %s", task, rsc, node, desc);
 	if(rc == EXECRA_NOT_RUNNING) {
 	    send_trap = FALSE;
 	}
 			    
     } else if(status == LRM_OP_DONE) {
 	desc = execra_code2string(rc);
 	crm_warn("%s of %s on %s failed: %s", task, rsc, node, desc);
 			    
     } else {
 	desc = op_status2text(status);
 	crm_warn("%s of %s on %s failed: %s", task, rsc, node, desc);
     }
 
     if(send_trap && snmp_target) {
 	send_snmp_trap(node, rsc, task, target_rc, rc, status, desc);
     }
     if(send_email && crm_mail_to) {
 	send_smtp_trap(node, rsc, task, target_rc, rc, status, desc);
     }
 }
 
 void
 crm_diff_update(const char *event, xmlNode *msg)
 {
     int rc = -1;
     long now = time(NULL);
     const char *op = NULL;
     unsigned int log_level = LOG_INFO;
 
     xmlNode *diff = NULL;
     xmlNode *cib_last = NULL;
     xmlNode *update = get_message_xml(msg, F_CIB_UPDATE);
 
     print_dot();
 	
     if(msg == NULL) {
 	crm_err("NULL update");
 	return;
     }
     
     crm_element_value_int(msg, F_CIB_RC, &rc);	
     op = crm_element_value(msg, F_CIB_OPERATION);
     diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
 
     if(rc < cib_ok) {
 	log_level = LOG_WARNING;
 	do_crm_log(log_level, "[%s] %s ABORTED: %s",
 		   event, op, cib_error2string(rc));
 	return;	
     } 
 
     if(current_cib != NULL) {
 	cib_last = current_cib; current_cib = NULL;
 	rc = cib_process_diff(op, cib_force_diff, NULL, NULL, diff, cib_last, &current_cib, NULL);
 	
 	if(rc != cib_ok) {
 	    crm_debug("Update didn't apply, requesting full copy: %s", cib_error2string(rc));
 	    free_xml(current_cib);
 	    current_cib = NULL;
 	}
     }
     
     if(current_cib == NULL) {
 	current_cib = get_cib_copy(cib);
     }
 
     if(log_diffs && diff) {
 	log_cib_diff(LOG_DEBUG, diff, op);
     }
     
     if(log_updates && update != NULL) {
 	print_xml_formatted(LOG_DEBUG, "raw_update", update, NULL);
     }
 
     if(diff && (crm_mail_to || snmp_target)) {
 	/* Process operation updates */
 	xmlXPathObject *xpathObj = xpath_search(
 	    diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_LRM_TAG_RSC_OP);
 	if(xpathObj && xpathObj->nodesetval->nodeNr > 0) {
 	    int lpc = 0, max = xpathObj->nodesetval->nodeNr;
 	    for(lpc = 0; lpc < max; lpc++) {
 		xmlNode *rsc_op = getXpathResult(xpathObj, lpc);
 		handle_rsc_op(rsc_op);
 	    }
 	    xmlXPathFreeObject(xpathObj);
 	}
     }
 
     if((now - last_refresh) > (reconnect_msec/1000)) {
 	/* Force a refresh */
 	mon_refresh_display(NULL);
 	
     } else {
 	G_main_set_trigger(refresh_trigger);
     }
     free_xml(cib_last);
 }
 
 gboolean
 mon_refresh_display(gpointer user_data) 
 {
     xmlNode *cib_copy = copy_xml(current_cib);
     pe_working_set_t data_set;
 
     last_refresh = time(NULL);
     
     if(cli_config_update(&cib_copy, NULL) == FALSE) {
 	if(cib) {
 	    cib->cmds->signoff(cib);
 	}
 	print_as("Upgrade failed: %s", cib_error2string(cib_dtd_validation));
 	if(as_console) { sleep(2); }
 	clean_up(LSB_EXIT_GENERIC);
 	return FALSE;
     }
 
     set_working_set_defaults(&data_set);
     data_set.input = cib_copy;
     cluster_status(&data_set);	
 
     if(as_html_file || web_cgi) {
 	if (print_html_status(&data_set, as_html_file, web_cgi) != 0) {
 	    fprintf(stderr, "Critical: Unable to output html file\n");
 	    clean_up(LSB_EXIT_GENERIC);
 	}
 	
     } else if(daemonize) {
 	/* do nothing */
 
     } else if (simple_status) {
 	print_simple_status(&data_set);
 	if (has_warnings) {
 	    clean_up(LSB_EXIT_GENERIC);
 	}
 	
     } else {
 	print_status(&data_set);
     }
     
     cleanup_calculations(&data_set);
     return TRUE;
 }
 
 void
 usage(const char *cmd, int exit_status)
 {
     FILE *stream;
 
     stream = exit_status ? stderr : stdout;
     fprintf(stream, "%s -- Provides a summary of cluster's current state.\n"
 	    "  Outputs varying levels of detail in a number of different formats.\n\n",
 	    cmd);
 
     fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS);
     fprintf(stream, "General options:\n");
     fprintf(stream, "\t--%s (-%c) \t: This text\n", "help", '?');
     fprintf(stream, "\t--%s (-%c) \t: Increase the debug output\n", "verbose", 'V');
     fprintf(stream, "\t--%s (-%c) <seconds>\t: Update frequency\n", "interval", 'i');
     fprintf(stream, "\t--%s (-%c) <filename>\t: Daemon pid file location\n", "pid-file", 'p');
 
     fprintf(stream, "Output detail options:\n");
     fprintf(stream, "\t--%s (-%c) \t: Group resources by node\n", "group-by-node", 'n');
     fprintf(stream, "\t--%s (-%c) \t: Display inactive resources\n", "inactive", 'r');
     fprintf(stream, "\t--%s (-%c) \t: Display resource fail counts\n", "failcount", 'f');
     fprintf(stream, "\t--%s (-%c) \t: Display resource operation history\n", "operations", 'o');
 
     fprintf(stream, "Output destination options:\n");
     fprintf(stream, "\t--%s (-%c) \t: Display the cluster status once as "
 	    "a simple one line output (suitable for nagios)\n", "simple-status", 's');
     fprintf(stream, "\t--%s (-%c) \t: Display the cluster status once on "
 	    "the console and exit (doesnt use ncurses)\n", "one-shot", '1');
     fprintf(stream, "\t--%s (-%c) <filename>\t: Write cluster status to the named file\n", "as-html", 'h');
     fprintf(stream, "\t--%s (-%c) \t: Web mode with output suitable for cgi\n", "web-cgi", 'w');
     fprintf(stream, "\t--%s (-%c) \t: Run in the background as a daemon\n", "daemonize", 'd');
 
     fflush(stream);
 
     exit(exit_status);
 }
 
 /*
  * De-init ncurses, signoff from the CIB and deallocate memory.
  */
 void clean_up(int rc)
 {
 #if ENABLE_SNMP
     netsnmp_session *session = crm_snmp_init(NULL);
     if(session) {
 	snmp_close(session);
 	snmp_shutdown("snmpapp");
     }
 #endif    
 
 #if CURSES_ENABLED
     if(as_console) {
 	as_console = FALSE;
 	echo();
 	nocbreak();
 	endwin();
     }
 #endif
 
     if (cib != NULL) {
 	cib->cmds->signoff(cib);
 	cib_delete(cib);
 	cib = NULL;
     }
 
     crm_free(as_html_file);
     crm_free(xml_file);
     crm_free(pid_file);
 
     if(rc >= 0) {
 	exit(rc);
     }
     return;
 }
diff --git a/tools/crmadmin.c b/tools/crmadmin.c
index 9cbdd44ce3..8d4a877857 100644
--- a/tools/crmadmin.c
+++ b/tools/crmadmin.c
@@ -1,711 +1,710 @@
 
 /* 
  * 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 <crm_internal.h>
 #include <ha_version.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 <clplumbing/uids.h>
 #include <clplumbing/Gmain_timeout.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/ctrl.h>
 #include <crm/common/ipc.h>
 
 #include <crm/cib.h>
 
 #ifdef HAVE_GETOPT_H
 #  include <getopt.h>
 #endif
 
 int message_timer_id = -1;
 int message_timeout_ms = 30*1000;
 
 GMainLoop *mainloop = NULL;
 IPC_Channel *crmd_channel = NULL;
 char *admin_uuid = NULL;
 
 void usage(const char *cmd, int exit_status);
 gboolean do_init(void);
 int do_work(void);
 void crmadmin_ipc_connection_destroy(gpointer user_data);
 
 gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data);
 char *pluralSection(const char *a_section);
 xmlNode *handleCibMod(void);
 int do_find_node_list(xmlNode *xml_node);
 gboolean admin_message_timeout(gpointer data);
 gboolean is_node_online(xmlNode *node_state);
 
 enum debug {
 	debug_none,
 	debug_dec,
 	debug_inc
 };
 
 gboolean BE_VERBOSE = FALSE;
 int expected_responses = 1;
 
 gboolean BASH_EXPORT      = FALSE;
 gboolean DO_HEALTH        = FALSE;
 gboolean DO_RESET         = FALSE;
 gboolean DO_RESOURCE      = FALSE;
 gboolean DO_ELECT_DC      = FALSE;
 gboolean DO_WHOIS_DC      = FALSE;
 gboolean DO_NODE_LIST     = FALSE;
 gboolean BE_SILENT        = FALSE;
 gboolean DO_RESOURCE_LIST = FALSE;
 enum debug DO_DEBUG       = debug_none;
 const char *crmd_operation = NULL;
 
 xmlNode *msg_options = NULL;
 
 const char *standby_on_off = "on";
 const char *admin_verbose = XML_BOOLEAN_FALSE;
 char *id = NULL;
 char *this_msg_reference = NULL;
 char *disconnect = NULL;
 char *dest_node  = NULL;
 char *rsc_name   = NULL;
 char *crm_option = NULL;
 
 int operation_status = 0;
 const char *sys_to = NULL;
 
 #define OPTARGS	"V?K:S:HE:Dd:i:RNqt:Bv"
 
 int
 main(int argc, char **argv)
 {
 	int argerr = 0;
 	int flag;
 
 #ifdef HAVE_GETOPT_H
 	int option_index = 0;
 	static struct option long_options[] = {
 		/* Top-level Options */
 		{"verbose", 0, 0, 'V'},
 		{"help", 0, 0, '?'},
 		{"quiet", 0, 0, 'q'},
 		{"reference", 1, 0, 0},
 		{XML_ATTR_TIMEOUT, 1, 0, 't'},
 		{"bash-export", 0, 0, 'B'},
 		
 		/* daemon options */
 		{"kill", 1, 0, 'K'},  /* stop a node */
 		{"die", 0, 0, 0},  /* kill a node, no respawn */
 		{"debug_inc", 1, 0, 'i'},
 		{"debug_dec", 1, 0, 'd'},
 		{"status", 1, 0, 'S'},
 		{"standby", 1, 0, 's'},
 		{"active", 1, 0, 'a'},
 		{"health", 0, 0, 'H'},
 		{"election", 0, 0, 'E'},
 		{"dc_lookup", 0, 0, 'D'},
 		{"nodes", 0, 0, 'N'},
 		{"option", 1, 0, 'o'},
 		{"version", 0, 0, 'v'},
 
 		{0, 0, 0, 0}
 	};
 #endif
 
 	crm_log_init(basename(argv[0]), LOG_ERR, FALSE, TRUE, argc, argv);
 	if(argc < 2) {
 		usage(crm_system_name, LSB_EXIT_EINVAL);
 	}
 	
 	while (1) {
 #ifdef HAVE_GETOPT_H
 		flag = getopt_long(argc, argv, OPTARGS,
 				   long_options, &option_index);
 #else
 		flag = getopt(argc, argv, OPTARGS);
 #endif
 		if (flag == -1)
 			break;
 
 		switch(flag) {
 #ifdef HAVE_GETOPT_H
 			case 0:
 				if (strcasecmp("reference",
 					   long_options[option_index].name) == 0) {
 					this_msg_reference =
 						crm_strdup(optarg);
 
 				} else if (strcasecmp("die",
 						  long_options[option_index].name) == 0) {
 					DO_RESET = TRUE;
 					crmd_operation = CRM_OP_DIE;
 					
 				} else {
 					printf( "?? Long option (--%s) is not yet properly supported ??\n",
 						long_options[option_index].name);
 					++argerr;
 				}
 				break;
 #endif
 			
 /* a sample test for multiple instance
    if (digit_optind != 0 && digit_optind != this_option_optind)
    printf ("digits occur in two different argv-elements.\n");
    digit_optind = this_option_optind;
    printf ("option %c\n", c);
 */
 
 			case 'v':
-				fprintf(stdout, "HA Version %s, CRM Version %s (CIB feature set %s) %s\n",
-					VERSION, CRM_FEATURE_SET, CIB_FEATURE_SET, HA_HG_VERSION);
+				fprintf(stdout, "%s %s (Build: %s)\n", crm_system_name, VERSION, BUILD_VERSION);
 				exit(0);
 				break;
 			case 'V':
 				BE_VERBOSE = TRUE;
 				admin_verbose = XML_BOOLEAN_TRUE;
 				cl_log_enable_stderr(TRUE);
 				alter_debug(DEBUG_INC);
 				break;
 			case 't':
 				message_timeout_ms = atoi(optarg);
 				if(message_timeout_ms < 1) {
 					message_timeout_ms = 30*1000;
 				}
 				break;
 				
 			case '?':
 				usage(crm_system_name, LSB_EXIT_OK);
 				break;
 			case 'D':
 				DO_WHOIS_DC = TRUE;
 				break;
 			case 'B':
 				BASH_EXPORT = TRUE;
 				break;
 			case 'K':
 				DO_RESET = TRUE;
 				crm_debug_2("Option %c => %s", flag, optarg);
 				dest_node = crm_strdup(optarg);
 				crmd_operation = CRM_OP_LOCAL_SHUTDOWN;
 				break;
 			case 'q':
 				BE_SILENT = TRUE;
 				break;
 			case 'i':
 				DO_DEBUG = debug_inc;
 				crm_debug_2("Option %c => %s", flag, optarg);
 				dest_node = crm_strdup(optarg);
 				break;
 			case 'd':
 				DO_DEBUG = debug_dec;
 				crm_debug_2("Option %c => %s", flag, optarg);
 				dest_node = crm_strdup(optarg);
 				break;
 			case 'S':
 				DO_HEALTH = TRUE;
 				crm_debug_2("Option %c => %s", flag, optarg);
 				dest_node = crm_strdup(optarg);
 				break;
 			case 'E':
 				DO_ELECT_DC = TRUE;
 				break;
 			case 'N':
 				DO_NODE_LIST = TRUE;
 				break;
 			case 'H':
 				DO_HEALTH = TRUE;
 				break;
 			default:
 				printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
 				++argerr;
 				break;
 		}
 	}
 
 	if (optind < argc) {
 		printf("non-option ARGV-elements: ");
 		while (optind < argc)
 			printf("%s ", argv[optind++]);
 		printf("\n");
 	}
 
 	if (optind > argc) {
 		++argerr;
 	}
 
 	if (argerr) {
 		usage(crm_system_name, LSB_EXIT_GENERIC);
 	}
 
 	if (do_init()) {
 		int res = 0;
 		res = do_work();
 		if (res > 0) {
 			/* wait for the reply by creating a mainloop and running it until
 			 * the callbacks are invoked...
 			 */
 			mainloop = g_main_new(FALSE);
 			expected_responses++;
 			crm_debug_2("Waiting for %d replies from the local CRM", expected_responses);
 
 			message_timer_id = Gmain_timeout_add(
 				message_timeout_ms, admin_message_timeout, NULL);
 			
 			g_main_run(mainloop);
 			return_to_orig_privs();
 			
 		} else if(res < 0) {
 			crm_err("No message to send");
 			operation_status = -1;
 		}
 	} else {
 		crm_warn("Init failed, could not perform requested operations");
 		operation_status = -2;
 	}
 
 	crm_debug_2("%s exiting normally", crm_system_name);
 	return operation_status;
 }
 
 
 
 int
 do_work(void)
 {
 	int ret = 1;
 	/* construct the request */
 	xmlNode *msg_data = NULL;
 	gboolean all_is_good = TRUE;
 	
 	msg_options = create_xml_node(NULL, XML_TAG_OPTIONS);
 	crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose);
 	crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 
 	if (DO_HEALTH == TRUE) {
 		crm_debug_2("Querying the system");
 		
 		sys_to = CRM_SYSTEM_DC;
 		
 		if (dest_node != NULL) {
 			sys_to = CRM_SYSTEM_CRMD;
 			crmd_operation = CRM_OP_PING;
 
 			if (BE_VERBOSE) {
 				expected_responses = 1;
 			}
 			
 			crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 
 		} else {
 			crm_info("Cluster-wide health not available yet");
 			all_is_good = FALSE;
 		}		
 		
 	} else if(DO_ELECT_DC) {
 		/* tell the local node to initiate an election */
 
 		sys_to = CRM_SYSTEM_CRMD;
 		crmd_operation = CRM_OP_VOTE;
 		
 		crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 		
 		dest_node = NULL;
 
 		ret = 0; /* no return message */
 		
 	} else if(DO_WHOIS_DC) {
 		sys_to = CRM_SYSTEM_DC;
 		crmd_operation = CRM_OP_PING;
 			
 		crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 
 		dest_node = NULL;
 
 	} else if(DO_NODE_LIST) {
 
 		cib_t *	the_cib = cib_new();
 		xmlNode *output = NULL;
 		
 		enum cib_errors rc = the_cib->cmds->signon(
 		    the_cib, crm_system_name, cib_command);
 
 		if(rc != cib_ok) {
 			return -1;
 		}
 			
 		output = get_cib_copy(the_cib);
 		do_find_node_list(output);
 		
 		free_xml(output);
 		the_cib->cmds->signoff(the_cib);
 		exit(rc);
 		
 	} else if(DO_RESET) {
 		/* tell dest_node to initiate the shutdown proceedure
 		 *
 		 * if dest_node is NULL, the request will be sent to the
 		 *   local node
 		 */
 		sys_to = CRM_SYSTEM_CRMD;
 		crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 		
 		ret = 0; /* no return message */
 		
 	} else if(DO_DEBUG == debug_inc) {
 		/* tell dest_node to increase its debug level
 		 *
 		 * if dest_node is NULL, the request will be sent to the
 		 *   local node
 		 */
 		sys_to = CRM_SYSTEM_CRMD;
 		crmd_operation = CRM_OP_DEBUG_UP;
 		
 		ret = 0; /* no return message */
 		
 	} else if(DO_DEBUG == debug_dec) {
 		/* tell dest_node to increase its debug level
 		 *
 		 * if dest_node is NULL, the request will be sent to the
 		 *   local node
 		 */
 		sys_to = CRM_SYSTEM_CRMD;
 		crmd_operation = CRM_OP_DEBUG_DOWN;
 		
 		ret = 0; /* no return message */
 		
 	} else {
 		crm_err("Unknown options");
 		all_is_good = FALSE;
 	}
 	
 
 	if(all_is_good == FALSE) {
 		crm_err("Creation of request failed.  No message to send");
 		return -1;
 	}
 
 /* send it */
 	if (crmd_channel == NULL) {
 		crm_err("The IPC connection is not valid, cannot send anything");
 		return -1;
 	}
 
 	if(sys_to == NULL) {
 		if (dest_node != NULL) {
 			sys_to = CRM_SYSTEM_CRMD;
 		} else {
 			sys_to = CRM_SYSTEM_DC;				
 		}
 	}
 	
 	{
 		xmlNode *cmd = create_request(
 			crmd_operation, msg_data, dest_node, sys_to,
 			crm_system_name, admin_uuid);
 
 		if(this_msg_reference != NULL) {
 			crm_xml_add(cmd, XML_ATTR_REFERENCE, this_msg_reference);
 		}
 		send_ipc_message(crmd_channel, cmd);
 		free_xml(cmd);
 	}
 	
 	return ret;
 }
 
 void
 crmadmin_ipc_connection_destroy(gpointer user_data)
 {
     crm_err("Connection to CRMd was terminated");
     if(mainloop) {
 	g_main_quit(mainloop);
     } else {
 	exit(1);
     }
 }
 
 
 gboolean
 do_init(void)
 {
 	GCHSource *src = NULL;
 	
 	crm_malloc0(admin_uuid, 11);
 	if(admin_uuid != NULL) {
 		snprintf(admin_uuid, 10, "%d", getpid());
 		admin_uuid[10] = '\0';
 	}
 	
 	src = init_client_ipc_comms(
 		CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel);
 
 	if(DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) {
 		return TRUE;
 		
 	} else if(crmd_channel != NULL) {
 		send_hello_message(
 			crmd_channel, admin_uuid, crm_system_name,"0", "1");
 
 		set_IPC_Channel_dnotify(src, crmadmin_ipc_connection_destroy);
 		
 		return TRUE;
 	} 
 	return FALSE;
 }
 
 gboolean
 admin_msg_callback(IPC_Channel * server, void *private_data)
 {
 	int rc = 0;
 	int lpc = 0;
 	xmlNode *xml = NULL;
 	IPC_Message *msg = NULL;
 	gboolean hack_return_good = TRUE;
 	static int received_responses = 0;
 	char *filename = NULL;
 	int filename_len = 0;
 	const char *result = NULL;
 
 	Gmain_timeout_remove(message_timer_id);
 
 	while (server->ch_status != IPC_DISCONNECT
 	       && server->ops->is_message_pending(server) == TRUE) {
 		rc = server->ops->recv(server, &msg);
 		if (rc != IPC_OK) {
 		    crm_perror(LOG_ERR,"Receive failure (%d)", rc);
 			return !hack_return_good;
 		}
 
 		if (msg == NULL) {
 			crm_debug_4("No message this time");
 			continue;
 		}
 
 		lpc++;
 		received_responses++;
 
 		xml = convert_ipc_message(msg, __FUNCTION__);
 		msg->msg_done(msg);
 		crm_log_xml(LOG_MSG, "ipc", xml);
 		
 		if (xml == NULL) {
 			crm_info("XML in IPC message was not valid... "
 				 "discarding.");
 			goto cleanup;
 			
 		} else if (validate_crm_message(
 				   xml, crm_system_name, admin_uuid,
 				   XML_ATTR_RESPONSE) == FALSE) {
 			crm_debug_2("Message was not a CRM response. Discarding.");
 			goto cleanup;
 		}
 
 		result = crm_element_value(xml, XML_ATTR_RESULT);
 		if(result == NULL || strcasecmp(result, "ok") == 0) {
 			result = "pass";
 		} else {
 			result = "fail";
 		}
 		
 		if(DO_HEALTH) {
 			xmlNode *data = get_message_xml(xml, F_CRM_DATA);
 			const char *state = crm_element_value(data, "crmd_state");
 
 			printf("Status of %s@%s: %s (%s)\n",
 			       crm_element_value(data,XML_PING_ATTR_SYSFROM),
 			       crm_element_value(xml, F_CRM_HOST_FROM),
 			       state,
 			       crm_element_value(data,XML_PING_ATTR_STATUS));
 			
 			if(BE_SILENT && state != NULL) {
 				fprintf(stderr, "%s\n", state);
 			}
 			
 		} else if(DO_WHOIS_DC) {
 			const char *dc = crm_element_value(xml, F_CRM_HOST_FROM);
 			
 			printf("Designated Controller is: %s\n", dc);
 			if(BE_SILENT && dc != NULL) {
 				fprintf(stderr, "%s\n", dc);
 			}
 		}
 		
 		if (this_msg_reference != NULL) {
 			/* in testing mode... */
 			/* 31 = "test-_.xml" + an_int_as_string + '\0' */
 			xmlNode *data = get_message_xml(xml, F_CRM_DATA);
 			filename_len = 31 + strlen(this_msg_reference);
 
 			crm_malloc0(filename, filename_len);
 			if(filename != NULL) {
 				snprintf(filename, filename_len,
 					"%s-%s_%d.xml",
 					result, this_msg_reference,
 					received_responses);
 				
 				filename[filename_len - 1] = '\0';
 				if (0 > write_xml_file(data, filename, FALSE)) {
 					crm_crit("Could not save response to"
 						 " %s", filename);
 				}
 			}
 		}
 	  cleanup:
 		free_xml(xml);
 		xml = NULL;		
 	}
 
 	if (server->ch_status == IPC_DISCONNECT) {
 		crm_debug_2("admin_msg_callback: received HUP");
 		return !hack_return_good;
 	}
 
 	if (received_responses >= expected_responses) {
 		crm_debug_2(
 		       "Recieved expected number (%d) of messages from Heartbeat."
 		       "  Exiting normally.", expected_responses);
 		exit(0);
 	}
 
 	message_timer_id = Gmain_timeout_add(
 		message_timeout_ms, admin_message_timeout, NULL);
 	
 	
 	return hack_return_good;
 }
 
 gboolean
 admin_message_timeout(gpointer data)
 {
 	fprintf(stderr, "No messages received in %d seconds.. aborting\n",
 		(int)message_timeout_ms/1000);
 	crm_err("No messages received in %d seconds",
 		(int)message_timeout_ms/1000);
 	operation_status = -3;
 	g_main_quit(mainloop);
 	return FALSE;
 }
 
 
 gboolean
 is_node_online(xmlNode *node_state) 
 {
 	const char *uname      = crm_element_value(node_state,XML_ATTR_UNAME);
 	const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE);
 	const char *exp_state  = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE);
 	const char *crm_state  = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE);
 	const char *ha_state   = crm_element_value(node_state,XML_CIB_ATTR_HASTATE);
 	const char *ccm_state  = crm_element_value(node_state,XML_CIB_ATTR_INCCM);
 
 	if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)
 	   && (ha_state == NULL || safe_str_eq(ha_state, "active"))
 	   && crm_is_true(ccm_state)
 	   && safe_str_eq(crm_state, "online")) {
 		crm_debug_3("Node %s is online", uname);
 		return TRUE;
 	}
 	crm_debug_3("Node %s: ha=%s ccm=%s join=%s exp=%s crm=%s",
 		  uname, crm_str(ha_state), crm_str(ccm_state),
                   crm_str(join_state), crm_str(exp_state),
                   crm_str(crm_state));
 	crm_debug_3("Node %s is offline", uname);
 	return FALSE;
 }
 
 int
 do_find_node_list(xmlNode *xml_node)
 {
 	int found = 0;
 	xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
 
 	xml_child_iter_filter(
 		nodes, node, XML_CIB_TAG_NODE,	
 		if(BASH_EXPORT) {
 			printf("export %s=%s\n",
 			       crm_element_value(node, XML_ATTR_UNAME),
 			       crm_element_value(node, XML_ATTR_ID));
 		} else {
 			printf("%s node: %s (%s)\n",
 			       crm_element_value(node, XML_ATTR_TYPE),
 			       crm_element_value(node, XML_ATTR_UNAME),
 			       crm_element_value(node, XML_ATTR_ID));
 		}
 		found++;
 		);
 	if(found == 0) {
 		printf("NO nodes configured\n");
 	}
 					
 	return found;
 }
 
 
 void
 usage(const char *cmd, int exit_status)
 {
 	FILE *stream;
 
 	stream = exit_status ? stderr : stdout;
 
 	fprintf(stream, "usage: %s [-?Vs] [command] [command args]\n", cmd);
 
 	fprintf(stream, "Options\n");
 	fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?');
 	fprintf(stream, "\t--%s (-%c)\t: version details\n", "version", 'v');
 	fprintf(stream, "\t--%s (-%c)\t: "
 		"turn on debug info. additional instances increase verbosity\n",
 		"verbose", 'V');
 	fprintf(stream, "\t--%s (-%c)\t: be very *very* quiet\n", "quiet", 'q');
 	fprintf(stream, "\t--%s (-%c)\t: Only applies to -N.\n"
 		"\t\tCreate Bash export entries of the form \"export uname=uuid\"\n", "bash-export", 'B');
 	fprintf(stream, "\nCommands\n");
 	fprintf(stream, "\t--%s (-%c) <node>\t: "
 		"increment the CRMd debug level on <node>\n", CRM_OP_DEBUG_UP,'i');
 	fprintf(stream, "\t--%s (-%c) <node>\t: "
 		"decrement the CRMd debug level on <node>\n", CRM_OP_DEBUG_DOWN,'d');
 	fprintf(stream, "\t--%s (-%c) <node>\t: "
 		"shutdown the CRMd on <node>\n", "kill", 'K');
 	fprintf(stream, "\t--%s (-%c) <node>\t: "
 		"request the status of <node>\n", "status", 'S');
 #if 0
 	fprintf(stream, "\t--%s (-%c)\t\t: "
 		"request the status of all nodes\n", "health", 'H');
 #endif
 	fprintf(stream, "\t--%s (-%c) <node>\t: "
 		"initiate an election from <node>\n", "election", 'E');
 	fprintf(stream, "\t--%s (-%c)\t: "
 		"request the uname of the DC\n", "dc_lookup", 'D');
 	fprintf(stream, "\t--%s (-%c)\t\t: "
 		"request the uname of all member nodes\n", "nodes", 'N');
 /*	fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */
 	fflush(stream);
 
 	exit(exit_status);
 }