diff --git a/crm/admin/crm_attribute.c b/crm/admin/crm_attribute.c
new file mode 100644
index 0000000000..a8a47095db
--- /dev/null
+++ b/crm/admin/crm_attribute.c
@@ -0,0 +1,389 @@
+/* $Id: crm_attribute.c,v 1.1 2005/09/12 11:04:22 andrew Exp $ */
+
+/* 
+ * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <portability.h>
+
+#include <sys/param.h>
+
+#include <crm/crm.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+
+#include <heartbeat.h>
+#include <hb_api.h>
+#include <clplumbing/uids.h>
+#include <clplumbing/Gmain_timeout.h>
+
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/common/ctrl.h>
+#include <crm/common/ipc.h>
+
+#include <crm/cib.h>
+
+#ifdef HAVE_GETOPT_H
+#  include <getopt.h>
+#endif
+#include <crm/dmalloc_wrapper.h>
+void usage(const char *cmd, int exit_status);
+
+gboolean BE_QUIET = FALSE;
+gboolean DO_WRITE = TRUE;
+gboolean DO_DELETE = FALSE;
+char *dest_node   = NULL;
+const char *type        = NULL;
+const char *dest_uname       = NULL;
+char *set_name    = NULL;
+char *attr_id   = NULL;
+char *attr_name   = NULL;
+const char *attr_value  = NULL;
+const char *crm_system_name = "crm_master";
+
+#define OPTARGS	"V?GDQU:u:s:n:v:l:t:i:"
+
+int
+main(int argc, char **argv)
+{
+	gboolean is_done = FALSE;
+	cib_t *	the_cib = NULL;
+	enum cib_errors rc = cib_ok;
+	
+	int argerr = 0;
+	int flag;
+
+#ifdef HAVE_GETOPT_H
+	int option_index = 0;
+	static struct option long_options[] = {
+		/* Top-level Options */
+		{"verbose", 0, 0, 'V'},
+		{"help", 0, 0, '?'},
+		{"quiet", 0, 0, 'Q'},
+		{"get-value", 0, 0, 'G'},
+		{"delete-attr", 0, 0, 'D'},
+		{"node-uname", 1, 0,  'U'},
+		{"node-uuid", 1, 0,  'u'},
+		{"set-name", 1, 0,   's'},
+		{"attr-name", 1, 0,  'n'},
+		{"attr-value", 1, 0, 'v'},
+		{"lifetime", 1, 0, 'l'},
+		{"type", 1, 0, 't'},
+
+		{0, 0, 0, 0}
+	};
+#endif
+
+	crm_system_name = basename(argv[0]);
+	crm_log_init(crm_system_name);
+	crm_log_level = LOG_ERR;
+	cl_log_enable_stderr(TRUE);
+	
+	if(argc < 2) {
+		usage(crm_system_name, LSB_EXIT_EINVAL);
+	}
+	
+	while (1) {
+#ifdef HAVE_GETOPT_H
+		flag = getopt_long(argc, argv, OPTARGS,
+				   long_options, &option_index);
+#else
+		flag = getopt(argc, argv, OPTARGS);
+#endif
+		if (flag == -1)
+			break;
+
+		switch(flag) {
+			case 'V':
+				cl_log_enable_stderr(TRUE);
+				alter_debug(DEBUG_INC);
+				break;
+			case '?':
+				usage(crm_system_name, LSB_EXIT_OK);
+				break;
+			case 'G':
+				DO_WRITE = FALSE;
+				break;
+			case 'Q':
+				BE_QUIET = TRUE;
+				break;
+			case 'D':
+				DO_DELETE = TRUE;
+				break;
+			case 'U':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				dest_uname = optarg;
+				break;
+			case 'u':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				dest_node = crm_strdup(optarg);
+				break;
+			case 's':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				set_name = crm_strdup(optarg);
+				break;
+			case 'l':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				type = optarg;
+				break;
+			case 't':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				type = optarg;
+				break;
+			case 'n':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				attr_name = crm_strdup(optarg);
+				if(attr_id == NULL) {
+					attr_id = crm_strdup(optarg);
+				}
+				break;
+			case 'i':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				attr_id = crm_strdup(optarg);
+				break;
+			case 'v':
+				crm_debug_2("Option %c => %s", flag, optarg);
+				attr_value = optarg;
+				break;
+			default:
+				printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
+				++argerr;
+				break;
+		}
+	}
+
+	if (optind < argc) {
+		printf("non-option ARGV-elements: ");
+		while (optind < argc)
+			printf("%s ", argv[optind++]);
+		printf("\n");
+	}
+
+	if (optind > argc) {
+		++argerr;
+	}
+
+	if (argerr) {
+		usage(crm_system_name, LSB_EXIT_GENERIC);
+	}
+
+	the_cib = cib_new();
+	rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
+
+	if(rc != cib_ok) {
+		crm_err("Error signing on to the CIB service: %s",
+			cib_error2string(rc));
+		return rc;
+	}
+	
+	if(dest_node == NULL && dest_uname != NULL) {
+		rc = query_node_uuid(the_cib, dest_uname, &dest_node);
+		if(rc != cib_ok) {
+			crm_err("Could not map uname=%s to a UUID: %s",
+				dest_uname, cib_error2string(rc));
+			return rc;
+		} else {
+			crm_info("Mapped %s to %s", dest_uname, crm_str(dest_node));
+		}
+	}
+
+	if(safe_str_eq(crm_system_name, "crm_master")) {
+		int len = 0;
+		char *rsc = NULL;
+		
+		dest_node = getenv("OCF_RESKEY_target_uuid");
+		if(dest_node == NULL) {
+			crm_err("Please specify a value for -U or -u");
+			return 1;
+		}
+		if(safe_str_eq(type, "reboot")) {
+			type = XML_CIB_TAG_STATUS;
+		} else {
+			type = XML_CIB_TAG_NODES;
+		}
+		rsc = getenv("OCF_RESOURCE_INSTANCE");
+
+		CRM_DEV_ASSERT(rsc != NULL);
+		CRM_DEV_ASSERT(dest_node != NULL);
+
+		len = 8 + strlen(rsc);
+		crm_malloc0(attr_name, len);
+		sprintf(attr_name, "master-%s", rsc);
+
+		len = 2 + strlen(attr_name) + strlen(dest_node);
+		crm_malloc0(attr_id, len);
+		sprintf(attr_id, "%s-%s", attr_name, dest_node);
+
+		len = 8 + strlen(dest_node);
+		crm_malloc0(set_name, len);
+		sprintf(set_name, "master-%s", dest_node);
+		
+	} else if(safe_str_eq(crm_system_name, "crm_standby")) {
+		if(dest_node == NULL) {
+			crm_err("Please specify a value for -U or -u");
+			fprintf(stderr,"Please specify a value for -U or -u\n");
+			return 1;
+
+		} else if(DO_DELETE) {
+			rc = delete_standby(
+				the_cib, dest_node, type, attr_value);
+			
+		} else if(DO_WRITE) {
+			rc = set_standby(the_cib, dest_node, type, attr_value);
+
+		} else {
+			char *read_value = NULL;
+			rc = query_standby(
+				the_cib, dest_node, type, &read_value);
+
+			if(BE_QUIET == FALSE) {
+				fprintf(stdout, "%s%s %s%s value=%s\n",
+					attr_id?"id=":"", attr_id?attr_id:"",
+					attr_name?"name=":"", attr_name?attr_name:"",
+					read_value?read_value:"(null)");
+				
+			} else if(read_value != NULL) {
+				fprintf(stdout, "%s\n", read_value);
+			}
+		}
+		is_done = TRUE;
+
+	} else if(type == NULL && dest_node == NULL) {
+		type = XML_CIB_TAG_CRMCONFIG;
+
+	} else if (type == NULL) {
+		crm_err("Please specify a value for -t");
+		fprintf(stderr,"Please specify a value for -t\n");
+		return 1;
+	}
+
+	if(is_done) {
+			
+	} else if(DO_DELETE) {
+		rc = delete_attr(the_cib, type, dest_node, set_name,
+				 attr_id, attr_name, attr_value);
+			
+	} else if(DO_WRITE) {
+		CRM_DEV_ASSERT(type != NULL);
+		CRM_DEV_ASSERT(attr_name != NULL);
+		CRM_DEV_ASSERT(attr_value != NULL);
+		
+		rc = update_attr(the_cib, type, dest_node, set_name,
+				 attr_id, attr_name, attr_value);
+
+	} else {
+		char *read_value = NULL;
+		rc = read_attr(the_cib, type, dest_node, set_name,
+				 attr_id, attr_name, &read_value);
+		crm_info("Read %s=%s %s%s",
+			 attr_name, crm_str(read_value),
+			 set_name?"in ":"", set_name?set_name:"");
+
+		if(BE_QUIET == FALSE) {
+			fprintf(stdout, "%s%s %s%s value=%s\n",
+				attr_id?"id=":"", attr_id?attr_id:"",
+				attr_name?"name=":"", attr_name?attr_name:"",
+				read_value?read_value:"(null)");
+
+		} else if(read_value != NULL) {
+			fprintf(stdout, "%s\n", read_value);
+		}
+	}
+	the_cib->cmds->signoff(the_cib);
+	if(rc != cib_ok) {
+		crm_err("Error performing operation: %s",
+			cib_error2string(rc));
+	}
+	return rc;
+}
+
+
+void
+usage(const char *cmd, int exit_status)
+{
+	FILE *stream;
+
+	stream = exit_status ? stderr : stdout;
+	if(safe_str_eq(cmd, "crm_master")) {
+		fprintf(stream, "usage: %s [-?VQ] -(D|G|v) [-l]\n", cmd);
+
+	} else if(safe_str_eq(cmd, "crm_standby")) {
+		fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) [-l]\n", cmd);
+
+	} else {
+		fprintf(stream, "usage: %s [-?V] -(D|G|v) [options]\n", cmd);
+	}
+	
+	fprintf(stream, "Options\n");
+	fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?');
+	fprintf(stream, "\t--%s (-%c)\t: "
+		"turn on debug info. additional instances increase verbosity\n",
+		"verbose", 'V');
+	fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout"
+		" (use with -G)\n", "quiet", 'Q');
+	fprintf(stream, "\t--%s (-%c)\t: "
+		"Retrieve rather than set the attribute\n", "get-value", 'G');
+	fprintf(stream, "\t--%s (-%c)\t: "
+		"Delete rather than set the attribute\n", "delete-attr", 'D');
+	fprintf(stream, "\t--%s (-%c) <string>\t: "
+		"Value to use (ignored with -G)\n", "attr-value", 'v');
+
+	if(safe_str_eq(cmd, "crm_master")) {
+		fprintf(stream, "\t--%s (-%c) <string>\t: "
+			"How long the preference lasts (reboot|forever)\n",
+			"lifetime", 'l');
+		exit(exit_status);
+	} else if(safe_str_eq(cmd, "crm_standby")) {
+		fprintf(stream, "\t--%s (-%c) <node_uuid>\t: "
+			"UUID of the node to change\n", "node-uuid", 'u');
+		fprintf(stream, "\t--%s (-%c) <node_uuid>\t: "
+			"uname of the node to change\n", "node-uname", 'U');
+		fprintf(stream, "\t--%s (-%c) <string>\t: "
+			"How long the preference lasts (reboot|forever)\n"
+			"\t    If a forever value exists, it is ALWAYS used by the CRM\n"
+			"\t    instead of any reboot value\n", "lifetime", 'l');
+		exit(exit_status);
+	}
+	
+	fprintf(stream, "\t--%s (-%c) <node_uuid>\t: "
+		"UUID of the node to change\n", "node-uuid", 'u');
+	fprintf(stream, "\t--%s (-%c) <node_uuid>\t: "
+		"uname of the node to change\n", "node-uname", 'U');
+	fprintf(stream, "\t--%s (-%c) <string>\t: "
+		"Set of attributes in which to read/write the attribute\n",
+		"set-name", 's');
+	fprintf(stream, "\t--%s (-%c) <string>\t: "
+		"Attribute to set\n", "attr-name", 'n');
+	fprintf(stream, "\t--%s (-%c) <string>\t: "
+		"Which section of the CIB to set the attribute: (%s|%s|%s)\n",
+		"type", 't',
+		XML_CIB_TAG_NODES, XML_CIB_TAG_STATUS, XML_CIB_TAG_CRMCONFIG);
+	fprintf(stream, "\t    -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_NODES);
+	fprintf(stream, "\t    -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_STATUS);
+	fprintf(stream, "\t    -t=%s options: -n [-s]\n", XML_CIB_TAG_CRMCONFIG);
+	fflush(stream);
+
+	exit(exit_status);
+}
diff --git a/crm/pengine/master.c b/crm/pengine/master.c
new file mode 100644
index 0000000000..353ddbd507
--- /dev/null
+++ b/crm/pengine/master.c
@@ -0,0 +1,417 @@
+/* $Id: master.c,v 1.1 2005/09/12 11:04:22 andrew Exp $ */
+/* 
+ * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <portability.h>
+
+#include <pengine.h>
+#include <pe_utils.h>
+#include <crm/msg_xml.h>
+
+extern void clone_create_notifications(
+	resource_t *rsc, action_t *action, action_t *action_complete,
+	pe_working_set_t *data_set);
+
+typedef struct clone_variant_data_s
+{
+		resource_t *self;
+
+		int clone_max;
+		int clone_max_node;
+
+		int active_clones;
+		int max_nodes;
+
+		gboolean interleave;
+		gboolean ordered;
+
+		gboolean notify_confirm;
+		
+		GListPtr child_list; /* resource_t* */
+		
+} clone_variant_data_t;
+
+#define NO_MASTER_PREFS 0
+
+#define get_clone_variant_data(data, rsc)				\
+	CRM_ASSERT(rsc->variant == pe_master);				\
+	data = (clone_variant_data_t *)rsc->variant_opaque;
+
+void master_unpack(resource_t *rsc, pe_working_set_t *data_set)
+{
+	add_hash_param(rsc->parameters, "stateful", XML_BOOLEAN_TRUE);
+	clone_unpack(rsc, data_set);
+}
+
+static void
+child_promoting_constraints(
+	clone_variant_data_t *clone_data, enum pe_ordering type,
+	resource_t *child, resource_t *last, pe_working_set_t *data_set)
+{
+/* 	if(clone_data->ordered */
+/* 	   || clone_data->self->restart_type == pe_restart_restart) { */
+/* 		type = pe_ordering_manditory; */
+/* 	} */
+	if(child == NULL) {
+		if(clone_data->ordered && last != NULL) {
+			crm_debug_4("Ordered version (last node)");
+			/* last child promote before promoted started */
+			custom_action_order(
+				last, promote_key(last), NULL,
+				clone_data->self, promoted_key(clone_data->self), NULL,
+				type, data_set);
+		}
+		
+	} else if(clone_data->ordered) {
+		crm_debug_4("Ordered version");
+		if(last == NULL) {
+			/* global promote before first child promote */
+			last = clone_data->self;
+
+		} /* else: child/child relative promote */
+
+		order_start_start(last, child, type);
+		custom_action_order(
+			last, promote_key(last), NULL,
+			child, promote_key(child), NULL,
+			type, data_set);
+
+	} else {
+		crm_debug_4("Un-ordered version");
+		
+		/* child promote before global promoted */
+		custom_action_order(
+			child, promote_key(child), NULL,
+			clone_data->self, promoted_key(clone_data->self), NULL,
+			type, data_set);
+                
+		/* global promote before child promote */
+		custom_action_order(
+			clone_data->self, promote_key(clone_data->self), NULL,
+			child, promote_key(child), NULL,
+			type, data_set);
+
+	}
+}
+
+static void
+child_demoting_constraints(
+	clone_variant_data_t *clone_data, enum pe_ordering type,
+	resource_t *child, resource_t *last, pe_working_set_t *data_set)
+{
+/* 	if(clone_data->ordered */
+/* 	   || clone_data->self->restart_type == pe_restart_restart) { */
+/* 		type = pe_ordering_manditory; */
+/* 	} */
+	
+	if(child == NULL) {
+		if(clone_data->ordered && last != NULL) {
+			crm_debug_4("Ordered version (last node)");
+			/* global demote before first child demote */
+			custom_action_order(
+				clone_data->self, demote_key(clone_data->self), NULL,
+				last, demote_key(last), NULL,
+				pe_ordering_manditory, data_set);
+		}
+		
+	} else if(clone_data->ordered && last != NULL) {
+		crm_debug_4("Ordered version");
+
+		/* child/child relative demote */
+		custom_action_order(child, demote_key(child), NULL,
+				    last, demote_key(last), NULL,
+				    type, data_set);
+
+	} else if(clone_data->ordered) {
+		crm_debug_4("Ordered version (1st node)");
+		/* first child stop before global stopped */
+		custom_action_order(
+			child, demote_key(child), NULL,
+			clone_data->self, demoted_key(clone_data->self), NULL,
+			type, data_set);
+
+	} else {
+		crm_debug_4("Un-ordered version");
+
+		/* child demote before global demoted */
+		custom_action_order(
+			child, demote_key(child), NULL,
+			clone_data->self, demoted_key(clone_data->self), NULL,
+			type, data_set);
+                        
+		/* global demote before child demote */
+		custom_action_order(
+			clone_data->self, demote_key(clone_data->self), NULL,
+			child, demote_key(child), NULL,
+			type, data_set);
+	}
+}
+
+
+static void
+master_update_pseudo_status(
+	resource_t *child, gboolean *demoting, gboolean *promoting) 
+{
+	CRM_ASSERT(demoting != NULL);
+	CRM_ASSERT(promoting != NULL);
+
+	slist_iter(
+		action, action_t, child->actions, lpc,
+
+		if(*promoting && *demoting) {
+			return;
+
+		} else if(action->optional) {
+			continue;
+
+		} else if(safe_str_eq(CRMD_ACTION_DEMOTE, action->task)) {
+			*demoting = TRUE;
+
+		} else if(safe_str_eq(CRMD_ACTION_PROMOTE, action->task)) {
+			*promoting = TRUE;
+		}
+		);
+
+}
+
+void master_create_actions(resource_t *rsc, pe_working_set_t *data_set)
+{
+	int len = 0;
+	node_t *chosen = NULL;
+	char *attr_name = NULL;
+	const char *attr_value = NULL;
+	
+	action_t *action = NULL;
+	action_t *action_complete = NULL;
+	gboolean any_promoting = FALSE;
+	gboolean any_demoting = FALSE;
+	resource_t *last_promote_rsc = NULL;
+	resource_t *last_demote_rsc = NULL;
+	const char *master_max_s =
+		get_rsc_param(rsc, XML_RSC_ATTR_MASTER_MAX);
+	const char *master_node_max_s =
+		get_rsc_param(rsc, XML_RSC_ATTR_MASTER_NODEMAX);
+
+	int promoted = 0;
+	int max_nodes = 0;
+	int master_max = crm_atoi(master_max_s, "1");
+	int master_node_max = crm_atoi(master_node_max_s, "1");
+	
+	clone_variant_data_t *clone_data = NULL;
+	get_clone_variant_data(clone_data, rsc);
+
+	/* how many can we have? */
+	if(master_max >  clone_data->max_nodes * clone_data->clone_max_node) {
+		master_max = clone_data->max_nodes * clone_data->clone_max_node;
+		crm_info("Limited to %d masters (potential slaves)",master_max);
+	}
+	if(master_max >  max_nodes * master_node_max) {
+		master_max = clone_data->max_nodes * master_node_max;
+		crm_info("Limited to %d masters (available nodes)", master_max);
+	}
+	
+	/*
+	 * assign priority
+	 */
+
+	slist_iter(
+		child_rsc, resource_t, clone_data->child_list, lpc,
+
+		CRM_DEV_ASSERT(child_rsc->color != NULL);
+		chosen = child_rsc->color->details->chosen_node;
+		
+		switch(child_rsc->next_role) {
+			case RSC_ROLE_STARTED:
+				if(NO_MASTER_PREFS) {
+					child_rsc->priority =
+						clone_data->clone_max - lpc;
+					break;
+				}
+				
+				child_rsc->priority = -1;
+
+				CRM_DEV_ASSERT(chosen != NULL);
+
+				len = 8 + strlen(child_rsc->id);
+				crm_malloc0(attr_name, len);
+				sprintf(attr_name, "master-%s", child_rsc->id);
+				
+				attr_value = g_hash_table_lookup(
+					chosen->details->attrs, attr_name);
+
+				crm_err("%s=%s for %s", attr_name,
+					crm_str(attr_value),
+					chosen->details->uname);
+				
+				if(attr_value != NULL) {
+					child_rsc->priority = char2score(
+						attr_value);
+				}
+				crm_free(attr_name);
+				break;
+			case RSC_ROLE_SLAVE:
+				child_rsc->priority = -1;
+				break;
+			case RSC_ROLE_STOPPED:
+				child_rsc->priority = -2;
+				break;
+			default:
+				CRM_DEV_ASSERT(FALSE/* unhandled */);
+		}
+		);
+
+	/* sort based on the new "promote" priority */
+	clone_data->child_list = g_list_sort(
+		clone_data->child_list, sort_rsc_priority);
+
+	/* mark the first N as masters */
+	slist_iter(
+		child_rsc, resource_t, clone_data->child_list, lpc,
+		switch(child_rsc->next_role) {
+			case RSC_ROLE_STARTED:
+				if(child_rsc->priority > 0 && master_max > lpc){
+					crm_info("Promoting %s", child_rsc->id);
+					child_rsc->next_role = RSC_ROLE_MASTER;
+					promoted++;
+					
+				} else {
+					crm_info("Demoting %s", child_rsc->id);
+					child_rsc->next_role = RSC_ROLE_SLAVE;
+				}
+				break;
+				
+			case RSC_ROLE_SLAVE:
+				if(child_rsc->priority < 0 ||master_max <= lpc){
+					pe_warn("Cannot promote %s (slave)",
+						child_rsc->id);
+					lpc--;
+				}
+				break;
+
+			case RSC_ROLE_STOPPED:
+				if(child_rsc->priority < 0 ||master_max <= lpc){
+					pe_warn("Cannot promote %s (stopping)",
+						child_rsc->id);
+					lpc--;
+				}
+				break;
+			default:
+				CRM_DEV_ASSERT(FALSE/* unhandled */);
+		}
+		);
+	crm_info("Promoted %d (of %d) slaves to master", promoted, master_max);
+	
+	/* create actions as normal */
+	clone_create_actions(rsc, data_set);
+
+	slist_iter(
+		child_rsc, resource_t, clone_data->child_list, lpc,
+		gboolean child_promoting = FALSE;
+		gboolean child_demoting = FALSE;
+
+		master_update_pseudo_status(
+			child_rsc, &child_demoting, &child_promoting);
+
+		any_demoting = any_demoting || child_demoting;
+		any_promoting = any_promoting || child_promoting;
+		);
+	
+	/* promote */
+	action = promote_action(clone_data->self, NULL, !any_promoting);
+	action_complete = custom_action(
+		clone_data->self, promoted_key(rsc),
+		CRMD_ACTION_PROMOTED, NULL, !any_promoting, data_set);
+
+	action->pseudo = TRUE;
+	action_complete->pseudo = TRUE;
+	
+	child_promoting_constraints(clone_data, pe_ordering_optional, 
+				   NULL, last_promote_rsc, data_set);
+
+	clone_create_notifications(rsc, action, action_complete, data_set);	
+
+
+	/* demote */
+	action = demote_action(clone_data->self, NULL, !any_demoting);
+	action_complete = custom_action(
+		clone_data->self, demoted_key(rsc),
+		CRMD_ACTION_DEMOTED, NULL, !any_demoting, data_set);
+
+	action->pseudo = TRUE;
+	action_complete->pseudo = TRUE;
+	
+	child_demoting_constraints(clone_data, pe_ordering_optional,
+				   NULL, last_demote_rsc, data_set);
+
+	clone_create_notifications(rsc, action, action_complete, data_set);	
+}
+
+void
+master_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
+{
+	resource_t *last_rsc = NULL;	
+	clone_variant_data_t *clone_data = NULL;
+	get_clone_variant_data(clone_data, rsc);
+
+	clone_internal_constraints(rsc, data_set);
+	
+	/* global demoted before start */
+	custom_action_order(
+		clone_data->self, demoted_key(clone_data->self), NULL,
+		clone_data->self, start_key(clone_data->self), NULL,
+		pe_ordering_optional, data_set);
+
+	/* global started before promote */
+	custom_action_order(
+		clone_data->self, started_key(clone_data->self), NULL,
+		clone_data->self, promote_key(clone_data->self), NULL,
+		pe_ordering_optional, data_set);
+
+	/* global demoted before stop */
+	custom_action_order(
+		clone_data->self, demoted_key(clone_data->self), NULL,
+		clone_data->self, stop_key(clone_data->self), NULL,
+		pe_ordering_optional, data_set);
+
+	/* global demote before demoted */
+	custom_action_order(
+		clone_data->self, demote_key(clone_data->self), NULL,
+		clone_data->self, demoted_key(clone_data->self), NULL,
+		pe_ordering_optional, data_set);
+	
+	slist_iter(
+		child_rsc, resource_t, clone_data->child_list, lpc,
+
+		/* child demote before promote */
+		custom_action_order(
+			child_rsc, demote_key(child_rsc), NULL,
+			child_rsc, promote_key(child_rsc), NULL,
+			pe_ordering_restart, data_set);
+		
+		child_promoting_constraints(clone_data, pe_ordering_optional,
+					    child_rsc, last_rsc, data_set);
+
+		child_demoting_constraints(clone_data, pe_ordering_optional,
+					   child_rsc, last_rsc, data_set);
+
+		last_rsc = child_rsc;
+		
+		);
+	
+}
+
diff --git a/lib/crm/cib/cib_attrs.c b/lib/crm/cib/cib_attrs.c
new file mode 100644
index 0000000000..9d764eb25e
--- /dev/null
+++ b/lib/crm/cib/cib_attrs.c
@@ -0,0 +1,426 @@
+/* $Id: cib_attrs.c,v 1.1 2005/09/12 11:04:22 andrew Exp $ */
+
+/* 
+ * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <portability.h>
+
+#include <sys/param.h>
+
+#include <crm/crm.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/cib.h>
+
+#include <crm/dmalloc_wrapper.h>
+
+
+enum cib_errors 
+update_attr(cib_t *the_cib,
+	    const char *section, const char *node_uuid, const char *set_name,
+	    const char *attr_id, const char *attr_name, const char *attr_value)
+{
+	const char *tag = NULL;
+	
+	enum cib_errors rc = cib_ok;
+	crm_data_t *xml_top = NULL;
+	crm_data_t *xml_obj = NULL;
+	crm_data_t *fragment = NULL;
+
+	if(attr_id == NULL) {
+		attr_id = attr_name;
+	}
+	if(attr_name == NULL) {
+		attr_name = attr_id;
+	}
+
+	CRM_ASSERT(attr_id != NULL);
+	CRM_ASSERT(attr_name != NULL);
+	
+	if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) {
+		tag = NULL;
+		
+	} else if(safe_str_eq(section, XML_CIB_TAG_NODES)) {
+		tag = XML_CIB_TAG_NODE;
+		
+	} else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) {
+		tag = XML_CIB_TAG_STATE;
+
+	} else {
+		return cib_NOSECTION;
+	}
+	
+	crm_debug("Creating %s/%s", section, tag);
+	if(tag != NULL) {
+		xml_obj = create_xml_node(NULL, tag);
+		crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid);
+		xml_top = xml_obj;
+	}
+
+	if(set_name != NULL) {
+		xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS);
+		if(xml_top == NULL) {
+			xml_top = xml_obj;
+		}
+		crm_xml_add(xml_obj, XML_ATTR_ID, set_name);
+		xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS);
+	}
+	xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
+	if(xml_top == NULL) {
+		xml_top = xml_obj;
+	}
+	crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
+	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
+	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value);
+	
+	fragment = create_cib_fragment(xml_top, NULL);
+	crm_log_xml_debug_2(xml_top, "Update");
+	crm_log_xml_debug(fragment, "Update Fragment");
+	
+	free_xml(xml_top);
+	
+	rc = the_cib->cmds->modify(the_cib, section, fragment, NULL,
+				   cib_sync_call|cib_quorum_override);
+	if(rc != cib_ok) {
+		crm_err("Error setting %s=%s (section=%s, set=%s): %s",
+			attr_name, attr_value, section, crm_str(set_name),
+			cib_error2string(rc));
+	}
+	
+	free_xml(fragment);
+	return rc;
+}
+
+enum cib_errors 
+read_attr(cib_t *the_cib,
+	  const char *section, const char *node_uuid, const char *set_name,
+	  const char *attr_id, const char *attr_name, char **attr_value)
+{
+	const char *tag = NULL;
+	enum cib_errors rc = cib_ok;
+	crm_data_t *a_node = NULL;
+	crm_data_t *xml_obj = NULL;
+	crm_data_t *xml_next = NULL;
+	crm_data_t *fragment = NULL;
+
+	CRM_ASSERT(attr_value != NULL);
+	*attr_value = NULL;
+
+	crm_debug("Searching for attribute %s (section=%s, node=%s, set=%s)",
+		  attr_name, section, crm_str(node_uuid), crm_str(set_name));
+
+	if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) {
+		tag = NULL;
+		
+	} else if(safe_str_eq(section, XML_CIB_TAG_NODES)) {
+		tag = XML_CIB_TAG_NODE;
+		
+	} else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) {
+		tag = XML_CIB_TAG_STATE;
+
+	} else {
+		return cib_NOSECTION;
+	}
+	
+	rc = the_cib->cmds->query(
+		the_cib, section, &fragment, cib_sync_call);
+
+	if(rc != cib_ok) {
+		crm_err("Query failed for attribute %s (section=%s, node=%s, set=%s): %s",
+			attr_name, section, crm_str(set_name), crm_str(node_uuid),
+			cib_error2string(rc));
+		return rc;
+	}
+	
+	a_node = find_xml_node(fragment, XML_TAG_CIB, TRUE);
+	xml_obj = get_object_root(section, a_node);
+	CRM_ASSERT(xml_obj != NULL);
+	crm_log_xml_debug_2(xml_obj, "Result section");
+	
+	if(tag != NULL) {
+		xml_next = find_entity(xml_obj, tag, node_uuid);
+		if(xml_next == NULL) {
+			crm_debug("%s=%s not found in %s", tag, node_uuid,
+				  crm_element_name(xml_obj));
+			return cib_NOTEXISTS;
+		}
+		xml_obj = xml_next;
+	}
+	if(set_name != NULL) {
+		xml_next = find_entity(xml_obj, XML_TAG_ATTR_SETS, set_name);
+		if(xml_next == NULL) {
+			crm_debug("%s=%s object not found in %s",
+				  XML_TAG_ATTR_SETS, set_name,
+				  crm_element_name(xml_obj));
+			return cib_NOTEXISTS;
+		}
+		xml_obj = xml_next;
+
+		xml_next = find_xml_node(xml_obj, XML_TAG_ATTRS, TRUE);
+		if(xml_next == NULL) {
+			crm_debug("%s object not found in %s",
+				  XML_TAG_ATTRS, crm_element_name(xml_obj));
+			return cib_NOTEXISTS;
+		}
+		xml_obj = xml_next;
+	}
+
+	xml_next = NULL;
+	xml_child_iter(
+		xml_obj, a_child, XML_CIB_TAG_NVPAIR,
+		const char *name = crm_element_value(
+			a_child, XML_NVPAIR_ATTR_NAME);
+
+		if(attr_id != NULL
+		   && safe_str_neq(attr_id, ID(a_child))) {
+			continue;
+			
+		} else if(attr_name != NULL
+			  && safe_str_neq(attr_name, name)) {
+			continue;
+		}
+		xml_next = a_child;
+		break;
+		);
+	
+	if(xml_next == NULL) {
+		crm_debug("<%s id=%s name=%s/> not found in %s",
+			  XML_CIB_TAG_NVPAIR, attr_id, attr_name,
+			  crm_element_name(xml_obj));
+		return cib_NOTEXISTS;
+	}
+	xml_obj = xml_next;
+	
+	if(crm_element_value(xml_obj, XML_NVPAIR_ATTR_VALUE) != NULL) {
+		*attr_value = crm_element_value_copy(
+			xml_obj, XML_NVPAIR_ATTR_VALUE);
+	}
+	
+	free_xml(fragment);
+	return cib_ok;
+}
+
+
+enum cib_errors 
+delete_attr(cib_t *the_cib,
+	    const char *section, const char *node_uuid, const char *set_name,
+	    const char *attr_id, const char *attr_name, const char *attr_value)
+{
+	char *tmp = NULL;
+	enum cib_errors rc = cib_ok;
+	crm_data_t *xml_obj = NULL;
+
+	rc = read_attr(the_cib, section, node_uuid, set_name,
+		       attr_id, attr_name, &tmp);
+
+	if(rc != cib_ok) {
+		return rc;
+
+	} else if(attr_value != NULL
+		  && safe_str_neq(attr_value, tmp)) {
+		crm_free(tmp);
+		return cib_NOTEXISTS;
+	}
+	crm_free(tmp);
+
+	xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR);
+	crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
+	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
+	crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value);
+	
+	rc = the_cib->cmds->delete(
+		the_cib, section, xml_obj, NULL,
+		cib_sync_call|cib_quorum_override);
+
+	free_xml(xml_obj);
+	return rc;
+}
+
+enum cib_errors 
+query_node_uuid(cib_t *the_cib, const char *uname, char **uuid)
+{
+	enum cib_errors rc = cib_ok;
+	crm_data_t *xml_obj = NULL;
+	crm_data_t *fragment = NULL;
+	const char *child_name = NULL;
+
+	CRM_ASSERT(uname != NULL);
+	CRM_ASSERT(uuid != NULL);
+	
+	rc = the_cib->cmds->query(
+		the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call);
+	if(rc != cib_ok) {
+		return rc;
+	}
+
+	xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE);
+	xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj);
+	CRM_ASSERT(xml_obj != NULL);
+	crm_log_xml_debug(xml_obj, "Result section");
+
+	rc = cib_NOTEXISTS;
+	*uuid = NULL;
+	
+	xml_child_iter(
+		xml_obj, a_child, XML_CIB_TAG_NODE,
+		child_name = crm_element_value(a_child, XML_ATTR_UNAME);
+
+		if(safe_str_eq(uname, child_name)) {
+			child_name = ID(a_child);
+			if(child_name != NULL) {
+				*uuid = crm_strdup(child_name);
+				rc = cib_ok;
+			}
+			break;
+		}
+		);
+	free_xml(fragment);
+	return rc;
+}
+
+enum cib_errors 
+query_node_uname(cib_t *the_cib, const char *uuid, char **uname)
+{
+	enum cib_errors rc = cib_ok;
+	crm_data_t *xml_obj = NULL;
+	crm_data_t *fragment = NULL;
+	const char *child_name = NULL;
+
+	CRM_ASSERT(uname != NULL);
+	CRM_ASSERT(uuid != NULL);
+	
+	rc = the_cib->cmds->query(
+		the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call);
+	if(rc != cib_ok) {
+		return rc;
+	}
+
+	xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE);
+	xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj);
+	CRM_ASSERT(xml_obj != NULL);
+	crm_log_xml_debug_2(xml_obj, "Result section");
+
+	rc = cib_NOTEXISTS;
+	*uname = NULL;
+	
+	xml_child_iter(
+		xml_obj, a_child, XML_CIB_TAG_NODE,
+		child_name = ID(a_child);
+
+		if(safe_str_eq(uuid, child_name)) {
+			child_name = crm_element_value(a_child, XML_ATTR_UNAME);
+			if(child_name != NULL) {
+				*uname = crm_strdup(child_name);
+				rc = cib_ok;
+			}
+			break;
+		}
+		);
+	free_xml(fragment);
+	return rc;
+}
+
+#define standby_common 	char *attr_id  = NULL;	\
+	char *set_name = NULL;			\
+	const char *attr_name  = "standby";	\
+	const char *type = XML_CIB_TAG_NODES;	\
+						\
+	if(safe_str_eq(scope, "reboot")				\
+	   || safe_str_eq(scope, XML_CIB_TAG_STATUS)) {		\
+		type = XML_CIB_TAG_STATUS;			\
+	}							\
+								\
+	CRM_DEV_ASSERT(uuid != NULL);					\
+	CRM_DEV_ASSERT(standby_value != NULL);				\
+									\
+	crm_malloc0(attr_id, 2 + strlen(attr_name) + strlen(uuid));	\
+	sprintf(attr_id, "%s-%s", attr_name, uuid);			\
+									\
+	crm_malloc0(set_name, 2 + strlen(attr_name) + strlen(uuid));	\
+	sprintf(set_name, "%s-%s", attr_name, uuid);			\
+	
+
+enum cib_errors 
+query_standby(cib_t *the_cib, const char *uuid, const char *scope,
+	char **standby_value)
+{
+	enum cib_errors rc = cib_ok;
+	standby_common;
+
+	if(scope != NULL) {
+		rc = read_attr(the_cib, type, uuid, set_name,
+			       attr_id, attr_name, standby_value);
+	} else {
+		rc = read_attr(the_cib, XML_CIB_TAG_NODES, uuid, set_name,
+			       attr_id, attr_name, standby_value);
+		if(rc == cib_NOTEXISTS) {
+			crm_info("No standby value found with lifetime=forever,"
+				 " checking lifetime=reboot.");
+			rc = read_attr(the_cib, XML_CIB_TAG_STATUS, uuid, set_name,
+				       attr_id, attr_name, standby_value);
+		}
+	}
+	
+	crm_free(attr_id);
+	crm_free(set_name);
+	return rc;
+}
+
+enum cib_errors 
+set_standby(cib_t *the_cib, const char *uuid, const char *scope,
+	    const char *standby_value)
+{
+	enum cib_errors rc = cib_ok;
+	standby_common;
+
+	rc = update_attr(the_cib, type, uuid, set_name,
+			 attr_id, attr_name, standby_value);
+
+	crm_free(attr_id);
+	crm_free(set_name);
+
+	return rc;
+}
+
+enum cib_errors 
+delete_standby(cib_t *the_cib, const char *uuid, const char *scope,
+	       const char *standby_value)
+{
+	enum cib_errors rc = cib_ok;
+	
+	standby_common;	
+	
+	rc = delete_attr(the_cib, type, uuid, set_name,
+			 attr_id, attr_name, standby_value);
+	
+	crm_free(attr_id);
+	crm_free(set_name);
+
+	return rc;
+}
+