diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am
index 9dff13e1be..cd1a0ea51d 100644
--- a/lib/common/Makefile.am
+++ b/lib/common/Makefile.am
@@ -1,59 +1,62 @@
 #
 # Copyright (C) 2004 Andrew Beekhof
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; either version 2
 # 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
 
 INCLUDES       	= -I$(top_builddir)/include  -I$(top_srcdir)/include   \
 		  -I$(top_builddir)/libltdl  -I$(top_srcdir)/libltdl   \
 		  -I$(AISPREFIX)/include/openais
 
+headerdir=$(includedir)/@PKG_NAME@/crm/common
+
+header_HEADERS = stack.h
 
 ## libraries
 lib_LTLIBRARIES	= libcrmcommon.la libcrmcluster.la
 
 libcrmcluster_la_SOURCES = cluster.c membership.c stack.h
 
 if BUILD_AIS_SUPPORT
 libcrmcluster_la_SOURCES += ais.c
 endif
 
 if BUILD_HEARTBEAT_SUPPORT
 libcrmcluster_la_SOURCES += heartbeat.c
 endif
 
 libcrmcluster_la_LDFLAGS = -version-info 1:0:0
 libcrmcluster_la_LIBADD  = $(CLUSTERLIBS) libcrmcommon.la
 libcrmcluster_la_DEPENDENCIES = libcrmcommon.la
 
 # Can't use -Wcast-qual here because glib insists on pretending things are const  
 # when they're not and thus we need the crm_element_value_const() hack
 
 # s390 needs -fPIC 
 # s390-suse-linux/bin/ld: .libs/ipc.o: relocation R_390_PC32DBL against `__stack_chk_fail@@GLIBC_2.4' can not be used when making a shared object; recompile with -fPIC
 
 CFLAGS		= $(CFLAGS_COPY:-Wcast-qual=) -fPIC
 
 libcrmcommon_la_SOURCES	= ipc.c utils.c xml.c iso8601.c iso8601_fields.c remote.c
 
 libcrmcommon_la_LDFLAGS	= -version-info 2:0:0  $(GNUTLSLIBS)
 
 clean-generic:
 	rm -f *.log *.debug *.xml *~
 
 install-exec-local:
 
 uninstall-local:
diff --git a/lib/common/ais.c b/lib/common/ais.c
index 0dd91b7518..960b3509a3 100644
--- a/lib/common/ais.c
+++ b/lib/common/ais.c
@@ -1,720 +1,724 @@
 /* 
  * 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 <bzlib.h>
 #include <crm/ais.h>
 #include <crm/common/cluster.h>
 #include <sys/uio.h>
 #include <sys/utsname.h>
 #include "stack.h"
 #include <clplumbing/timers.h>
 #include <clplumbing/Gmain_timeout.h>
 
 #define TRADITIONAL_AIS_IPC 0
 
 #ifdef AIS_WHITETANK 
 extern int openais_fd_get(void *ipc_context);
 extern SaAisErrorT openais_service_connect(enum service_types service, void **ipc_context);
 extern int openais_dispatch_recv(void *ipc_context, void *buf, int timeout);
 extern SaAisErrorT openais_msg_send_reply_receive(
     void *ipc_context, struct iovec *iov, int iov_len,
     void *res_msg, int res_len);
 #endif
 
 enum crm_ais_msg_types text2msg_type(const char *text) 
 {
 	int type = crm_msg_none;
 
 	CRM_CHECK(text != NULL, return type);
 	if(safe_str_eq(text, "ais")) {
 		type = crm_msg_ais;
 	} else if(safe_str_eq(text, "crm_plugin")) {
 		type = crm_msg_ais;
 	} else if(safe_str_eq(text, CRM_SYSTEM_CIB)) {
 		type = crm_msg_cib;
 	} else if(safe_str_eq(text, CRM_SYSTEM_CRMD)) {
 		type = crm_msg_crmd;
 	} else if(safe_str_eq(text, CRM_SYSTEM_DC)) {
 		type = crm_msg_crmd;
 	} else if(safe_str_eq(text, CRM_SYSTEM_TENGINE)) {
 		type = crm_msg_te;
 	} else if(safe_str_eq(text, CRM_SYSTEM_PENGINE)) {
 		type = crm_msg_pe;
 	} else if(safe_str_eq(text, CRM_SYSTEM_LRMD)) {
 		type = crm_msg_lrmd;
 	} else if(safe_str_eq(text, CRM_SYSTEM_STONITHD)) {
 		type = crm_msg_stonithd;
 	} else if(safe_str_eq(text, "attrd")) {
 		type = crm_msg_attrd;
 	} else {
 		crm_debug_2("Unknown message type: %s", text);
 	}
 	return type;
 }
 
 char *get_ais_data(AIS_Message *msg)
 {
     int rc = BZ_OK;
     char *uncompressed = NULL;
     unsigned int new_size = msg->size;
     
     if(msg->is_compressed == FALSE) {
 	crm_debug_2("Returning uncompressed message data");
 	uncompressed = strdup(msg->data);
 
     } else {
 	crm_debug_2("Decompressing message data");
 	crm_malloc0(uncompressed, new_size);
 	
 	rc = BZ2_bzBuffToBuffDecompress(
 	    uncompressed, &new_size, msg->data, msg->compressed_size, 1, 0);
 	
 	CRM_ASSERT(rc = BZ_OK);
 	CRM_ASSERT(new_size == msg->size);
     }
     
     return uncompressed;
 }
 
 
 #if SUPPORT_AIS
 int ais_fd_sync = -1;
 int ais_fd_async = -1; /* never send messages via this channel */
 void *ais_ipc_ctx = NULL;
 GFDSource *ais_source = NULL;
 GFDSource *ais_source_sync = NULL;
 
 gboolean get_ais_nodeid(uint32_t *id, char **uname)
 {
     struct iovec iov;
     int retries = 0;
     int rc = SA_AIS_OK;
     mar_res_header_t header;
     struct crm_ais_nodeid_resp_s answer;
 
     header.id = crm_class_nodeid;
     header.size = sizeof(mar_res_header_t);
 
     CRM_CHECK(id != NULL, return FALSE);
     CRM_CHECK(uname != NULL, return FALSE);
 
     iov.iov_base = &header;
     iov.iov_len = header.size;
     
   retry:
     errno = 0;
 #if TRADITIONAL_AIS_IPC
     rc = saSendReceiveReply(ais_fd_sync, &header, header.size, &answer, sizeof (struct crm_ais_nodeid_resp_s));
 #else
     rc = openais_msg_send_reply_receive(
 	ais_ipc_ctx, &iov, 1, &header, sizeof (mar_res_header_t));
 #endif
     if(rc == SA_AIS_OK) {
 	CRM_CHECK(answer.header.size == sizeof (struct crm_ais_nodeid_resp_s),
 		  crm_err("Odd message: id=%d, size=%d, error=%d",
 			  answer.header.id, answer.header.size, answer.header.error));
 	CRM_CHECK(answer.header.id == CRM_MESSAGE_NODEID_RESP, crm_err("Bad response id"));
     }
 
     if(rc == SA_AIS_ERR_TRY_AGAIN && retries < 20) {
 	retries++;
 	crm_info("Peer overloaded: Re-sending message (Attempt %d of 20)", retries);
 	mssleep(retries * 100); /* Proportional back off */
 	goto retry;
     }
 
     if(rc != SA_AIS_OK) {    
 	crm_err("Sending nodeid request: FAILED (rc=%d): %s", rc, ais_error2text(rc));
 	return FALSE;
 	
     } else if(answer.header.error != SA_AIS_OK) {
 	crm_err("Bad response from peer: (rc=%d): %s", rc, ais_error2text(rc));
 	return FALSE;
     }
 
     crm_info("Server details: id=%u uname=%s", answer.id, answer.uname);
     
     *id = answer.id;
     *uname = crm_strdup(answer.uname);
     return TRUE;
 }
 
 gboolean
 send_ais_text(int class, const char *data,
 	      gboolean local, const char *node, enum crm_ais_msg_types dest)
 {
     int retries = 0;
     static int msg_id = 0;
     static int local_pid = 0;
 
     int rc = SA_AIS_OK;
     struct iovec iov;
     mar_res_header_t header;
     AIS_Message *ais_msg = NULL;
     enum crm_ais_msg_types sender = text2msg_type(crm_system_name);
 
     if(local_pid == 0) {
 	local_pid = getpid();
     }
 
     CRM_CHECK(data != NULL, return FALSE);
     crm_malloc0(ais_msg, sizeof(AIS_Message));
     
     ais_msg->id = msg_id++;
     ais_msg->header.id = class;
     
     ais_msg->host.type = dest;
     ais_msg->host.local = local;
     if(node) {
 	ais_msg->host.size = strlen(node);
 	memset(ais_msg->host.uname, 0, MAX_NAME);
 	memcpy(ais_msg->host.uname, node, ais_msg->host.size);
 	ais_msg->host.id = 0;
 	
     } else {
 	ais_msg->host.size = 0;
 	memset(ais_msg->host.uname, 0, MAX_NAME);
 	ais_msg->host.id = 0;
     }
     
     ais_msg->sender.type = sender;
     ais_msg->sender.pid = local_pid;
     ais_msg->sender.size = 0;
     memset(ais_msg->sender.uname, 0, MAX_NAME);
     ais_msg->sender.id = 0;
     
     ais_msg->size = 1 + strlen(data);
 
     if(ais_msg->size < CRM_BZ2_THRESHOLD) {
   failback:
 	crm_realloc(ais_msg, sizeof(AIS_Message) + ais_msg->size);
 	memcpy(ais_msg->data, data, ais_msg->size);
 	
     } else {
 	char *compressed = NULL;
 	char *uncompressed = crm_strdup(data);
 	unsigned int len = (ais_msg->size * 1.1) + 600; /* recomended size */
 	
 	crm_debug_5("Compressing message payload");
 	crm_malloc(compressed, len);
 	
 	rc = BZ2_bzBuffToBuffCompress(
 	    compressed, &len, uncompressed, ais_msg->size, CRM_BZ2_BLOCKS, 0, CRM_BZ2_WORK);
 
 	crm_free(uncompressed);
 	
 	if(rc != BZ_OK) {
 	    crm_err("Compression failed: %d", rc);
 	    crm_free(compressed);
 	    goto failback;  
 	}
 
 	crm_realloc(ais_msg, sizeof(AIS_Message) + len + 1);
 	memcpy(ais_msg->data, compressed, len);
 	ais_msg->data[len] = 0;
 	crm_free(compressed);
 
 	ais_msg->is_compressed = TRUE;
 	ais_msg->compressed_size = len;
 
 	crm_debug_2("Compression details: %d -> %d",
 		  ais_msg->size, ais_data_len(ais_msg));
     } 
 
     ais_msg->header.size = sizeof(AIS_Message) + ais_data_len(ais_msg);
 
     crm_debug_3("Sending%s message %d to %s.%s (data=%d, total=%d)",
 		ais_msg->is_compressed?" compressed":"",
 		ais_msg->id, ais_dest(&(ais_msg->host)), msg_type2text(dest),
 		ais_data_len(ais_msg), ais_msg->header.size);
 
     iov.iov_base = ais_msg;
     iov.iov_len = ais_msg->header.size;
   retry:
     errno = 0;
 
 #if TRADITIONAL_AIS_IPC
     rc = saSendReceiveReply(ais_fd_sync, ais_msg, ais_msg->header.size,
 			    &header, sizeof (mar_res_header_t));
 #else
     rc = openais_msg_send_reply_receive(
 	ais_ipc_ctx, &iov, 1, &header, sizeof (mar_res_header_t));
 #endif
 
     if(rc == SA_AIS_OK) {
 	CRM_CHECK(header.size == sizeof (mar_res_header_t),
 		  crm_err("Odd message: id=%d, size=%d, error=%d",
 			  header.id, header.size, header.error));
 	CRM_CHECK(header.id == CRM_MESSAGE_IPC_ACK, crm_err("Bad response id"));
 	CRM_CHECK(header.error == SA_AIS_OK, rc = header.error);
     }
 
     if(rc == SA_AIS_ERR_TRY_AGAIN && retries < 20) {
 	retries++;
 	crm_info("Peer overloaded: Re-sending message (Attempt %d of 20)", retries);
 	mssleep(retries * 100); /* Proportional back off */
 	goto retry;
     }
 
     if(rc != SA_AIS_OK) {    
 	crm_perror(LOG_ERR,"Sending message %d: FAILED (rc=%d): %s",
 		  ais_msg->id, rc, ais_error2text(rc));
 	ais_fd_async = -1;
     } else {
 	crm_debug_4("Message %d: sent", ais_msg->id);
     }
 
     crm_free(ais_msg);
     return (rc == SA_AIS_OK);
 }
 
 gboolean
 send_ais_message(xmlNode *msg, 
 		 gboolean local, const char *node, enum crm_ais_msg_types dest)
 {
     gboolean rc = TRUE;
     char *data = NULL;
 
     if(ais_fd_async < 0 || ais_source == NULL) {
 	crm_err("Not connected to AIS");
 	return FALSE;
     }
 
     data = dump_xml_unformatted(msg);
     rc = send_ais_text(0, data, local, node, dest);
     crm_free(data);
     return rc;
 }
 
 void terminate_ais_connection(void) 
 {
     if(ais_fd_sync > 0) {
 	close(ais_fd_sync);
     }
     if(ais_fd_async > 0) {
 	close(ais_fd_async);
     }
     
     crm_notice("Disconnected from AIS");
 /*     G_main_del_fd(ais_source); */
 /*     G_main_del_fd(ais_source_sync);     */
 }
 
 int ais_membership_timer = 0;
 gboolean ais_membership_force = FALSE;
 
 static gboolean ais_membership_dampen(gpointer data)
 {
     crm_debug_2("Requesting cluster membership after stabilization delay");
     send_ais_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais);
     ais_membership_force = TRUE;
     ais_membership_timer = 0;
     return FALSE; /* never repeat automatically */
 }
 
 gboolean ais_dispatch(int sender, gpointer user_data)
 {
     char *data = NULL;
     char *uncompressed = NULL;
 
     int rc = SA_AIS_OK;
     AIS_Message *msg = NULL;
     gboolean (*dispatch)(AIS_Message*,char*,int) = user_data;
 
 #if TRADITIONAL_AIS_IPC
     mar_res_header_t *header = NULL;
     static int header_len = sizeof(mar_res_header_t);
 
     crm_malloc0(header, header_len);
     
     errno = 0;
     rc = saRecvRetry(sender, header, header_len);
     if (rc != SA_AIS_OK) {
 	crm_perror(LOG_ERR, "Receiving message header failed: (%d/%d) %s", rc, errno, ais_error2text(rc));
 	goto bail;
 
     } else if(header->size == header_len) {
 	crm_err("Empty message: id=%d, size=%d, error=%d, header_len=%d",
 		header->id, header->size, header->error, header_len);
 	goto done;
 	
     } else if(header->size == 0 || header->size < header_len) {
 	crm_err("Mangled header: size=%d, header=%d, error=%d",
 		header->size, header_len, header->error);
 	goto done;
 	
     } else if(header->error != 0) {
 	crm_err("Header contined error: %d", header->error);
     }
     
     crm_debug_2("Looking for %d (%d - %d) more bytes",
 		header->size - header_len, header->size, header_len);
 
     crm_realloc(header, header->size);
     /* Use a char* so we can store the remainder into an offset */
     data = (char*)header;
 
     errno = 0;
     rc = saRecvRetry(sender, data+header_len, header->size - header_len);
 #else
     crm_malloc0(data, 1000000);
     rc = openais_dispatch_recv (ais_ipc_ctx, data, 0);
 #endif
     msg = (AIS_Message*)data;
 
     if (rc != SA_AIS_OK) {
 	crm_perror(LOG_ERR,"Receiving message body failed: (%d) %s", rc, ais_error2text(rc));
 	goto bail;
     }
 
     crm_debug_3("Got new%s message (size=%d, %d, %d)",
 		msg->is_compressed?" compressed":"",
 		ais_data_len(msg), msg->size, msg->compressed_size);
     
     data = msg->data;
     if(msg->is_compressed && msg->size > 0) {
 	int rc = BZ_OK;
 	unsigned int new_size = msg->size;
 
 	if(check_message_sanity(msg, NULL) == FALSE) {
 	    goto badmsg;
 	}
 
 	crm_debug_5("Decompressing message data");
 	crm_malloc0(uncompressed, new_size);
 	rc = BZ2_bzBuffToBuffDecompress(
 	    uncompressed, &new_size, data, msg->compressed_size, 1, 0);
 
 	if(rc != BZ_OK) {
 	    crm_err("Decompression failed: %d", rc);
 	    goto badmsg;
 	}
 	
 	CRM_ASSERT(rc == BZ_OK);
 	CRM_ASSERT(new_size == msg->size);
 
 	data = uncompressed;
 
     } else if(check_message_sanity(msg, data) == FALSE) {
 	goto badmsg;
 
     } else if(safe_str_eq("identify", data)) {
 	int pid = getpid();
 	char *pid_s = crm_itoa(pid);
 	send_ais_text(0, pid_s, TRUE, NULL, crm_msg_ais);
 	crm_free(pid_s);
 	goto done;
     }
 
     if(msg->header.id == crm_class_rmpeer) {
 	uint32_t id = crm_int_helper(data, NULL);
 	crm_info("Removing peer %s/%u", data, id);
 	reap_crm_member(id);
 	crm_calculate_quorum();
 	goto done;
     }
     
     if(msg->header.id == crm_class_members) {
 	xmlNode *xml = string2xml(data);
 
 	if(xml != NULL) {
 	    gboolean do_ask = FALSE;
 	    gboolean do_process = TRUE;
 	    
 	    unsigned long long seq = 0;
 	    int new_size = 0;
 	    int current_size = crm_active_members();
 
 	    const char *reason = "unknown";
 	    const char *value = crm_element_value(xml, "id");
 	    seq = crm_int_helper(value, NULL);
 
 	    crm_debug_2("Received membership %llu", seq);
 
 	    xml_child_iter(xml, node,
 			   const char *state = crm_element_value(node, "state");
 			   if(safe_str_eq(state, CRM_NODE_MEMBER)) {
 			       new_size++;
 			   }
 		);
 
 	    if(ais_membership_force) {
 		/* always process */
 		crm_debug_2("Processing delayed membership change");
 		
 	    } else if(current_size == 0 && new_size == 1) {
 		do_ask = TRUE;
 		do_process = FALSE;
 		reason = "We've come up alone";
 
 	    } else if(new_size < (current_size/2)) {
 		do_process = FALSE;
 		reason = "We've lost more than half our peers";
 
 		if(ais_membership_timer == 0) {
 		    reason = "We've lost more than half our peers";
 		    crm_log_xml_debug(xml, __PRETTY_FUNCTION__);
 		    do_ask = TRUE;
 		}		
 	    }
 	    
 	    if(do_process) {
 		static long long last = 0;
 		/* if there is a timer running - let it run
 		 * there is no harm in getting an extra membership message
 		 */
 
 		/* Skip resends */
 		if(last < seq) {
 		    crm_info("Processing membership %llu", seq);
 		}
 		    
 /*		crm_log_xml_debug(xml, __PRETTY_FUNCTION__); */
 		if(ais_membership_force) {
 		    ais_membership_force = FALSE;
 		}
 		
 		xml_child_iter(xml, node, crm_update_ais_node(node, seq));
 		crm_calculate_quorum();
 		last = seq;
 		
 	    } else if(do_ask) {
 		dispatch = NULL;
 		crm_warn("Pausing to allow membership stability (size %d -> %d): %s",
 			 current_size, new_size, reason);
 		ais_membership_timer = Gmain_timeout_add(4*1000, ais_membership_dampen, NULL);
 
 		/* process node additions */
 		xml_child_iter(xml, node,
 			       const char *state = crm_element_value(node, "state");
 			       if(crm_str_eq(state, CRM_NODE_MEMBER, FALSE)) {
 				   crm_update_ais_node(node, seq);
 			       }
 		    );
 
 	    } else {
 		dispatch = NULL;
 		crm_warn("Membership is still unstable (size %d -> %d): %s",
 			current_size, new_size, reason);
 	    }
 	    
 	} else {
 	    crm_warn("Invalid peer update: %s", data);
 	}
 
 	free_xml(xml);
 
     } else {
 	const char *uuid = msg->sender.uname;
 	crm_update_peer(msg->sender.id, 0,0,0,0, uuid, msg->sender.uname, NULL, NULL);
     }
 
     if(dispatch != NULL) {
 	dispatch(msg, data, sender);
     }
     
   done:
     crm_free(uncompressed);
     crm_free(msg);
     return TRUE;
 
   badmsg:
     crm_err("Invalid message (id=%d, dest=%s:%s, from=%s:%s.%d):"
 	    " min=%d, total=%d, size=%d, bz2_size=%d",
 	    msg->id, ais_dest(&(msg->host)), msg_type2text(msg->host.type),
 	    ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
 	    msg->sender.pid, (int)sizeof(AIS_Message),
 	    msg->header.size, msg->size, msg->compressed_size);
     goto done;
     
   bail:
     crm_err("AIS connection failed");
     return FALSE;
 }
 
 static void
 ais_destroy(gpointer user_data)
 {
     crm_err("AIS connection terminated");
     ais_fd_sync = -1;
     exit(1);
 }
 
 gboolean init_ais_connection(
     gboolean (*dispatch)(AIS_Message*,char*,int),
-    void (*destroy)(gpointer), char **our_uuid, char **our_uname)
+    void (*destroy)(gpointer), char **our_uuid, char **our_uname, int *nodeid)
 {
     int pid = 0;
     int retries = 0;
     int rc = SA_AIS_OK;
     char *pid_s = NULL;
     struct utsname name;
     uint32_t local_nodeid = 0;
     char *local_uname = NULL;
     
   retry:
     crm_info("Creating connection to our AIS plugin");
 #if TRADITIONAL_AIS_IPC
     rc = saServiceConnect (&ais_fd_sync, &ais_fd_async, CRM_SERVICE);
 #else
     rc = openais_service_connect(CRM_SERVICE, &ais_ipc_ctx);
     ais_fd_async = openais_fd_get(ais_ipc_ctx);
 #endif
     if (rc != SA_AIS_OK) {
 	crm_info("Connection to our AIS plugin (%d) failed: %s (%d)", CRM_SERVICE, ais_error2text(rc), rc);
     }
 
     switch(rc) {
 	case SA_AIS_OK:
 	    break;
 	case SA_AIS_ERR_TRY_AGAIN:
 	    if(retries < 30) {
 		sleep(1);
 		retries++;
 		goto retry;
 	    }
 	    crm_err("Retry count exceeded");
 	    return FALSE;
 	default:
 	    return FALSE;
     }
 
     if(destroy == NULL) {
 	crm_debug("Using the default destroy handler");
 	destroy = ais_destroy;
     } 
    
     crm_info("AIS connection established");
     
     pid = getpid();
     pid_s = crm_itoa(pid);
     send_ais_text(0, pid_s, TRUE, NULL, crm_msg_ais);
     crm_free(pid_s);
 
     crm_peer_init();
     get_ais_nodeid(&local_nodeid, &local_uname);
 
     if(uname(&name) < 0) {
 	crm_perror(LOG_ERR,"uname(2) call failed");
 	exit(100);
     }
 
     if(safe_str_neq(name.nodename, local_uname)) {
 	crm_crit("Node name mismatch!  OpenAIS supplied %s, our lookup returned %s", local_uname, name.nodename);
 	crm_notice("Node name mismatches usually occur when assigned automatically by DHCP servers");
 	crm_notice("If this node was part of the cluster with a different name,"
 		   " you will need to remove the old entry with crm_node --remove");
     }
     
     if(our_uuid != NULL) {
 	*our_uuid = crm_strdup(local_uname);
     }
     if(our_uname != NULL) {
 	*our_uname = local_uname;
     }
+
+    if(nodeid != NULL) {
+	*nodeid = local_nodeid;
+    }
     
     if(local_nodeid != 0) {
 	/* Ensure the local node always exists */
 	crm_update_peer(local_nodeid, 0, 0, 0, 0, local_uname, local_uname, NULL, NULL);
     }
 
     if(dispatch) {
 	ais_source = G_main_add_fd(
 	    G_PRIORITY_HIGH, ais_fd_async, FALSE, ais_dispatch, dispatch, destroy);
     }
     return TRUE;
 }
 
 gboolean check_message_sanity(AIS_Message *msg, char *data) 
 {
     gboolean sane = TRUE;
     gboolean repaired = FALSE;
     int dest = msg->host.type;
     int tmp_size = msg->header.size - sizeof(AIS_Message);
 
     if(sane && msg->header.size == 0) {
 	crm_warn("Message with no size");
 	sane = FALSE;
     }
 
     if(sane && msg->header.error != 0) {
 	crm_warn("Message header contains an error: %d", msg->header.error);
 	sane = FALSE;
     }
 
     if(sane && ais_data_len(msg) != tmp_size) {
 	int cur_size = ais_data_len(msg);
 
 	repaired = TRUE;
 	if(msg->is_compressed) {
 	    msg->compressed_size = tmp_size;
 	    
 	} else {
 	    msg->size = tmp_size;
 	}
 	
 	crm_warn("Repaired message payload size %d -> %d", cur_size, tmp_size);
     }
 
     if(sane && ais_data_len(msg) == 0) {
 	crm_warn("Message with no payload");
 	sane = FALSE;
     }
 
     if(sane && data && msg->is_compressed == FALSE) {
 	int str_size = strlen(data) + 1;
 	if(ais_data_len(msg) != str_size) {
 	    int lpc = 0;
 	    crm_warn("Message payload is corrupted: expected %d bytes, got %d",
 		    ais_data_len(msg), str_size);
 	    sane = FALSE;
 	    for(lpc = (str_size - 10); lpc < msg->size; lpc++) {
 		if(lpc < 0) {
 		    lpc = 0;
 		}
 		crm_debug("bad_data[%d]: %d / '%c'", lpc, data[lpc], data[lpc]);
 	    }
 	}
     }
     
     if(sane == FALSE) {
 	crm_err("Invalid message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
 		msg->id, ais_dest(&(msg->host)), msg_type2text(dest),
 		ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
 		msg->sender.pid, msg->is_compressed, ais_data_len(msg),
 		msg->header.size);
 	
     } else if(repaired) {
 	crm_err("Repaired message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
 		msg->id, ais_dest(&(msg->host)), msg_type2text(dest),
 		ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
 		msg->sender.pid, msg->is_compressed, ais_data_len(msg),
 		msg->header.size);
     } else {
 	crm_debug_3("Verfied message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
 		    msg->id, ais_dest(&(msg->host)), msg_type2text(dest),
 		    ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
 		    msg->sender.pid, msg->is_compressed, ais_data_len(msg),
 		    msg->header.size);
     }
     
     return sane;
 }
 #endif
 
diff --git a/lib/common/cluster.c b/lib/common/cluster.c
index 42c015c9be..27a76b883a 100644
--- a/lib/common/cluster.c
+++ b/lib/common/cluster.c
@@ -1,247 +1,247 @@
 /* 
  * 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 <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <string.h>
 
 #include <stdlib.h>
 
 #include <clplumbing/cl_log.h>
 #include <ha_msg.h>
 
 #include <time.h> 
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/msg.h>
 #include <crm/common/ipc.h>
 #include <crm/common/cluster.h>
 #include "stack.h"
 
 
 xmlNode *create_common_message(
 	xmlNode *original_request, xmlNode *xml_response_data);
 
 gboolean crm_cluster_connect(
     char **our_uname, char **our_uuid, void *dispatch, void *destroy,
 #if SUPPORT_HEARTBEAT
     ll_cluster_t **hb_conn
 #else
     void **hb_conn
 #endif
     ) {
     if(hb_conn != NULL) {
 	*hb_conn = NULL;
     }
     
 #if SUPPORT_AIS
     if(is_openais_cluster()) {
 	crm_peer_init();
-	return init_ais_connection(dispatch, destroy, our_uuid, our_uname);
+	return init_ais_connection(dispatch, destroy, our_uuid, our_uname, NULL);
     }
 #endif
     
 #if SUPPORT_HEARTBEAT
     if(is_heartbeat_cluster()) {	
 	CRM_ASSERT(hb_conn != NULL);
 
 	if(*hb_conn == NULL) {
 	    *hb_conn = ll_cluster_new("heartbeat");
 	}
 	heartbeat_cluster = *hb_conn;
 
 	/* make sure we are disconnected first */
 	heartbeat_cluster->llc_ops->signoff(heartbeat_cluster, FALSE);
 
 	return register_heartbeat_conn(
 	    heartbeat_cluster, our_uuid, our_uname, dispatch, destroy);
     }
 #endif
     return FALSE;
 }
 
 gboolean send_cluster_message(
     const char *node, enum crm_ais_msg_types service, xmlNode *data, gboolean ordered) {
 
 #if SUPPORT_AIS
     if(is_openais_cluster()) {
 	return send_ais_message(data, FALSE, node, service);
     }
 #endif
 #if SUPPORT_HEARTBEAT
     if(is_heartbeat_cluster()) {
 	return send_ha_message(heartbeat_cluster, data, node, ordered);
     }
 #endif
     return FALSE;
 }
 
 static GHashTable *crm_uuid_cache = NULL;
 static GHashTable *crm_uname_cache = NULL;
 
 void
 empty_uuid_cache(void)
 {
 	if(crm_uuid_cache != NULL) {
 		g_hash_table_destroy(crm_uuid_cache);
 		crm_uuid_cache = NULL;
 	}
 }
 
 void
 unget_uuid(const char *uname)
 {
 	if(crm_uuid_cache == NULL) {
 		return;
 	}
 	g_hash_table_remove(crm_uuid_cache, uname);
 }
 
 const char *
 get_uuid(const char *uname) 
 {
     char *uuid_calc = NULL;
     CRM_CHECK(uname != NULL, return NULL);
 
     if(crm_uuid_cache == NULL) {
 	crm_uuid_cache = g_hash_table_new_full(
 	    g_str_hash, g_str_equal,
 	    g_hash_destroy_str, g_hash_destroy_str);
     }
 	
     CRM_CHECK(uname != NULL, return NULL);
     
     /* avoid blocking calls where possible */
     uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname);
     if(uuid_calc != NULL) {
 	return uuid_calc;
     }
     
 #if SUPPORT_AIS
     if(is_openais_cluster()) {
 	uuid_calc = crm_strdup(uname);
 	goto fallback;
     }
 #endif
 #if SUPPORT_HEARTBEAT
     if(is_heartbeat_cluster()) {
 	cl_uuid_t uuid_raw;
 	const char *unknown = "00000000-0000-0000-0000-000000000000";
 
 	if(heartbeat_cluster == NULL) {
 	    crm_warn("No connection to heartbeat, using uuid=uname");
 	    uuid_calc = crm_strdup(uname);
 	    goto fallback;
 	}
 	
 	if(heartbeat_cluster->llc_ops->get_uuid_by_name(
 	       heartbeat_cluster, uname, &uuid_raw) == HA_FAIL) {
 	    crm_err("get_uuid_by_name() call failed for host %s", uname);
 	    crm_free(uuid_calc);
 	    return NULL;	
 	} 
 
 	crm_malloc0(uuid_calc, 50);
 	cl_uuid_unparse(&uuid_raw, uuid_calc);
 
 	if(safe_str_eq(uuid_calc, unknown)) {
 		crm_warn("Could not calculate UUID for %s", uname);
 		crm_free(uuid_calc);
 		return NULL;
 	}
     }
 #endif
     
   fallback:
 	g_hash_table_insert(crm_uuid_cache, crm_strdup(uname), uuid_calc);
 	uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname);
 
 	return uuid_calc;
 }
 
 const char *
 get_uname(const char *uuid) 
 {
     char *uname = NULL;
     
     if(crm_uuid_cache == NULL) {
 	crm_uname_cache = g_hash_table_new_full(
 	    g_str_hash, g_str_equal,
 	    g_hash_destroy_str, g_hash_destroy_str);
     }
     
     CRM_CHECK(uuid != NULL, return NULL);
     
     /* avoid blocking calls where possible */
     uname = g_hash_table_lookup(crm_uname_cache, uuid);
     if(uname != NULL) {
 	return uname;
     }
     
 #if SUPPORT_AIS
     if(is_openais_cluster()) {
 	g_hash_table_insert(crm_uuid_cache, crm_strdup(uuid), crm_strdup(uuid));
     }
 #endif
     
 #if SUPPORT_HEARTBEAT
     if(is_heartbeat_cluster()) {
 	if(heartbeat_cluster != NULL && uuid != NULL) {
 	    cl_uuid_t uuid_raw;
 	    char *uuid_copy = crm_strdup(uuid);
 	    cl_uuid_parse(uuid_copy, &uuid_raw);
 	    
 	    if(heartbeat_cluster->llc_ops->get_name_by_uuid(
 		   heartbeat_cluster, &uuid_raw, uname, 256) == HA_FAIL) {
 		crm_err("Could not calculate UUID for %s", uname);
 		crm_free(uuid_copy);
 	    } else {
 		g_hash_table_insert(crm_uuid_cache, uuid_copy, crm_strdup(uname));
 	    }
 	}
     }
 #endif
     return g_hash_table_lookup(crm_uname_cache, uuid);
 }
 
 void
 set_uuid(xmlNode *node,const char *attr,const char *uname) 
 {
 	const char *uuid_calc = get_uuid(uname);
 	crm_xml_add(node, attr, uuid_calc);
 	return;
 }
 
 xmlNode*
 createPingAnswerFragment(const char *from, const char *status)
 {
 	xmlNode *ping = NULL;
 	
 	
 	ping = create_xml_node(NULL, XML_CRM_TAG_PING);
 	
 	crm_xml_add(ping, XML_PING_ATTR_STATUS, status);
 	crm_xml_add(ping, XML_PING_ATTR_SYSFROM, from);
 
 	return ping;
 }
diff --git a/lib/common/stack.h b/lib/common/stack.h
index 714f91adeb..4a75ee4e7e 100644
--- a/lib/common/stack.h
+++ b/lib/common/stack.h
@@ -1,48 +1,48 @@
 /* 
  * 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_STACK__H
 #define CRM_STACK__H
 
 #if SUPPORT_HEARTBEAT
 extern ll_cluster_t *heartbeat_cluster;
 extern gboolean send_ha_message(ll_cluster_t *hb_conn, xmlNode *msg,
 				const char *node, gboolean force_ordered);
 extern gboolean ha_msg_dispatch(ll_cluster_t *cluster_conn, gpointer user_data);
 
 extern gboolean register_heartbeat_conn(
     ll_cluster_t *hb_cluster, char **uuid, char **uname,
     void (*hb_message)(HA_Message *msg, void* private_data),
     void (*hb_destroy)(gpointer user_data));
 
 #endif
 
 #if SUPPORT_AIS
 
 extern gboolean send_ais_message(
     xmlNode *msg, gboolean local,
     const char *node, enum crm_ais_msg_types dest);
 
 extern void terminate_ais_connection(void);
 extern gboolean init_ais_connection(
     gboolean (*dispatch)(AIS_Message*,char*,int),
-    void (*destroy)(gpointer), char **our_uuid, char **our_uname);
+    void (*destroy)(gpointer), char **our_uuid, char **our_uname, int *nodeid);
 
 #endif
 
 #endif
diff --git a/tools/ccm_epoche.c b/tools/ccm_epoche.c
index b88166dce7..9f7baec570 100644
--- a/tools/ccm_epoche.c
+++ b/tools/ccm_epoche.c
@@ -1,376 +1,371 @@
 /* 
  * 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 <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 
 #ifdef HAVE_GETOPT_H
 #  include <getopt.h>
 #endif
 
 #include <libgen.h> /* for basename() */
 
 #include <clplumbing/cl_log.h>
 #include <clplumbing/cl_signal.h>
 #include <clplumbing/lsb_exitcodes.h>
 
 #include <crm/crm.h>
 #include <crm/ais.h>
 #include <crm/common/cluster.h>
 
 int command = 0;
 
 #define OPTARGS	"hVqepHR:"
 
 int ccm_fd = 0;
 int try_hb = 1;
 int try_ais = 1;
 
 const char *uname = NULL;
 void usage(const char* cmd, int exit_status);
 
 void ais_membership_destroy(gpointer user_data);
 gboolean ais_membership_dispatch(AIS_Message *wrapper, char *data, int sender);
-
-#if SUPPORT_AIS
-extern gboolean init_ais_connection(
-    gboolean (*dispatch)(AIS_Message*,char*,int),
-    void (*destroy)(gpointer), char **our_uuid, char **our_uname);
-#endif
+#include <../lib/common/stack.h>
 
 #if SUPPORT_HEARTBEAT
 #  include <ocf/oc_event.h>
 #  include <ocf/oc_membership.h>
 oc_ev_t *ccm_token = NULL;
 void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
 void ccm_age_callback(
     oc_ed_t event, void *cookie, size_t size, const void *data);
 gboolean ccm_age_connect(int *ccm_fd);
 #endif
 
 int
 main(int argc, char ** argv)
 {
 	int flag = 0;
 	int argerr = 0;
 	gboolean force_flag = FALSE;
 	gboolean dangerous_cmd = FALSE;
 
 #ifdef HAVE_GETOPT_H
 	int option_index = 0;
 	static struct option long_options[] = {
 		/* Top-level Options */
 
 		{"remove",      1, 0, 'R'},
 		{"partition",   0, 0, 'p'},
 		{"epoch",	0, 0, 'e'},
 		{"quorum",      0, 0, 'q'},
 		{"force",	0, 0, 'f'},
 		{"verbose",     0, 0, 'V'},
 		{"help",        0, 0, '?'},
 
 		{0, 0, 0, 0}
 	};
 #endif
 
 	crm_peer_init();
 	crm_log_init(basename(argv[0]), LOG_WARNING, FALSE, FALSE, 0, NULL);
 
 	while (flag >= 0) {
 #ifdef HAVE_GETOPT_H
 		flag = getopt_long(argc, argv, OPTARGS,
 				   long_options, &option_index);
 #else
 		flag = getopt(argc, argv, OPTARGS);
 #endif
 		switch(flag) {
 			case -1:
 			    break;
 			case 'V':
 				cl_log_enable_stderr(TRUE);
 				alter_debug(DEBUG_INC);
 				break;
 			case 'h':		/* Help message */
 				usage(crm_system_name, LSB_EXIT_OK);
 				break;
 			case 'H':
 				try_ais = 0;
 				break;
 			case 'A':
 				try_hb = 0;
 				break;
 			case 'f':
 				force_flag = TRUE;
 				break;
 			case 'R':
 			    dangerous_cmd = TRUE;
 			    command = flag;
 			    uname = optarg;
 			    break;
 			case 'p':
 			case 'e':
 			case 'q':
 				command = flag;
 				break;
 			default:
 				++argerr;
 				break;
 		}
 	}
     
 	if (optind > argc) {
 		++argerr;
 	}
     
 	if (argerr) {
 		usage(crm_system_name,LSB_EXIT_GENERIC);
 	}
 
 	if(dangerous_cmd && force_flag == FALSE) {
 	    fprintf(stderr, "The supplied command is considered dangerous."
 		    "  To prevent accidental destruction of the cluster,"
 		    " the --force flag is required in order to proceed.\n");
 	    fflush(stderr);
 	    exit(LSB_EXIT_GENERIC);
 	}
 	
 #if SUPPORT_AIS
 	if(try_ais && init_ais_connection(
-	       ais_membership_dispatch, ais_membership_destroy, NULL, NULL)) {
+	       ais_membership_dispatch, ais_membership_destroy, NULL, NULL, NULL)) {
 
 		GMainLoop*  amainloop = NULL;
 		if(command == 'r') {
 		    send_ais_text(crm_class_rmpeer, uname, TRUE, NULL, crm_msg_ais);
 		    return 0;
 		    
 		} else {
 		    crm_info("Requesting the list of configured nodes");
 		    send_ais_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais);
 		}
 		amainloop = g_main_new(FALSE);
 		g_main_run(amainloop);
 	}
 #endif
 #if SUPPORT_HEARTBEAT
 	if(try_hb && ccm_age_connect(&ccm_fd)) {
 		int rc = 0;
 		fd_set rset;	
 		oc_ev_t *ccm_token = NULL;
 		while (1) {
 			FD_ZERO(&rset);
 			FD_SET(ccm_fd, &rset);
 
 			rc = select(ccm_fd + 1, &rset, NULL,NULL,NULL);
 			if(rc < 0) {
 				crm_perror(LOG_ERR, "select failed");
 				if(errno == EINTR) {
 					crm_debug("Retry...");
 					continue;
 				}
 				
 			} else if(oc_ev_handle_event(ccm_token) != 0){
 				crm_err("oc_ev_handle_event failed");
 			}
 			return(1);
 		}
 	}
 #endif
 	return(1);    
 }
 
 
 void
 usage(const char* cmd, int exit_status)
 {
 	FILE* stream;
 
 	stream = exit_status ? stderr : stdout;
 
 	fprintf(stream, "usage: %s [-V] [-p|-e|-q]\n", cmd);
 	fprintf(stream, "\t--%s (-%c)\tprint the members of this partition\n", "partition", 'p');
 	fprintf(stream, "\t--%s (-%c)\tprint the epoch this node joined the partition\n", "epoch",  'e');
 	fprintf(stream, "\t--%s (-%c)\tprint a 1 if our partition has quorum\n", "quorum", 'q');
 	fflush(stream);
 
 	exit(exit_status);
 }
 
 #if SUPPORT_HEARTBEAT
 gboolean
 ccm_age_connect(int *ccm_fd) 
 {
 	gboolean did_fail = FALSE;
 	int ret = 0;
 	
 	crm_debug("Registering with CCM");
 	ret = oc_ev_register(&ccm_token);
 	if (ret != 0) {
 		crm_warn("CCM registration failed");
 		did_fail = TRUE;
 	}
 	
 	if(did_fail == FALSE) {
 		crm_debug("Setting up CCM callbacks");
 		ret = oc_ev_set_callback(ccm_token, OC_EV_MEMB_CLASS,
 					 ccm_age_callback, NULL);
 		if (ret != 0) {
 			crm_warn("CCM callback not set");
 			did_fail = TRUE;
 		}
 	}
 	if(did_fail == FALSE) {
 		oc_ev_special(ccm_token, OC_EV_MEMB_CLASS, 0/*don't care*/);
 		
 		crm_debug("Activating CCM token");
 		ret = oc_ev_activate(ccm_token, ccm_fd);
 		if (ret != 0){
 			crm_warn("CCM Activation failed");
 			did_fail = TRUE;
 		}
 	}
 	
 	return !did_fail;
 }
 
 
 void 
 ccm_age_callback(oc_ed_t event, void *cookie, size_t size, const void *data)
 {
 	int lpc;
 	int node_list_size;
 	const oc_ev_membership_t *oc = (const oc_ev_membership_t *)data;
 
 	node_list_size = oc->m_n_member;
 	if(command == 'q') {
 		crm_debug("Processing \"%s\" event.", 
 			  event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP":
 			  event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY":
 			  event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED":
 			  event==OC_EV_MS_EVICTED?"EVICTED":
 			  "NO QUORUM MEMBERSHIP");
 		if(ccm_have_quorum(event)) {
 			fprintf(stdout, "1\n");
 		} else {
 			fprintf(stdout, "0\n");
 		}
 		
 	} else if(command == 'e') {
 		crm_debug("Searching %d members for our birth", oc->m_n_member);
 	}
 	for(lpc=0; lpc<node_list_size; lpc++) {
 		if(command == 'p') {
 			fprintf(stdout, "%s ",
 				oc->m_array[oc->m_memb_idx+lpc].node_uname);
 
 		} else if(command == 'e') {
 			if(oc_ev_is_my_nodeid(ccm_token, &(oc->m_array[lpc]))){
 				crm_debug("MATCH: nodeid=%d, uname=%s, born=%d",
 					  oc->m_array[oc->m_memb_idx+lpc].node_id,
 					  oc->m_array[oc->m_memb_idx+lpc].node_uname,
 					  oc->m_array[oc->m_memb_idx+lpc].node_born_on);
 				fprintf(stdout, "%d\n",
 					oc->m_array[oc->m_memb_idx+lpc].node_born_on);
 			}
 		}
 	}
 
 	oc_ev_callback_done(cookie);
 
 	if(command == 'p') {
 		fprintf(stdout, "\n");
 	}
 	fflush(stdout);
 	exit(0);
 }
 #endif
 
 #if SUPPORT_AIS
 void
 ais_membership_destroy(gpointer user_data)
 {
     crm_err("AIS connection terminated");
     ais_fd_sync = -1;
     exit(1);
 }
 #endif
 
 static gint member_sort(gconstpointer a, gconstpointer b) 
 {
     const crm_node_t *node_a = a;
     const crm_node_t *node_b = b;
     return strcmp(node_a->uname, node_b->uname);
 }
 
 static void crm_add_member(
     gpointer key, gpointer value, gpointer user_data)
 {
     GList **list = user_data;
     crm_node_t *node = value;
     if(node->uname != NULL) {
 	*list = g_list_insert_sorted(*list, node, member_sort);
     }
 }
 
 gboolean
 ais_membership_dispatch(AIS_Message *wrapper, char *data, int sender) 
 {
     crm_info("Message received");
     switch(wrapper->header.id) {
 	case crm_class_members:
 	case crm_class_notify:
 	    break;
 	default:
 	    return TRUE;
 	    
 	    break;
     }
 
     if(command == 'q') {
 	if(crm_have_quorum) {
 	    fprintf(stdout, "1\n");
 	} else {
 	    fprintf(stdout, "0\n");
 	}
 		
     } else if(command == 'e') {
 	/* Age makes no sense (yet) in an AIS cluster */
 	fprintf(stdout, "1\n");
 
     } else if(command == 'p') {
 	GList *nodes = NULL;
 	g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes);
 	slist_iter(node, crm_node_t, nodes, lpc,
 		   if(node->uname && crm_is_member_active(node)) {
 		       fprintf(stdout, "%s ", node->uname);
 		   }
 	    );
 	fprintf(stdout, "\n");
     }
 
     exit(0);
     
     return TRUE;
 }