summaryrefslogtreecommitdiffstats
path: root/__root__/ccs-flatten
diff options
context:
space:
mode:
authorJan Pokorný <jpokorny@redhat.com>2014-04-25 21:35:17 +0200
committerJan Pokorný <jpokorny@redhat.com>2014-04-25 21:56:41 +0200
commit6d68205c666e84995f0b9c1d4ad17f7fb22cd27d (patch)
treed286cf8c5ccf7bd6ee53d30b50a324a1eaebf748 /__root__/ccs-flatten
parentaa08c2c7106dca9423fd3057ecd8ceb111083928 (diff)
downloadclufter-6d68205c666e84995f0b9c1d4ad17f7fb22cd27d.tar.gz
clufter-6d68205c666e84995f0b9c1d4ad17f7fb22cd27d.tar.xz
clufter-6d68205c666e84995f0b9c1d4ad17f7fb22cd27d.zip
Embed ccs_flatten utility and make (almost) directly usable
(prerequisite is the previous commit) Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
Diffstat (limited to '__root__/ccs-flatten')
-rw-r--r--__root__/ccs-flatten/Makefile13
-rw-r--r--__root__/ccs-flatten/flatten.c240
-rw-r--r--__root__/ccs-flatten/list.h91
-rw-r--r--__root__/ccs-flatten/resgroup.h122
-rw-r--r--__root__/ccs-flatten/reslist.c518
-rw-r--r--__root__/ccs-flatten/reslist.h205
-rw-r--r--__root__/ccs-flatten/resrules.c971
-rw-r--r--__root__/ccs-flatten/restree.c723
-rw-r--r--__root__/ccs-flatten/xmlconf.c139
-rw-r--r--__root__/ccs-flatten/xmlconf.h11
10 files changed, 3033 insertions, 0 deletions
diff --git a/__root__/ccs-flatten/Makefile b/__root__/ccs-flatten/Makefile
new file mode 100644
index 0000000..8172cb9
--- /dev/null
+++ b/__root__/ccs-flatten/Makefile
@@ -0,0 +1,13 @@
+.PHONY: all clean
+
+TARGET = ccs_flatten
+OBJS = flatten.o reslist.o resrules.o restree.o xmlconf.o
+CFLAGS += $(shell pkg-config --cflags libxml-2.0) -I.
+LDFLAGS += $(shell pkg-config --libs libxml-2.0)
+
+all: ${TARGET}
+${TARGET}: ${OBJS}
+ ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@
+
+clean:
+ ${RM} ${TARGET} ${OBJS}
diff --git a/__root__/ccs-flatten/flatten.c b/__root__/ccs-flatten/flatten.c
new file mode 100644
index 0000000..068056b
--- /dev/null
+++ b/__root__/ccs-flatten/flatten.c
@@ -0,0 +1,240 @@
+/*
+ Copyright Red Hat, Inc. 2004-2006
+
+ 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, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/xpath.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <resgroup.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <list.h>
+#include <reslist.h>
+#include <xmlconf.h>
+#include <libgen.h>
+
+#define shift() {++argv; --argc;}
+
+const char *agentpath = RESOURCE_ROOTDIR;
+
+static xmlNode *
+get_rm_node(xmlDocPtr doc)
+{
+ xmlNodePtr n, o;
+
+ if (!doc)
+ return NULL;
+ n = xmlDocGetRootElement(doc);
+ if (!n)
+ return NULL;
+ if (strcmp((char *)n->name, "cluster")) {
+ fprintf(stderr, "Expected cluster tag, got %s\n", (char *)n->name);
+ return NULL;
+ }
+
+ for (o = n->xmlChildrenNode; o; o = o->next) {
+ if (o->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp((char *)o->name, "rm"))
+ return o;
+ }
+
+ return NULL;
+}
+
+static void
+remove_resources_block(xmlNodePtr rm)
+{
+ xmlNodePtr o, r = NULL;
+
+ for (o = rm->xmlChildrenNode; o; o = o->next) {
+ if (o->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp((char *)o->name, "resources")) {
+ r = o;
+ break;
+ }
+ }
+
+ if (!r)
+ return;
+
+ xmlUnlinkNode(r);
+ xmlFreeNode(r);
+}
+
+static int
+replace_resource(xmlNodePtr rm, char *restype, char *primattr, char *ident, xmlNodePtr n)
+{
+ xmlNodePtr o, r = NULL;
+ char *p;
+
+ for (o = rm->xmlChildrenNode; o; o = o->next) {
+ if (o->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp((char *)o->name, restype)) {
+ p = (char *)xmlGetProp(o, (xmlChar *) primattr);
+ if (!strcmp(p, ident)) {
+ r = o;
+ break;
+ }
+ }
+ }
+
+ if (!r)
+ return -1;
+
+ xmlUnlinkNode(r);
+ xmlFreeNode(r);
+
+ xmlAddChild(rm, n);
+
+ return 0;
+}
+
+static int
+flatten(int argc, char **argv, xmlDocPtr * doc)
+{
+ xmlDocPtr d = NULL;
+ xmlNode *n = NULL, *rm = NULL, *new_rb = NULL;
+ resource_rule_t *rulelist = NULL;
+ resource_t *reslist = NULL, *curres;
+ resource_node_t *tree = NULL, *rn;
+ FILE *f = stdout;
+ int ret = 0;
+
+ conf_setconfig(argv[0]);
+ if (conf_open() < 0) {
+ xmlFree(new_rb);
+ goto out;
+ }
+
+ while (argc >= 2) {
+ shift();
+ if (!strcmp(argv[0], "-r")) {
+ if (!new_rb)
+ new_rb = xmlNewNode(NULL, (xmlChar *) "rm");
+ } else {
+ if (f == stdout)
+ f = fopen(argv[0], "w+");
+ }
+ }
+
+ d = conf_get_doc();
+ rm = get_rm_node(d);
+
+ load_resource_rules(agentpath, &rulelist);
+ if (!rulelist) {
+ fprintf(stderr, "No resource rules available\n");
+ goto out;
+ }
+ load_resources(&reslist, &rulelist);
+ build_resource_tree(&tree, &rulelist, &reslist);
+ if (!tree) {
+ fprintf(stderr, "No resource trees defined; nothing to do\n");
+ goto out;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Resources %p tree %p\n", reslist, tree);
+#endif
+
+ shift();
+
+ list_do(&tree, rn) {
+ n = NULL;
+
+ curres = rn->rn_resource;
+
+#ifdef DEBUG
+ fprintf(stderr, "Flatten %s:%s ... \n", curres->r_rule->rr_type,
+ curres->r_attrs[0].ra_value);
+#endif
+ if (res_flatten(&n, new_rb, &tree, curres)) {
+ fprintf(stderr, "FAIL 1\n");
+ ret = -1;
+ goto out;
+ }
+
+ if (replace_resource(rm, curres->r_rule->rr_type,
+ curres->r_attrs[0].ra_name, curres->r_attrs[0].ra_value, n) != 0) {
+ fprintf(stderr, "FAIL 2\n");
+ ret = -1;
+ goto out;
+ }
+
+ }
+ while (!list_done(&tree, rn)) ;
+
+ remove_resources_block(rm);
+ if (new_rb) {
+ xmlAddChild(rm, new_rb);
+ }
+
+ xmlDocFormatDump(f, d, 1);
+ if (f != stdout)
+ fclose(f);
+
+ out:
+ if (ret < 0) {
+ xmlFreeDoc(d);
+ } else {
+ *doc = d;
+ }
+ conf_close();
+ destroy_resource_tree(&tree);
+ destroy_resources(&reslist);
+ destroy_resource_rules(&rulelist);
+
+ return ret;
+}
+
+static void
+usage(const char *arg0, int ret)
+{
+ fprintf(stderr, "usage: %s <input.conf> [output.conf] [-r]\n", arg0);
+ exit(ret);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *arg0 = basename(argv[0]);
+ int ret = 0;
+ xmlDocPtr doc = NULL;
+
+ if (argc < 2) {
+ usage(arg0, 1);
+ }
+
+ if (!strcasecmp(argv[1], "-h") || !strcasecmp(argv[1], "-?")) {
+ usage(arg0, 0);
+ }
+
+ xmlInitParser();
+ xmlIndentTreeOutput = 1;
+ xmlKeepBlanksDefault(0);
+
+ shift();
+ ret = flatten(argc, argv, &doc);
+
+ //if (doc)
+ //xmlFreeDoc(doc);
+ xmlCleanupParser();
+ return ret;
+}
diff --git a/__root__/ccs-flatten/list.h b/__root__/ccs-flatten/list.h
new file mode 100644
index 0000000..d43ba01
--- /dev/null
+++ b/__root__/ccs-flatten/list.h
@@ -0,0 +1,91 @@
+#ifndef _LIST_H
+# define _LIST_H
+
+/**
+ Simple list handlig macros.
+ Needs rewrite or inclusion of /usr/include/linux/list.h as a replacement.
+ */
+
+/* Must be first if structure is going to use it. */
+struct list_entry {
+ struct list_entry *le_next, *le_prev;
+};
+
+# define list_head() struct list_entry _list_head
+
+# define le(p) (&((*p)._list_head))
+
+# define list_insert(list, newnode) \
+do { \
+ if (!(*list)) { \
+ le(newnode)->le_next = \
+ le(newnode)->le_prev = le(newnode); \
+ *list = (void *)le(newnode); \
+ } else { \
+ le(*list)->le_prev->le_next = le(newnode); \
+ le(newnode)->le_next = le(*list); \
+ le(newnode)->le_prev = le(*list)->le_prev; \
+ le(*list)->le_prev = le(newnode); \
+ } \
+} while (0)
+
+# define list_prepend(list, newnode) \
+do { \
+ list_insert(list, newnode); \
+ *list = newnode; \
+} while (0)
+
+# define list_remove(list, oldnode) \
+do { \
+ if (le(oldnode) == le(*list)) { \
+ *list = (void *)le(*list)->le_next; \
+ } \
+ if (le(oldnode) == le(*list)) { \
+ le(oldnode)->le_next = NULL; \
+ le(oldnode)->le_prev = NULL; \
+ *list = NULL; \
+ } else { \
+ le(oldnode)->le_next->le_prev = le(oldnode)->le_prev; \
+ le(oldnode)->le_prev->le_next = le(oldnode)->le_next; \
+ le(oldnode)->le_prev = NULL; \
+ le(oldnode)->le_next = NULL; \
+ } \
+} while (0)
+
+/*
+list_do(list, node) {
+ stuff;
+} while (!list_done(list, node));
+ */
+# define list_do(list, curr) \
+ if (*list && (curr = *list)) do
+
+# define list_done(list, curr) \
+ (curr && (((curr = (void *)le(curr)->le_next)) && (curr == *list)))
+
+/*
+ * list_for(list, tmp, counter) {
+ * stuff;
+ * }
+ *
+ * counter = # of items in list when done.
+ * * sets cnt to 0 before even checking list;
+ * * checks for valid list
+ * * traverses list, incrementing counter. If we get to the for loop,
+ * there must be at least one item in the list
+ */
+# define list_for(list, curr, cnt) \
+ if (!(cnt=0) && (list != NULL) && (*list != NULL)) \
+ for (curr = *list; \
+ (cnt == 0) || (curr != *list); \
+ curr = (void*)le(curr)->le_next, \
+ cnt++)
+
+# define list_for_rev(list, curr, cnt) \
+ if (!(cnt=0) && list && *list) \
+ for (curr = (void *)(le(*list)->le_prev); \
+ (cnt == 0) || ((void *)curr != le(*list)->le_prev); \
+ curr = (void*)(le(curr)->le_prev), \
+ cnt++)
+
+#endif
diff --git a/__root__/ccs-flatten/resgroup.h b/__root__/ccs-flatten/resgroup.h
new file mode 100644
index 0000000..50db8e0
--- /dev/null
+++ b/__root__/ccs-flatten/resgroup.h
@@ -0,0 +1,122 @@
+#ifndef __RESGROUP_H
+# define __RESGROUP_H
+
+# include <pthread.h>
+# include <stdio.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <string.h>
+# include <unistd.h>
+# include <sys/types.h>
+# include <errno.h>
+
+/* Requests */
+# define RG_SUCCESS 0
+# define RG_FAIL 1
+# define RG_START 2
+# define RG_STOP 3
+# define RG_STATUS 4
+# define RG_DISABLE 5
+# define RG_STOP_RECOVER 6
+# define RG_START_RECOVER 7
+# define RG_RESTART 8
+# define RG_EXITING 9
+# define RG_INIT 10
+# define RG_ENABLE 11
+# define RG_STATUS_NODE 12
+# define RG_RELOCATE 13
+# define RG_CONDSTOP 14
+# define RG_CONDSTART 15
+# define RG_START_REMOTE 16 /* Part of a relocate */
+# define RG_STOP_USER 17 /* User-stop request */
+# define RG_STOP_EXITING 18
+ /* Exiting. */
+# define RG_LOCK 19
+# define RG_UNLOCK 20
+# define RG_QUERY_LOCK 21
+# define RG_MIGRATE 22
+# define RG_FREEZE 23
+# define RG_UNFREEZE 24
+# define RG_STATUS_INQUIRY 25
+# define RG_CONVALESCE 26
+# define RG_NONE 999
+
+/* Resource group states (for now) */
+# define RG_STATE_BASE 110
+# define RG_STATE_STOPPED 110 /** Resource group is stopped */
+# define RG_STATE_STARTING 111 /** Resource is starting */
+# define RG_STATE_STARTED 112 /** Resource is started */
+# define RG_STATE_STOPPING 113 /** Resource is stopping */
+# define RG_STATE_FAILED 114
+ /** Resource has failed */
+# define RG_STATE_UNINITIALIZED 115
+ /** Thread not running yet */
+# define RG_STATE_CHECK 116
+ /** Checking status */
+# define RG_STATE_ERROR 117
+ /** Recoverable error */
+# define RG_STATE_RECOVER 118 /** Pending recovery */
+# define RG_STATE_DISABLED 119 /** Resource not allowd to run */
+# define RG_STATE_MIGRATE 120 /** Resource migrating */
+
+# define DEFAULT_CHECK_INTERVAL 10
+
+/* Resource group flags (for now) */
+# define RG_FLAG_FROZEN (1<<0)
+ /** Resource frozen */
+# define RG_FLAG_PARTIAL (1<<1)
+ /** One or more non-critical
+ resources offline */
+
+/* Return codes */
+# define RG_EEXCL -16 /* Service not runnable due to
+ the fact that it is tagged
+ exclusive and there are no
+ empty nodes. */
+# define RG_EDOMAIN -15 /* Service not runnable given the
+ set of nodes and its failover
+ domain */
+# define RG_ESCRIPT -14 /* S/Lang script failed */
+# define RG_EFENCE -13 /* Fencing operation pending */
+# define RG_ENODE -12 /* Node is dead/nonexistent */
+# define RG_EFROZEN -11 /* Forward compat. with -HEAD */
+# define RG_ERUN -10
+ /* Service is already running */
+# define RG_EQUORUM -9 /* Operation requires quorum */
+# define RG_EINVAL -8 /* Invalid operation for resource */
+# define RG_EDEPEND -7 /* Operation violates dependency */
+# define RG_EAGAIN -6 /* Try again */
+# define RG_EDEADLCK -5 /* Aborted - would deadlock */
+# define RG_ENOSERVICE -4 /* Service does not exist */
+# define RG_EFORWARD -3 /* Service not mastered locally */
+# define RG_EABORT -2 /* Abort; service unrecoverable */
+# define RG_EFAIL -1 /* Generic failure */
+# define RG_ESUCCESS 0
+# define RG_YES 1
+# define RG_NO 2
+
+const char *rg_strerror(int val);
+
+/*
+ * Fail-over domain states
+ */
+# define FOD_ILLEGAL 0
+# define FOD_GOOD 1
+# define FOD_BETTER 2
+# define FOD_BEST 3
+
+/*
+ Fail-over domain flags
+ */
+# define FOD_ORDERED (1<<0)
+# define FOD_RESTRICTED (1<<1)
+# define FOD_NOFAILBACK (1<<2)
+
+/*
+ Status tree flags
+ */
+# define SFL_FAILURE (1<<0)
+# define SFL_RECOVERABLE (1<<1)
+# define SFL_PARTIAL (1<<2)
+
+#endif
diff --git a/__root__/ccs-flatten/reslist.c b/__root__/ccs-flatten/reslist.c
new file mode 100644
index 0000000..4c50c90
--- /dev/null
+++ b/__root__/ccs-flatten/reslist.c
@@ -0,0 +1,518 @@
+/*
+ Copyright Red Hat, Inc. 2004
+
+ 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, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/xpath.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <resgroup.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <list.h>
+#include <libgen.h>
+#include <reslist.h>
+#include <xmlconf.h>
+
+void
+res_build_name(char *buf, size_t buflen, resource_t * res)
+{
+ snprintf(buf, buflen, "%s:%s", res->r_rule->rr_type, res->r_attrs[0].ra_value);
+}
+
+/**
+ Find and determine an attribute's value.
+
+ @param res Resource node to look examine
+ @param attrname Attribute to retrieve.
+ @return value of attribute or NULL if not found
+ */
+char *
+res_attr_value(resource_t * res, const char *attrname)
+{
+ resource_attr_t *ra;
+ int x;
+
+ for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) {
+ if (strcmp(attrname, res->r_attrs[x].ra_name))
+ continue;
+
+ ra = &res->r_attrs[x];
+
+ if (ra->ra_flags & RA_INHERIT)
+ /* Can't check inherited resources */
+ return NULL;
+
+ return ra->ra_value;
+ }
+
+ return NULL;
+}
+
+/**
+ Find and determine an attribute's value. Takes into account inherited
+ attribute flag, and append attribute flag, which isn't implemented yet.
+
+ @param node Resource tree node to look examine
+ @param attrname Attribute to retrieve.
+ @param ptype Resource type to look for (if inheritance)
+ @return value of attribute or NULL if not found
+ */
+static char *
+_attr_value(resource_node_t * node, const char *attrname, const char *ptype)
+{
+ resource_t *res;
+ resource_attr_t *ra;
+ char *c, p_type[32];
+ ssize_t len;
+ int x;
+
+ if (!node)
+ return NULL;
+
+ res = node->rn_resource;
+
+ /* Go up the tree if it's not the right parent type */
+ if (ptype && strcmp(res->r_rule->rr_type, ptype))
+ return _attr_value(node->rn_parent, attrname, ptype);
+
+ for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) {
+ if (strcmp(attrname, res->r_attrs[x].ra_name))
+ continue;
+
+ ra = &res->r_attrs[x];
+
+ if (!(ra->ra_flags & RA_INHERIT))
+ return ra->ra_value;
+ /*
+ Handle resource_type%field to be more precise, so we
+ don't have to worry about this being a child
+ of an unexpected type. E.g. lots of things have the
+ "name" attribute.
+ */
+ c = strchr(ra->ra_value, '%');
+ if (!c) {
+ /* Someone doesn't care or uses older
+ semantics on inheritance */
+ return _attr_value(node->rn_parent, ra->ra_value, NULL);
+ }
+
+ len = (c - ra->ra_value);
+ memset(p_type, 0, sizeof(p_type));
+ memcpy(p_type, ra->ra_value, len);
+
+ /* Skip the "%" and recurse */
+ return _attr_value(node->rn_parent, ++c, p_type);
+ }
+
+ return NULL;
+}
+
+char *
+attr_value(resource_node_t * node, const char *attrname)
+{
+ return _attr_value(node, attrname, NULL);
+}
+
+char *
+primary_attr_value(resource_t * res)
+{
+ int x;
+ resource_attr_t *ra;
+
+ for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) {
+ ra = &res->r_attrs[x];
+
+ if (!(ra->ra_flags & RA_PRIMARY))
+ continue;
+
+ return ra->ra_value;
+ }
+
+ return NULL;
+}
+
+/**
+ Find a resource given its reference. A reference is the value of the
+ primary attribute.
+
+ @param reslist List of resources to traverse.
+ @param type Type of resource to look for.
+ @param ref Reference
+ @return Resource matching type/ref or NULL if none.
+ */
+resource_t *
+find_resource_by_ref(resource_t ** reslist, char *type, char *ref)
+{
+ resource_t *curr;
+ int x;
+
+ list_do(reslist, curr) {
+ if (strcmp(curr->r_rule->rr_type, type))
+ continue;
+
+ /*
+ This should be one operation - the primary attr
+ is generally at the head of the array.
+ */
+ for (x = 0; curr->r_attrs && curr->r_attrs[x].ra_name; x++) {
+ if (!(curr->r_attrs[x].ra_flags & RA_PRIMARY))
+ continue;
+ if (strcmp(ref, curr->r_attrs[x].ra_value))
+ continue;
+
+ return curr;
+ }
+ }
+ while (!list_done(reslist, curr)) ;
+
+ return NULL;
+}
+
+/**
+ Store a resource in the resource list if it's legal to do so.
+ Otherwise, don't store it.
+ Note: This function needs to be rewritten; it's way too long and way
+ too indented.
+
+ @param reslist Resource list to store the new resource.
+ @param newres Resource to store
+ @return 0 on succes; nonzero on failure.
+ */
+int
+store_resource(resource_t ** reslist, resource_t * newres)
+{
+ resource_t *curr;
+ int x, y;
+
+ if (!*reslist) {
+ /* first resource */
+ list_insert(reslist, newres);
+ return 0;
+ }
+
+ list_do(reslist, curr) {
+
+ if (strcmp(curr->r_rule->rr_type, newres->r_rule->rr_type))
+ continue;
+
+ for (x = 0; newres->r_attrs && newres->r_attrs[x].ra_name; x++) {
+ /*
+ Look for conflicting primary/unique keys
+ */
+ if (!(newres->r_attrs[x].ra_flags & (RA_PRIMARY | RA_UNIQUE)))
+ continue;
+
+ for (y = 0; curr->r_attrs[y].ra_name; y++) {
+ if (curr->r_attrs[y].ra_flags & RA_INHERIT)
+ continue;
+
+ if (strcmp(curr->r_attrs[y].ra_name, newres->r_attrs[x].ra_name))
+ continue;
+ if (!strcmp(curr->r_attrs[y].ra_value, newres->r_attrs[x].ra_value)) {
+ /*
+ Unique/primary is not unique
+ */
+ fprintf(stderr,
+ "%s attribute collision. "
+ "type=%s attr=%s value=%s\n",
+ (newres->r_attrs[x].ra_flags &
+ RA_PRIMARY) ? "Primary" :
+ "Unique",
+ newres->r_rule->rr_type,
+ newres->r_attrs[x].ra_name, newres->r_attrs[x].ra_value);
+ return -1;
+ }
+ break;
+ }
+ }
+ }
+ while (!list_done(reslist, curr)) ;
+
+ list_insert(reslist, newres);
+ return 0;
+}
+
+/**
+ Obliterate a resource_t structure.
+
+ @param res Resource to free.
+ */
+void
+destroy_resource(resource_t * res)
+{
+ int x;
+
+ if (res->r_name)
+ free(res->r_name);
+
+ if (res->r_attrs) {
+ for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) {
+ free(res->r_attrs[x].ra_name);
+ free(res->r_attrs[x].ra_value);
+ }
+
+ free(res->r_attrs);
+ }
+
+ if (res->r_actions) {
+ /* Don't free the strings; they're part of the rule */
+ free(res->r_actions);
+ }
+
+ free(res);
+}
+
+/**
+ Obliterate a resource_t list.
+
+ @param list Resource list to free.
+ */
+void
+destroy_resources(resource_t ** list)
+{
+ resource_t *res;
+
+ while ((res = *list)) {
+ list_remove(list, res);
+ destroy_resource(res);
+ }
+}
+
+void *
+act_dup(resource_act_t * acts)
+{
+ int x;
+ resource_act_t *newacts;
+
+ for (x = 0; acts[x].ra_name; x++) ;
+
+ ++x;
+ x *= sizeof(resource_act_t);
+
+ newacts = malloc(x);
+ if (!newacts)
+ return NULL;
+
+ memcpy(newacts, acts, x);
+
+ return newacts;
+}
+
+/* Copied from resrules.c -- _get_actions */
+static void
+_get_actions_ccs(const char *base, resource_t * res)
+{
+ char xpath[256];
+ int idx = 0;
+ char *act, *ret;
+ int interval, timeout, depth;
+
+ do {
+ /* setting these to -1 prevents overwriting with 0 */
+ interval = -1;
+ depth = -1;
+ act = NULL;
+ timeout = -1;
+
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@name", base, ++idx);
+
+ if (conf_get(xpath, &act) != 0)
+ break;
+
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@timeout", base, idx);
+ if (conf_get(xpath, &ret) == 0 && ret) {
+ timeout = expand_time(ret);
+ if (timeout < 0)
+ timeout = 0;
+ free(ret);
+ }
+
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@interval", base, idx);
+ if (conf_get(xpath, &ret) == 0 && ret) {
+ interval = expand_time(ret);
+ if (interval < 0)
+ interval = 0;
+ free(ret);
+ }
+
+ if (!strcmp(act, "status") || !strcmp(act, "monitor")) {
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@depth", base, idx);
+ if (conf_get(xpath, &ret) == 0 && ret) {
+ depth = atoi(ret);
+ if (depth < 0)
+ depth = 0;
+
+ /* */
+ if (ret[0] == '*')
+ depth = -1;
+ free(ret);
+ }
+ }
+
+ if (store_action(&res->r_actions, act, depth, timeout, interval) != 0)
+ free(act);
+ } while (1);
+}
+
+/**
+ Try to load all the attributes in our rule set. If none are found,
+ or an error occurs, return NULL and move on to the next one.
+
+ @param rule Resource rule set to use when looking for data
+ @param base Base XPath path to start with.
+ @return New resource if legal or NULL on failure/error
+ */
+resource_t *
+load_resource(resource_rule_t * rule, const char *base)
+{
+ resource_t *res;
+ char ccspath[1024];
+ char *attrname, *attr;
+ int x, found = 0, flags;
+
+ res = malloc(sizeof(*res));
+ if (!res) {
+ fprintf(stderr, "Out of memory\n");
+ return NULL;
+ }
+
+ memset(res, 0, sizeof(*res));
+ res->r_rule = rule;
+
+ for (x = 0; res->r_rule->rr_attrs && res->r_rule->rr_attrs[x].ra_name; x++) {
+
+ flags = rule->rr_attrs[x].ra_flags;
+ attrname = strdup(rule->rr_attrs[x].ra_name);
+ if (!attrname) {
+ destroy_resource(res);
+ return NULL;
+ }
+
+ /*
+ Ask CCS for the respective attribute
+ */
+ attr = NULL;
+ snprintf(ccspath, sizeof(ccspath), "%s/@%s", base, attrname);
+
+ if (conf_get(ccspath, &attr) != 0) {
+
+ if (flags & (RA_REQUIRED | RA_PRIMARY)) {
+ /* Missing required attribute. We're done. */
+ free(attrname);
+ destroy_resource(res);
+ return NULL;
+ }
+
+ if (!(flags & RA_INHERIT)) {
+ /*
+ If we don't have the inherit flag, see if
+ we have a value anyway. If we do,
+ this value is the default value, and
+ should be used.
+ */
+ if (!rule->rr_attrs[x].ra_value) {
+ free(attrname);
+ continue;
+ }
+
+ /* Copy default value from resource rule */
+ attr = strdup(rule->rr_attrs[x].ra_value);
+ }
+ }
+
+ found = 1;
+
+ /*
+ If we are supposed to inherit and we don't have an
+ instance of the specified attribute in CCS, then we
+ keep the inherit flag and use it as the attribute.
+
+ However, if we _do_ have the attribute for this instance,
+ we drop the inherit flag and use the attribute.
+ */
+ if (flags & RA_INHERIT) {
+ if (attr) {
+ flags &= ~RA_INHERIT;
+ } else {
+ attr = strdup(rule->rr_attrs[x].ra_value);
+ if (!attr) {
+ destroy_resource(res);
+ free(attrname);
+ return NULL;
+ }
+ }
+ }
+
+ /*
+ Store the attribute. We'll ensure all required
+ attributes are present soon.
+ */
+ if (attrname && attr)
+ store_attribute(&res->r_attrs, attrname, attr, flags);
+ }
+
+ if (!found) {
+ destroy_resource(res);
+ return NULL;
+ }
+
+ res->r_actions = act_dup(rule->rr_actions);
+ _get_actions_ccs(base, res);
+
+ return res;
+}
+
+/**
+ Read all resources in the resource manager block in CCS.
+
+ @param reslist Empty list to fill with resources.
+ @param rulelist List of rules to use when searching CCS.
+ @return 0 on success, nonzero on failure.
+ */
+int
+load_resources(resource_t ** reslist, resource_rule_t ** rulelist)
+{
+ int resID = 0;
+ resource_t *newres;
+ resource_rule_t *currule;
+ char tok[256];
+
+ list_do(rulelist, currule) {
+
+ for (resID = 1;; resID++) {
+ snprintf(tok, sizeof(tok), RESOURCE_BASE "/%s[%d]", currule->rr_type, resID);
+
+ newres = load_resource(currule, tok);
+ if (!newres)
+ break;
+
+ if (store_resource(reslist, newres) != 0) {
+ fprintf(stderr, "Error storing %s resource\n", newres->r_rule->rr_type);
+
+ destroy_resource(newres);
+ }
+
+ /* Just information */
+ newres->r_flags = RF_DEFINED;
+ }
+ }
+ while (!list_done(rulelist, currule)) ;
+
+ return 0;
+}
diff --git a/__root__/ccs-flatten/reslist.h b/__root__/ccs-flatten/reslist.h
new file mode 100644
index 0000000..07c84fe
--- /dev/null
+++ b/__root__/ccs-flatten/reslist.h
@@ -0,0 +1,205 @@
+/*
+ Copyright Red Hat, Inc. 2004
+
+ 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, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+#ifndef _RESLIST_H
+# define _RESLIST_H
+
+# include <stdint.h>
+# include <libxml/parser.h>
+# include <libxml/xmlmemory.h>
+# include <libxml/xpath.h>
+
+# define RA_PRIMARY (1<<0) /** Primary key */
+# define RA_UNIQUE (1<<1) /** Unique for given type */
+# define RA_REQUIRED (1<<2) /** Required (or an error if not present */
+# define RA_INHERIT (1<<3) /** Inherit a parent resource's attr */
+# define RA_RECONFIG (1<<4) /** Allow inline reconfiguration */
+
+# define RF_INLINE (1<<0)
+# define RF_DEFINED (1<<1)
+# define RF_NEEDSTART (1<<2) /** Used when adding/changing resources */
+# define RF_NEEDSTOP (1<<3) /** Used when deleting/changing resources */
+# define RF_COMMON (1<<4) /** " */
+# define RF_INDEPENDENT (1<<5)
+ /** Define this for a resource if it is
+ otherwise an independent subtree */
+# define RF_RECONFIG (1<<6)
+
+# define RF_INIT (1<<7)
+ /** Resource rule: Initialize this resource
+ class on startup */
+# define RF_DESTROY (1<<8) /** Resource rule flag: Destroy this
+ resource class if you delete it from
+ the configuration */
+# define RF_ENFORCE_TIMEOUTS (1<<9)
+ /** Enforce timeouts for this node */
+# define RF_NON_CRITICAL (1<<10)
+ /** stop this resource if it fails */
+# define RF_QUIESCE (1<<11) /** don't restart this resource */
+
+# define RES_STOPPED (0)
+# define RES_STARTED (1)
+# define RES_FAILED (2)
+# define RES_DISABLED (3)
+
+# ifndef SHAREDIR
+# define SHAREDIR "/usr/share/cluster"
+# endif
+
+# define RESOURCE_ROOTDIR SHAREDIR
+# define RESOURCE_TREE_ROOT "//rm"
+# define RESOURCE_BASE RESOURCE_TREE_ROOT "/resources"
+# define RESOURCE_ROOT_FMT RESOURCE_TREE_ROOT "/%s[%d]"
+
+# define RESOURCE_MAX_LEVELS 100
+
+/* Include OCF definitions */
+//#include <res-ocf.h>
+
+typedef struct _resource_attribute {
+ char *ra_name;
+ char *ra_value;
+ int ra_flags;
+ int _pad_;
+} resource_attr_t;
+
+typedef struct _resource_child {
+ char *rc_name;
+ int rc_startlevel;
+ int rc_stoplevel;
+ int rc_forbid;
+ int rc_flags;
+} resource_child_t;
+
+typedef struct _resource_act {
+ char *ra_name;
+ time_t ra_timeout;
+ time_t ra_last;
+ time_t ra_interval;
+ int ra_depth;
+ int _pad_;
+} resource_act_t;
+
+typedef struct _resource_rule {
+ list_head();
+ char *rr_type;
+ char *rr_agent;
+ char *rr_version; /** agent XML spec version; OCF-ism */
+ int rr_flags;
+ int rr_maxrefs;
+ resource_attr_t *rr_attrs;
+ resource_child_t *rr_childtypes;
+ resource_act_t *rr_actions;
+} resource_rule_t;
+
+typedef struct _resource {
+ list_head();
+ resource_rule_t *r_rule;
+ char *r_name;
+ resource_attr_t *r_attrs;
+ resource_act_t *r_actions;
+ int r_flags;
+ int r_refs;
+ int r_incarnations; /** Number of instances running locally */
+ int _pad_; /* align */
+} resource_t;
+
+typedef struct _rg_node {
+ list_head();
+ struct _rg_node *rn_child, *rn_parent;
+ resource_t *rn_resource;
+ resource_act_t *rn_actions;
+ int rn_state; /* State of this instance of rn_resource */
+ int rn_flags;
+ int rn_last_status;
+ int rn_last_depth;
+ int rn_checked;
+ int rn_pad;
+} resource_node_t;
+
+typedef struct _fod_node {
+ list_head();
+ char *fdn_name;
+ int fdn_prio;
+ int fdn_nodeid; /* on rhel4 this will be 64-bit int */
+} fod_node_t;
+
+typedef struct _fod {
+ list_head();
+ char *fd_name;
+ fod_node_t *fd_nodes;
+ int fd_flags;
+ int _pad_; /* align */
+} fod_t;
+
+/*
+ Exported Functions
+ */
+int res_flatten(xmlNode ** n, xmlNode * r, resource_node_t ** tree, resource_t * res);
+
+int expand_time(char *val);
+int store_action(resource_act_t ** actsp, char *name, int depth, int timeout, int interval);
+
+/*
+ Load/kill resource rule sets
+ */
+int load_resource_rules(const char *rpath, resource_rule_t ** rules);
+void destroy_resource_rules(resource_rule_t ** rules);
+
+/*
+ Load/kill resource sets
+ */
+int load_resources(resource_t ** reslist, resource_rule_t ** rulelist);
+void dump_resources(FILE * fp, resource_t ** reslist);
+void destroy_resources(resource_t ** list);
+
+/*
+ Construct/deconstruct resource trees
+ */
+int build_resource_tree(resource_node_t ** tree,
+ resource_rule_t ** rulelist, resource_t ** reslist);
+void destroy_resource_tree(resource_node_t ** tree);
+
+/*
+ Construct/deconstruct failover domains
+ */
+int construct_domains(fod_t ** domains);
+void deconstruct_domains(fod_t ** domains);
+
+/*
+ Handy functions
+ */
+resource_t *find_resource_by_ref(resource_t ** reslist, char *type, char *ref);
+resource_rule_t *find_rule_by_type(resource_rule_t ** rulelist, char *type);
+void res_build_name(char *, size_t, resource_t *);
+
+/*
+ Internal functions; shouldn't be needed.
+ */
+int store_attribute(resource_attr_t ** attrsp, char *name, char *value, int flags);
+
+resource_t *load_resource(resource_rule_t * rule, const char *base);
+int store_resource(resource_t ** reslist, resource_t * newres);
+void destroy_resource(resource_t * res);
+
+char *attr_value(resource_node_t * node, const char *attrname);
+char *res_attr_value(resource_t * res, const char *attrname);
+char *primary_attr_value(resource_t *);
+void *act_dup(resource_act_t * acts);
+
+#endif /* _RESLIST_H */
diff --git a/__root__/ccs-flatten/resrules.c b/__root__/ccs-flatten/resrules.c
new file mode 100644
index 0000000..c0b670d
--- /dev/null
+++ b/__root__/ccs-flatten/resrules.c
@@ -0,0 +1,971 @@
+/*
+ Copyright Red Hat, Inc. 2004-2010
+
+ 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, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/xpath.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <resgroup.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <list.h>
+#include <ctype.h>
+#include <reslist.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <sys/wait.h>
+#include <xmlconf.h>
+
+/**
+ Store a new resource rule in the given rule list.
+
+ @param rulelist List of rules to store new rule in.
+ @param newrule New rule to store.
+ @return 0 on success or -1 if rule with same name
+ already exists in rulelist
+ */
+static int
+store_rule(resource_rule_t ** rulelist, resource_rule_t * newrule)
+{
+ resource_rule_t *curr;
+
+ list_do(rulelist, curr) {
+ if (!strcmp(newrule->rr_type, curr->rr_type)) {
+ fprintf(stderr, "Error storing %s: Duplicate\n", newrule->rr_type);
+ return -1;
+ }
+
+ }
+ while (!list_done(rulelist, curr)) ;
+
+ list_insert(rulelist, newrule);
+ return 0;
+}
+
+/**
+ Obliterate a resource_rule_t structure.
+
+ @param rr Resource rule to free.
+ */
+static void
+destroy_resource_rule(resource_rule_t * rr)
+{
+ int x;
+
+ if (rr->rr_type)
+ free(rr->rr_type);
+ if (rr->rr_agent)
+ free(rr->rr_agent);
+ if (rr->rr_version)
+ free(rr->rr_version);
+
+ if (rr->rr_attrs) {
+ for (x = 0; rr->rr_attrs && rr->rr_attrs[x].ra_name; x++) {
+ free(rr->rr_attrs[x].ra_name);
+ if (rr->rr_attrs[x].ra_value)
+ free(rr->rr_attrs[x].ra_value);
+ }
+
+ free(rr->rr_attrs);
+ }
+
+ if (rr->rr_actions) {
+ for (x = 0; rr->rr_actions && rr->rr_actions[x].ra_name; x++) {
+ free(rr->rr_actions[x].ra_name);
+ }
+
+ free(rr->rr_actions);
+ }
+
+ if (rr->rr_childtypes) {
+ for (x = 0; rr->rr_childtypes && rr->rr_childtypes[x].rc_name; x++)
+ free(rr->rr_childtypes[x].rc_name);
+ free(rr->rr_childtypes);
+ }
+
+ free(rr);
+}
+
+/**
+ Destroy a list of resource rules.
+
+ @param rules List of rules to destroy.
+ */
+void
+destroy_resource_rules(resource_rule_t ** rules)
+{
+ resource_rule_t *rr;
+
+ while ((rr = *rules)) {
+ list_remove(rules, rr);
+ destroy_resource_rule(rr);
+ }
+}
+
+/**
+ Get and store the maxparents (max instances) attribute for a given
+ resource rule set.
+
+ @param doc Pre-parsed XML document pointer.
+ @param ctx Pre-allocated XML XPath context pointer.
+ @param base XPath prefix to search
+ @param rr Resource rule to store new information in.
+ */
+static void
+_get_maxparents(xmlDocPtr doc, xmlXPathContextPtr ctx, char *base, resource_rule_t * rr)
+{
+ char xpath[256];
+ char *ret = NULL;
+
+ snprintf(xpath, sizeof(xpath), "%s/attributes/@maxinstances", base);
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (ret) {
+ rr->rr_maxrefs = atoi(ret);
+ if (rr->rr_maxrefs < 0)
+ rr->rr_maxrefs = 0;
+ free(ret);
+ }
+}
+
+/**
+ Get and store a bit field.
+
+ @param doc Pre-parsed XML document pointer.
+ @param ctx Pre-allocated XML XPath context pointer.
+ @param base XPath prefix to search
+ @param rr Resource rule to store new information in.
+ */
+static void
+_get_rule_flag(xmlDocPtr doc, xmlXPathContextPtr ctx, const char *base,
+ resource_rule_t * rr, const char *flag, int bit)
+{
+ char xpath[256];
+ char *ret = NULL;
+
+ snprintf(xpath, sizeof(xpath), "%s/attributes/@%s", base, flag);
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (ret) {
+ if (atoi(ret)) {
+ rr->rr_flags |= bit;
+ } else {
+ rr->rr_flags &= ~bit;
+ }
+ free(ret);
+ }
+}
+
+/**
+ Get and store the version
+
+ @param doc Pre-parsed XML document pointer.
+ @param ctx Pre-allocated XML XPath context pointer.
+ @param base XPath prefix to search
+ @param rr Resource rule to store new information in.
+ */
+static void
+_get_version(xmlDocPtr doc, xmlXPathContextPtr ctx, char *base, resource_rule_t * rr)
+{
+ char xpath[256];
+ char *ret = NULL;
+
+ snprintf(xpath, sizeof(xpath), "%s/@version", base);
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (ret) {
+ rr->rr_version = ret;
+ free(ret);
+ }
+ rr->rr_version = NULL;
+}
+
+int
+expand_time(char *val)
+{
+ int curval, len;
+ int ret = 0;
+ char *start = val, ival[16];
+
+ if (!val)
+ return (time_t) 0;
+
+ while (start[0]) {
+
+ len = 0;
+ curval = 0;
+ memset(ival, 0, sizeof(ival));
+
+ while (isdigit(start[len])) {
+ ival[len] = start[len];
+ len++;
+ }
+
+ if (len) {
+ curval = atoi(ival);
+ } else {
+ len = 1;
+ }
+
+ switch (start[len]) {
+ case 0:
+ case 'S':
+ case 's':
+ break;
+ case 'M':
+ case 'm':
+ curval *= 60;
+ break;
+ case 'h':
+ case 'H':
+ curval *= 3600;
+ break;
+ case 'd':
+ case 'D':
+ curval *= 86400;
+ break;
+ case 'w':
+ case 'W':
+ curval *= 604800;
+ break;
+ case 'y':
+ case 'Y':
+ curval *= 31536000;
+ break;
+ default:
+ curval = 0;
+ }
+
+ ret += (time_t) curval;
+ start += len;
+ }
+
+ return ret;
+}
+
+/**
+ * Store a resource action
+ * @param actsp Action array; may be modified and returned!
+ * @param name Name of the action
+ * @param depth Resource depth (status/monitor; -1 means *ALL LEVELS*
+ * ... this means that only the highest-level check depth
+ * will ever be performed!)
+ * @param timeout Timeout (not used)
+ * @param interval Time interval for status/monitor
+ * @return 0 on success, -1 on failure
+ *
+ */
+int
+store_action(resource_act_t ** actsp, char *name, int depth, int timeout, int interval)
+{
+ int x = 0, replace = 0;
+ resource_act_t *acts = *actsp;
+
+ if (!name)
+ return -1;
+
+ if (depth < 0 && timeout < 0 && interval < 0)
+ return -1;
+
+ if (!acts) {
+ /* Can't create with anything < 0 */
+ if (depth < 0 || timeout < 0 || interval < 0)
+ return -1;
+
+ acts = malloc(sizeof(resource_act_t) * 2);
+ if (!acts)
+ return -1;
+ acts[0].ra_name = name;
+ acts[0].ra_depth = depth;
+ acts[0].ra_timeout = timeout;
+ acts[0].ra_interval = interval;
+ acts[0].ra_last = 0;
+ acts[1].ra_name = NULL;
+
+ *actsp = acts;
+ return 0;
+ }
+
+ for (x = 0; acts[x].ra_name; x++) {
+ if (!strcmp(acts[x].ra_name, name) && (depth == acts[x].ra_depth || depth == -1)) {
+ fprintf(stderr, "Replacing action '%s' depth %d: ", name, acts[x].ra_depth);
+ if (timeout >= 0) {
+ fprintf(stderr, "timeout: %d->%d ", (int)acts[x].ra_timeout, (int)timeout);
+ acts[x].ra_timeout = timeout;
+ }
+ if (interval >= 0) {
+ fprintf(stderr, "interval: %d->%d", (int)acts[x].ra_interval, (int)interval);
+ acts[x].ra_interval = interval;
+ }
+ fprintf(stderr, "\n");
+ replace = 1;
+ }
+ }
+
+ if (replace)
+ /* If we replaced something, we're done */
+ return 1;
+
+ /* Can't create with anything < 0 */
+ if (depth < 0 || timeout < 0 || interval < 0)
+ return -1;
+
+ acts = realloc(acts, sizeof(resource_act_t) * (x + 2));
+ if (!acts)
+ return -1;
+
+ acts[x].ra_name = name;
+ acts[x].ra_depth = depth;
+ acts[x].ra_timeout = timeout;
+ acts[x].ra_interval = interval;
+ acts[x].ra_last = 0;
+
+ acts[x + 1].ra_name = NULL;
+
+ *actsp = acts;
+ return 0;
+}
+
+static void
+_get_actions(xmlDocPtr doc, xmlXPathContextPtr ctx, char *base, resource_rule_t * rr)
+{
+ char xpath[256];
+ int idx = 0;
+ char *act, *ret;
+ int interval, timeout, depth;
+
+ do {
+ interval = 0;
+ depth = 0;
+ act = NULL;
+ timeout = 0;
+
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@name", base, ++idx);
+
+ act = xpath_get_one(doc, ctx, xpath);
+ if (!act)
+ break;
+
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@timeout", base, idx);
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (ret) {
+ timeout = expand_time(ret);
+ if (timeout < 0)
+ timeout = 0;
+ free(ret);
+ }
+
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@interval", base, idx);
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (ret) {
+ interval = expand_time(ret);
+ if (interval < 0)
+ interval = 0;
+ free(ret);
+ }
+
+ if (!strcmp(act, "status") || !strcmp(act, "monitor")) {
+ snprintf(xpath, sizeof(xpath), "%s/action[%d]/@depth", base, idx);
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (ret) {
+ depth = atoi(ret);
+ if (depth < 0)
+ depth = 0;
+ free(ret);
+ }
+ }
+
+ if (store_action(&rr->rr_actions, act, depth, timeout, interval) != 0)
+ free(act);
+ } while (1);
+}
+
+/**
+ Store an attribute with the given name, value, and flags in a resource_t
+ structure.
+ XXX This could be rewritten to use the list macros.
+
+ @param attrsp Attribute array to store new attribute in.
+ @param name Name of attribute (must be non-null)
+ @param value Value of attribute
+ @param flags Attribute flags, or 0 if none.
+ @return 0 on success, nonzero on error/failure
+ */
+int
+store_attribute(resource_attr_t ** attrsp, char *name, char *value, int flags)
+{
+ int x = 0;
+ resource_attr_t *attrs = *attrsp;
+
+ if (!name)
+ return -1;
+
+ if (!attrs) {
+ attrs = malloc(sizeof(resource_attr_t) * 2);
+ if (!attrs)
+ return -1;
+ attrs[0].ra_name = name;
+ attrs[0].ra_value = value;
+ attrs[0].ra_flags = flags;
+ attrs[1].ra_name = NULL;
+ attrs[1].ra_value = NULL;
+
+ *attrsp = attrs;
+ return 0;
+ }
+
+ for (x = 0; attrs[x].ra_name; x++) ;
+
+ attrs = realloc(attrs, sizeof(resource_attr_t) * (x + 2));
+ if (!attrs)
+ return -1;
+
+ /* Primary attribute goes first. This makes this interaction
+ with CCS work way faster. */
+ if (flags & RA_PRIMARY) {
+ attrs[x].ra_name = attrs[0].ra_name;
+ attrs[x].ra_value = attrs[0].ra_value;
+ attrs[x].ra_flags = attrs[0].ra_flags;
+ attrs[0].ra_name = name;
+ attrs[0].ra_value = value;
+ attrs[0].ra_flags = flags;
+ } else {
+ attrs[x].ra_name = name;
+ attrs[x].ra_value = value;
+ attrs[x].ra_flags = flags;
+ }
+ attrs[x + 1].ra_name = NULL;
+ attrs[x + 1].ra_value = NULL;
+
+ *attrsp = attrs;
+ return 0;
+}
+
+/**
+ Store a child type in the child array of a resource rule.
+ XXX Could be rewritten to use list macros.
+
+ @param childp Child array. Might be modified.
+ @param name Name of child type
+ @param start Start level
+ @param stop Stop level
+ @param forbid Do NOT allow this child type to exist
+ @param flags set to 1 to note that it was defined inline
+ @return 0 on success, nonzero on failure
+ */
+static int
+store_childtype(resource_child_t ** childp, char *name, int start, int stop, int forbid, int flags)
+{
+ int x = 0;
+ resource_child_t *child = *childp;
+
+ if (!name)
+ return -1;
+
+ if (!child) {
+ child = malloc(sizeof(resource_child_t) * 2);
+ if (!child)
+ return -1;
+ child[0].rc_name = name;
+ child[0].rc_startlevel = start;
+ child[0].rc_stoplevel = stop;
+ child[0].rc_forbid = forbid;
+ child[0].rc_flags = flags;
+ child[1].rc_name = NULL;
+
+ *childp = child;
+ return 0;
+ }
+
+ for (x = 0; child[x].rc_name; x++) ;
+
+ child = realloc(child, sizeof(resource_child_t) * (x + 2));
+ if (!child)
+ return -1;
+
+ child[x].rc_name = name;
+ child[x].rc_startlevel = start;
+ child[x].rc_stoplevel = stop;
+ child[x].rc_forbid = forbid;
+ child[x].rc_flags = flags;
+ child[x + 1].rc_name = NULL;
+
+ *childp = child;
+ return 0;
+}
+
+/**
+ Get and store attributes for a given instance of a resource rule.
+
+ @param doc Pre-parsed XML document pointer.
+ @param ctx Pre-allocated XML XPath context pointer.
+ @param base XPath prefix to search
+ @param rr Resource rule to store new information in.
+ @return 0
+ */
+static int
+_get_rule_attrs(xmlDocPtr doc, xmlXPathContextPtr ctx, const char *base, resource_rule_t * rr)
+{
+ char *ret, *attrname, *dflt = NULL, xpath[256];
+ int x, flags, primary_found = 0;
+
+ for (x = 1; 1; x++) {
+ snprintf(xpath, sizeof(xpath), "%s/parameter[%d]/@name", base, x);
+
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (!ret)
+ break;
+
+ flags = 0;
+ attrname = ret;
+
+ /*
+ See if there's a default value.
+ */
+ snprintf(xpath, sizeof(xpath), "%s/parameter[%d]/content/@default", base, x);
+ dflt = xpath_get_one(doc, ctx, xpath);
+
+ /*
+ See if this is either the primary identifier or
+ a required field.
+ */
+ snprintf(xpath, sizeof(xpath), "%s/parameter[%d]/@required", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ if ((atoi(ret) != 0) || (ret[0] == 'y'))
+ flags |= RA_REQUIRED;
+ free(ret);
+ }
+
+ /*
+ See if this is supposed to be unique
+ */
+ snprintf(xpath, sizeof(xpath), "%s/parameter[%d]/@unique", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ if ((atoi(ret) != 0) || (ret[0] == 'y'))
+ flags |= RA_UNIQUE;
+ free(ret);
+ }
+
+ snprintf(xpath, sizeof(xpath), "%s/parameter[%d]/@primary", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ if ((atoi(ret) != 0) || (ret[0] == 'y')) {
+ if (primary_found) {
+ free(ret);
+ fprintf(stderr, "Multiple primary "
+ "definitions for " "resource type %s\n", rr->rr_type);
+ return -1;
+ }
+ flags |= RA_PRIMARY;
+ primary_found = 1;
+ }
+ free(ret);
+ }
+
+ /*
+ See if this can be reconfigured on the fly without a
+ stop/start
+ */
+ snprintf(xpath, sizeof(xpath), "%s/parameter[%d]/@reconfig", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ if ((atoi(ret) != 0) || (ret[0] == 'y'))
+ flags |= RA_RECONFIG;
+ free(ret);
+ }
+
+ /*
+ See if this is supposed to be inherited
+ */
+ snprintf(xpath, sizeof(xpath), "%s/parameter[%d]/@inherit", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ flags |= RA_INHERIT;
+
+ if (flags & (RA_REQUIRED | RA_PRIMARY | RA_UNIQUE)) {
+ free(ret);
+ fprintf(stderr, "Can not inherit and be primary, " "unique, or required\n");
+ return -1;
+ }
+ /*
+ don't free ret. Store as attr value. If we had
+ a default value specified from above, free it;
+ inheritance supercedes a specified default value.
+ */
+ if (dflt)
+ free(dflt);
+ } else {
+ /*
+ Use default value, if specified, as the attribute
+ value.
+ */
+ ret = dflt;
+ }
+
+ /*
+ Store the attribute. We'll ensure all required
+ attributes are present soon.
+ */
+ if (attrname)
+ store_attribute(&rr->rr_attrs, attrname, ret, flags);
+ }
+
+ return 0;
+}
+
+/**
+ Get and store attributes for a given instance of a resource.
+
+ @param doc Pre-parsed XML document pointer.
+ @param ctx Pre-allocated XML XPath context pointer.
+ @param base XPath prefix to search
+ @param rr Resource rule to store new information in.
+ @return 0
+ */
+static int
+_get_childtypes(xmlDocPtr doc, xmlXPathContextPtr ctx, char *base, resource_rule_t * rr)
+{
+ char *ret, *childname, xpath[256];
+ int x, startlevel = 0, stoplevel = 0, forbid = 0;
+
+ for (x = 1; 1; x++) {
+ snprintf(xpath, sizeof(xpath), "%s/child[%d]/@type", base, x);
+
+ ret = xpath_get_one(doc, ctx, xpath);
+ if (!ret)
+ break;
+
+ startlevel = stoplevel = forbid = 0;
+ childname = ret;
+
+ /*
+ Try to get the start level if it exists
+ */
+ snprintf(xpath, sizeof(xpath), "%s/child[%d]/@start", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ startlevel = atoi(ret);
+ free(ret);
+ }
+
+ /*
+ Try to get the stop level if it exists
+ */
+ snprintf(xpath, sizeof(xpath), "%s/child[%d]/@stop", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ stoplevel = atoi(ret);
+ free(ret);
+ }
+
+ /*
+ Get the 'forbidden' flag if it exists
+ */
+ snprintf(xpath, sizeof(xpath), "%s/child[%d]/@forbid", base, x);
+ if ((ret = xpath_get_one(doc, ctx, xpath))) {
+ forbid = atoi(ret);
+ free(ret);
+ }
+
+ /*
+ Store the attribute. We'll ensure all required
+ attributes are present soon.
+ */
+ if (childname)
+ store_childtype(&rr->rr_childtypes, childname, startlevel, stoplevel, forbid, 0);
+ }
+
+ return 0;
+}
+
+/**
+ Read a file from a stdout pipe.
+ */
+static int
+read_pipe(int fd, char **file, size_t * length)
+{
+ char buf[4096];
+ int n, done = 0;
+
+ *file = NULL;
+ *length = 0;
+
+ while (!done) {
+
+ n = read(fd, buf, sizeof(buf));
+ if (n < 0) {
+
+ if (errno == EINTR)
+ continue;
+
+ if (*file)
+ free(*file);
+ return -1;
+ }
+
+ if (n == 0 && (!*length))
+ return 0;
+
+ if (n == 0) {
+ done = 1;
+ }
+
+ if (*file)
+ *file = realloc(*file, (*length) + n + done);
+ else
+ *file = malloc(n + done);
+
+ if (!*file)
+ return -1;
+
+ memcpy((*file) + (*length), buf, n);
+ *length += (done + n);
+ }
+
+ /* Null terminator */
+ (*file)[(*length) - 1] = 0;
+
+ return 0;
+}
+
+static xmlDocPtr
+read_resource_agent_metadata(char *filename)
+{
+ int pid;
+ int _pipe[2];
+ char *data;
+ size_t size;
+ xmlDocPtr doc;
+
+ if (pipe(_pipe) == -1)
+ return NULL;
+
+ pid = fork();
+ if (pid == -1) {
+ close(_pipe[0]);
+ close(_pipe[1]);
+ }
+
+ if (pid == 0) {
+ /* child */
+ close(0);
+ close(1);
+ close(2);
+
+ close(_pipe[0]);
+ dup2(_pipe[1], 1);
+ close(_pipe[1]);
+
+ /* exec */
+ execl(filename, filename, "meta-data", NULL);
+ exit(1);
+ }
+
+ close(_pipe[1]);
+ /* parent */
+ if (read_pipe(_pipe[0], &data, &size) == -1) {
+ close(_pipe[0]);
+ return NULL;
+ }
+
+ waitpid(pid, NULL, 0);
+ close(_pipe[0]);
+
+ if (!size)
+ return NULL;
+
+ doc = xmlParseMemory(data, size);
+ free(data);
+ return doc;
+}
+
+/**
+ Load the XML rule set for a resource and store attributes, constructing
+ a new resource_t structure.
+
+ @param filename File name to load rules from
+ @param rules Rule list to add new rules to
+ @return 0
+ */
+static int
+load_resource_rulefile(char *filename, resource_rule_t ** rules)
+{
+ resource_rule_t *rr = NULL;
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctx = NULL;
+ int ruleid = 0;
+ char *type;
+ char base[256];
+
+ doc = read_resource_agent_metadata(filename);
+ if (!doc)
+ return 0;
+ ctx = xmlXPathNewContext(doc);
+
+ do {
+ /* Look for resource types */
+ snprintf(base, sizeof(base), "/resource-agent[%d]/@name", ++ruleid);
+ type = xpath_get_one(doc, ctx, base);
+ if (!type)
+ break;
+
+ if (!strcasecmp(type, "action")) {
+ fprintf(stderr, "Error: Resource type '%s' is reserved", type);
+ free(type);
+ break;
+ }
+
+ rr = malloc(sizeof(*rr));
+ if (!rr)
+ break;
+ memset(rr, 0, sizeof(*rr));
+
+ rr->rr_flags = RF_INIT | RF_DESTROY;
+ rr->rr_type = type;
+ snprintf(base, sizeof(base), "/resource-agent[%d]", ruleid);
+
+ /*
+ First, grab the global attributes if existent
+ */
+ _get_version(doc, ctx, base, rr);
+
+ snprintf(base, sizeof(base), "/resource-agent[%d]/special[@tag=\"rgmanager\"]", ruleid);
+ _get_maxparents(doc, ctx, base, rr);
+ _get_rule_flag(doc, ctx, base, rr, "init_on_add", RF_INIT);
+ _get_rule_flag(doc, ctx, base, rr, "destroy_on_delete", RF_DESTROY);
+ rr->rr_agent = strdup(filename);
+
+ /*
+ Second, add the children fields
+ */
+ _get_childtypes(doc, ctx, base, rr);
+
+ /*
+ Get the OCF status check intervals/monitor.
+ */
+ snprintf(base, sizeof(base), "/resource-agent[%d]/actions", ruleid);
+ _get_actions(doc, ctx, base, rr);
+
+ /*
+ Last, load the attributes from our XML file and their
+ respective instantiations from CCS
+ */
+ snprintf(base, sizeof(base), "/resource-agent[%d]/parameters", ruleid);
+ if (_get_rule_attrs(doc, ctx, base, rr) < 0) {
+ destroy_resource_rule(rr);
+ rr = NULL;
+ }
+
+ if (!rr)
+ continue;
+
+ if (store_rule(rules, rr) != 0) {
+ destroy_resource_rule(rr);
+ rr = NULL;
+ }
+ } while (1);
+
+ if (ctx)
+ xmlXPathFreeContext(ctx);
+ if (doc)
+ xmlFreeDoc(doc);
+
+ return 0;
+}
+
+/**
+ Load all the resource rules we can find from our resource root
+ directory.
+
+ @param rules Rule list to create/add to
+ @return 0 on success, -1 on failure. Sucess does not
+ imply any rules have been found; only that no
+ errors were encountered.
+ */
+int
+load_resource_rules(const char *rpath, resource_rule_t ** rules)
+{
+ DIR *dir;
+ struct dirent *de;
+ char *fn, *dot;
+ char path[2048];
+ struct stat st_buf;
+
+ dir = opendir(rpath);
+ if (!dir)
+ return -1;
+
+ xmlInitParser();
+ while ((de = readdir(dir))) {
+
+ fn = basename(de->d_name);
+ if (!fn)
+ continue;
+
+ /* Ignore files with common backup extension */
+ if ((fn != NULL) && (strlen(fn) > 0) && (fn[strlen(fn) - 1] == '~'))
+ continue;
+
+ /* Ignore hidden files */
+ if (*fn == '.')
+ continue;
+
+ dot = strrchr(fn, '.');
+ if (dot) {
+ /* Ignore RPM installed save files, patches,
+ diffs, etc. */
+ if (!strncasecmp(dot, ".rpm", 4)) {
+ fprintf(stderr, "Warning: "
+ "Ignoring %s/%s: Bad extension %s\n", rpath, de->d_name, dot);
+ continue;
+ }
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", rpath, de->d_name);
+
+ if (stat(path, &st_buf) < 0)
+ continue;
+
+ if (S_ISDIR(st_buf.st_mode))
+ continue;
+
+ if (st_buf.st_mode & (S_IXUSR | S_IXOTH | S_IXGRP)) {
+ //printf("Loading resource rule from %s\n", path);
+ load_resource_rulefile(path, rules);
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+/**
+ Find a resource rule given its type.
+
+ @param rulelist Rule list to search
+ @param type Rule type identifier
+ @return Resource rule or NULL if not found.
+ */
+resource_rule_t *
+find_rule_by_type(resource_rule_t ** rulelist, char *type)
+{
+ resource_rule_t *curr = NULL;
+
+ list_do(rulelist, curr) {
+ if (!strcmp(curr->rr_type, type))
+ return curr;
+ }
+ while (!list_done(rulelist, curr)) ;
+
+ return NULL;
+}
diff --git a/__root__/ccs-flatten/restree.c b/__root__/ccs-flatten/restree.c
new file mode 100644
index 0000000..2a00427
--- /dev/null
+++ b/__root__/ccs-flatten/restree.c
@@ -0,0 +1,723 @@
+/*
+ Copyright Red Hat, Inc. 2004-2006
+
+ 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, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+
+ Fix for #193859 - relocation of a service w/o umounting file-systems
+ by Navid Sheikhol-Eslami [ navid at redhat dot com ]
+*/
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/xpath.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <list.h>
+#include <sys/wait.h>
+#include <resgroup.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <reslist.h>
+#include <assert.h>
+#include <xmlconf.h>
+
+/* XXX from resrules.c */
+int store_childtype(resource_child_t ** childp, char *name, int start,
+ int stop, int forbid, int flags);
+int _res_op(xmlNode ** xpp, xmlNode * rmp, resource_node_t ** tree, resource_t * first, char *type);
+static inline int
+
+
+_res_op_internal(xmlNode ** xpp, xmlNode * rmp, resource_node_t ** tree, resource_t * first,
+ char *type, resource_node_t * node);
+
+/* XXX from reslist.c */
+void *act_dup(resource_act_t * acts);
+
+/**
+ Fold a resource into an XML node.
+
+ @param xpp XML node pp
+ @param rmp resources block pp
+ @param node Resource tree node we're dealing with
+ @param op Operation to perform (stop/start/etc.)
+ @param depth OCF Check level/depth
+ @return Return value of script.
+ @see build_env
+ */
+static int
+res_do_flatten(xmlNode ** xpp, xmlNode * rmp, resource_node_t * node, const char *arg, int depth)
+{
+ xmlNode *n, *r;
+ resource_attr_t *ra;
+ resource_t *res = node->rn_resource;
+ char *val;
+ char buf[256];
+ int x, y;
+
+ n = xmlNewNode(NULL, (xmlChar *) node->rn_resource->r_rule->rr_type);
+
+ xmlSetProp(n, (xmlChar *) "rgmanager-meta-agent",
+ (xmlChar *) basename(node->rn_resource->r_rule->rr_agent));
+
+ /* Multiple-instance resources must be decomposed into separate
+ resources */
+ if (node->rn_resource->r_refs > 1) {
+ snprintf(buf, sizeof(buf), "%s_%d",
+ primary_attr_value(node->rn_resource), node->rn_resource->r_incarnations);
+ ++node->rn_resource->r_incarnations;
+ } else {
+ snprintf(buf, sizeof(buf), "%s", primary_attr_value(node->rn_resource));
+ }
+
+ for (x = 0; node->rn_resource->r_attrs && node->rn_resource->r_attrs[x].ra_name; x++) {
+ ra = &node->rn_resource->r_attrs[x];
+
+ if (ra->ra_flags & RA_PRIMARY) {
+ xmlSetProp(n, (xmlChar *) ra->ra_name, (xmlChar *) buf);
+ } else {
+ val = attr_value(node, res->r_attrs[x].ra_name);
+ if (!val)
+ continue;
+
+ for (y = 0; res->r_rule->rr_attrs[y].ra_name; y++) {
+ if (strcmp(ra->ra_name, res->r_rule->rr_attrs[y].ra_name))
+ continue;
+
+ if (!res->r_rule->rr_attrs[y].ra_value ||
+ strcmp(val, res->r_rule->rr_attrs[y].ra_value))
+ xmlSetProp(n, (xmlChar *) ra->ra_name, (xmlChar *) val);
+ }
+ }
+ }
+
+ if (!*xpp) {
+ /* Add top-level container */
+ *xpp = n;
+ } else {
+ if (!rmp) {
+ xmlAddChild(*xpp, n);
+ } else {
+ r = xmlNewNode(NULL, (xmlChar *) node->rn_resource->r_rule->rr_type);
+ xmlSetProp(r, (xmlChar *) "ref", (xmlChar *) primary_attr_value(node->rn_resource));
+ xmlAddChild(rmp, n);
+ xmlAddChild(*xpp, r);
+ }
+ }
+
+ return 0;
+}
+
+static inline void
+assign_restart_policy(resource_t * curres, resource_node_t * parent,
+ resource_node_t * node, char *base)
+{
+ char *val;
+ int max_restarts = 0;
+ time_t restart_expire_time = 0;
+ char tok[1024];
+
+ if (!curres || !node)
+ return;
+ if (parent && !(node->rn_flags & RF_INDEPENDENT))
+ return;
+
+ if (node->rn_flags & RF_INDEPENDENT) {
+ /* per-resource-node failures / expire times */
+ snprintf(tok, sizeof(tok), "%s/@__max_restarts", base);
+ if (conf_get(tok, &val) == 0) {
+ max_restarts = atoi(val);
+ if (max_restarts <= 0)
+ max_restarts = 0;
+ free(val);
+ }
+
+ snprintf(tok, sizeof(tok), "%s/@__restart_expire_time", base);
+ if (conf_get(tok, &val) == 0) {
+ restart_expire_time = (time_t) expand_time(val);
+ if ((int64_t) restart_expire_time <= 0)
+ restart_expire_time = 0;
+ free(val);
+ }
+ //if (restart_expire_time == 0 || max_restarts == 0)
+ return;
+ //goto out_assign;
+ }
+
+ val = (char *)res_attr_value(curres, "max_restarts");
+ if (!val)
+ return;
+ max_restarts = atoi(val);
+ if (max_restarts <= 0)
+ return;
+ val = res_attr_value(curres, "restart_expire_time");
+ if (val) {
+ restart_expire_time = (time_t) expand_time(val);
+ if ((int64_t) restart_expire_time < 0)
+ return;
+ }
+//out_assign:
+ return;
+}
+
+static inline int
+do_load_resource(char *base,
+ resource_rule_t * rule,
+ resource_node_t ** tree,
+ resource_t ** reslist, resource_node_t * parent, resource_node_t ** newnode)
+{
+ char tok[512];
+ char *ref;
+ resource_node_t *node;
+ resource_t *curres;
+ time_t failure_expire = 0;
+ int max_failures = 0;
+
+ snprintf(tok, sizeof(tok), "%s/@ref", base);
+
+ if (conf_get(tok, &ref) != 0) {
+ /* There wasn't an existing resource. See if there
+ is one defined inline */
+ curres = load_resource(rule, base);
+ if (!curres) {
+ /* No ref and no new one inline ==
+ no more of the selected type */
+ return 1;
+ }
+
+ if (store_resource(reslist, curres) != 0) {
+ fprintf(stderr, "Error storing %s resource\n", curres->r_rule->rr_type);
+ destroy_resource(curres);
+ return -1;
+ }
+
+ curres->r_flags = RF_INLINE;
+
+ } else {
+
+ curres = find_resource_by_ref(reslist, rule->rr_type, ref);
+ if (!curres) {
+ fprintf(stderr, "Error: Reference to nonexistent "
+ "resource %s (type %s)\n", ref, rule->rr_type);
+ free(ref);
+ return -1;
+ }
+
+ if (curres->r_flags & RF_INLINE) {
+ fprintf(stderr, "Error: Reference to inlined "
+ "resource %s (type %s) is illegal\n", ref, rule->rr_type);
+ free(ref);
+ return -1;
+ }
+ free(ref);
+ }
+
+ /* Load it if its max refs hasn't been exceeded */
+ if (rule->rr_maxrefs && (curres->r_refs >= rule->rr_maxrefs)) {
+ fprintf(stderr, "Warning: Max references exceeded for resource"
+ " %s (type %s)\n", curres->r_attrs[0].ra_name, rule->rr_type);
+ return -1;
+ }
+
+ node = malloc(sizeof(*node));
+ if (!node)
+ return -1;
+
+ memset(node, 0, sizeof(*node));
+
+ //printf("New resource tree node: %s:%s \n", curres->r_rule->rr_type,curres->r_attrs->ra_value);
+
+ node->rn_child = NULL;
+ node->rn_parent = parent;
+ node->rn_resource = curres;
+ node->rn_state = RES_STOPPED;
+ node->rn_flags = 0;
+ node->rn_actions = (resource_act_t *) act_dup(curres->r_actions);
+
+ if (parent) {
+ /* Independent subtree / non-critical for top-level is
+ * not useful and can interfere with restart thresholds for
+ * non critical resources */
+ snprintf(tok, sizeof(tok), "%s/@__independent_subtree", base);
+ if (conf_get(tok, &ref) == 0) {
+ if (atoi(ref) == 1 || strcasecmp(ref, "yes") == 0)
+ node->rn_flags |= RF_INDEPENDENT;
+ if (atoi(ref) == 2 || strcasecmp(ref, "non-critical") == 0) {
+ curres->r_flags |= RF_NON_CRITICAL;
+ }
+ free(ref);
+ }
+ }
+
+ snprintf(tok, sizeof(tok), "%s/@__enforce_timeouts", base);
+ if (conf_get(tok, &ref) == 0) {
+ if (atoi(ref) > 0 || strcasecmp(ref, "yes") == 0)
+ node->rn_flags |= RF_ENFORCE_TIMEOUTS;
+ free(ref);
+ }
+
+ /* per-resource-node failures / expire times */
+ snprintf(tok, sizeof(tok), "%s/@__max_failures", base);
+ if (conf_get(tok, &ref) == 0) {
+ max_failures = atoi(ref);
+ if (max_failures < 0)
+ max_failures = 0;
+ free(ref);
+ }
+
+ snprintf(tok, sizeof(tok), "%s/@__failure_expire_time", base);
+ if (conf_get(tok, &ref) == 0) {
+ failure_expire = (time_t) expand_time(ref);
+ if ((int64_t) failure_expire < 0)
+ failure_expire = 0;
+ free(ref);
+ }
+
+ if (max_failures && failure_expire) {
+ /*
+ node->rn_failure_counter = restart_init(failure_expire,
+ max_failures);
+ */
+ }
+
+ curres->r_refs++;
+
+ if (curres->r_refs > 1 && (curres->r_flags & RF_NON_CRITICAL)) {
+ res_build_name(tok, sizeof(tok), curres);
+ fprintf(stderr, "Non-critical flag for %s is being cleared due to multiple references.\n",
+ tok);
+ curres->r_flags &= ~RF_NON_CRITICAL;
+ }
+
+ if (curres->r_flags & RF_NON_CRITICAL) {
+ /* Independent subtree is implied if a
+ * resource is non-critical
+ */
+ node->rn_flags |= RF_NON_CRITICAL | RF_INDEPENDENT;
+
+ }
+
+ assign_restart_policy(curres, parent, node, base);
+
+ *newnode = node;
+
+ list_insert(tree, node);
+
+ return 0;
+}
+
+/**
+ Build the resource tree. If a new resource is defined inline, add it to
+ the resource list. All rules, however, must have already been read in.
+
+ @param tree Tree to modify/insert on to
+ @param parent Parent node, if one exists.
+ @param rule Rule surrounding the new node
+ @param rulelist List of all rules allowed in the tree.
+ @param reslist List of all currently defined resources
+ @param base Base CCS path.
+ @see destroy_resource_tree
+ */
+#define RFL_FOUND 0x1
+#define RFL_FORBID 0x2
+static int
+build_tree(resource_node_t ** tree,
+ resource_node_t * parent,
+ resource_rule_t * rule, resource_rule_t ** rulelist, resource_t ** reslist, char *base)
+{
+ char tok[512];
+ resource_rule_t *childrule;
+ resource_node_t *node;
+ char *ref;
+ char *tmp;
+ int ccount = 0, x = 0, y = 0, flags = 0;
+
+ //printf("DESCEND: %s / %s\n", rule?rule->rr_type:"(none)", base);
+
+ /* Pass 1: typed / defined children */
+ for (y = 0; rule && rule->rr_childtypes && rule->rr_childtypes[y].rc_name; y++) {
+
+ flags = 0;
+ list_for(rulelist, childrule, x) {
+ if (strcmp(rule->rr_childtypes[y].rc_name, childrule->rr_type))
+ continue;
+
+ flags |= RFL_FOUND;
+
+ if (rule->rr_childtypes[y].rc_forbid)
+ flags |= RFL_FORBID;
+
+ break;
+ }
+
+ if (flags & RFL_FORBID)
+ /* Allow all *but* forbidden */
+ continue;
+
+ if (!(flags & RFL_FOUND))
+ /* Not found? Wait for pass 2 */
+ continue;
+
+ //printf("looking for %s %s @ %s\n",
+ //rule->rr_childtypes[y].rc_name,
+ //childrule->rr_type, base);
+ for (x = 1;; x++) {
+
+ /* Search for base/type[x]/@ref - reference an existing
+ resource */
+ snprintf(tok, sizeof(tok), "%s/%s[%d]", base, childrule->rr_type, x);
+
+ flags = 1;
+ switch (do_load_resource(tok, childrule, tree, reslist, parent, &node)) {
+ case -1:
+ continue;
+ case 1:
+ /* 1 == no more */
+ //printf("No resource found @ %s\n", tok);
+ flags = 0;
+ break;
+ case 0:
+ break;
+ }
+ if (!flags)
+ break;
+
+ /* Got a child :: bump count */
+ snprintf(tok, sizeof(tok), "%s/%s[%d]", base, childrule->rr_type, x);
+
+ /* Kaboom */
+ build_tree(&node->rn_child, node, childrule, rulelist, reslist, tok);
+
+ }
+ }
+
+ /* Pass 2: untyped children */
+ for (ccount = 1;; ccount++) {
+ snprintf(tok, sizeof(tok), "%s/child::*[%d]", base, ccount);
+
+ if (conf_get(tok, &ref) != 0) {
+ /* End of the line. */
+ //printf("End of the line: %s\n", tok);
+ break;
+ }
+
+ tmp = strchr(ref, '=');
+ if (tmp) {
+ *tmp = 0;
+ } else {
+ /* no = sign... bad */
+ free(ref);
+ continue;
+ }
+
+ /* Find the resource rule */
+ flags = 0;
+ list_for(rulelist, childrule, x) {
+ if (!strcasecmp(childrule->rr_type, ref)) {
+ /* Ok, matching rule found */
+ flags = 1;
+ break;
+ }
+ }
+ /* No resource rule matching the child? Press on... */
+ if (!flags) {
+ free(ref);
+ continue;
+ }
+
+ flags = 0;
+ /* Don't descend on anything we should have already picked
+ up on in the above loop */
+ for (y = 0; rule && rule->rr_childtypes && rule->rr_childtypes[y].rc_name; y++) {
+ /* SKIP defined child types of any type */
+ if (strcmp(rule->rr_childtypes[y].rc_name, ref))
+ continue;
+ if (rule->rr_childtypes[y].rc_flags == 0) {
+ /* 2 = defined as a real child */
+ flags = 2;
+ break;
+ }
+
+ flags = 1;
+ break;
+ }
+
+ free(ref);
+ if (flags == 2)
+ continue;
+
+ x = 1;
+ switch (do_load_resource(tok, childrule, tree, reslist, parent, &node)) {
+ case -1:
+ continue;
+ case 1:
+ /* no more found */
+ x = 0;
+ fprintf(stderr, "No resource found @ %s\n", tok);
+ break;
+ case 0:
+ /* another is found */
+ break;
+ }
+ if (!x) /* no more found */
+ break;
+
+ /* childrule = rule set of this child at this point */
+ /* tok = set above; if we got this far, we're all set */
+ /* Kaboom */
+
+ build_tree(&node->rn_child, node, childrule, rulelist, reslist, tok);
+ }
+
+ //printf("ASCEND: %s / %s\n", rule?rule->rr_type:"(none)", base);
+ return 0;
+}
+
+/**
+ Set up to call build_tree. Hides the nastiness from the user.
+
+ @param tree Tree pointer. Should start as a pointer to NULL.
+ @param rulelist List of all rules allowed
+ @param reslist List of all currently defined resources
+ @return 0
+ @see build_tree destroy_resource_tree
+ */
+int
+build_resource_tree(resource_node_t ** tree, resource_rule_t ** rulelist, resource_t ** reslist)
+{
+ resource_node_t *root = NULL;
+ char tok[512];
+
+ snprintf(tok, sizeof(tok), "%s", RESOURCE_TREE_ROOT);
+
+ /* Find and build the list of root nodes */
+ build_tree(&root, NULL, NULL /*curr */ , rulelist, reslist, tok);
+
+ if (root)
+ *tree = root;
+
+ return 0;
+}
+
+/**
+ Deconstruct a resource tree.
+
+ @param tree Tree to obliterate.
+ @see build_resource_tree
+ */
+void
+destroy_resource_tree(resource_node_t ** tree)
+{
+ resource_node_t *node;
+
+ while ((node = *tree)) {
+ if ((*tree)->rn_child)
+ destroy_resource_tree(&(*tree)->rn_child);
+
+ list_remove(tree, node);
+
+ if (node->rn_actions) {
+ free(node->rn_actions);
+ }
+ free(node);
+ }
+}
+
+static inline int
+_do_child_levels(xmlNode ** xpp, xmlNode * rmp, resource_node_t ** tree, resource_t * first)
+{
+ resource_node_t *node = *tree;
+ resource_t *res = node->rn_resource;
+ resource_rule_t *rule = res->r_rule;
+ int l, lev, x, rv = 0;
+
+ for (l = 1; l <= RESOURCE_MAX_LEVELS; l++) {
+
+ for (x = 0; rule->rr_childtypes && rule->rr_childtypes[x].rc_name; x++) {
+
+ lev = rule->rr_childtypes[x].rc_startlevel;
+
+ if (!lev || lev != l)
+ continue;
+
+ /* Do op on all children at our level */
+ rv |= _res_op(xpp, rmp, &node->rn_child, first, rule->rr_childtypes[x].rc_name);
+
+ if (rv & SFL_FAILURE)
+ return rv;
+ }
+
+ if (rv != 0)
+ return rv;
+ }
+
+ return rv;
+}
+
+static inline int
+_xx_child_internal(xmlNode ** xpp, xmlNode * rmp, resource_node_t * node, resource_t * first,
+ resource_node_t * child)
+{
+ int x;
+ resource_rule_t *rule = node->rn_resource->r_rule;
+
+ for (x = 0; rule->rr_childtypes && rule->rr_childtypes[x].rc_name; x++) {
+ if (!strcmp(child->rn_resource->r_rule->rr_type, rule->rr_childtypes[x].rc_name)) {
+ if (rule->rr_childtypes[x].rc_startlevel || rule->rr_childtypes[x].rc_stoplevel) {
+ return 0;
+ }
+ }
+ }
+
+ return _res_op_internal(xpp, rmp, &child, first, child->rn_resource->r_rule->rr_type, child);
+}
+
+static inline int
+_do_child_default_level(xmlNode ** xpp, xmlNode * rmp, resource_node_t ** tree, resource_t * first)
+{
+ resource_node_t *node = *tree, *child;
+ int y, rv = 0;
+
+ list_for(&node->rn_child, child, y) {
+ rv |= _xx_child_internal(xpp, rmp, node, first, child);
+
+ if (rv & SFL_FAILURE)
+ return rv;
+ }
+
+ return rv;
+}
+
+/**
+ Nasty codependent function. Perform an operation by numerical level
+ at some point in the tree. This allows indirectly-dependent resources
+ (such as IP addresses and user scripts) to have ordering without requiring
+ a direct dependency.
+
+ @param tree Resource tree to search/perform operations on
+ @param first Resource we're looking to perform the operation on,
+ if one exists.
+ @param ret Unused, but will be used to store status information
+ such as resources consumed, etc, in the future.
+ @param op Operation to perform if either first is found,
+ or no first is declared (in which case, all nodes
+ in the subtree).
+ @see _res_op res_exec
+ */
+static int
+_res_op_by_level(xmlNode ** xpp, xmlNode * rmp, resource_node_t ** tree, resource_t * first)
+{
+ resource_node_t *node = *tree;
+ resource_t *res = node->rn_resource;
+ resource_rule_t *rule = res->r_rule;
+ int rv = 0;
+
+ if (!rule->rr_childtypes)
+ return _res_op(xpp, rmp, &node->rn_child, first, NULL);
+
+ rv |= _do_child_levels(xpp, rmp, tree, first);
+ if (rv & SFL_FAILURE)
+ return rv;
+
+ /* default level after specified ones */
+ rv |= _do_child_default_level(xpp, rmp, tree, first);
+
+ return rv;
+}
+
+/**
+ Nasty codependent function. Perform an operation by type for all siblings
+ at some point in the tree. This allows indirectly-dependent resources
+ (such as IP addresses and user scripts) to have ordering without requiring
+ a direct dependency.
+
+ @param tree Resource tree to search/perform operations on
+ @param first Resource we're looking to perform the operation on,
+ if one exists.
+ @param type Type to look for.
+ @see _res_op_by_level res_exec
+ */
+static inline int
+_res_op_internal(xmlNode ** xpp, xmlNode * rmp,
+ resource_node_t __attribute__ ((unused)) ** tree,
+ resource_t * first, char *type, resource_node_t * node)
+{
+ int rv = 0, me;
+
+ /* Restore default operation. */
+
+ /* If we're starting by type, do that funky thing. */
+ if (type && strlen(type) && strcmp(node->rn_resource->r_rule->rr_type, type))
+ return 0;
+
+ /* If the resource is found, all nodes in the subtree must
+ have the operation performed as well. */
+ me = !first || (node->rn_resource == first);
+
+ /* Start starts before children */
+ if (me) {
+
+ rv = res_do_flatten(xpp, rmp, node, NULL, 0);
+
+ }
+
+ if (node->rn_child) {
+ rv |= _res_op_by_level(xpp, rmp, &node, me ? NULL : first);
+ }
+
+ return rv;
+}
+
+/**
+ Nasty codependent function. Perform an operation by type for all siblings
+ at some point in the tree. This allows indirectly-dependent resources
+ (such as IP addresses and user scripts) to have ordering without requiring
+ a direct dependency.
+
+ @param tree Resource tree to search/perform operations on
+ @param first Resource we're looking to perform the operation on,
+ if one exists.
+ @param type Type to look for.
+ @see _res_op_by_level res_exec
+ */
+int
+_res_op(xmlNode ** xpp, xmlNode * rmp, resource_node_t ** tree, resource_t * first, char *type)
+{
+ resource_node_t *node;
+ int count = 0, rv = 0;
+
+ list_for(tree, node, count) {
+ rv |= _res_op_internal(xpp, rmp, tree, first, type, node);
+
+ if (rv & SFL_FAILURE)
+ return rv;
+ }
+
+ return rv;
+}
+
+/**
+ Flatten resources for a service and return the pointer to it.
+
+ @param tree Tree to search for our resource.
+ @param res Resource to start/stop
+ @param ret Unused
+ */
+int
+res_flatten(xmlNode ** xpp, xmlNode * rmp, resource_node_t ** tree, resource_t * res)
+{
+ return _res_op(xpp, rmp, tree, res, NULL);
+}
diff --git a/__root__/ccs-flatten/xmlconf.c b/__root__/ccs-flatten/xmlconf.c
new file mode 100644
index 0000000..92a7245
--- /dev/null
+++ b/__root__/ccs-flatten/xmlconf.c
@@ -0,0 +1,139 @@
+/*
+ Copyright Red Hat, Inc. 2004
+
+ 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, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+#include <stdio.h>
+#include <assert.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <string.h>
+#include <xmlconf.h>
+
+static xmlDocPtr conf_doc = NULL;
+static const char *conffile = "/etc/cluster/cluster.conf";
+
+/**
+ Execute an XPath query, returning the first match. Multiple matches are
+ ignored. Please be advised that this is quite inefficient.
+
+ @param doc Loaded XML document to search
+ @param ctx Predefined XML XPath context
+ @param query Query to execute.
+ @return newly allocated pointer to value or NULL if not found.
+ */
+char *
+xpath_get_one(xmlDocPtr __attribute__ ((unused)) doc, xmlXPathContextPtr ctx, char *query)
+{
+ char *val = NULL, *ret = NULL;
+ xmlXPathObjectPtr obj;
+ xmlNodePtr node;
+ size_t size = 0;
+ int nnv = 0;
+
+ obj = xmlXPathEvalExpression((unsigned char *)query, ctx);
+ if (!obj)
+ return NULL;
+ if (!obj->nodesetval)
+ goto out;
+ if (obj->nodesetval->nodeNr <= 0)
+ goto out;
+
+ node = obj->nodesetval->nodeTab[0];
+ if (!node)
+ goto out;
+
+ if (((node->type == XML_ATTRIBUTE_NODE) && strstr(query, "@*")) ||
+ ((node->type == XML_ELEMENT_NODE) && strstr(query, "child::*"))) {
+ if (node->children && node->children->content)
+ size = strlen((char *)node->children->content) + strlen((char *)node->name) + 2;
+ else
+ size = strlen((char *)node->name) + 2;
+ nnv = 1;
+ } else {
+ if (node->children && node->children->content) {
+ size = strlen((char *)node->children->content) + 1;
+ } else {
+ goto out;
+ }
+ }
+
+ val = (char *)malloc(size);
+ if (!val)
+ goto out;
+ memset(val, 0, size);
+ if (nnv) {
+ sprintf(val, "%s=%s", node->name, (node->children && node->children->content) ?
+ (char *)node->children->content : "");
+ } else {
+ sprintf(val, "%s", (node->children && node->children->content) ? node->children->content :
+ node->name);
+ }
+
+ ret = val;
+ out:
+ xmlXPathFreeObject(obj);
+
+ return ret;
+}
+
+int
+conf_open(void)
+{
+ xmlInitParser();
+ conf_doc = xmlParseFile(conffile);
+ if (!conf_doc)
+ return -1;
+ return 0;
+}
+
+xmlDocPtr
+conf_get_doc(void)
+{
+ return conf_doc;
+}
+
+int
+conf_close(void)
+{
+ xmlFreeDoc(conf_doc);
+ conf_doc = NULL;
+ return 0;
+}
+
+void
+conf_setconfig(char *path)
+{
+ conffile = path;
+}
+
+int
+conf_get(char *path, char **value)
+{
+ char *foo;
+ xmlXPathContextPtr ctx;
+
+ ctx = xmlXPathNewContext(conf_doc);
+ foo = xpath_get_one(conf_doc, ctx, path);
+ xmlXPathFreeContext(ctx);
+
+ if (foo) {
+ *value = foo;
+ return 0;
+ }
+ return 1;
+}
diff --git a/__root__/ccs-flatten/xmlconf.h b/__root__/ccs-flatten/xmlconf.h
new file mode 100644
index 0000000..5df7ce0
--- /dev/null
+++ b/__root__/ccs-flatten/xmlconf.h
@@ -0,0 +1,11 @@
+#ifndef _RG_LOCKS_H
+# define _RG_LOCKS_H
+
+int conf_open(void);
+int conf_close(void);
+void conf_setconfig(char *path);
+int conf_get(char *path, char **value);
+xmlDocPtr conf_get_doc(void);
+char *xpath_get_one(xmlDocPtr doc, xmlXPathContextPtr ctx, char *query);
+
+#endif