File pacemaker.diff of Package openais

--- whitetank-svn/Makefile	
+++ whitetank-dev/Makefile	
@@ -29,30 +29,30 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
-DESTDIR=/usr/local
-SBINDIR=/usr/sbin
-INCLUDEDIR=/usr/include/openais
-INCLUDEDIR_TOTEM=/usr/include/openais/totem
-INCLUDEDIR_LCR=/usr/include/openais/lcr
-INCLUDEDIR_SERVICE=/usr/include/openais/service
-MANDIR=/usr/share/man
+include Makefile.inc
+
+SBINDIR=$(PREFIX)/sbin
+INCLUDEDIR=$(PREFIX)/include/openais
+INCLUDEDIR_TOTEM=$(PREFIX)/include/openais/totem
+INCLUDEDIR_LCR=$(PREFIX)/include/openais/lcr
+INCLUDEDIR_SERVICE=$(PREFIX)/include/openais/service
+MANDIR=$(PREFIX)/share/man
 ETCDIR=/etc/ais
-LCRSODIR=/usr/libexec/lcrso
 ARCH=$(shell uname -p)
 
 ifeq (,$(findstring 64,$(ARCH)))
-LIBDIR=/usr/lib/openais
+LIBDIR=$(PREFIX)/lib/openais
 else
-LIBDIR=/usr/lib64/openais
+LIBDIR=$(PREFIX)/lib64/openais
 endif
 ifeq (s390,$(ARCH))
-LIBDIR=/usr/lib/openais
+LIBDIR=$(PREFIX)/lib/openais
 endif
 ifeq (s390x,$(ARCH))
-LIBDIR=/usr/lib64/openais
+LIBDIR=$(PREFIX)/lib64/openais
 endif
 ifeq (ia64,$(ARCH))
-LIBDIR=/usr/lib/openais
+LIBDIR=$(PREFIX)/lib/openais
 endif
 
 all:
@@ -106,29 +106,29 @@ install:
 	ln -sf libcfg.so.2.0.0 lib/libcfg.so.2
 	ln -sf libtotem_pg.so.2.0.0 exec/libtotem_pg.so.2
 
-	cp -a lib/libais.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaAmf.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaClm.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaCkpt.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaEvt.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaLck.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaMsg.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libevs.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libcpg.so $(DESTDIR)$(LIBDIR)
-	cp -a lib/libcfg.so $(DESTDIR)$(LIBDIR)
-	cp -a exec/libtotem_pg.so $(DESTDIR)$(LIBDIR)
-
-	cp -a lib/libais.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaAmf.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaClm.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaCkpt.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaEvt.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaLck.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libSaMsg.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libevs.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libcpg.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a lib/libcfg.so.2 $(DESTDIR)$(LIBDIR)
-	cp -a exec/libtotem_pg.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libais.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaAmf.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaClm.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaCkpt.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaEvt.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaLck.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaMsg.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libevs.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libcpg.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libcfg.so $(DESTDIR)$(LIBDIR)
+	$(CP) -a exec/libtotem_pg.so $(DESTDIR)$(LIBDIR)
+
+	$(CP) -a lib/libais.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaAmf.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaClm.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaCkpt.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaEvt.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaLck.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libSaMsg.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libevs.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libcpg.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a lib/libcfg.so.2 $(DESTDIR)$(LIBDIR)
+	$(CP) -a exec/libtotem_pg.so.2 $(DESTDIR)$(LIBDIR)
 
 	install -m 755 lib/libais.so.2.* $(DESTDIR)$(LIBDIR)
 	install -m 755 lib/libSaAmf.so.2.* $(DESTDIR)$(LIBDIR)
@@ -158,7 +158,7 @@ ifneq "NO" "$(STATICLIBS)"
 	install -m 755 exec/libtotem_pg.a $(DESTDIR)$(LIBDIR)
 endif
 
-	echo $(LIBDIR) > $(DESTDIR)/etc/ld.so.conf.d/openais-$(ARCH).conf
+	echo $(LIBDIR) > "$(DESTDIR)/etc/ld.so.conf.d/openais-$(ARCH).conf"
 
 	install -m 755 exec/*lcrso $(DESTDIR)$(LCRSODIR)
 
--- whitetank-svn/Makefile.inc	
+++ whitetank-dev/Makefile.inc	
@@ -29,12 +29,17 @@
 # THE POSSIBILITY OF SUCH DAMAGE.
 # Basic OS detection
 #
+CP=cp
+DESTDIR=
+PREFIX=/usr/local
 UNAME=$(shell uname)
+LCRSODIR=$(PREFIX)/libexec/lcrso
 
 ifeq "$(UNAME)" "Linux"
 	OPENAIS_COMPAT=LINUX
 endif
 ifeq "$(UNAME)" "Darwin"
+	CP=rsync
 	OPENAIS_COMPAT=DARWIN
 endif
 ifneq "" "$(findstring BSD,$(UNAME))"
--- whitetank-svn/conf/openais.conf	
+++ whitetank-dev/conf/openais.conf	
@@ -1,22 +1,66 @@
 # Please read the openais.conf.5 manual page
 
+aisexec {
+	# Run as root - this is necessary to be able to manage resources with Pacemaker
+	user:	root
+	group:	root
+}
+
+service {
+	# Load the Pacemaker Cluster Resource Manager
+	name: pacemaker
+	ver:  0
+}
+
 totem {
 	version: 2
+
+	# How long before declaring a token lost (ms)
+	token:          10000
+
+	# How many token retransmits before forming a new configuration
+	token_retransmits_before_loss_const: 20
+
+	# How long to wait for join messages in the membership protocol (ms)
+	join:           60
+
+	# How long to wait for consensus to be achieved before starting a new round of membership configuration (ms)
+	consensus:      4800
+
+	# Turn off the virtual synchrony filter
+	vsftype:        none
+
+	# Number of messages that may be sent by one processor on receipt of the token
+	max_messages:   20
+
+	# Limit generated nodeids to 31-bits (positive signed integers)
+	clear_node_high_bit: yes
+
+	# Disable encryption
 	secauth: off
+
+	# How many threads to use for encryption/decryption
 	threads: 0
+
+	# Optionally assign a fixed node id (integer)
+	# nodeid:         1234
+
 	interface {
 		ringnumber: 0
-		bindnetaddr: 192.168.2.0
-		mcastaddr: 226.94.1.1
-		mcastport: 5405
+
+		# The following values need to be set based on your environment
+		#bindnetaddr: 192.168.2.0
+		#mcastaddr: 226.94.1.1
+		#mcastport: 5405
 	}
 }
 
 logging {
-	to_stderr: yes
-	to_file: yes
-	logfile: /tmp/ais
 	debug: off
+	fileline: off
+	to_syslog: yes
+	to_stderr: yes
+	syslog_facility: daemon
 	timestamp: on
 }
 
--- whitetank-svn/exec/cfg.c	
+++ whitetank-dev/exec/cfg.c	
@@ -109,6 +109,14 @@ static void message_handler_req_lib_cfg_
 	void *conn,
 	void *msg);
 
+static void message_handler_req_lib_cfg_serviceload (
+	void *conn,
+	void *msg);
+
+static void message_handler_req_lib_cfg_serviceunload (
+	void *conn,
+	void *msg);
+
 /*
  * Service Handler Definition
  */
@@ -120,35 +128,47 @@ static struct openais_lib_handler cfg_li
 		.response_id		= MESSAGE_RES_CFG_RINGSTATUSGET,
 		.flow_control		= OPENAIS_FLOW_CONTROL_REQUIRED
 	},
-	{ /* 0 */
+	{ /* 1 */
 		.lib_handler_fn		= message_handler_req_lib_cfg_ringreenable,
 		.response_size		= sizeof (struct res_lib_cfg_ringreenable),
 		.response_id		= MESSAGE_RES_CFG_RINGREENABLE,
 		.flow_control		= OPENAIS_FLOW_CONTROL_REQUIRED
 	},
-	{ /* 0 */
+	{ /* 2 */
 		.lib_handler_fn		= message_handler_req_lib_cfg_statetrack,
 		.response_size		= sizeof (struct res_lib_cfg_statetrack),
 		.response_id		= MESSAGE_RES_CFG_STATETRACKSTART,
 		.flow_control		= OPENAIS_FLOW_CONTROL_REQUIRED
 	},
-	{ /* 1 */
+	{ /* 3 */
 		.lib_handler_fn		= message_handler_req_lib_cfg_statetrackstop,
 		.response_size		= sizeof (struct res_lib_cfg_statetrackstop),
 		.response_id		= MESSAGE_RES_CFG_STATETRACKSTOP,
 		.flow_control		= OPENAIS_FLOW_CONTROL_REQUIRED
 	},
-	{ /* 2 */
+	{ /* 4 */
 		.lib_handler_fn		= message_handler_req_lib_cfg_administrativestateset,
 		.response_size		= sizeof (struct res_lib_cfg_administrativestateset),
 		.response_id		= MESSAGE_RES_CFG_ADMINISTRATIVESTATESET,
 		.flow_control		= OPENAIS_FLOW_CONTROL_NOT_REQUIRED
 	},
-	{ /* 3 */
+	{ /* 5 */
 		.lib_handler_fn		= message_handler_req_lib_cfg_administrativestateget,
 		.response_size		= sizeof (struct res_lib_cfg_administrativestateget),
 		.response_id		= MESSAGE_RES_CFG_ADMINISTRATIVESTATEGET,
 		.flow_control		= OPENAIS_FLOW_CONTROL_NOT_REQUIRED
+	},
+	{ /* 6 */
+		.lib_handler_fn		= message_handler_req_lib_cfg_serviceload,
+		.response_size		= sizeof (struct res_lib_cfg_serviceload),
+		.response_id		= MESSAGE_RES_CFG_SERVICELOAD,
+		.flow_control		= OPENAIS_FLOW_CONTROL_NOT_REQUIRED
+	},
+	{ /* 7 */
+		.lib_handler_fn		= message_handler_req_lib_cfg_serviceunload,
+		.response_size		= sizeof (struct res_lib_cfg_serviceunload),
+		.response_id		= MESSAGE_RES_CFG_SERVICEUNLOAD,
+		.flow_control		= OPENAIS_FLOW_CONTROL_NOT_REQUIRED
 	}
 };
 
@@ -177,6 +197,8 @@ struct openais_service_handler cfg_servi
 	.confchg_fn				= cfg_confchg_fn,
 };
 
+static struct objdb_iface_ver0 *my_objdb;
+
 /*
  * Dynamic Loader definition
  */
@@ -226,6 +248,7 @@ struct req_exec_cfg_ringreenable {
 static int cfg_exec_init_fn (struct objdb_iface_ver0 *objdb)
 {
 	log_init ("CFG");
+	my_objdb = objdb;
 	return (0);
 }
 static void cfg_confchg_fn (
@@ -380,3 +403,49 @@ static void message_handler_req_lib_cfg_
 	LEAVE("");
 }
 
+static void message_handler_req_lib_cfg_serviceload (
+	void *conn,
+	void *msg)
+{
+	struct req_lib_cfg_serviceload *req_lib_cfg_serviceload =
+		(struct req_lib_cfg_serviceload *)msg;
+	struct res_lib_cfg_serviceload res_lib_cfg_serviceload;
+
+	ENTER("");
+	openais_service_link_and_init (
+		my_objdb,
+		(char *)req_lib_cfg_serviceload->service_name,
+		req_lib_cfg_serviceload->service_ver, 0);
+
+	res_lib_cfg_serviceload.header.id = MESSAGE_RES_CFG_SERVICEUNLOAD;
+	res_lib_cfg_serviceload.header.size = sizeof (struct res_lib_cfg_serviceload);
+	res_lib_cfg_serviceload.header.error = SA_AIS_OK;
+	openais_response_send (
+		conn,
+		&res_lib_cfg_serviceload,
+		sizeof (struct res_lib_cfg_serviceload));
+	LEAVE("");
+}
+
+static void message_handler_req_lib_cfg_serviceunload (
+	void *conn,
+	void *msg)
+{
+	struct req_lib_cfg_serviceunload *req_lib_cfg_serviceunload =
+		(struct req_lib_cfg_serviceunload *)msg;
+	struct res_lib_cfg_serviceunload res_lib_cfg_serviceunload;
+
+	ENTER("");
+	openais_service_unlink_and_exit (
+		my_objdb,
+		(char *)req_lib_cfg_serviceunload->service_name,
+		req_lib_cfg_serviceunload->service_ver);
+	res_lib_cfg_serviceunload.header.id = MESSAGE_RES_CFG_SERVICEUNLOAD;
+	res_lib_cfg_serviceunload.header.size = sizeof (struct res_lib_cfg_serviceunload);
+	res_lib_cfg_serviceunload.header.error = SA_AIS_OK;
+	openais_response_send (
+		conn,
+		&res_lib_cfg_serviceunload,
+		sizeof (struct res_lib_cfg_serviceunload));
+	LEAVE("");
+}
--- whitetank-svn/exec/clm.c	
+++ whitetank-dev/exec/clm.c	
@@ -134,6 +134,8 @@ static void clm_sync_abort (void);
 
 static int clm_exec_init_fn (struct objdb_iface_ver0 *objdb);
 
+static int clm_exec_exit_fn (struct objdb_iface_ver0 *objdb);
+
 static int clm_lib_init_fn (void *conn);
 
 static int clm_lib_exit_fn (void *conn);
@@ -208,6 +210,7 @@ struct openais_service_handler clm_servi
 	.lib_service		= clm_lib_service,
 	.lib_service_count	= sizeof (clm_lib_service) / sizeof (struct openais_lib_handler),
 	.exec_init_fn		= clm_exec_init_fn,
+	.exec_exit_fn		= clm_exec_exit_fn,
 	.exec_dump_fn		= NULL,
 	.exec_service		= clm_exec_service,
 	.exec_service_count	= sizeof (clm_exec_service) / sizeof (struct openais_exec_handler),
@@ -336,6 +339,11 @@ static int clm_exec_init_fn (struct objd
 	return (0);
 }
 
+static int clm_exec_exit_fn (struct objdb_iface_ver0 *objdb)
+{
+	return (0);
+}
+
 static int clm_lib_exit_fn (void *conn)
 {
 	struct clm_pd *clm_pd = (struct clm_pd *)openais_conn_private_data_get (conn);
--- whitetank-svn/exec/main.c	
+++ whitetank-dev/exec/main.c	
@@ -92,6 +92,8 @@ static struct totem_logging_configuratio
 
 static char delivery_data[MESSAGE_SIZE_MAX];
 
+static struct objdb_iface_ver0 *objdb = NULL;
+
 SaClmClusterNodeT *(*main_clm_get_by_nodeid) (unsigned int node_id);
 
 static void sigusr2_handler (int num)
@@ -105,6 +107,50 @@ static void sigusr2_handler (int num)
 	}
 }
 
+static void *aisexec_exit (void *arg)
+{
+	if(objdb) {
+		openais_service_unlink_all (objdb);
+	}
+
+#ifdef DEBUG_MEMPOOL
+	int stats_inuse[MEMPOOL_GROUP_SIZE];
+	int stats_avail[MEMPOOL_GROUP_SIZE];
+	int stats_memoryused[MEMPOOL_GROUP_SIZE];
+	int i;
+
+	mempool_getstats (stats_inuse, stats_avail, stats_memoryused);
+	log_printf (LOG_LEVEL_DEBUG, "Memory pools:\n");
+	for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
+	log_printf (LOG_LEVEL_DEBUG, "order %d size %d inuse %d avail %d memory used %d\n",
+		i, 1<<i, stats_inuse[i], stats_avail[i], stats_memoryused[i]);
+	}
+#endif
+
+	totempg_finalize ();
+	log_flush ();
+
+	openais_exit_error (AIS_DONE_EXIT);
+
+	/* never reached */
+	return NULL;
+}
+
+pthread_t aisexec_exit_thread;
+static void init_shutdown(void *data) 
+{
+	pthread_create (&aisexec_exit_thread, NULL, aisexec_exit, NULL);
+}
+
+
+static poll_timer_handle shutdown_handle;
+static void sigquit_handler (int num)
+{
+	/* avoid creating threads from within the interrupt context */
+	poll_timer_add (aisexec_poll_handle, 500, NULL, init_shutdown, &shutdown_handle);
+}
+
+
 static void sigsegv_handler (int num)
 {
 	signal (SIGSEGV, SIG_DFL);
@@ -131,23 +177,7 @@ struct totempg_group openais_group = {
 
 void sigintr_handler (int signum)
 {
-
-#ifdef DEBUG_MEMPOOL
-	int stats_inuse[MEMPOOL_GROUP_SIZE];
-	int stats_avail[MEMPOOL_GROUP_SIZE];
-	int stats_memoryused[MEMPOOL_GROUP_SIZE];
-	int i;
-
-	mempool_getstats (stats_inuse, stats_avail, stats_memoryused);
-	log_printf (LOG_LEVEL_DEBUG, "Memory pools:\n");
-	for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
-	log_printf (LOG_LEVEL_DEBUG, "order %d size %d inuse %d avail %d memory used %d\n",
-		i, 1<<i, stats_inuse[i], stats_avail[i], stats_memoryused[i]);
-	}
-#endif
-
-	totempg_finalize ();
-	openais_exit_error (AIS_DONE_EXIT);
+	poll_timer_add (aisexec_poll_handle, 500, NULL, init_shutdown, &shutdown_handle);
 }
 
 
@@ -273,6 +303,7 @@ static void aisexec_tty_detach (void)
 	/*
 	 * Disconnect from TTY if this is not a debug run
 	 */
+
 	switch (fork ()) {
 		case -1:
 			openais_exit_error (AIS_DONE_FORK);
@@ -281,6 +312,10 @@ static void aisexec_tty_detach (void)
 			/*
 			 * child which is disconnected, run this process
 			 */
+/* 			setset(); */
+			close (0);
+			close (1);
+			close (2);
 			break;
 		default:
 			exit (0);
@@ -373,6 +408,13 @@ static void deliver_fn (
 	 */
 	service = header->id >> 16;
 	fn_id = header->id & 0xffff;
+
+	if(service >= SERVICE_HANDLER_MAXIMUM_COUNT
+	   || ais_service[service] == NULL) {
+	    /* The component is no longer loaded */
+	    return;
+	}
+	
 	if (endian_conversion_required) {
 		ais_service[service]->exec_service[fn_id].exec_endian_convert_fn
 			(header);
@@ -390,7 +432,6 @@ int main (int argc, char **argv)
 	unsigned int objdb_handle;
 	unsigned int config_handle;
 	unsigned int config_version = 0;
-	struct objdb_iface_ver0 *objdb;
 	void *objdb_p;
 	struct config_iface_ver0 *config;
 	void *config_p;
@@ -427,6 +468,7 @@ int main (int argc, char **argv)
 	signal (SIGUSR2, sigusr2_handler);
 	signal (SIGSEGV, sigsegv_handler);
 	signal (SIGABRT, sigabrt_handler);
+	signal (SIGQUIT, sigquit_handler);
 
 	openais_timer_init (
 		serialize_mutex_lock,
@@ -456,7 +498,11 @@ int main (int argc, char **argv)
 
 	objdb->objdb_init ();
 
-	/* User's bootstrap config service */
+	/*
+	 * Bootstrap in the default configuration parser or use
+	 * the openais default built in parser if the configuration parser
+	 * isn't overridden
+	 */
 	config_iface = getenv("OPENAIS_DEFAULT_CONFIG_IFACE");
 	if (!config_iface) {
 		config_iface = "aisparser";
@@ -481,14 +527,6 @@ int main (int argc, char **argv)
 		openais_exit_error (AIS_DONE_MAINCONFIGREAD);
 	}
 
-	openais_service_default_objdb_set (objdb);
-
-	res = openais_service_link_all (objdb);
-	if (res == -1) {
-		log_printf (LOG_LEVEL_ERROR, "Could not load services\n");
-		openais_exit_error (AIS_DONE_DYNAMICLOAD);
-	}
-
 	res = openais_main_config_read (objdb, &error_string, &main_config);
 	if (res == -1) {
 		log_printf (LOG_LEVEL_ERROR, error_string);
@@ -568,12 +606,13 @@ int main (int argc, char **argv)
 	/*
 	 * This must occur after totempg is initialized because "this_ip" must be set
 	 */
-	res = openais_service_init_all (service_count, objdb);
+	res = openais_service_defaults_link_and_init (objdb);
 	if (res == -1) {
-		log_printf (LOG_LEVEL_ERROR, "Could not init services\n");
+		log_printf (LOG_LEVEL_ERROR, "Could not initialize default services\n");
 		openais_exit_error (AIS_DONE_INIT_SERVICES);
 	}
 
+
 	sync_register (openais_sync_callbacks_retrieve, openais_sync_completed,
 		totem_config.vsf_type);
 
--- whitetank-svn/exec/objdb.c	
+++ whitetank-dev/exec/objdb.c	
@@ -52,10 +52,13 @@ struct object_instance {
 	void *object_name;
 	int object_name_len;
 	unsigned int object_handle;
+	unsigned int parent_handle;
 	struct list_head key_head;
 	struct list_head child_head;
 	struct list_head child_list;
 	struct list_head *find_child_list;
+	struct list_head *iter_key_list;
+	struct list_head *iter_list;
 	void *priv;
 	struct object_valid *object_valid_list;
 	int object_valid_list_entries;
@@ -70,6 +73,7 @@ static struct hdb_handle_database object
 	.mutex		= PTHREAD_MUTEX_INITIALIZER
 };
 
+
 static int objdb_init (void)
 {
 	unsigned int handle;
@@ -179,9 +183,12 @@ static int object_create (
 
 	object_instance->object_handle = *object_handle;
 	object_instance->find_child_list = &object_instance->child_head;
+	object_instance->iter_key_list = &object_instance->key_head;
+	object_instance->iter_list = &object_instance->child_head;
 	object_instance->priv = NULL;
 	object_instance->object_valid_list = NULL;
 	object_instance->object_valid_list_entries = 0;
+	object_instance->parent_handle = parent_object_handle;
 
 	hdb_handle_put (&object_instance_database, *object_handle);
 
@@ -313,10 +320,66 @@ error_exit:
 	return (-1);
 }
 
+
+static int _clear_object(struct object_instance *instance)
+{
+	struct list_head *list;
+	int res;
+	struct object_instance *find_instance = NULL;
+	struct object_key *object_key = NULL;
+
+	for (list = instance->key_head.next;
+	     list != &instance->key_head; ) {
+
+                object_key = list_entry (list, struct object_key,
+					 list);
+
+		list = list->next;
+
+		list_del(&object_key->list);
+		free(object_key->key_name);
+		free(object_key->value);
+	}
+
+	for (list = instance->child_head.next;
+	     list != &instance->child_head; ) {
+
+                find_instance = list_entry (list, struct object_instance,
+					    child_list);
+		res = _clear_object(find_instance);
+		if (res)
+			return res;
+
+		list = list->next;
+
+		list_del(&find_instance->child_list);
+		free(find_instance->object_name);
+		free(find_instance);
+	}
+
+	return 0;
+}
+
 static int object_destroy (
 	unsigned int object_handle)
 {
-	return (0);
+	struct object_instance *instance;
+	unsigned int res;
+
+	res = hdb_handle_get (&object_instance_database,
+		object_handle, (void *)&instance);
+	if (res != 0) {
+		return (res);
+	}
+
+	/* Recursively clear sub-objects & keys */
+	res = _clear_object(instance);
+
+	list_del(&instance->child_list);
+	free(instance->object_name);
+	free(instance);
+
+	return (res);
 }
 
 static int object_valid_set (
@@ -478,6 +541,153 @@ error_exit:
 	return (-1);
 }
 
+static int object_key_delete (
+	unsigned int object_handle,
+	void *key_name,
+	int key_len,
+	void *value,
+	int value_len)
+{
+	unsigned int res;
+	int ret = 0;
+	struct object_instance *instance;
+	struct object_key *object_key = NULL;
+	struct list_head *list;
+	int found = 0;
+
+	res = hdb_handle_get (&object_instance_database,
+		object_handle, (void *)&instance);
+	if (res != 0) {
+		goto error_exit;
+	}
+	for (list = instance->key_head.next;
+		list != &instance->key_head; list = list->next) {
+
+		object_key = list_entry (list, struct object_key, list);
+
+		if ((object_key->key_len == key_len) &&
+		    (memcmp (object_key->key_name, key_name, key_len) == 0) &&
+		    (value == NULL ||
+		     (object_key->value_len == value_len &&
+		      (memcmp (object_key->value, value, value_len) == 0)))) {
+			found = 1;
+			break;
+		}
+	}
+	if (found) {
+		list_del(&object_key->list);
+		free(object_key->key_name);
+		free(object_key->value);
+		free(object_key);
+	}
+	else {
+		ret = -1;
+		errno = ENOENT;
+	}
+
+	hdb_handle_put (&object_instance_database, object_handle);
+	return (ret);
+
+error_exit:
+	return (-1);
+}
+
+static int object_key_replace (
+	unsigned int object_handle,
+	void *key_name,
+	int key_len,
+	void *old_value,
+	int old_value_len,
+	void *new_value,
+	int new_value_len)
+{
+	unsigned int res;
+	int ret = 0;
+	struct object_instance *instance;
+	struct object_key *object_key = NULL;
+	struct list_head *list;
+	int found = 0;
+
+	res = hdb_handle_get (&object_instance_database,
+		object_handle, (void *)&instance);
+	if (res != 0) {
+		goto error_exit;
+	}
+	for (list = instance->key_head.next;
+		list != &instance->key_head; list = list->next) {
+
+		object_key = list_entry (list, struct object_key, list);
+
+		if ((object_key->key_len == key_len) &&
+		    (memcmp (object_key->key_name, key_name, key_len) == 0) &&
+		    (old_value == NULL ||
+		     (object_key->value_len == old_value_len &&
+		      (memcmp (object_key->value, old_value, old_value_len) == 0)))) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found) {
+		int i;
+
+		/*
+		 * Do validation check if validation is configured for the parent object
+		 */
+		if (instance->object_key_valid_list_entries) {
+			for (i = 0; i < instance->object_key_valid_list_entries; i++) {
+				if ((key_len ==
+				     instance->object_key_valid_list[i].key_len) &&
+				    (memcmp (key_name,
+					     instance->object_key_valid_list[i].key_name,
+					     key_len) == 0)) {
+
+					found = 1;
+					break;
+				}
+			}
+
+			/*
+			 * Item not found in validation list
+			 */
+			if (found == 0) {
+				goto error_put;
+			} else {
+				if (instance->object_key_valid_list[i].validate_callback) {
+					res = instance->object_key_valid_list[i].validate_callback (
+						key_name, key_len, new_value, new_value_len);
+					if (res != 0) {
+						goto error_put;
+					}
+				}
+			}
+		}
+
+		if (new_value_len != object_key->value_len) {
+			void *replacement_value;
+			replacement_value = malloc(new_value_len);
+			if (!replacement_value)
+				goto error_exit;
+			free(object_key->value);
+			object_key->value = replacement_value;
+		}
+		memcpy(object_key->value, new_value, new_value_len);
+		object_key->value_len = new_value_len;
+	}
+	else {
+		ret = -1;
+		errno = ENOENT;
+	}
+
+	hdb_handle_put (&object_instance_database, object_handle);
+	return (ret);
+
+error_put:
+	hdb_handle_put (&object_instance_database, object_handle);
+error_exit:
+	return (-1);
+}
+
 static int object_priv_get (
 	unsigned int object_handle,
 	void **priv)
@@ -500,18 +710,276 @@ error_exit:
 	return (-1);
 }
 
+static int _dump_object(struct object_instance *instance, FILE *file, int depth)
+{
+	struct list_head *list;
+	int res;
+	int i;
+	struct object_instance *find_instance = NULL;
+	struct object_key *object_key = NULL;
+	char stringbuf1[1024];
+	char stringbuf2[1024];
+
+	memcpy(stringbuf1, instance->object_name, instance->object_name_len);
+	stringbuf1[instance->object_name_len] = '\0';
+
+	for (i=0; i<depth; i++)
+		fprintf(file, "    ");
+
+	if (instance->object_handle != OBJECT_PARENT_HANDLE)
+		fprintf(file, "%s {\n", stringbuf1);
+
+	for (list = instance->key_head.next;
+	     list != &instance->key_head; list = list->next) {
+
+                object_key = list_entry (list, struct object_key,
+					 list);
+
+		memcpy(stringbuf1, object_key->key_name, object_key->key_len);
+		stringbuf1[object_key->key_len] = '\0';
+		memcpy(stringbuf2, object_key->value, object_key->value_len);
+		stringbuf2[object_key->value_len] = '\0';
+
+		for (i=0; i<depth+1; i++)
+			fprintf(file, "    ");
+
+		fprintf(file, "%s: %s\n", stringbuf1, stringbuf2);
+	}
+
+	for (list = instance->child_head.next;
+	     list != &instance->child_head; list = list->next) {
+
+                find_instance = list_entry (list, struct object_instance,
+					    child_list);
+		res = _dump_object(find_instance, file, depth+1);
+		if (res)
+			return res;
+	}
+	for (i=0; i<depth; i++)
+		fprintf(file, "    ");
+
+	if (instance->object_handle != OBJECT_PARENT_HANDLE)
+		fprintf(file, "}\n");
+
+	return 0;
+}
+
+
+static int object_key_iter_reset(unsigned int object_handle)
+{
+	unsigned int res;
+	struct object_instance *instance;
+
+	res = hdb_handle_get (&object_instance_database,
+		object_handle, (void *)&instance);
+	if (res != 0) {
+		goto error_exit;
+	}
+	instance->iter_key_list = &instance->key_head;
+
+	hdb_handle_put (&object_instance_database, object_handle);
+	return (0);
+
+error_exit:
+	return (-1);
+}
+
+static int object_key_iter(unsigned int parent_object_handle,
+			   void **key_name,
+			   int *key_len,
+			   void **value,
+			   int *value_len)
+{
+	unsigned int res;
+	struct object_instance *instance;
+	struct object_key *find_key = NULL;
+	struct list_head *list;
+	unsigned int found = 0;
+
+	res = hdb_handle_get (&object_instance_database,
+		parent_object_handle, (void *)&instance);
+	if (res != 0) {
+		goto error_exit;
+	}
+	res = -ENOENT;
+	list = instance->iter_key_list->next;
+	if (list != &instance->key_head) {
+                find_key = list_entry (list, struct object_key, list);
+		found = 1;
+	}
+	instance->iter_key_list = list;
+	if (found) {
+		*key_name = find_key->key_name;
+		if (key_len)
+			*key_len = find_key->key_len;
+		*value = find_key->value;
+		if (value_len)
+			*value_len = find_key->value_len;
+		res = 0;
+	}
+	else {
+		res = -1;
+	}
+
+	hdb_handle_put (&object_instance_database, parent_object_handle);
+	return (res);
+
+error_exit:
+	return (-1);
+}
+
+static int object_iter_reset(unsigned int parent_object_handle)
+{
+	unsigned int res;
+	struct object_instance *instance;
+
+	res = hdb_handle_get (&object_instance_database,
+		parent_object_handle, (void *)&instance);
+	if (res != 0) {
+		goto error_exit;
+	}
+	instance->iter_list = &instance->child_head;
+
+	hdb_handle_put (&object_instance_database, parent_object_handle);
+	return (0);
+
+error_exit:
+	return (-1);
+}
+
+static int object_iter(unsigned int parent_object_handle,
+		       void **object_name,
+		       int *name_len,
+		       unsigned int *object_handle)
+{
+	unsigned int res;
+	struct object_instance *instance;
+	struct object_instance *find_instance = NULL;
+	struct list_head *list;
+	unsigned int found = 0;
+
+	res = hdb_handle_get (&object_instance_database,
+		parent_object_handle, (void *)&instance);
+	if (res != 0) {
+		goto error_exit;
+	}
+	res = -ENOENT;
+	list = instance->iter_list->next;
+	if (list != &instance->child_head) {
+
+                find_instance = list_entry (list, struct object_instance,
+					    child_list);
+		found = 1;
+	}
+	instance->iter_list = list;
+
+	if (found) {
+		*object_handle = find_instance->object_handle;
+		*object_name = find_instance->object_name;
+		*name_len = find_instance->object_name_len;
+		res = 0;
+	}
+	else {
+		res = -1;
+	}
+
+	return (res);
+
+error_exit:
+	return (-1);
+}
+
+
+static int object_parent_get(unsigned int object_handle,
+			     unsigned int *parent_handle)
+{
+	struct object_instance *instance;
+	unsigned int res;
+
+	res = hdb_handle_get (&object_instance_database,
+			      object_handle, (void *)&instance);
+	if (res != 0) {
+		return (res);
+	}
+
+	if (object_handle == OBJECT_PARENT_HANDLE)
+		*parent_handle = 0;
+	else
+		*parent_handle = instance->parent_handle;
+
+	hdb_handle_put (&object_instance_database, object_handle);
+
+	return (0);
+}
+
+
+static int object_dump(unsigned int object_handle,
+		       FILE *file)
+{
+	struct object_instance *instance;
+	unsigned int res;
+
+	res = hdb_handle_get (&object_instance_database,
+			      object_handle, (void *)&instance);
+	if (res != 0) {
+		return (res);
+	}
+
+	res = _dump_object(instance, file, -1);
+
+	hdb_handle_put (&object_instance_database, object_handle);
+
+	return (res);
+}
+
+static struct list_head *last_result = NULL;
+static int save_search_iter (unsigned int parent_object_handle)
+{
+	struct object_instance *instance;
+	if(0 != hdb_handle_get (&object_instance_database,
+				parent_object_handle, (void *)&instance)) {
+		return -1;
+	}
+	last_result = instance->find_child_list;
+	hdb_handle_put (&object_instance_database, parent_object_handle);
+	return 0;
+}
+
+static int restore_search_iter (unsigned int parent_object_handle)
+{
+	struct object_instance *instance;
+	if(0 != hdb_handle_get (&object_instance_database,
+				parent_object_handle, (void *)&instance)) {
+		return -1;
+	}
+	instance->find_child_list = last_result;
+	hdb_handle_put (&object_instance_database, parent_object_handle);
+	return 0;
+}
+
+
 struct objdb_iface_ver0 objdb_iface = {
 	.objdb_init		= objdb_init,
 	.object_create		= object_create,
 	.object_priv_set	= object_priv_set,
 	.object_key_create	= object_key_create,
+	.object_key_delete	= object_key_delete,
+	.object_key_replace	= object_key_replace,
 	.object_destroy		= object_destroy,
 	.object_valid_set	= object_valid_set,
 	.object_key_valid_set	= object_key_valid_set,
 	.object_find_reset	= object_find_reset,
 	.object_find		= object_find,
 	.object_key_get		= object_key_get,
-	.object_priv_get	= object_priv_get
+	.object_key_iter	= object_key_iter,
+	.object_key_iter_reset	= object_key_iter_reset,
+	.object_iter	        = object_iter,
+	.object_iter_reset	= object_iter_reset,
+	.object_priv_get	= object_priv_get,
+	.object_parent_get	= object_parent_get,
+	.object_dump	        = object_dump,
+	.save_iter	        = save_search_iter,
+	.restore_iter	        = restore_search_iter
 };
 
 struct lcr_iface objdb_iface_ver0[1] = {
--- whitetank-svn/exec/objdb.h	
+++ whitetank-dev/exec/objdb.h	
@@ -38,6 +38,8 @@
 
 #define OBJECT_PARENT_HANDLE 0
 
+#include <stdio.h>
+
 struct object_valid {
 	char *object_name;
 	int object_len;
@@ -101,6 +103,51 @@ struct objdb_iface_ver0 {
 	int (*object_priv_get) (
 		unsigned int jobject_handle,
 		void **priv);
+
+	int (*object_key_replace) (
+		unsigned int object_handle,
+		void *key_name,
+		int key_len,
+		void *old_value,
+		int old_value_len,
+		void *new_value,
+		int new_value_len);
+
+	int (*object_key_delete) (
+		unsigned int object_handle,
+		void *key_name,
+		int key_len,
+		void *value,
+		int value_len);
+
+	int (*object_iter_reset) (
+		unsigned int parent_object_handle);
+
+	int (*object_iter) (
+		unsigned int parent_object_handle,
+		void **object_name,
+		int *name_len,
+		unsigned int *object_handle);
+
+	int (*object_key_iter_reset) (
+		unsigned int object_handle);
+
+	int (*object_key_iter) (
+		unsigned int parent_object_handle,
+		void **key_name,
+		int *key_len,
+		void **value,
+		int *value_len);
+
+	int (*object_parent_get) (
+		unsigned int object_handle,
+		unsigned int *parent_handle);
+
+	int (*object_dump) (
+		unsigned int object_handle,
+		FILE *file);
+	int (*save_iter) (unsigned int object_handle);
+	int (*restore_iter) (unsigned int object_handle);
 };
 
 #endif /* OBJDB_H_DEFINED */
--- whitetank-svn/exec/service.c	
+++ whitetank-dev/exec/service.c	
@@ -84,59 +84,19 @@ static struct default_service default_se
 	{
 		.name			 = "openais_cpg",
 		.ver			 = 0,
-	}
+	},
 };
 
 struct openais_service_handler *ais_service[SERVICE_HANDLER_MAXIMUM_COUNT];
 
-/*
- * Adds a service handler to the object database
- */
-int openais_service_objdb_add (
-	struct objdb_iface_ver0 *objdb,
-	char *name,
-	int version)
+static unsigned int default_services_requested (struct objdb_iface_ver0 *objdb)
 {
-	unsigned int object_handle;
-
-	objdb->object_create (OBJECT_PARENT_HANDLE, &object_handle,
-		"service", strlen ("service"));
-	objdb->object_key_create (object_handle, "name", strlen ("name"),
-		name, strlen (name) + 1);
-	objdb->object_key_create (object_handle, "ver", strlen ("ver"),
-		&version, sizeof (version));
-
-	return (0);
-}
-
-static int service_handler_config (
-	struct openais_service_handler *handler,
-	struct objdb_iface_ver0 *objdb)
-{
-	int res = 0;
-
-	/* Already loaded? */
-	if (ais_service[handler->id] != NULL)
-		return 0;
-
-	log_printf (LOG_LEVEL_NOTICE, "Registering service handler '%s'\n", handler->name);
-	ais_service[handler->id] = handler;
-	if (ais_service[handler->id]->config_init_fn) {
-		res = ais_service[handler->id]->config_init_fn (objdb);
-	}
-	return (res);
-}
+	unsigned int object_service_handle = 0;
+	char *value = NULL;
 
 /*
- * adds the default services to the object database
+	 * Don't link default services if they have been disabled
  */
-int openais_service_default_objdb_set (struct objdb_iface_ver0 *objdb)
-{
-	int i;
-	unsigned int object_service_handle;
-	char *value = NULL;
-
-	/* Load default services unless they have been explicitly disabled */
 	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
 	if (objdb->object_find (
 		OBJECT_PARENT_HANDLE,
@@ -158,25 +118,144 @@ int openais_service_default_objdb_set (s
 
 	log_init ("SERV");
 
-	for (i = 0; i < sizeof (default_services) / sizeof (struct default_service); i++) {
-		openais_service_objdb_add (objdb, default_services[i].name, default_services[i].ver);
+	return (-1);
 	}
-	return (0);
+
+unsigned int openais_service_link_and_init (
+	struct objdb_iface_ver0 *objdb,
+	char *service_name,
+	unsigned int service_ver, unsigned int object_handle)
+{
+	struct openais_service_handler_iface_ver0 *iface_ver0;
+	void *iface_ver0_p;
+	unsigned int handle;
+	struct openais_service_handler *service;
+	unsigned int res;
+
+	/*
+	 * reference the service interface
+	 */
+	iface_ver0_p = NULL;
+	lcr_ifact_reference (
+		&handle,
+		service_name,
+		service_ver,
+		&iface_ver0_p,
+		(void *)0);
+
+	iface_ver0 = (struct openais_service_handler_iface_ver0 *)iface_ver0_p;
+
+	if (iface_ver0 == 0) {
+		log_printf(LOG_LEVEL_ERROR, "Service failed to load '%s'.\n", service_name);
+		return (-1);
+	}
+
+
+	/*
+	 * Initialize service
+	 */
+	service = iface_ver0->openais_get_service_handler_ver0();
+
+	ais_service[service->id] = service;
+	if (service->config_init_fn) {
+		res = service->config_init_fn (objdb);
 }
 
+	if (service->exec_init_fn) {
+		res = service->exec_init_fn (objdb);
+	}
+
+	if(object_handle == 0) {
 /*
- * Links dynamic services into the executive
+	 * Store service in object database
  */
-int openais_service_link_all (struct objdb_iface_ver0 *objdb)
+	objdb->object_create (OBJECT_PARENT_HANDLE,
+		&object_handle,
+		"service",
+		strlen ("service"));
+
+	objdb->object_key_create (object_handle,
+		"name",
+		strlen ("name"),
+		service_name,
+		strlen (service_name) + 1);
+	}
+
+	objdb->object_key_create (object_handle,
+		"ver",
+		strlen ("ver"),
+		&service_ver,
+		sizeof (service_ver));
+
+	res = objdb->object_key_create (object_handle,
+		"handle",
+		strlen ("handle"),
+		&handle,
+		sizeof (handle));
+
+	objdb->object_key_create (object_handle,
+		"service_id",
+		strlen ("service_id"),
+		&service->id,
+		sizeof (service->id));
+
+	log_printf (LOG_LEVEL_NOTICE, "Service initialized '%s'\n", service->name);
+	return (res);
+}
+
+static int openais_service_unlink_common(
+	struct objdb_iface_ver0 *objdb,
+	unsigned int object_service_handle,
+	const char *service_name,
+	unsigned int service_version) 
 {
-	char *service_name;
-	char *service_ver;
-	unsigned int object_service_handle;
-	int ret;
-	unsigned int handle;
-	struct openais_service_handler_iface_ver0 *iface_ver0;
-	void *iface_ver0_p;
-	unsigned int ver_int;
+	unsigned int res;
+	unsigned short *service_id;
+	unsigned int *found_service_handle;
+	res = objdb->object_key_get (object_service_handle,
+				     "handle",
+				     strlen ("handle"),
+				     (void *)&found_service_handle,
+				     NULL);
+	
+	res = objdb->object_key_get (object_service_handle,
+				     "service_id",
+				     strlen ("service_id"),
+				     (void *)&service_id,
+				     NULL);
+	
+	log_printf(LOG_LEVEL_NOTICE, "Unloading openais component: %s v%u (%d/%d)\n",
+		   service_name, service_version, object_service_handle, *service_id);
+
+	if((*service_id) >= SERVICE_HANDLER_MAXIMUM_COUNT) {
+	    log_printf(LOG_LEVEL_NOTICE, "Invalid component: %s v%u (%d)\n",
+		       service_name, service_version, *service_id);
+	    return 0;
+	} 
+
+	if(ais_service[*service_id] == NULL) {
+	    /* The component is no longer loaded */
+	    log_printf(LOG_LEVEL_NOTICE, "Openais component is already unloaded: %s v%u (%d)\n",
+		       service_name, service_version, *service_id);
+	    return 0;
+	    
+	} else if (ais_service[*service_id]->exec_exit_fn) {
+	    ais_service[*service_id]->exec_exit_fn (objdb);
+	}
+
+	ais_service[*service_id] = NULL;
+	return lcr_ifact_release (*found_service_handle);	
+}
+
+extern unsigned int openais_service_unlink_and_exit (
+	struct objdb_iface_ver0 *objdb,
+	char *service_name,
+	unsigned int service_ver)
+{
+	unsigned int res = 0;
+	unsigned int object_service_handle = 0;
+	char *found_service_name = NULL;
+	unsigned int *found_service_ver = 0;
 
 	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
 	while (objdb->object_find (
@@ -188,56 +267,120 @@ int openais_service_link_all (struct obj
 		objdb->object_key_get (object_service_handle,
 			"name",
 			strlen ("name"),
-			(void *)&service_name,
+			(void *)&found_service_name,
 			NULL);
 
-		ret = objdb->object_key_get (object_service_handle,
+		objdb->object_key_get (object_service_handle,
 			"ver",
 			strlen ("ver"),
-			(void *)&service_ver,
+			(void *)&found_service_ver,
 			NULL);
 
-		ver_int = atoi (service_ver);
-
 		/*
-		 * reference the interface and register it
+		 * If service found and linked exit it
 		 */
-		lcr_ifact_reference (
-			&handle,
-			service_name,
-			ver_int,
-			&iface_ver0_p,
-			(void *)0);
+		if ((strcmp (service_name, found_service_name) == 0) &&
+			(service_ver == *found_service_ver)) {
+			res = openais_service_unlink_common(
+			    objdb, object_service_handle, service_name, service_ver);
+			objdb->object_destroy (object_service_handle);
+			return res;
+		}
+	}
+	return (-1);
+}
 
-		iface_ver0 = (struct openais_service_handler_iface_ver0 *)iface_ver0_p;
+extern unsigned int openais_service_unlink_all (
+	struct objdb_iface_ver0 *objdb)
+{
+	char *service_name = NULL;
+	unsigned int *service_ver = 0;
+	unsigned int object_service_handle = 0;
 
-		if (iface_ver0 == 0) {
-			log_printf(LOG_LEVEL_ERROR, "openais component %s did not load.\n", service_name);
-			openais_exit_error (AIS_DONE_DYNAMICLOAD);
-		} else {
-			log_printf(LOG_LEVEL_NOTICE, "openais component %s loaded.\n", service_name);
-		}
+	log_printf(LOG_LEVEL_NOTICE, "Unloading all openais components\n");
 
-		service_handler_config (
-			iface_ver0->openais_get_service_handler_ver0(), objdb);
+	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
+	while (objdb->object_find (OBJECT_PARENT_HANDLE,
+				   "service",
+				   strlen ("service"),
+				   &object_service_handle) == 0) {
+		
+		objdb->object_key_get (object_service_handle,
+			"name",
+			strlen ("name"),
+			(void *)&service_name,
+			NULL);
+
+		objdb->object_key_get (object_service_handle,
+			"ver",
+			strlen ("ver"),
+			(void *)&service_ver,
+			NULL);
+				
+		openais_service_unlink_common(
+			objdb, object_service_handle, service_name, *service_ver);
+
+		objdb->object_destroy (object_service_handle);
+		objdb->object_find_reset (OBJECT_PARENT_HANDLE);
 	}
+
 	return (0);
 }
 
-int openais_service_init_all (int service_count,
-			      struct objdb_iface_ver0 *objdb)
+/*
+ * Links default services into the executive
+ */
+unsigned int openais_service_defaults_link_and_init (struct objdb_iface_ver0 *objdb)
 {
-	int i;
-	int res=0;
+	unsigned int i = 0;
+	unsigned int object_service_handle = 0;
+	char *found_service_name = NULL;
+	char *found_service_ver = NULL;
+	unsigned int found_service_ver_atoi = 0;
 
-	for (i = 0; i < service_count; i++) {
-		if (ais_service[i] && ais_service[i]->exec_init_fn) {
-			log_printf (LOG_LEVEL_NOTICE, "Initialising service handler '%s'\n", ais_service[i]->name);
-			res = ais_service[i]->exec_init_fn (objdb);
-			if (res != 0) {
-				break;
-			}
+	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
+	while (objdb->object_find (
+		OBJECT_PARENT_HANDLE,
+		"service",
+		strlen ("service"),
+		&object_service_handle) == 0) {
+
+		objdb->object_key_get (object_service_handle,
+			"name",
+			strlen ("name"),
+			(void *)&found_service_name,
+			NULL);
+
+		objdb->object_key_get (object_service_handle,
+			"ver",
+			strlen ("ver"),
+			(void *)&found_service_ver,
+			NULL);
+
+		found_service_ver_atoi = atoi (found_service_ver);
+		
+		/* Delete this so openais_service_link_and_init() can create it correctly */
+		objdb->object_key_delete(
+		    object_service_handle, "ver", strlen ("ver"), NULL, 0);
+
+		objdb->save_iter (OBJECT_PARENT_HANDLE);
+		openais_service_link_and_init (
+			objdb,
+			found_service_name,
+			found_service_ver_atoi, object_service_handle);
+		objdb->restore_iter (OBJECT_PARENT_HANDLE);
+ 	}
+
+	if (default_services_requested (objdb)) {
+	    for (i = 0;
+		i < sizeof (default_services) / sizeof (struct default_service); i++) {
+
+		openais_service_link_and_init (
+			objdb,
+			default_services[i].name,
+			default_services[i].ver, 0);
 		}
 	}
-	return (res);
+	
+	return (0);
 }
--- whitetank-svn/exec/service.h	
+++ whitetank-dev/exec/service.h	
@@ -74,6 +74,7 @@ struct openais_service_handler {
 	int lib_service_count;
 	struct openais_exec_handler *exec_service;
 	int (*exec_init_fn) (struct objdb_iface_ver0 *);
+	int (*exec_exit_fn) (struct objdb_iface_ver0 *);
 	int (*config_init_fn) (struct objdb_iface_ver0 *);
 	void (*exec_dump_fn) (void);
 	int exec_service_count;
@@ -90,26 +91,37 @@ struct openais_service_handler {
 };
 
 struct openais_service_handler_iface_ver0 {
-	void (*test) (void);
 	struct openais_service_handler *(*openais_get_service_handler_ver0) (void);
 };
 
-extern int openais_service_objdb_add (
+/*
+ * Link and initialize a service
+ */
+extern unsigned int openais_service_link_and_init (
 	struct objdb_iface_ver0 *objdb,
-	char *name,
-	int version);
-
-
-extern int openais_service_handler_register (
-	struct openais_service_handler *handler);
-
-extern int openais_service_default_objdb_set (struct objdb_iface_ver0 *objdb);
+    char *service_name,
+    unsigned int service_ver,
+    unsigned int object_handle);
+
+/*
+ * Unlink and exit a service
+ */
+extern unsigned int openais_service_unlink_and_exit (
+    struct objdb_iface_ver0 *objdb,
+    char *service_name,
+    unsigned int service_ver);
 
-extern int openais_service_link_all (
+/*
+ * Unlink and exit all openais services
+ */
+extern unsigned int openais_service_unlink_all (
 	struct objdb_iface_ver0 *objdb);
 
-extern int openais_service_init_all (
-	int service_count,
+
+/*
+ * Load all of the default services
+ */
+extern unsigned int openais_service_defaults_link_and_init (
 	struct objdb_iface_ver0 *objdb);
 
 extern struct openais_service_handler *ais_service[];
--- whitetank-svn/exec/tlist.h	
+++ whitetank-dev/exec/tlist.h	
@@ -45,7 +45,7 @@
 
 #include "../include/list.h"
 
-#if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
+#ifndef HZ
 	#define HZ 100  /* 10ms */
 #endif
 
--- whitetank-svn/exec/totem.h	
+++ whitetank-dev/exec/totem.h	
@@ -44,26 +44,6 @@
 #define SEND_THREADS_MAX	16
 #define INTERFACE_MAX		2
 
-/*
- * Array location of various timeouts as
- * specified in openais.conf.  The last enum
- * specifies the size of the timeouts array and
- * needs to remain the last item in the list.
- */
-enum {
-	TOTEM_RETRANSMITS_BEFORE_LOSS,
-	TOTEM_TOKEN,
-	TOTEM_RETRANSMIT_TOKEN,
-	TOTEM_HOLD_TOKEN,
-	TOTEM_JOIN,
-	TOTEM_CONSENSUS,
-	TOTEM_MERGE,
-	TOTEM_DOWNCHECK,
-	TOTEM_FAIL_RECV_CONST,
-
-	MAX_TOTEM_TIMEOUTS	/* Last item */
-} totem_timeout_types;
-
 struct totem_interface {
 	struct totem_ip_address bindnet;
 	struct totem_ip_address boundto;
--- whitetank-svn/exec/totemconfig.c	
+++ whitetank-dev/exec/totemconfig.c	
@@ -52,10 +52,7 @@
 #include "totemconfig.h"
 #include "print.h"
 #include "objdb.h"
-
-#if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
-	#define HZ 100  /* 10ms */
-#endif
+#include "tlist.h" /* for HZ */
 
 #define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST	4
 #define TOKEN_TIMEOUT				1000
--- whitetank-svn/exec/totemip.c	
+++ whitetank-dev/exec/totemip.c	
@@ -516,7 +516,7 @@ int totemip_iface_check(struct totem_ip_
 					memcpy(&network, RTA_DATA(tb[IFA_BROADCAST]), sizeof(uint32_t));
 					memcpy(&addr, bindnet->addr, sizeof(uint32_t));
 
-					if (addr == (network & netmask)) {
+					if ((addr & netmask) == (network & netmask)) {
 						memcpy(ipaddr.addr, RTA_DATA(tb[IFA_ADDRESS]), TOTEMIP_ADDRLEN);
 						found_if = 1;
 					}
--- whitetank-svn/exec/totemnet.c	
+++ whitetank-dev/exec/totemnet.c	
@@ -702,7 +702,12 @@ static int netif_determine (
 	 * field is only 32 bits.
 	 */
 	if (bound_to->family == AF_INET && bound_to->nodeid == 0) {
-		memcpy (&bound_to->nodeid, bound_to->addr, sizeof (int));
+		int32_t nodeid = 0;
+		memcpy (&nodeid, bound_to->addr, sizeof (int));
+		if(nodeid < 0 && instance->totem_config->clear_node_high_bit) {
+			nodeid = 0 - nodeid;
+		}
+		bound_to->nodeid = nodeid;
 	}
 
 	return (res);
@@ -1227,15 +1232,6 @@ int totemnet_initialize (
 
 	instance->totemnet_poll_handle = poll_handle;
 
-	if(instance->totem_config->node_id == 0) {	
-		int32_t nodeid = 0;
-		memcpy (&nodeid, instance->totem_interface->bindnet.addr, sizeof (int32_t));
-		if(nodeid < 0 && instance->totem_config->clear_node_high_bit) {
-			nodeid = 0 - nodeid;
-		}
-		instance->totem_config->node_id = nodeid;
-	}
-
 	instance->totem_interface->bindnet.nodeid = instance->totem_config->node_id;
 
 	instance->context = context;
--- whitetank-svn/include/cfg.h	
+++ whitetank-dev/include/cfg.h	
@@ -140,6 +140,18 @@ openais_cfg_ring_reenable (
 	openais_cfg_handle_t cfg_handle);
 
 SaAisErrorT
+openais_cfg_service_load (
+	openais_cfg_handle_t cfg_handle,
+	char *service_name,
+	unsigned int service_ver);
+
+SaAisErrorT
+openais_cfg_service_unload (
+	openais_cfg_handle_t cfg_handle,
+	char *service_name,
+	unsigned int service_ver);
+
+SaAisErrorT
 openais_cfg_administrative_state_get (
 	openais_cfg_handle_t cfg_handle,
 	OpenaisCfgAdministrativeTargetT administrativeTarget,
--- whitetank-svn/include/ipc_cfg.h	
+++ whitetank-dev/include/ipc_cfg.h	
@@ -47,6 +47,8 @@ enum req_lib_cfg_types {
         MESSAGE_REQ_CFG_STATETRACKSTOP = 3,
         MESSAGE_REQ_CFG_ADMINISTRATIVESTATESET = 4,
         MESSAGE_REQ_CFG_ADMINISTRATIVESTATEGET = 5,
+        MESSAGE_REQ_CFG_SERVICELOAD = 6,
+        MESSAGE_REQ_CFG_SERVICEUNLOAD = 7
 };
 
 enum res_lib_cfg_types {
@@ -56,6 +58,8 @@ enum res_lib_cfg_types {
         MESSAGE_RES_CFG_STATETRACKSTOP = 3,
         MESSAGE_RES_CFG_ADMINISTRATIVESTATESET = 4,
         MESSAGE_RES_CFG_ADMINISTRATIVESTATEGET = 5,
+        MESSAGE_RES_CFG_SERVICELOAD = 6,
+        MESSAGE_RES_CFG_SERVICEUNLOAD = 7
 };
 
 struct req_lib_cfg_statetrack {
@@ -117,6 +121,26 @@ struct res_lib_cfg_ringreenable {
 	mar_res_header_t header __attribute__((aligned(8)));
 };
 
+struct req_lib_cfg_serviceload {
+	mar_res_header_t header __attribute__((aligned(8)));
+	char *service_name[256] __attribute__((aligned(8)));
+	unsigned int service_ver;
+};
+
+struct res_lib_cfg_serviceload {
+	mar_res_header_t header __attribute__((aligned(8)));
+};
+
+struct req_lib_cfg_serviceunload {
+	mar_res_header_t header __attribute__((aligned(8)));
+	char *service_name[256] __attribute__((aligned(8)));
+	unsigned int service_ver;
+};
+
+struct res_lib_cfg_serviceunload {
+	mar_res_header_t header __attribute__((aligned(8)));
+};
+
 typedef enum {
 	AIS_AMF_ADMINISTRATIVETARGET_SERVICEUNIT = 0,
 	AIS_AMF_ADMINISTRATIVETARGET_SERVICEGROUP = 1,
--- whitetank-svn/init/generic	1970-01-01 01:00:00.000000000 +0100
+++ whitetank-dev/init/generic	
@@ -0,0 +1,146 @@
+#!/bin/sh
+#
+# openais       Start the openais cluster service
+#
+# Author:       Andrew Beekhof <abeekhof@suse.de>
+# License:      Revised BSD
+#
+# chkconfig: - 20 20
+# processname:  aisexec
+# description:  OpenAIS daemon
+#
+### BEGIN INIT INFO
+# Description: openais....
+#
+# Short-Description: openais cluster services.
+# Provides: openais
+# Required-Start: $network
+# Should-Start: $syslog
+# Required-Stop: $network
+# Default-Start: 3 5
+# Default-Stop: 0 6
+# Should-Stop: $null
+### END INIT INFO
+
+do_force=0
+prog="aisexec"
+lockfile="/var/lock/subsys/$prog"
+
+internal_status() {
+    killall -0 aisexec > /dev/null 2>&1
+    return $?
+}
+
+status() {
+    if 
+	! internal_status
+    then
+	echo "Stopped"
+	return 7
+    fi
+
+    echo "Running"
+    return 0
+}
+
+start() {
+    echo -n $"Starting OpenAIS daemon ($prog): "
+    if 
+	! internal_status
+    then
+	echo -n "starting... "
+	$prog 2>&1 > /dev/null 2>&1
+	echo -n "rc=$?: "
+    fi
+
+    sleep 2 # give it time to fail... $? isn't definitive
+
+    if 
+	internal_status
+    then
+	echo "OK"
+	return 0
+    fi
+
+    echo "Failed"
+    return 1
+}
+
+do_force=0
+do_forever=1
+
+stop() {
+    echo -n $"Stopping OpenAIS daemon ($prog): "
+
+    killall -QUIT aisexec
+
+    if [ $do_forever = 0 ]; then
+	for i in 1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20; do
+	    if
+		internal_status
+	    then
+		sleep 2
+		echo -n "."
+	    else
+		rm -f "$lockfile"
+		echo "OK"
+		return 0
+	    fi
+	done
+
+	if [ $do_force = 1 ]; then
+	    echo -n "Escalating... "
+	    killall -KILL aisexec
+	    sleep 5
+	    
+	    if
+		! internal_status
+	    then
+		rm -f "$lockfile"
+		echo "OK"
+		return 0
+	    fi
+	fi
+
+	echo "Failed"
+	return 1
+    fi
+
+    while 
+        internal_status
+    do
+	sleep 1
+	echo -n "."
+    done
+    
+    rm -f "$lockfile"
+    echo "OK"
+    return 0
+}
+
+restart() {
+    stop
+    start
+}
+
+case "$1" in
+    start|stop|restart)
+        $1
+        ;;
+    force-stop)
+	do_force=1
+        stop
+        ;;
+    reload|force-reload)
+        restart
+        ;;
+    condrestart|try-restart)
+        [ ! -f "$lockfile" ] || restart
+        ;;
+    status)
+        status $prog
+        ;;
+    *)
+        echo $"Usage: $0 {start|stop|restart|try-restart|condrestart|reload|force-reload|force-stop|status}"
+        exit 2
+esac
--- whitetank-svn/lcr/Makefile	
+++ whitetank-dev/lcr/Makefile	
@@ -26,8 +26,8 @@
 #
 include ../Makefile.inc
 
-CFLAGS += -I../include
 override LDFLAGS += ${DYFLAGS}
+override CFLAGS  += -I../include -DLCRSODIR='"$(LCRSODIR)"'
 
 ifeq (${OPENAIS_COMPAT}, LINUX) 
 	LDFLAGS += -ldl
--- whitetank-svn/lcr/lcr_ifact.c	
+++ whitetank-dev/lcr/lcr_ifact.c	
@@ -174,7 +174,7 @@ static void defaults_path_build (void)
 		path_list[0] = strdup (cwd);
 		path_list_entries++;
 	}
-	path_list[path_list_entries++] = "/usr/libexec/lcrso";
+	path_list[path_list_entries++] = LCRSODIR;
 }
 
 static void ld_library_path_build (void)
--- whitetank-svn/lib/Makefile	
+++ whitetank-dev/lib/Makefile	
@@ -55,35 +55,37 @@ libSaClm.a: util.o clm.o
 
 ifeq (${OPENAIS_COMPAT}, DARWIN)
 
+DARWIN_OPTS=-dynamiclib -bind_at_load -current_version 2.0.0 -compatibility_version 2.0.0
+
 libSaClm.so.2.0.0: util.o clm.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o clm.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o clm.o -o $@
 
 libSaAmf.so.2.0.0: util.o amf.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o amf.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o amf.o -o $@
 
 libSaCkpt.so.2.0.0: util.o ckpt.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o ckpt.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o ckpt.o -o $@
 
 libSaEvt.so.2.0.0: util.o evt.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o evt.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o evt.o -o $@
 
 libSaLck.so.2.0.0: util.o lck.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o lck.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o lck.o -o $@
 
 libSaMsg.so.2.0.0: util.o msg.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o msg.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o msg.o -o $@
 
 libais.so.2.0.0: util.o amf.o clm.o ckpt.o evt.o lck.o msg.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o amf.o clm.o ckpt.o evt.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o amf.o clm.o ckpt.o evt.o -o $@
 
 libevs.so.2.0.0: util.o evs.o
-	$(CC) $(LDFLAGS) -bundle -bind_at_load util.o evs.o -o $@
+	$(CC) $(LDFLAGS) $(DARWIN_OPTS) util.o evs.o -o $@
 
 libcpg.so.2.0.0: util.o cpg.o
-	$(CC) -bundle -bind_at_load util.o cpg.o -o $@
+	$(CC) $(DARWIN_OPTS) util.o cpg.o -o $@
 
 libcfg.so.2.0.0: util.o cfg.o
-	$(CC) -bundle -bind_at_load util.o cfg.o -o $@
+	$(CC) $(DARWIN_OPTS) util.o cfg.o -o $@
 
 else
 
--- whitetank-svn/lib/cfg.c	
+++ whitetank-dev/lib/cfg.c	
@@ -458,6 +458,81 @@ openais_cfg_ring_reenable (
 }
 
 SaAisErrorT
+openais_cfg_service_load (
+	openais_cfg_handle_t cfg_handle,
+	char *service_name,
+	unsigned int service_ver)
+{
+	struct cfg_instance *cfg_instance;
+	struct req_lib_cfg_serviceload req_lib_cfg_serviceload;
+	struct res_lib_cfg_serviceload res_lib_cfg_serviceload;
+	SaAisErrorT error;
+
+	error = saHandleInstanceGet (&cfg_hdb, cfg_handle, (void *)&cfg_instance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	req_lib_cfg_serviceload.header.size = sizeof (struct req_lib_cfg_serviceload);
+	req_lib_cfg_serviceload.header.id = MESSAGE_REQ_CFG_SERVICELOAD;
+	memset (&req_lib_cfg_serviceload.service_name, 0,
+		sizeof (req_lib_cfg_serviceload.service_name));
+	strncpy ((char *)req_lib_cfg_serviceload.service_name, service_name,
+		sizeof (req_lib_cfg_serviceload.service_name) - 1);
+	req_lib_cfg_serviceload.service_ver = service_ver;
+
+	pthread_mutex_lock (&cfg_instance->response_mutex);
+
+	error = saSendReceiveReply (cfg_instance->response_fd,
+		&req_lib_cfg_serviceload,
+		sizeof (struct req_lib_cfg_serviceload),
+		&res_lib_cfg_serviceload,
+		sizeof (struct res_lib_cfg_serviceload));
+
+	pthread_mutex_unlock (&cfg_instance->response_mutex);
+	saHandleInstancePut (&cfg_hdb, cfg_handle);
+
+	return (error);
+}
+
+SaAisErrorT
+openais_cfg_service_unload (
+	openais_cfg_handle_t cfg_handle,
+	char *service_name,
+	unsigned int service_ver)
+{
+	struct cfg_instance *cfg_instance;
+	struct req_lib_cfg_serviceunload req_lib_cfg_serviceunload;
+	struct res_lib_cfg_serviceunload res_lib_cfg_serviceunload;
+	SaAisErrorT error;
+
+	error = saHandleInstanceGet (&cfg_hdb, cfg_handle, (void *)&cfg_instance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	req_lib_cfg_serviceunload.header.size = sizeof (struct req_lib_cfg_serviceunload);
+	req_lib_cfg_serviceunload.header.id = MESSAGE_REQ_CFG_SERVICEUNLOAD;
+	memset (&req_lib_cfg_serviceunload.service_name, 0,
+		sizeof (req_lib_cfg_serviceunload.service_name));
+	strncpy ((char *)req_lib_cfg_serviceunload.service_name, service_name,
+		sizeof (req_lib_cfg_serviceunload.service_name) - 1);
+	req_lib_cfg_serviceunload.service_ver = service_ver;
+
+	pthread_mutex_lock (&cfg_instance->response_mutex);
+
+	error = saSendReceiveReply (cfg_instance->response_fd,
+		&req_lib_cfg_serviceunload,
+		sizeof (struct req_lib_cfg_serviceunload),
+		&res_lib_cfg_serviceunload,
+		sizeof (struct res_lib_cfg_serviceunload));
+
+	pthread_mutex_unlock (&cfg_instance->response_mutex);
+	saHandleInstancePut (&cfg_hdb, cfg_handle);
+
+	return (error);
+}
+SaAisErrorT
 openais_cfg_state_track (
 	openais_cfg_handle_t cfg_handle,
 	SaUint8T trackFlags,
--- whitetank-svn/lib/libSaMsg.versions	
+++ whitetank-dev/lib/libSaMsg.versions	
@@ -24,18 +24,18 @@ OPENAIS_MSG_B.01.01 {
 		saMsgMessageCancel;
 		saMsgMessageReply;
 		saMsgMessageReplyAsync;
+		saSendReceiveReply;
+		saServiceConnect;
+		saRecvRetry;
+		saSendMsgReceiveReply;
+		saSendMsgRetry;
+		saSendRetry;
 	local:
 		saHandleCreate;
 		saHandleDestroy;
 		saHandleInstanceGet;
 		saHandleInstancePut;
 		saPollRetry;
-		saRecvRetry;
-		saSendMsgReceiveReply;
-		saSendMsgRetry;
-		saSendReceiveReply;
-		saSendRetry;
-		saServiceConnect;
 		saVersionVerify;
 		clustTimeNow;
 };
--- whitetank-svn/lib/libcfg.versions	
+++ whitetank-dev/lib/libcfg.versions	
@@ -1,6 +1,6 @@
 # Version and symbol export for libcfg.so
 
-OPENAIS_CFG_0.80 {
+OPENAIS_CFG_0.82 {
 	global:
 		openais_cfg_initialize;
 		openais_cfg_fd_get;
@@ -12,6 +12,8 @@ OPENAIS_CFG_0.80 {
 		openais_cfg_track_stop;
 		openais_cfg_ring_status_get;
 		openais_cfg_ring_reenable;
+		openais_cfg_service_load;
+		openais_cfg_service_unload;
 		
 		
 	local:
--- whitetank-svn/lib/util.c	
+++ whitetank-dev/lib/util.c	
@@ -525,7 +525,7 @@ saHandleCreate (
 {
 	uint32_t handle;
 	uint32_t check;
-	void *newHandles;
+	void *newHandles = NULL;
 	int found = 0;
 	void *instance;
 	int i;
--- whitetank-svn/test/openais-cfgtool.c	
+++ whitetank-dev/test/openais-cfgtool.c	
@@ -98,19 +98,61 @@ static void ringreenable_do (void)
 	openais_cfg_finalize (handle);
 }
 
+void service_load_do (char *service, unsigned int version)
+{
+	SaAisErrorT result;
+	openais_cfg_handle_t handle;
+
+	printf ("Loading service '%s' version '%d'\n", service, version);
+	result = openais_cfg_initialize (&handle, NULL);
+	if (result != SA_AIS_OK) {
+		printf ("Could not initialize openais configuration API error %d\n", result);
+		exit (1);
+	}
+	result = openais_cfg_service_load (handle, service, version);
+	if (result != SA_AIS_OK) {
+		printf ("Could not load service (error = %d)\n", result);
+	}
+	openais_cfg_finalize (handle);
+}
+
+void service_unload_do (char *service, unsigned int version)
+{
+	SaAisErrorT result;
+	openais_cfg_handle_t handle;
+
+	printf ("Unloading service '%s' version '%d'\n", service, version);
+	result = openais_cfg_initialize (&handle, NULL);
+	if (result != SA_AIS_OK) {
+		printf ("Could not initialize openais configuration API error %d\n", result);
+		exit (1);
+	}
+	result = openais_cfg_service_unload (handle, service, version);
+	if (result != SA_AIS_OK) {
+		printf ("Could not unload service (error = %d)\n", result);
+	}
+	openais_cfg_finalize (handle);
+}
+
 void usage_do (void)
 {
-	printf ("openais-cfgtool [-s] [-r]\n\n");
+	printf ("openais-cfgtool [-s] [-r] [-l] [-u] [service_name] [-v] [version]\n\n");
 	printf ("A tool for displaying and configuring active parameters within openais.\n");
 	printf ("options:\n");
 	printf ("\t-s\tDisplays the status of the current rings on this node.\n");
 	printf ("\t-r\tReset redundant ring state cluster wide after a fault to\n");
 	printf ("\t\tre-enable redundant ring operation.\n");
+	printf ("\t-l\tLoad a service identified by name.\n");
+	printf ("\t-u\tUnload a service identified by name.\n");
 }
 
 int main (int argc, char *argv[]) {
-	const char *options = "sr";
+	const char *options = "srl:u:v:";
 	int opt;
+	int service_load = 0;
+	int service_unload = 0;
+	char *service;
+	unsigned int version;
 
 	if (argc == 1) {
 		usage_do ();
@@ -123,8 +165,25 @@ int main (int argc, char *argv[]) {
 		case 'r':
 			ringreenable_do ();
 			break;
+		case 'l':
+			service_load = 1;
+			service = strdup (optarg);
+			break;
+		case 'u':
+			service_unload = 1;
+			service = strdup (optarg);
+			break;
+		case 'v':
+			version = atoi (optarg);
 		}
 	}
 
+	if (service_load) {
+		service_load_do (service, version);
+	} else 
+	if (service_unload) {
+		service_unload_do (service, version);
+	}
+		
 	return (0);
 }
openSUSE Build Service is sponsored by