public inbox for cluster-cvs@sourceware.org
help / color / mirror / Atom feed
* master - config: move ccs/ccs_tool to config/tools/ccs_tool
@ 2008-08-14 16:00 Fabio M. Di Nitto
  0 siblings, 0 replies; only message in thread
From: Fabio M. Di Nitto @ 2008-08-14 16:00 UTC (permalink / raw)
  To: cluster-cvs-relay

Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=c84e65d62b7ff3fffbf02985a39f187bf59eb541
Commit:        c84e65d62b7ff3fffbf02985a39f187bf59eb541
Parent:        3fc1b89bcf0f0b2bfd53da2541e023865619cf24
Author:        Fabio M. Di Nitto <fdinitto@redhat.com>
AuthorDate:    Thu Aug 7 06:40:01 2008 +0200
Committer:     Fabio M. Di Nitto <fdinitto@redhat.com>
CommitterDate: Thu Aug 14 15:18:02 2008 +0200

config: move ccs/ccs_tool to config/tools/ccs_tool

ccs_tool is now a generic tool for handling configuration.

Move it to a proper location.

Signed-off-by: Fabio M. Di Nitto <fdinitto@redhat.com>
---
 ccs/Makefile                     |    2 +-
 ccs/ccs_tool/Makefile            |   56 --
 ccs/ccs_tool/ccs_tool.c          |  353 -----------
 ccs/ccs_tool/editconf.c          | 1261 --------------------------------------
 ccs/ccs_tool/editconf.h          |    8 -
 ccs/ccs_tool/update.c            |  673 --------------------
 ccs/ccs_tool/update.h            |    6 -
 ccs/man/Makefile                 |    8 +-
 ccs/man/ccs_test.8               |  132 ----
 ccs/man/ccs_tool.8               |  185 ------
 config/tools/Makefile            |    2 +-
 config/tools/ccs_tool/Makefile   |   56 ++
 config/tools/ccs_tool/ccs_tool.c |  353 +++++++++++
 config/tools/ccs_tool/editconf.c | 1261 ++++++++++++++++++++++++++++++++++++++
 config/tools/ccs_tool/editconf.h |    8 +
 config/tools/ccs_tool/update.c   |  673 ++++++++++++++++++++
 config/tools/ccs_tool/update.h   |    6 +
 config/tools/man/Makefile        |    8 +-
 config/tools/man/ccs_test.8      |  132 ++++
 config/tools/man/ccs_tool.8      |  185 ++++++
 20 files changed, 2684 insertions(+), 2684 deletions(-)

diff --git a/ccs/Makefile b/ccs/Makefile
index cb36c8c..ec46665 100644
--- a/ccs/Makefile
+++ b/ccs/Makefile
@@ -1,4 +1,4 @@
 include ../make/defines.mk
 include $(OBJDIR)/make/passthrough.mk
 
-SUBDIRS=libccscompat daemon ccsais ccs_tool man
+SUBDIRS=libccscompat daemon ccsais man
diff --git a/ccs/ccs_tool/Makefile b/ccs/ccs_tool/Makefile
deleted file mode 100644
index ff77b9f..0000000
--- a/ccs/ccs_tool/Makefile
+++ /dev/null
@@ -1,56 +0,0 @@
-TARGET1 = ccs_tool
-TARGET2 = ccs_test
-
-SBINDIRT = $(TARGET1)
-SBINSYMT = $(TARGET2)
-
-include ../../make/defines.mk
-
-ifdef legacy_code
-all: depends ${TARGET1} ${TARGET2}
-else
-all: ${TARGET1} ${TARGET2}
-endif
-
-include $(OBJDIR)/make/cobj.mk
-include $(OBJDIR)/make/clean.mk
-include $(OBJDIR)/make/install.mk
-include $(OBJDIR)/make/uninstall.mk
-
-OBJS =	ccs_tool.o \
-	editconf.o
-
-ifdef legacy_code
-OBJS += update.o
-endif
-
-CFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
-CFLAGS += -I${cmanincdir} `xml2-config --cflags`
-CFLAGS += -I${ccsincdir} -I$(S)/../include
-CFLAGS += -I$(S)/../libccscompat
-CFLAGS += -I${incdir}
-
-LDFLAGS += -L${cmanlibdir} -lcman
-ifdef legacy_code
-LDFLAGS += -L../libccscompat -lccscompat
-LDDEPS += ../libccscompat/libccscompat.a
-else
-LDFLAGS += -L${ccslibdir} -lccs
-endif
-LDFLAGS += `xml2-config --libs`
-LDFLAGS += -L${libdir}
-
-${TARGET1}: ${OBJS} ${LDDEPS}
-	$(CC) -o $@ $^ $(LDFLAGS)
-
-${TARGET2}: ${TARGET1}
-	ln -sf ${TARGET1} ${TARGET2}
-
-ifdef legacy_code
-depends:
-	$(MAKE) -C ../libccscompat all
-endif
-
-clean: generalclean
-
--include $(OBJS:.o=.d)
diff --git a/ccs/ccs_tool/ccs_tool.c b/ccs/ccs_tool/ccs_tool.c
deleted file mode 100644
index c05a07e..0000000
--- a/ccs/ccs_tool/ccs_tool.c
+++ /dev/null
@@ -1,353 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <string.h>
-#include <errno.h>
-
-#include "copyright.cf"
-#include "editconf.h"
-#ifdef LEGACY_CODE
-#include "update.h"
-#include "libccscompat.h"
-#else
-#include "ccs.h"
-#endif
-
-
-/*
- * Old libccs retruned -error (mostly!) but didn't set errno (sigh)
- * New libccs sets errno correctly
- */
-static char *errstring(int retcode)
-{
-#ifdef LEGACY_CODE
-	return strerror(retcode);
-#else
-	return strerror(errno);
-#endif
-}
-
-static void tool_print_usage(FILE *stream);
-
-int globalverbose=0;
-
-static void test_print_usage(FILE *stream);
-
-static int test_main(int argc, char *argv[], int old_format){
-  int desc=0;
-  int i=0;
-  int error = 0;
-  int force = 0, blocking = 0;
-  char *str=NULL;
-  char *cluster_name = NULL;
-
-  if(argc <= 1){
-    test_print_usage(stderr);
-    exit(EXIT_FAILURE);
-  }
-
-  for(i=1; i < argc; i++){
-    if(!strcmp(argv[i], "-h")){
-      test_print_usage(stdout);
-      exit(EXIT_SUCCESS);
-    }
-    if(!strcmp(argv[i], "-V")){
-      printf("%s %s (built %s %s)\n", argv[0], RELEASE_VERSION, __DATE__, __TIME__);
-      printf("%s\n", REDHAT_COPYRIGHT);
-      exit(EXIT_SUCCESS);
-    }
-  }
-
-  if(!strcmp(argv[1], "connect")){
-    for(i=2; i < argc; i++){
-      if(!strcmp(argv[i], "force")){
-	printf("Force is set.\n");
-	force = 1;
-      } else if(!strcmp(argv[i], "block")){
-	printf("Blocking is set.\n");
-	blocking = 1;
-      } else {
-	cluster_name = argv[i];
-	printf("Setting cluster name to %s\n", cluster_name);
-      }
-    }
-    if(blocking && !force){
-      fprintf(stderr, "Blocking can only be used with \"force\".\n");
-      exit(EXIT_FAILURE);
-    }
-    if(force){
-      desc = ccs_force_connect(cluster_name, blocking);
-    } else {
-      if(cluster_name){
-	fprintf(stderr, "A cluster name can only be specified when using 'force'.\n");
-	exit(EXIT_FAILURE);
-      }
-      desc = ccs_connect();
-    }
-    if(desc < 0){
-      fprintf(stderr, "ccs_connect failed: %s\n", errstring(-desc));
-      exit(EXIT_FAILURE);
-    } else {
-      printf("Connect successful.\n");
-      printf(" Connection descriptor = %d\n", desc);
-#ifndef LEGACY_CODE
-      ccs_disconnect(desc);
-#endif
-    }
-  }
-  else if(!strcmp(argv[1], "disconnect")){
-    if(argc < 3){
-      fprintf(stderr, "Wrong number of arguments.\n");
-      exit(EXIT_FAILURE);
-    }
-#ifdef LEGACY_CODE
-    desc = atoi(argv[2]);
-#else
-    desc = ccs_connect();
-#endif
-    if((error = ccs_disconnect(desc))){
-      fprintf(stderr, "ccs_disconnect failed: %s\n", errstring(-error));
-      exit(EXIT_FAILURE);
-    } else {
-      printf("Disconnect successful.\n");
-    }
-  }
-  else if(!strcmp(argv[1], "get")){
-    if(argc < 4){
-      fprintf(stderr, "Wrong number of arguments.\n");
-      exit(EXIT_FAILURE);
-    }
-#ifdef LEGACY_CODE
-    desc = atoi(argv[2]);
-#else
-    desc = ccs_connect();
-#endif
-    if((desc < 0) || (error = ccs_get(desc, argv[3], &str))){
-      fprintf(stderr, "ccs_get failed: %s\n", errstring(-error));
-      exit(EXIT_FAILURE);
-    } else {
-	    if (old_format) {
-		    printf("Get successful.\n");
-		    printf(" Value = <%s>\n", str);
-	    }
-	    else {
-		    printf("%s\n", str);
-	    }
-      if(str)free(str);
-#ifndef LEGACY_CODE
-      ccs_disconnect(desc);
-#endif
-    }
-  }
-  else {
-    fprintf(stderr, "Unknown command: %s\n", argv[1]);
-    exit(EXIT_FAILURE);
-  }
-
-  exit(EXIT_SUCCESS);
-}
-
-static void test_print_usage(FILE *stream)
-{
-	fprintf(stream,
-	  "Usage:\n"
-	  "\n"
-	  "ccs_test [Options] <Command>\n"
-	  "\n"
-	  "Options:\n"
-	  "  -h                        Print usage.\n"
-	  "  -V                        Print version information.\n"
-	  "\n"
-	  "Commands:\n"
-	  "  connect <force> <block>   Connect to CCS and return connection descriptor.\n"
-	  "  disconnect <desc>         Disconnect from CCS.\n"
-	  "  get <desc> <request>      Get a value from CCS.\n"
-	  );
-}
-
-#ifndef LEGACY_CODE
-static int xpath_query(int argc, char **argv)
-{
-	int handle;
-	char *ret;
-	int i;
-
-	if (argc < 2) {
-		fprintf(stderr,
-			"Usage:\n"
-			"\n"
-			"ccs_tool query <xpath query>\n");
-		return 1;
-	}
-
-	/* Tell the library we want full XPath parsing */
-	fullxpath = 1;
-
-	handle = ccs_connect();
-
-	/* Process all the queries on the command-line */
-	for (i=1; i<argc; i++) {
-		if (!ccs_get(handle, argv[1], &ret)) {
-			printf("%s\n", ret);
-			free(ret);
-		}
-		else {
-			fprintf(stderr, "Query failed: %s\n", strerror(errno));
-			ccs_disconnect(handle);
-			return -1;
-		}
-	}
-	ccs_disconnect(handle);
-	return 0;
-}
-#endif
-
-static int tool_main(int argc, char *argv[])
-{
-  optind = 1;
-
-  if (argc < 2 || !strcmp(argv[optind], "-h")) {
-      tool_print_usage(stdout);
-      exit(EXIT_SUCCESS);
-  }
-  if (!strcmp(argv[optind], "-V")) {
-      printf("%s %s (built %s %s)\n", argv[0], RELEASE_VERSION,
-	     __DATE__, __TIME__);
-      printf("%s\n", REDHAT_COPYRIGHT);
-      exit(EXIT_SUCCESS);
-  }
-
-  if(optind < argc){
-    if(!strcmp(argv[optind], "-verbose")){
-      optind++;
-      globalverbose=1;
-    }
-    if(!strcmp(argv[optind], "help")){
-      tool_print_usage(stdout);
-      exit(EXIT_SUCCESS);
-    }
-#ifdef LEGACY_CODE
-    /* Update is meaningless now */
-    else if(!strcmp(argv[optind], "update")){
-      if(optind+1 >= argc){
-	fprintf(stderr, "Too few arguments.\n"
-		"Try 'ccs_tool help' for help.\n");
-	exit(EXIT_FAILURE);
-      }
-      if(update(argv[optind+1])){
-	fprintf(stderr, "\nFailed to update config file.\n");
-	exit(EXIT_FAILURE);
-      }
-      printf("\nUpdate complete.\n");
-    }
-    /* Do old ccs queries */
-    else if(!strcmp(argv[optind], "query")){
-	    char *new_argv[argc+2];
-	    int i;
-
-	    new_argv[0] = "ccs_test";
-	    new_argv[1] = "get";
-	    new_argv[2] = "0"; /* Dummy connection ID */
-	    for (i=2; i<argc; i++)
-		    new_argv[1+i] = argv[i];
-
-	    return test_main(argc+1, new_argv, 0);
-    }
-#else
-    else if(!strcmp(argv[optind], "query")){
-	    return xpath_query(argc-1, argv+1);
-    }
-#endif
-    else if(!strcmp(argv[optind], "addnode")){
-	    add_node(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-    else if(!strcmp(argv[optind], "delnode")){
-	    del_node(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-    else if(!strcmp(argv[optind], "addfence")){
-	    add_fence(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-    else if(!strcmp(argv[optind], "delfence")){
-	    del_fence(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-    else if(!strcmp(argv[optind], "lsnode")){
-	    list_nodes(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-    else if(!strcmp(argv[optind], "lsfence")){
-	    list_fences(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-    else if(!strcmp(argv[optind], "create")){
-	    create_skeleton(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-    else if(!strcmp(argv[optind], "addnodeids")){
-	    add_nodeids(argc-1, argv+1);
-	    exit(EXIT_SUCCESS);
-    }
-
-    else {
-      fprintf(stderr, "Unknown command, %s.\n"
-	      "Try 'ccs_tool help' for help.\n", argv[optind]);
-      exit(EXIT_FAILURE);
-    }
-  } else {
-    fprintf(stderr, "Too few arguments.\n"
-	    "Try 'ccs_tool help' for help.\n");
-    exit(EXIT_FAILURE);
-  }
-  exit(EXIT_SUCCESS);
-}
-
-static void tool_print_usage(FILE *stream){
-  fprintf(stream,
-	  "Usage:\n"
-	  "  ccs_tool [options] <command>\n"
-	  "\n"
-	  "Options:\n"
-	  "  -verbose            Make some operations print more details.\n"
-	  "  -h                  Print this usage and exit.\n"
-	  "  -V                  Print version information and exit.\n"
-	  "\n"
-	  "Commands:\n"
-	  "  help                Print this usage and exit.\n"
-#ifdef LEGACY_CODE
-	  "  update <xml file>   Tells ccsd to upgrade to new config file version.\n"
-	  "  query <ccs query>   Query the cluster configuration.\n"
-#else
-	  "  query <xpath query> Query the cluster configuration.\n"
-#endif
-	  "  addnode <node>      Add a node\n"
-          "  delnode <node>      Delete a node\n"
-          "  lsnode              List nodes\n"
-          "  lsfence             List fence devices\n"
-	  "  addfence <fencedev> Add a new fence device\n"
-	  "  delfence <fencedev> Delete a fence device\n"
-	  "  create              Create a skeleton config file\n"
-	  "  addnodeids          Assign node ID numbers to all nodes\n"
-	  "\n");
-}
-
-
-int main(int argc, char *argv[])
-{
-	char *name = strdup(argv[0]);
-
-	/*
-	 * Don't be anal about the binary name.
-	 * We expect either 'ccs_tool' or 'ccs_test',
-	 * but interpret anything other than 'ccs_test'
-	 * as 'ccs_tool'.
-	 * That's not a bug, it's a feature.
-	 */
-
-	if (strcmp(basename(name), "ccs_test") == 0)
-		return test_main(argc, argv, 1);
-	else
-		return tool_main(argc, argv);
-}
diff --git a/ccs/ccs_tool/editconf.c b/ccs/ccs_tool/editconf.c
deleted file mode 100644
index 53b0ed6..0000000
--- a/ccs/ccs_tool/editconf.c
+++ /dev/null
@@ -1,1261 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <getopt.h>
-#include <errno.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include <libxml/tree.h>
-
-#ifdef LEGACY_CODE
-#include "update.h"
-#endif
-
-#define MAX_NODES 256
-
-char *prog_name = "ccs_tool";
-
-#define die(fmt, args...) \
-do { \
-	fprintf(stderr, "%s: ", prog_name); \
-	fprintf(stderr, fmt "\n", ##args); \
-	exit(EXIT_FAILURE); \
-} while (0)
-
-
-struct option_info
-{
-	char *name;
-	char *altname;
-	char *votes;
-	char *nodeid;
-	char *mcast_addr;
-	char *fence_type;
-	char *configfile;
-	char *outputfile;
-	int  do_delete;
-	int  tell_ccsd;
-	int  force_ccsd;
-};
-
-static void config_usage(int rw)
-{
-	fprintf(stderr, " -c --configfile    Name of configuration file (" DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE ")\n");
-	if (rw)
-	{
-		fprintf(stderr, " -o --outputfile    Name of output file (defaults to same as --configfile)\n");
-		fprintf(stderr, " -C --no_ccs        Don't tell CCSD about this change\n");
-		fprintf(stderr, "                    default: run \"ccs_tool update\" if file is updated in place)\n");
-		fprintf(stderr, " -F --force_ccs     Force \"ccs_tool upgrade\" even if input & output files differ\n");
-	}
-}
-
-static void help_usage(void)
-{
-	fprintf(stderr, " -h --help          Display this help text\n");
-}
-
-static void list_usage(const char *name)
-{
-	fprintf(stderr, "Usage: %s %s [options]\n", prog_name, name);
-	fprintf(stderr, " -v --verbose       Print all properties of the item\n");
-	config_usage(0);
-	help_usage();
-
-	exit(0);
-}
-
-static void create_usage(const char *name)
-{
-	fprintf(stderr, "Usage: %s %s [-2] <clustername>\n", prog_name, name);
-	fprintf(stderr, " -2                 Create a 2-node cman cluster config file\n");
-	config_usage(0);
-	help_usage();
-	fprintf(stderr, "\n"
-	  "Note that \"create\" on its own will not create a valid configuration file.\n"
-	  "Fence agents and nodes will need to be added to it before handing it over\n"
-	  "to ccsd.\n"
-	  "\n"
-	  "eg:\n"
-	  "  ccs_tool create MyCluster\n"
-	  "  ccs_tool addfence apc fence_apc ipaddr=apc.domain.net user=apc password=apc\n"
-	  "  ccs_tool addnode node1 -n 1 -f apc port=1\n"
-	  "  ccs_tool addnode node2 -n 2 -f apc port=2\n"
-	  "  ccs_tool addnode node3 -n 3 -f apc port=3\n"
-	  "  ccs_tool addnode node4 -n 4 -f apc port=4\n"
-          "\n");
-
-	exit(0);
-}
-
-static void addfence_usage(const char *name)
-{
-	fprintf(stderr, "Usage: %s %s [options] <name> <agent> [param=value]\n", prog_name, name);
-	config_usage(1);
-	help_usage();
-
-	exit(0);
-}
-
-static void delfence_usage(const char *name)
-{
-	fprintf(stderr, "Usage: %s %s [options] <name>\n", prog_name, name);
-	config_usage(1);
-	help_usage();
-	fprintf(stderr, "\n");
-	fprintf(stderr, "%s will allow you to remove a fence device that is in use by nodes.\n", name);
-	fprintf(stderr, "This is to allow changes to be made, but be aware that it may produce an\n");
-	fprintf(stderr, "invalid configuration file if you don't add it back in again.\n");
-
-	exit(0);
-}
-
-static void delnode_usage(const char *name)
-{
-	fprintf(stderr, "Usage: %s %s [options] <name>\n", prog_name, name);
-	config_usage(1);
-	help_usage();
-
-	exit(0);
-}
-
-static void addnodeid_usage(const char *name)
-{
-	fprintf(stderr, "Add node IDs to all nodes in the config file that don't have them.\n");
-	fprintf(stderr, "Nodes with IDs will not be afftected, so you can run this as many times\n");
-	fprintf(stderr, "as you like without doing any harm.\n");
-	fprintf(stderr, "It will optionally add a multicast address to the cluster config too.\n");
-	fprintf(stderr, "\n");
-	fprintf(stderr, "Usage: %s %s [options] <name>\n", prog_name, name);
-	fprintf(stderr, " -n --nodeid        Nodeid to start with (default 1)\n");
-	fprintf(stderr, " -m --multicast     Set or change the multicast address\n");
-	fprintf(stderr, " -v --verbose       Print nodeids that are assigned\n");
-	config_usage(1);
-	help_usage();
-
-	exit(0);
-}
-
-static void addnode_usage(const char *name)
-{
-	fprintf(stderr, "Usage: %s %s [options] <nodename> [<fencearg>=<value>]...\n", prog_name, name);
-	fprintf(stderr, " -n --nodeid        Nodeid (required)\n");
-	fprintf(stderr, " -v --votes         Number of votes for this node (default 1)\n");
-	fprintf(stderr, " -a --altname       Alternative name/interface for multihomed hosts\n");
-	fprintf(stderr, " -f --fence_type    Type of fencing to use\n");
-	config_usage(1);
-	help_usage();
-
-	fprintf(stderr, "\n");
-	fprintf(stderr, "Examples:\n");
-	fprintf(stderr, "\n");
-	fprintf(stderr, "Add a new node to default configuration file:\n");
-	fprintf(stderr, "  %s %s -n 1 -f manual ipaddr=newnode\n", prog_name, name);
-	fprintf(stderr, "\n");
-	fprintf(stderr, "Add a new node and dump config file to stdout rather than save it\n");
-	fprintf(stderr, "  %s %s -n 2 -f apc -o- newnode.temp.net port=1\n", prog_name, name);
-
-	exit(0);
-}
-
-/* Is it really ?
- * Actually, we don't check that this is a valid multicast address(!),
- * merely that it is a valid IP[46] address.
- */
-static int valid_mcast_addr(char *mcast)
-{
-        struct addrinfo *ainfo;
-        struct addrinfo ahints;
-	int ret;
-
-        memset(&ahints, 0, sizeof(ahints));
-
-        ret = getaddrinfo(mcast, NULL, &ahints, &ainfo);
-	if (ret) {
-		freeaddrinfo(ainfo);
-		return 0;
-	}
-	return 1;
-}
-
-static void save_file(xmlDoc *doc, struct option_info *ninfo)
-{
-	char tmpfile[strlen(ninfo->outputfile)+5];
-	char oldfile[strlen(ninfo->outputfile)+5];
-	int using_stdout = 0;
-	mode_t old_mode;
-	int ret;
-
-	old_mode = umask(026);
-
-	if (strcmp(ninfo->outputfile, "-") == 0)
-		using_stdout = 1;
-
-	/*
-	 * Save it to a temp file before moving the old one out of the way
-	 */
-	if (!using_stdout)
-	{
-		snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", ninfo->outputfile);
-		snprintf(oldfile, sizeof(oldfile), "%s.old", ninfo->outputfile);
-	}
-	else
-	{
-		strcpy(tmpfile, ninfo->outputfile);
-	}
-
-	xmlKeepBlanksDefault(0);
-	ret = xmlSaveFormatFile(tmpfile, doc, 1);
-	if (ret == -1)
-		die("Error writing new config file %s", ninfo->outputfile);
-
-	if (!using_stdout)
-	{
-		if (rename(ninfo->outputfile, oldfile) == -1 && errno != ENOENT)
-			die("Can't move old config file out of the way\n");
-
-		if (rename(tmpfile, ninfo->outputfile))
-		{
-			perror("Error renaming new file to its real filename");
-
-			/* Drat, that failed, try to put the old one back */
-			if (rename(oldfile, ninfo->outputfile))
-				die("Can't move old config fileback in place - clean up after me please\n");
-		}
-	}
-
-#ifdef LEGACY_CODE
-	/* Try to tell ccsd if needed */
-	if ((strcmp(ninfo->configfile, ninfo->outputfile) == 0 && ninfo->tell_ccsd) ||
-	    ninfo->force_ccsd)
-	{
-		printf("running ccs_tool update...\n");
-		update(ninfo->outputfile);
-	}
-#endif
-
-	/* free the document */
-	xmlFreeDoc(doc);
-
-	umask(old_mode);
-}
-
-static void validate_int_arg(char argopt, char *arg)
-{
-	char *tmp;
-	int val;
-
-	val = strtol(arg, &tmp, 10);
-	if (tmp == arg || tmp != arg + strlen(arg))
-		die("argument to %c (%s) is not an integer", argopt, arg);
-
-	if (val < 0)
-		die("argument to %c cannot be negative", argopt);
-}
-
-/* Get the config_version string from the file */
-static xmlChar *find_version(xmlNode *root)
-{
-	if (xmlHasProp(root, BAD_CAST "config_version"))
-	{
-		xmlChar *ver;
-
-		ver = xmlGetProp(root, BAD_CAST "config_version");
-		return ver;
-	}
-	return NULL;
-}
-
-/* Get the cluster name string from the file */
-static xmlChar *cluster_name(xmlNode *root)
-{
-	if (xmlHasProp(root, BAD_CAST "name"))
-	{
-		xmlChar *ver;
-
-		ver = xmlGetProp(root, BAD_CAST "name");
-		return ver;
-	}
-	return NULL;
-}
-
-static void increment_version(xmlNode *root_element)
-{
-	int ver;
-	unsigned char *version_string;
-	char newver[32];
-
-	/* Increment version */
-	version_string = find_version(root_element);
-	if (!version_string)
-		die("Can't find \"config_version\" in config file\n");
-
-	ver = atoi((char *)version_string);
-	snprintf(newver, sizeof(newver), "%d", ++ver);
-	xmlSetProp(root_element, BAD_CAST "config_version", BAD_CAST newver);
-}
-
-static xmlNode *findnode(xmlNode *root, char *name)
-{
-	xmlNode *cur_node;
-
-	for (cur_node = root->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, name)==0)
-		{
-			return cur_node;
-		}
-	}
-	return NULL;
-}
-
-/* Return the fence type name (& node) for a cluster node */
-static xmlChar *get_fence_type(xmlNode *clusternode, xmlNode **fencenode)
-{
-	xmlNode *f;
-
-	f = findnode(clusternode, "fence");
-	if (f)
-	{
-		f = findnode(f, "method");
-		if (f)
-		{
-			f = findnode(f, "device");
-			*fencenode = f;
-			return xmlGetProp(f, BAD_CAST "name");
-		}
-	}
-	return NULL;
-}
-
-/* Check the fence type exists under <fencedevices> */
-static xmlNode *valid_fence_type(xmlNode *root, char *fencetype)
-{
-	xmlNode *devs;
-	xmlNode *cur_node;
-
-	devs = findnode(root, "fencedevices");
-	if (!devs)
-		return NULL;
-
-	for (cur_node = devs->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "fencedevice") == 0)
-		{
-			xmlChar *name = xmlGetProp(cur_node, BAD_CAST "name");
-			if (strcmp((char *)name, fencetype) == 0)
-				return cur_node;
-		}
-	}
-	return NULL;
-}
-
-/* Check the nodeid is not already in use by another node */
-static xmlNode *get_by_nodeid(xmlNode *root, int nodeid)
-{
-	xmlNode *cnodes;
-	xmlNode *cur_node;
-
-	cnodes = findnode(root, "clusternodes");
-	if (!cnodes)
-		return NULL;
-
-	for (cur_node = cnodes->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
-		{
-			xmlChar *idstring = xmlGetProp(cur_node, BAD_CAST "nodeid");
-			if (idstring && atoi((char *)idstring) == nodeid)
-				return cur_node;
-		}
-	}
-	return NULL;
-}
-
-
-/* Get the multicast address node.
- */
-static xmlNode *find_multicast_addr(xmlNode *clusternodes)
-{
-	xmlNode *clnode = findnode(clusternodes, "cman");
-	if (clnode)
-	{
-		xmlNode *mcast = findnode(clnode, "multicast");
-		return mcast;
-	}
-	return NULL;
-}
-
-static xmlNode *find_node(xmlNode *clusternodes, char *nodename)
-{
-	xmlNode *cur_node;
-
-	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
-		{
-			xmlChar *name = xmlGetProp(cur_node, BAD_CAST "name");
-			if (strcmp((char *)name, nodename) == 0)
-				return cur_node;
-		}
-	}
-	return NULL;
-}
-
-/* Print name=value pairs for a (n XML) node.
- * "ignore" is a string to ignore if present as a property (probably already printed on the main line)
- */
-static int print_properties(xmlNode *node, char *prefix, char *ignore, char *ignore2)
-{
-	xmlAttr *attr;
-	int done_prefix = 0;
-
-	for (attr = node->properties; attr; attr = attr->next)
-	{
-		/* Don't print "name=" */
-		if (strcmp((char *)attr->name, "name") &&
-		    strcmp((char *)attr->name, ignore) &&
-		    strcmp((char *)attr->name, ignore2)
-			)
-		{
-			if (!done_prefix)
-			{
-				done_prefix = 1;
-				printf("%s", prefix);
-			}
-			printf(" %s=%s", attr->name, xmlGetProp(node, attr->name));
-		}
-	}
-	if (done_prefix)
-		printf("\n");
-	return done_prefix;
-}
-
-/* Add name=value pairs from the commandline as properties to a node */
-static void add_fence_args(xmlNode *fencenode, int argc, char **argv, int optind)
-{
-	int i;
-
-	for (i = optind; i<argc; i++)
-	{
-		char *prop;
-		char *value;
-		char *equals;
-
-		prop = strdup(argv[i]);
-		equals = strchr(prop, '=');
-		if (!equals)
-			die("option '%s' is not opt=value pair\n", prop);
-
-		value = equals+1;
-		*equals = '\0';
-
-		/* "name" is used for the fence type itself, so this is just
-		 *  to protect the user from their own stupidity
-		 */
-		if (strcmp(prop, "name") == 0)
-			die("Can't use \"name\" as a fence argument name\n");
-
-		xmlSetProp(fencenode, BAD_CAST prop, BAD_CAST value);
-		free(prop);
-	}
-}
-
-static void add_clusternode(xmlNode *root_element, struct option_info *ninfo,
-			    int argc, char **argv, int optind)
-{
-	xmlNode *clusternodes;
-	xmlNode *newnode;
-
-	xmlNode *newfence;
-	xmlNode *newfencemethod;
-	xmlNode *newfencedevice;
-
-	clusternodes = findnode(root_element, "clusternodes");
-	if (!clusternodes)
-		die("Can't find \"clusternodes\" in %s\n", ninfo->configfile);
-
-	/* Don't allow duplicate node names */
-	if (find_node(clusternodes, ninfo->name))
-		die("node %s already exists in %s\n", ninfo->name, ninfo->configfile);
-
-	/* Check for duplicate node ID */
-	if (!ninfo->nodeid)
-		die("nodeid not specified\n");
-
-	if (get_by_nodeid(root_element, atoi((char *)ninfo->nodeid)))
-		die("nodeid %s already in use\n", ninfo->nodeid);
-
-        /* Don't allow random fence types */
-	if (!valid_fence_type(root_element, ninfo->fence_type))
-		die("fence type '%s' not known\n", ninfo->fence_type);
-
-	/* Add the new node */
-	newnode = xmlNewNode(NULL, BAD_CAST "clusternode");
-	xmlSetProp(newnode, BAD_CAST "name", BAD_CAST ninfo->name);
-	xmlSetProp(newnode, BAD_CAST "votes", BAD_CAST ninfo->votes);
-	xmlSetProp(newnode, BAD_CAST "nodeid", BAD_CAST ninfo->nodeid);
-	xmlAddChild(clusternodes, newnode);
-
-	if (ninfo->altname)
-	{
-		xmlNode *altnode;
-
-		altnode = xmlNewNode(NULL, BAD_CAST "altname");
-		xmlSetProp(altnode, BAD_CAST "name", BAD_CAST ninfo->altname);
-		xmlAddChild(newnode, altnode);
-	}
-
-	/* Add the fence attributes */
-	newfence = xmlNewNode(NULL, BAD_CAST "fence");
-	newfencemethod = xmlNewNode(NULL, BAD_CAST "method");
-	xmlSetProp(newfencemethod, BAD_CAST "name", BAD_CAST "single");
-
-	newfencedevice = xmlNewNode(NULL, BAD_CAST "device");
-	xmlSetProp(newfencedevice, BAD_CAST "name", BAD_CAST ninfo->fence_type);
-
-	/* Add name=value options */
-	add_fence_args(newfencedevice, argc, argv, optind+1);
-
-	xmlAddChild(newnode, newfence);
-	xmlAddChild(newfence, newfencemethod);
-	xmlAddChild(newfencemethod, newfencedevice);
-}
-
-static xmlDoc *open_configfile(struct option_info *ninfo)
-{
-	xmlDoc *doc;
-
-	/* Init libxml */
-	xmlInitParser();
-	LIBXML_TEST_VERSION;
-
-	if (!ninfo->configfile)
-		ninfo->configfile = DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE;
-	if (!ninfo->outputfile)
-		ninfo->outputfile = ninfo->configfile;
-
-	/* Load XML document */
-	doc = xmlParseFile(ninfo->configfile);
-	if (doc == NULL)
-		die("Error: unable to parse requested configuration file\n");
-
-	return doc;
-
-}
-
-static void del_clusternode(xmlNode *root_element, struct option_info *ninfo)
-{
-	xmlNode *clusternodes;
-	xmlNode *oldnode;
-
-	clusternodes = findnode(root_element, "clusternodes");
-	if (!clusternodes)
-	{
-		fprintf(stderr, "Can't find \"clusternodes\" in %s\n", ninfo->configfile);
-		exit(1);
-	}
-
-	oldnode = find_node(clusternodes, ninfo->name);
-	if (!oldnode)
-	{
-		fprintf(stderr, "node %s does not exist in %s\n", ninfo->name, ninfo->configfile);
-		exit(1);
-	}
-
-	xmlUnlinkNode(oldnode);
-}
-
-struct option addnode_options[] =
-{
-      { "votes", required_argument, NULL, 'v'},
-      { "nodeid", required_argument, NULL, 'n'},
-      { "altname", required_argument, NULL, 'a'},
-      { "fence_type", required_argument, NULL, 'f'},
-      { "outputfile", required_argument, NULL, 'o'},
-      { "configfile", required_argument, NULL, 'c'},
-      { "no_ccs", no_argument, NULL, 'C'},
-      { "force_ccs", no_argument, NULL, 'F'},
-      { NULL, 0, NULL, 0 },
-};
-
-struct option delnode_options[] =
-{
-      { "outputfile", required_argument, NULL, 'o'},
-      { "configfile", required_argument, NULL, 'c'},
-      { "no_ccs", no_argument, NULL, 'C'},
-      { "force_ccs", no_argument, NULL, 'F'},
-      { NULL, 0, NULL, 0 },
-};
-
-struct option addfence_options[] =
-{
-      { "outputfile", required_argument, NULL, 'o'},
-      { "configfile", required_argument, NULL, 'c'},
-      { "no_ccs", no_argument, NULL, 'C'},
-      { "force_ccs", no_argument, NULL, 'F'},
-      { NULL, 0, NULL, 0 },
-};
-
-struct option addnodeid_options[] =
-{
-      { "outputfile", required_argument, NULL, 'o'},
-      { "configfile", required_argument, NULL, 'c'},
-      { "multicast", required_argument, NULL, 'm'},
-      { "nodeid", no_argument, NULL, 'n'},
-      { "verbose", no_argument, NULL, 'v'},
-      { NULL, 0, NULL, 0 },
-};
-
-struct option list_options[] =
-{
-      { "configfile", required_argument, NULL, 'c'},
-      { "verbose", no_argument, NULL, 'v'},
-      { NULL, 0, NULL, 0 },
-};
-
-
-static int next_nodeid(int startid, int *nodeids, int nodecount)
-{
-	int i;
-	int nextid = startid;
-
-retry:
-	for (i=0; i<nodecount; i++)
-	{
-		if (nodeids[i] == nextid)
-		{
-			nextid++;
-			goto retry;
-		}
-	}
-
-	return nextid;
-}
-
-void add_nodeids(int argc, char **argv)
-{
-	struct option_info ninfo;
-	unsigned char *nodenames[MAX_NODES];
-	xmlDoc *doc;
-	xmlNode *root_element;
-	xmlNode *clusternodes;
-	xmlNode *cur_node;
-	xmlNode *mcast;
-	int  verbose = 0;
-	int  opt;
-	int  i;
-	int  nodenumbers[MAX_NODES];
-	int  nodeidx;
-	int  totalnodes;
-	int  nextid;
-
-	memset(nodenames, 0, sizeof(nodenames));
-	memset(nodenumbers, 0, sizeof(nodenumbers));
-	memset(&ninfo, 0, sizeof(ninfo));
-	ninfo.nodeid = "1";
-
-	while ( (opt = getopt_long(argc, argv, "n:o:c:m:vh?", addnodeid_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'n':
-			validate_int_arg(opt, optarg);
-			ninfo.nodeid = strdup(optarg);
-			break;
-
-		case 'c':
-			ninfo.configfile = strdup(optarg);
-			break;
-
-		case 'o':
-			ninfo.outputfile = strdup(optarg);
-			break;
-
-		case 'm':
-			if (!valid_mcast_addr(optarg)) {
-				fprintf(stderr, "%s is not a valid multicast address\n", optarg);
-				return;
-			}
-			ninfo.mcast_addr = strdup(optarg);
-			break;
-
-		case 'v':
-			verbose++;
-			break;
-
-		case '?':
-		default:
-			addnodeid_usage(argv[0]);
-		}
-	}
-
-	doc = open_configfile(&ninfo);
-
-	root_element = xmlDocGetRootElement(doc);
-
-	increment_version(root_element);
-
-	/* Warn if the cluster doesn't have a multicast address */
-	mcast = find_multicast_addr(root_element);
-	if (!mcast & !ninfo.mcast_addr) {
-		fprintf(stderr, "\nWARNING: The cluster does not have a multicast address.\n");
-		fprintf(stderr, "A default will be assigned a run-time which might not suit your installation\n\n");
-	}
-
-	if (ninfo.mcast_addr) {
-		if (!mcast) {
-			xmlNode *cman = xmlNewNode(NULL, BAD_CAST "cman");
-			mcast = xmlNewNode(NULL, BAD_CAST "multicast");
-
-			xmlAddChild(cman, mcast);
-			xmlAddChild(root_element, cman);
-		}
-		xmlSetProp(mcast, BAD_CAST "addr", BAD_CAST ninfo.mcast_addr);
-	}
-
-	/* Get a list of nodes that /do/ have nodeids so we don't generate
-	   any duplicates */
-	nodeidx=0;
-	clusternodes = findnode(root_element, "clusternodes");
-	if (!clusternodes)
-		die("Can't find \"clusternodes\" in %s\n", ninfo.configfile);
-
-
-	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
-		{
-			xmlChar *name   = xmlGetProp(cur_node, BAD_CAST "name");
-			xmlChar *nodeid = xmlGetProp(cur_node, BAD_CAST "nodeid");
-			nodenames[nodeidx]  = name;
-			if (nodeid)
-				nodenumbers[nodeidx] = atoi((char*)nodeid);
-			nodeidx++;
-		}
-	}
-	totalnodes = nodeidx;
-
-	/* Loop round nodes adding nodeIDs where they don't exist. */
-	nextid = next_nodeid(atoi(ninfo.nodeid), nodenumbers, totalnodes);
-	for (i=0; i<totalnodes; i++)
-	{
-		if (nodenumbers[i] == 0)
-		{
-			nodenumbers[i] = nextid;
-			nextid = next_nodeid(nextid, nodenumbers, totalnodes);
-			if (verbose)
-				fprintf(stderr, "Node %s now has id %d\n", nodenames[i], nodenumbers[i]);
-		}
-	}
-
-	/* Now write them into the tree */
-	nodeidx = 0;
-	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
-		{
-			char tmp[80];
-			xmlChar *name = xmlGetProp(cur_node, BAD_CAST "name");
-
-			assert(strcmp((char*)nodenames[nodeidx], (char*)name) == 0);
-
-			sprintf(tmp, "%d", nodenumbers[nodeidx]);
-			xmlSetProp(cur_node, BAD_CAST "nodeid", BAD_CAST tmp);
-			nodeidx++;
-		}
-	}
-
-
-	/* Write it out */
-	save_file(doc, &ninfo);
-
-	/* Shutdown libxml */
-	xmlCleanupParser();
-}
-
-void add_node(int argc, char **argv)
-{
-	struct option_info ninfo;
-	int opt;
-	xmlDoc *doc;
-	xmlNode *root_element;
-
-	memset(&ninfo, 0, sizeof(ninfo));
-	ninfo.tell_ccsd = 1;
-	ninfo.votes = "1";
-
-	while ( (opt = getopt_long(argc, argv, "v:n:a:f:o:c:CFh?", addnode_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'v':
-			validate_int_arg(opt, optarg);
-			ninfo.votes = optarg;
-			break;
-
-		case 'n':
-			validate_int_arg(opt, optarg);
-			ninfo.nodeid = optarg;
-			break;
-
-		case 'a':
-			ninfo.altname = strdup(optarg);
-			break;
-
-		case 'f':
-			ninfo.fence_type = strdup(optarg);
-			break;
-
-		case 'c':
-			ninfo.configfile = strdup(optarg);
-			break;
-
-		case 'o':
-			ninfo.outputfile = strdup(optarg);
-			break;
-
-		case 'C':
-			ninfo.tell_ccsd = 0;
-			break;
-
-		case 'F':
-			ninfo.force_ccsd = 1;
-			break;
-
-		case '?':
-		default:
-			addnode_usage(argv[0]);
-		}
-	}
-
-	/* Get node name parameter */
-	if (optind < argc)
-		ninfo.name = strdup(argv[optind]);
-	else
-		addnode_usage(argv[0]);
-
-	if (!ninfo.fence_type)
-		addnode_usage(argv[0]);
-
-
-	doc = open_configfile(&ninfo);
-
-	root_element = xmlDocGetRootElement(doc);
-
-	increment_version(root_element);
-
-	add_clusternode(root_element, &ninfo, argc, argv, optind);
-
-	/* Write it out */
-	save_file(doc, &ninfo);
-	/* Shutdown libxml */
-	xmlCleanupParser();
-
-}
-
-void del_node(int argc, char **argv)
-{
-	struct option_info ninfo;
-	int opt;
-	xmlDoc *doc;
-	xmlNode *root_element;
-
-	memset(&ninfo, 0, sizeof(ninfo));
-	ninfo.tell_ccsd = 1;
-
-	while ( (opt = getopt_long(argc, argv, "o:c:CFh?", delnode_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'c':
-			ninfo.configfile = strdup(optarg);
-			break;
-
-		case 'o':
-			ninfo.outputfile = strdup(optarg);
-			break;
-
-		case 'C':
-			ninfo.tell_ccsd = 0;
-			break;
-
-		case 'F':
-			ninfo.force_ccsd = 1;
-			break;
-
-		case '?':
-		default:
-			delnode_usage(argv[0]);
-		}
-	}
-
-	/* Get node name parameter */
-	if (optind < argc)
-		ninfo.name = strdup(argv[optind]);
-	else
-		delnode_usage(argv[0]);
-
-	doc = open_configfile(&ninfo);
-
-	root_element = xmlDocGetRootElement(doc);
-
-	increment_version(root_element);
-
-	del_clusternode(root_element, &ninfo);
-
-	/* Write it out */
-	save_file(doc, &ninfo);
-}
-
-void list_nodes(int argc, char **argv)
-{
-	xmlNode *cur_node;
-	xmlNode *root_element;
-	xmlNode *clusternodes;
-	xmlNode *fencenode = NULL;
-	xmlDocPtr doc;
-	xmlNode *mcast;
-	struct option_info ninfo;
-	int opt;
-	int verbose = 0;
-
-	memset(&ninfo, 0, sizeof(ninfo));
-
-	while ( (opt = getopt_long(argc, argv, "c:vh?", list_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'c':
-			ninfo.configfile = strdup(optarg);
-			break;
-		case 'v':
-			verbose++;
-			break;
-		case '?':
-		default:
-			list_usage(argv[0]);
-		}
-	}
-	doc = open_configfile(&ninfo);
-
-	root_element = xmlDocGetRootElement(doc);
-
-
-	printf("\nCluster name: %s, config_version: %s\n\n",
-	       (char *)cluster_name(root_element),
-	       (char *)find_version(root_element));
-
-	clusternodes = findnode(root_element, "clusternodes");
-	if (!clusternodes)
-		die("Can't find \"clusternodes\" in %s\n", ninfo.configfile);
-
-	mcast = find_multicast_addr(root_element);
-	if (mcast)
-		printf("Multicast address for cluster: %s\n\n", xmlGetProp(mcast, BAD_CAST "addr"));
-
-	printf("Nodename                        Votes Nodeid Fencetype\n");
-	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
-		{
-			xmlChar *name   = xmlGetProp(cur_node, BAD_CAST "name");
-			xmlChar *votes  = xmlGetProp(cur_node, BAD_CAST "votes");
-			xmlChar *nodeid = xmlGetProp(cur_node, BAD_CAST "nodeid");
-			xmlChar *ftype  = get_fence_type(cur_node, &fencenode);
-
-			if (!nodeid)
-				nodeid=(unsigned char *)"0";
-			if (!votes)
-				votes = (unsigned char *)"1";
-
-			printf("%-32s %3d  %3d    %s\n", name, atoi((char *)votes),
-			       atoi((char *)nodeid),
-			       ftype?ftype:(xmlChar *)"");
-			if (verbose)
-			{
-				xmlNode *a = findnode(cur_node, "altname");
-				if (a)
-				{
-					printf(" altname %s=%s", "name", xmlGetProp(a, BAD_CAST "name"));
-					if (!print_properties(a, "","",""))
-						printf("\n");
-				}
-				print_properties(cur_node, "  Node properties: ", "votes", "nodeid");
-				print_properties(fencenode, "  Fence properties: ", "agent", "");
-			}
-
-		}
-	}
-}
-
-void create_skeleton(int argc, char **argv)
-{
-	xmlNode *root_element;
-	xmlNode *fencedevices;
-	xmlNode *clusternodes;
-	xmlNode *rm;
-	xmlNode *rm1;
-	xmlNode *rm2;
-	xmlDocPtr doc;
-	char *clustername;
-	struct option_info ninfo;
-	struct stat st;
-	int twonode = 0;
-	int opt;
-
-	memset(&ninfo, 0, sizeof(ninfo));
-
-	while ( (opt = getopt_long(argc, argv, "c:2h?", list_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'c':
-			ninfo.outputfile = strdup(optarg);
-			break;
-
-		case '2':
-			twonode = 1;
-			break;
-
-		case '?':
-		default:
-			create_usage(argv[0]);
-		}
-	}
-	if (!ninfo.outputfile)
-		ninfo.outputfile = DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE;
-	ninfo.configfile = "-";
-
-	if (argc - optind < 1)
-		create_usage(argv[0]);
-
-	clustername = argv[optind];
-
-	if (stat(ninfo.outputfile, &st) == 0)
-		die("%s already exists", ninfo.outputfile);
-
-	/* Init libxml */
-	xmlInitParser();
-	LIBXML_TEST_VERSION;
-
-	doc = xmlNewDoc(BAD_CAST "1.0");
-	root_element = xmlNewNode(NULL, BAD_CAST "cluster");
-	xmlDocSetRootElement(doc, root_element);
-
-	xmlSetProp(root_element, BAD_CAST "name", BAD_CAST clustername);
-	xmlSetProp(root_element, BAD_CAST "config_version", BAD_CAST "1");
-
-	/* Generate extra bits for a 2node cman cluster */
-	if (twonode) {
-
-		xmlNode *cman = xmlNewNode(NULL, BAD_CAST "cman");
-		xmlSetProp(cman, BAD_CAST "two_node", BAD_CAST "1");
-		xmlSetProp(cman, BAD_CAST "expected_votes", BAD_CAST "1");
-		xmlAddChild(root_element, cman);
-	}
-
-	clusternodes = xmlNewNode(NULL, BAD_CAST "clusternodes");
-	fencedevices = xmlNewNode(NULL, BAD_CAST "fencedevices");
-	rm = xmlNewNode(NULL, BAD_CAST "rm");
-	rm1 = xmlNewNode(NULL, BAD_CAST "failoverdomains");
-
-	xmlAddChild(root_element, clusternodes);
-	xmlAddChild(root_element, fencedevices);
-	xmlAddChild(root_element, rm);
-
-	/* Create empty resource manager sections to keep GUI happy */
-	rm2 = xmlNewNode(NULL, BAD_CAST "resources");
-	xmlAddChild(rm, rm1);
-	xmlAddChild(rm, rm2);
-
-	save_file(doc, &ninfo);
-
-}
-
-void add_fence(int argc, char **argv)
-{
-	xmlNode *root_element;
-	xmlNode *fencedevices;
-	xmlNode *fencenode = NULL;
-	xmlDocPtr doc;
-	char *fencename;
-	char *agentname;
-	struct option_info ninfo;
-	int opt;
-
-	memset(&ninfo, 0, sizeof(ninfo));
-	ninfo.tell_ccsd = 1;
-
-	while ( (opt = getopt_long(argc, argv, "c:o:CFh?", list_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'c':
-			ninfo.configfile = strdup(optarg);
-			break;
-		case 'o':
-			ninfo.outputfile = strdup(optarg);
-			break;
-
-		case 'C':
-			ninfo.tell_ccsd = 0;
-			break;
-
-		case 'F':
-			ninfo.force_ccsd = 1;
-			break;
-
-		case '?':
-		default:
-			addfence_usage(argv[0]);
-		}
-	}
-
-	if (argc - optind < 2)
-		addfence_usage(argv[0]);
-
-	doc = open_configfile(&ninfo);
-	root_element = xmlDocGetRootElement(doc);
-
-	increment_version(root_element);
-
-	fencedevices = findnode(root_element, "fencedevices");
-	if (!fencedevices)
-		die("Can't find \"fencedevices\" %s\n", ninfo.configfile);
-
-	/* First param is the fence name - check it doesn't already exist */
-	fencename = argv[optind++];
-
-	if (valid_fence_type(root_element, fencename))
-		die("fence type %s already exists\n", fencename);
-
-	agentname = argv[optind++];
-
-	/* Add it */
-	fencenode = xmlNewNode(NULL, BAD_CAST "fencedevice");
-	xmlSetProp(fencenode, BAD_CAST "name", BAD_CAST fencename);
-	xmlSetProp(fencenode, BAD_CAST "agent", BAD_CAST agentname);
-
-	/* Add name=value options */
-	add_fence_args(fencenode, argc, argv, optind);
-
-	xmlAddChild(fencedevices, fencenode);
-
-	save_file(doc, &ninfo);
-}
-
-void del_fence(int argc, char **argv)
-{
-	xmlNode *root_element;
-	xmlNode *fencedevices;
-	xmlNode *fencenode;
-	xmlDocPtr doc;
-	char *fencename;
-	struct option_info ninfo;
-	int opt;
-
-	memset(&ninfo, 0, sizeof(ninfo));
-	ninfo.tell_ccsd = 1;
-
-	while ( (opt = getopt_long(argc, argv, "c:o:CFhv?", list_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'c':
-			ninfo.configfile = strdup(optarg);
-			break;
-		case 'o':
-			ninfo.outputfile = strdup(optarg);
-			break;
-
-		case 'C':
-			ninfo.tell_ccsd = 0;
-			break;
-
-		case 'F':
-			ninfo.force_ccsd = 1;
-			break;
-
-		case '?':
-		default:
-			delfence_usage(argv[0]);
-		}
-	}
-
-	if (argc - optind < 1)
-		delfence_usage(argv[0]);
-
-	fencename = argv[optind];
-
-	doc = open_configfile(&ninfo);
-	root_element = xmlDocGetRootElement(doc);
-	increment_version(root_element);
-
-	fencedevices = findnode(root_element, "fencedevices");
-	if (!fencedevices)
-		die("Can't find \"fencedevices\" in %s\n", ninfo.configfile);
-
-	fencenode = valid_fence_type(root_element, fencename);
-	if (!fencenode)
-		die("fence type %s does not exist\n", fencename);
-
-	xmlUnlinkNode(fencenode);
-
-	save_file(doc, &ninfo);
-}
-
-void list_fences(int argc, char **argv)
-{
-	xmlNode *cur_node;
-	xmlNode *root_element;
-	xmlNode *fencedevices;
-	xmlDocPtr doc;
-	struct option_info ninfo;
-	int opt;
-	int verbose=0;
-
-	memset(&ninfo, 0, sizeof(ninfo));
-
-	while ( (opt = getopt_long(argc, argv, "c:hv?", list_options, NULL)) != EOF)
-	{
-		switch(opt)
-		{
-		case 'c':
-			ninfo.configfile = strdup(optarg);
-			break;
-		case 'v':
-			verbose++;
-			break;
-		case '?':
-		default:
-			list_usage(argv[0]);
-		}
-	}
-	doc = open_configfile(&ninfo);
-	root_element = xmlDocGetRootElement(doc);
-
-	fencedevices = findnode(root_element, "fencedevices");
-	if (!fencedevices)
-		die("Can't find \"fencedevices\" in %s\n", ninfo.configfile);
-
-
-	printf("Name             Agent\n");
-	for (cur_node = fencedevices->children; cur_node; cur_node = cur_node->next)
-	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "fencedevice") == 0)
-		{
-			xmlChar *name  = xmlGetProp(cur_node, BAD_CAST "name");
-			xmlChar *agent = xmlGetProp(cur_node, BAD_CAST "agent");
-
-			printf("%-16s %s\n", name, agent);
-			if (verbose)
-				print_properties(cur_node, "  Properties: ", "agent", "");
-		}
-	}
-}
-
diff --git a/ccs/ccs_tool/editconf.h b/ccs/ccs_tool/editconf.h
deleted file mode 100644
index 1847e2c..0000000
--- a/ccs/ccs_tool/editconf.h
+++ /dev/null
@@ -1,8 +0,0 @@
-void add_node(int argc, char **argv);
-void add_nodeids(int argc, char **argv);
-void add_fence(int argc, char **argv);
-void del_node(int argc, char **argv);
-void del_fence(int argc, char **argv);
-void list_nodes(int argc, char **argv);
-void list_fences(int argc, char **argv);
-void create_skeleton(int argc, char **argv);
diff --git a/ccs/ccs_tool/update.c b/ccs/ccs_tool/update.c
deleted file mode 100644
index d8c1308..0000000
--- a/ccs/ccs_tool/update.c
+++ /dev/null
@@ -1,673 +0,0 @@
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include "comm_headers.h"
-#include "libccscompat.h"
-#include "libcman.h"
-
-typedef struct member_list {
-  int count;
-  int pad;
-  cman_node_t *nodes;
-} member_list_t;
-
-static member_list_t *get_member_list(cman_handle_t handle);
-static void free_member_list(member_list_t *list);
-
-static int select_retry(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *xfds,
-			struct timeval *timeout);
-
-static ssize_t read_retry(int fd, void *buf, int count, struct timeval *timeout);
-
-static int ccs_open(cman_node_t node, uint16_t baseport, int timeout);
-static int ipv4_connect(struct in_addr *addr, uint16_t port, int timeout);
-static int ipv6_connect(struct in6_addr *addr, uint16_t port, int timeout);
-static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, int timeout);
-
-extern int globalverbose;
-
-int cluster_base_port = 50008;
-
-static int get_doc_version(xmlDocPtr ldoc)
-{
-  int i;
-  int error = 0;
-
-  xmlXPathObjectPtr  obj = NULL;
-  xmlXPathContextPtr ctx = NULL;
-  xmlNodePtr        node = NULL;
-
-  ctx = xmlXPathNewContext(ldoc);
-
-  if (!ctx) {
-    fprintf(stderr, "Unable to create new XPath context.\n");
-    error = -EIO;  /* ATTENTION -- what should this be? */
-    goto fail;
-  }
-
-  obj = xmlXPathEvalExpression((xmlChar *)"/cluster/@config_version", ctx);
-
-  if (!obj || !obj->nodesetval || (obj->nodesetval->nodeNr != 1)) {
-    fprintf(stderr, "Error while retrieving config_version.\n");
-    error = -ENODATA;
-    goto fail;
-  }
-
-  node = obj->nodesetval->nodeTab[0];
-
-  if (node->type != XML_ATTRIBUTE_NODE) {
-    fprintf(stderr, "Object returned is not of attribute type.\n");
-    error = -ENODATA;
-    goto fail;
-  }
-
-  if (!node->children->content || !strlen((char *)node->children->content)) {
-    error = -ENODATA;
-    goto fail;
-  }
-
-  for (i = 0; i < strlen((char *)node->children->content); i++) {
-    if (!isdigit(node->children->content[i])) {
-      fprintf(stderr, "config_version is not a valid integer.\n");
-      error = -EINVAL;
-      goto fail;
-    }
-  }
-
-  error = atoi((char *)node->children->content);
-
-fail:
-
-  if (ctx) {
-    xmlXPathFreeContext(ctx);
-  }
-
-  if (obj) {
-    xmlXPathFreeObject(obj);
-  }
-
-  return error;
-}
-
-
-int update(char *location)
-{
-  int error = 0;
-  int i, fd;
-  int cluster_fd = -1;
-  char true_location[256];
-  xmlDocPtr doc = NULL;
-  xmlChar *mem_doc;
-  int doc_size = 0;
-  char *buffer = NULL;
-  comm_header_t *ch = NULL, rch;
-  member_list_t *members = NULL;
-  cman_handle_t handle = NULL;
-  int desc;
-  char *v1_str,*v3_str;
-  int v1, v2, v3;
-
-  struct timeval tv;
-
-  if (location[0] != '/') {
-    memset(true_location, 0, 256);
-    if (!getcwd(true_location, 256)) {
-      fprintf(stderr, "Unable to get the current working directory.\n");
-      return -errno;
-    }
-    true_location[strlen(true_location)] = '/';
-    strncpy(true_location+strlen(true_location), location, 256-strlen(true_location));
-  } else {
-    strncpy(true_location, location, 256);
-  }
-
-  desc = ccs_connect();
-
-  if (desc < 0) {
-    fprintf(stderr, "Unable to connect to the CCS daemon: %s\n", strerror(-desc));
-    return desc;
-  }
-
-  if ((error = ccs_get(desc, "/cluster/@config_version", &v1_str))) {
-    fprintf(stderr, "Unable to get current config_version: %s\n", strerror(-error));
-    ccs_disconnect(desc);
-    return error;
-  }
-
-  ccs_disconnect(desc);
-
-  for (i = 0; i < strlen(v1_str); i++) {
-    if (!isdigit(v1_str[i])) {
-      fprintf(stderr, "config_version is not a valid integer.\n");
-      free(v1_str);
-      return -EINVAL;
-    }
-  }
-
-  v1 = atoi(v1_str);
-  free(v1_str);
-
-  doc = xmlParseFile(true_location);
-
-  if (!doc) {
-    fprintf(stderr, "Unable to parse %s\n", true_location);
-    return -EINVAL;
-  }
-
-  v2 = get_doc_version(doc);
-
-  if (v2 < 0) {
-    fprintf(stderr, "Unable to get the config_version from %s\n", location);
-    xmlFreeDoc(doc);
-    return -EINVAL;
-  }
-
-  if (v2 <= v1)  {
-    fprintf(stderr,
-	    "Proposed updated config file does not have greater version number.\n"
-	    "  Current config_version :: %d\n"
-	    "  Proposed config_version:: %d\n", v1, v2);
-    xmlFreeDoc(doc);
-    return -EINVAL;
-  }    
-
-  xmlDocDumpFormatMemory(doc, &mem_doc, &doc_size, 0);
-
-  if (!mem_doc) {
-    fprintf(stderr, "Unable to allocate memory for update document.\n");
-    xmlFreeDoc(doc);
-    return -ENOMEM;
-  }
-
-  xmlFreeDoc(doc);
-
-  buffer = malloc(doc_size + sizeof(comm_header_t));
-
-  if (!buffer) {
-    fprintf(stderr, "Unable to allocate memory for transfer buffer.\n");
-    free(mem_doc);
-    return -ENOMEM;
-  }
-
-  memset(buffer, 0, (doc_size + sizeof(comm_header_t)));
-  ch = (comm_header_t *)buffer;
-
-  memcpy(buffer+sizeof(comm_header_t), mem_doc, doc_size);
-  free(mem_doc);
-
-  ch->comm_type = COMM_UPDATE;
-  ch->comm_flags= COMM_UPDATE_NOTICE;
-  ch->comm_payload_size = doc_size;
-
-  handle = cman_admin_init(NULL);
-
-  cluster_fd = cman_get_fd(handle);
-
-  /* Should we test the cman handle of file descriptor to determine connectivity? */
-
-  if (cluster_fd < 0) {
-    fprintf(stderr, "Unable to connect to cluster infrastructure.\n");
-    return cluster_fd;
-  }
-
-  if (!cman_is_quorate(handle)) {
-    fprintf(stderr, "Unable to honor update request. Cluster is not quorate.\n");
-    return -EPERM;
-  }
-
-  members = get_member_list(handle);
-
-  swab_header(ch);
-  
-  for (i = 0; i < members->count; i++) {
-    if (members->nodes[i].cn_nodeid == 0)
-      continue;
-    if (members->nodes[i].cn_member == 0)
-      continue;
-
-    fd = ccs_open(members->nodes[i], cluster_base_port, 5);
-
-    if (fd < 0) {
-      fprintf(stderr, "Unable to open connection to %s: %s\n",
-	      members->nodes[i].cn_name, strerror(errno));
-      free(buffer);
-      free_member_list(members);
-      return -errno;
-    }
-
-    error = write(fd, buffer, sizeof(comm_header_t) + doc_size);
-
-    if (error < 0) {
-      fprintf(stderr, "Unable to send msg to %s: %s\n",
-	      members->nodes[i].cn_name, strerror(errno));
-      close(fd);
-      free(buffer);
-      free_member_list(members);
-      return -errno;
-    }
-
-    tv.tv_sec = 5;
-    tv.tv_usec = 0;
-
-    error = read_retry(fd, &rch, sizeof(comm_header_t), &tv);
-
-    swab_header(&rch);
-
-    if (error < 0) {
-      fprintf(stderr, "Failed to receive COMM_UPDATE_NOTICE_ACK from %s.\n",
-	      members->nodes[i].cn_name);
-      fprintf(stderr, "Hint: Check the log on %s for reason.\n",
-	      members->nodes[i].cn_name);
-      close(fd);
-      free(buffer);
-      free_member_list(members);
-      return -errno;
-    }
-
-    close(fd);
-  }
-
-  swab_header(ch);
-  
-  ch->comm_flags = COMM_UPDATE_COMMIT;
-
-  swab_header(ch);
-
-  for (i=0; i < members->count; i++) {
-    if (members->nodes[i].cn_nodeid == 0)
-      continue;
-    if (members->nodes[i].cn_member == 0)
-      continue;
-
-    fd = ccs_open(members->nodes[i], cluster_base_port, 5);
-    if(fd < 0){
-      fprintf(stderr, "Unable to open connection to %s: %s\n",
-	      members->nodes[i].cn_name, strerror(errno));
-      free(buffer);
-      free_member_list(members);
-      return -errno;
-    }
-
-    error = write(fd, buffer, sizeof(comm_header_t));
-
-    if (error < 0) {
-      fprintf(stderr, "Unable to send msg to %s: %s\n",
-	      members->nodes[i].cn_name, strerror(errno));
-      close(fd);
-      free(buffer);
-      free_member_list(members);
-      return -errno;
-    }
-
-    tv.tv_sec = 5;
-    tv.tv_usec = 0;
-
-    error = read_retry(fd, &rch, sizeof(comm_header_t), &tv);
-
-    swab_header(&rch);
-
-    if (error < 0) {
-      fprintf(stderr, "Failed to receive COMM_UPDATE_COMMIT_ACK from %s.\n",
-	      members->nodes[i].cn_name);
-      fprintf(stderr, "Hint: Check the log on %s for reason.\n",
-	      members->nodes[i].cn_name);
-      close(fd);
-      free(buffer);
-      free_member_list(members);
-      return -errno;
-    }
-
-    close(fd);
-    error = 0;
-  }
-
-  free(buffer);
-  free_member_list(members);
-
-  /* If we can't connect here, it doesn't mean the update failed **
-  ** It means that we simply can't report the change in version  */
-  desc = ccs_connect();
-
-  if (desc < 0) {
-    fprintf(stderr, "Unable to connect to the CCS daemon: %s\n", strerror(-desc));
-    return 0;
-  }
-
-  if ((error = ccs_get(desc, "/cluster/@config_version", &v3_str))) {
-    ccs_disconnect(desc);
-    return 0;
-  }
-
-  v3 = atoi(v3_str);
-  free(v3_str);
-
-  ccs_disconnect(desc);
-
-  if (v2 == v3) {
-    cman_version_t cman_ver;
-    printf("Config file updated from version %d to %d\n", v1, v2);
-    cman_get_version(handle, &cman_ver);
-    cman_ver.cv_config = v2;
-    if (cman_set_version(handle, &cman_ver)) {
-	    perror("Failed to tell cman of new version number");
-    }
-  } else {
-    fprintf(stderr, "Warning:: Simultaneous update requests detected.\n"
-	    "  You have lost the race.\n"
-	    "  Old config version :: %d\n"
-	    "  Proposed config version :: %d\n"
-	    "  Winning config version  :: %d\n\n"
-	    "Check " DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE " to ensure it contains the desired contents.\n", v1, v2, v3);
-    return -EAGAIN;
-  }
-
-  return 0;
-}
-
-
-static member_list_t *get_member_list(cman_handle_t handle)
-{
-  int count = 0;
-
-  member_list_t *list = NULL;
-  cman_node_t *nodes = NULL;
-
-  do
-  {
-
-    if (nodes != NULL) {
-      free(nodes);
-    }
-
-    count = cman_get_node_count(handle);
-
-    if (count <= 0) {
-      return NULL;
-    }
-
-    if (list == NULL) {
-      list = malloc(sizeof(*list));
-    }
-
-    if (list == NULL) {
-      return NULL;
-    }
-
-    nodes = malloc(sizeof(*nodes) * count);
-
-    if (nodes == NULL) {
-      free(list);
-      return NULL;
-    }
-
-    memset(list, 0, sizeof(*list));
-    memset(nodes, 0, sizeof(*nodes) * count);
-
-    cman_get_nodes(handle, count, &list->count, nodes);
-
-  } while (list->count != count);
-
-  list->count = count;
-  list->nodes = nodes;
-
-  return list;
-}
-
-
-static void free_member_list(member_list_t *list)
-{
-  if (list != NULL) {
-    if (list->nodes != NULL) {
-      free(list->nodes);
-    }
-    free(list);
-  }
-}
-
-
-static int select_retry(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *xfds,
-			struct timeval *timeout)
-{
-  int rv;
-
-  while (1) {
-    rv = select(max_fd, rfds, wfds, xfds, timeout);
-    if ((rv == -1) && (errno == EINTR)) {
-      /* return on EBADF/EINVAL/ENOMEM; continue on EINTR */
-      continue;
-    }
-    return rv;
-  }
-}
-
-
-static ssize_t read_retry(int fd, void *buf, int count, struct timeval *timeout)
-{
-  int n, total = 0, remain = count, rv = 0;
-  fd_set rfds, xfds;
-
-  while (total < count) 
-  {
-    FD_ZERO(&rfds);
-    FD_SET(fd, &rfds);
-    FD_ZERO(&xfds);
-    FD_SET(fd, &xfds);
-
-    /*
-     * Select on the socket, in case it closes while we're not
-     * looking...
-     */
-    rv = select_retry(fd + 1, &rfds, NULL, &xfds, timeout);
-    if (rv == -1) {
-      return -1;
-    }
-    else if (rv == 0) {
-      errno = ETIMEDOUT;
-      return -1;
-    }
-
-    if (FD_ISSET(fd, &xfds)) {
-      errno = EPIPE;
-      return -1;
-    }
-
-    /* 
-     * Attempt to read off the socket 
-     */
-    n = read(fd, buf + (off_t) total, remain);
-
-    /*
-     * When we know our socket was select()ed and we receive 0 bytes
-     * when we read, the socket was closed.
-     */
-    if ((n == 0) && (rv == 1)) {
-      errno = EPIPE;
-      return -1;
-    }
-
-    if (n == -1) {
-      if ((errno == EAGAIN) || (errno == EINTR)) {
-	/* 
-	 * Not ready? Wait for data to become available
-	 */
-	continue;
-      }
-
-      /* Other errors: EPIPE, EINVAL, etc */
-      return -1;
-    }
-
-    total += n;
-    remain -= n;
-  }
-
-  return total;
-}
-
-
-static int ccs_open(cman_node_t node, uint16_t port, int timeout)
-{
-  struct in_addr *addr;
-  struct in6_addr *addr6;
-  int fd, family;
-  char buf[INET6_ADDRSTRLEN];
-
-  if (globalverbose) {
-    memset(buf, 0, sizeof(buf));
-    printf("Processing node: %s\n", node.cn_name);
-  }
-
-  family = ((struct sockaddr *)&(node.cn_address.cna_address))->sa_family;
-
-  if (family == AF_INET6) {
-
-    addr6 = &(((struct sockaddr_in6 *)&(node.cn_address.cna_address))->sin6_addr);
-
-    if (globalverbose) {
-      inet_ntop(family, addr6, buf, sizeof(buf));
-      printf(" family: ipv6\n address: %s\n", buf);
-    }
-
-    if ((fd = ipv6_connect(addr6, port, timeout)) < 0) {
-      return -1;
-    }
-
-  } else {
-
-    addr = &(((struct sockaddr_in *)&(node.cn_address.cna_address))->sin_addr);
-
-    if (globalverbose) {
-      inet_ntop(family, addr, buf, sizeof(buf));
-      printf(" family: ipv4\n address: %s\n", buf);
-    }
-
-    if ((fd = ipv4_connect(addr, port, timeout)) < 0) {
-      return -1;
-    }
-
-  }
-
-  return fd;
-}
-
-
-static int ipv4_connect(struct in_addr *addr, uint16_t port, int timeout)
-{
-  struct sockaddr_in sin;
-
-  int fd;
-
-  if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-    return -1;
-  }
-
-  sin.sin_family = AF_INET;
-  sin.sin_port = htons(port);
-
-  memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
-
-  if (connect_nb(fd, (struct sockaddr *)&sin, sizeof(sin), timeout) < 0) {
-    close(fd);
-    return -1;
-  }
-
-  return fd;
-}
-
-
-static int ipv6_connect(struct in6_addr *addr, uint16_t port, int timeout)
-{
-  struct sockaddr_in6 sin6;
-
-  int fd;
-
-  if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
-    return -1;
-  }
-
-  memset(&sin6, 0, sizeof(sin6));
-
-  sin6.sin6_family = AF_INET6;
-  sin6.sin6_port = htons(port);
-  sin6.sin6_flowinfo = 0;
-
-  memcpy(&sin6.sin6_addr, addr, sizeof(sin6.sin6_addr));
-
-  if (connect_nb(fd, (struct sockaddr *)&sin6, sizeof(sin6), timeout)) {
-    close(fd);
-    return -1;
-  }
-
-  return fd;
-}
-
-
-static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, int timeout)
-{
-  int err;
-  int ret;
-  int flags = 1;
-  unsigned l;
-  fd_set rfds, wfds;
-
-  struct timeval tv;
-
-  if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0) {
-    return -1;
-  }
-
-  flags = fcntl(fd, F_GETFL, 0);
-  fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-
-  ret = connect(fd, addr, len);
-
-  if ((ret < 0) && (errno != EINPROGRESS)) {
-    return -1;
-  }
-
-  if (ret != 0) {
-    FD_ZERO(&rfds);
-    FD_SET(fd, &rfds);
-    FD_ZERO(&wfds);
-    FD_SET(fd, &wfds);
-
-    tv.tv_sec = timeout;
-    tv.tv_usec = 0;
-
-    if (select_retry((fd + 1), &rfds, &wfds, NULL, &tv) == 0) {
-      errno = ETIMEDOUT;
-      return -1;
-    }
-
-    if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds)) {
-      l = sizeof(err);
-      if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &l) < 0) {
-	close(fd);
-	return -1;
-      }
-
-      if (err != 0) {
-	close(fd);
-	errno = err;
-	return -1;
-      }
-
-      fcntl(fd, F_SETFL, flags);
-      return 0;
-    }
-  }
-
-  errno = EIO;
-  return -1;
-}
diff --git a/ccs/ccs_tool/update.h b/ccs/ccs_tool/update.h
deleted file mode 100644
index 2f41aa4..0000000
--- a/ccs/ccs_tool/update.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __UPDATE_DOT_H__
-#define __UPDATE_DOT_H__
-
-int update(char *location);
-
-#endif /* __UPDATE_DOT_H__ */
diff --git a/ccs/man/Makefile b/ccs/man/Makefile
index 43133a6..abedd52 100644
--- a/ccs/man/Makefile
+++ b/ccs/man/Makefile
@@ -1,12 +1,6 @@
 TARGET= cluster.conf.5 \
 	ccs.7 \
-	ccsd.8 \
-	ccs_tool.8
+	ccsd.8
 
 include ../../make/defines.mk
-
-ifdef legacy_code
-TARGET += ccs_test.8
-endif
-
 include $(OBJDIR)/make/man.mk
diff --git a/ccs/man/ccs_test.8 b/ccs/man/ccs_test.8
deleted file mode 100644
index 9dce13c..0000000
--- a/ccs/man/ccs_test.8
+++ /dev/null
@@ -1,132 +0,0 @@
-.TH ccs_test 8
-
-.SH NAME
-ccs_test - CCS daemon (ccsd) diagnostic tool
-
-.SH SYNOPSIS
-.B ccs_test
-[\fBoptions\fP]
-<\fBcommand\fP>
-
-.SH DESCRIPTION
-\fBccs_test\fP is part of the Cluster Configuration System (CCS).  It is a
-diagnostic tool that reads cluster.conf information to test ccsd.
-
-.SH OPTIONS
-.TP
-\fB-h\fP
-Help.  Print out the usage syntax and exit.
-.TP
-\fB-V\fP
-Print the version information and exit.
-
-.SH COMMANDS
-.TP
-\fBconnect\fP \fI[force]\fP \fI[block]\fP \fI[cluster name]\fP
-This command creates a connection to ccsd.  It returns a descriptor, which
-is used as an parameter to other commands.
-
-The 'force' key-word is used to establish a connection to ccsd in the
-absence of a quorate cluster manager.
-
-The 'block' key-word is used (with the 'force' key-word) to tell ccsd to
-keep broadcasting for a valid configuration file until one is found.
-
-The 'cluster name' is used (with the 'force' key-word) to specify that
-only configuration files containing the given cluster name are valid
-possibilities.
-
-.TP
-\fBget\fP \fI<desc>\fP \fI<request>\fP
-Get the results of a given request.  The 'desc' is the number returned
-from the \fBconnect\fP command.  The 'request' is a valid Xpath request.
-
-If 'request' results in multiple matches, the first will be returned.
-Subsequent calls with the same 'request' will result in the subsequent
-matches.  Once all the matches have been returned, a subsequent call
-will begin again with the first result.
-
-.TP
-\fBget_list\fP \fI<desc>\fP \fI<request>\fP
-Similar to the \fBget\fP command.  However, issuing subsequent calls
-with the same 'request' will result in all matches being returned (one
-at a time), then null, then starting over with the first result.
-
-.TP
-\fBset\fP \fI<desc>\fP \fI<path>\fP \fI<value>\fP
-Sets a particular 'path' to the given 'value'.  Not yet implemented.
-
-.TP
-\fBget_state\fP \fI<desc>\fP
-Get the state associated with a given connection.
-
-.TP
-\fBset_state\fP \fI<desc>\fP \fI<ncwp>\fP
-Set the current working path (cwp) to 'ncwp' for a given connection.
-
-.SH EXAMPLES
-.SS To connect to ccsd:
-
-> ccs_test connect
-
-Connect successful.
- Connection descriptor = 0
-
-Or, if the cluster is not yet quorate and the name of the cluster is 'mycluster':
-
-> ccs_test connect force block mycluster
-
-Connect successful.
- Connection descriptor = 0
-
-.SS To get the cluster name from ccsd:
-
-> ccs_test get 0 /cluster/@name
-
-Get successful.
- Value = <mycluster>
-
-.SS To get the connection state:
-
-> ccs_test get_state 0
-
-Get state successful.
- Current working path:
- Previous query      : /cluster/@name
-
-
-.SS To set the connection state:
-
-> ccs_test set_state 0 /cluster
-
-Set state successful.
-
-
-.SS After setting the connection state, note the change:
-
-> ccs_test get_state 0
-
-Get state successful.
- Current working path: /cluster
- Previous query      : /cluster/@name
-
-.SS After setting the connection state, you can now query with an absolute or relative path:
-
-> ccs_test get 0 @name
-
-Get successful.
- Value = <brassow>
-
-> ccs_test get 0 /cluster/@name
-
-Get successful.
- Value = <brassow>
-
-.SS To disconnect:
-
-> ccs_test disconnect 0
-
-Disconnect successful.
-
-.SH SEE ALSO
-ccs(7), ccsd(8), cluster.conf(5)
diff --git a/ccs/man/ccs_tool.8 b/ccs/man/ccs_tool.8
deleted file mode 100644
index ef13406..0000000
--- a/ccs/man/ccs_tool.8
+++ /dev/null
@@ -1,185 +0,0 @@
-.TH "ccs_tool" "8" "" "" ""
-.SH "NAME"
-ccs_tool \- The tool used to make online updates of CCS config files.
-
-.SH "SYNOPSIS"
-.B ccs_tool
-[\fIOPTION\fR].. <\fBcommand\fP>
-
-.SH "DESCRIPTION"
-
-\fBccs_tool\fP is part of the Cluster Configuration System (CCS).  It is
-used to make online updates to cluster.conf.  It can also be used to
-upgrade old style (GFS <= 6.0) CCS archives to the new xml cluster.conf
-format.
-
-.SH "OPTIONS"
-.TP 
-\fB\-h\fP
-Help.  Print out the usage.
-.TP 
-\fB\-V\fP
-Print the version information.
-
-sub\-commands have their own options, see below for more detail
-.SH "COMMANDS"
-.TP 
-\fBupdate\fP \fI<xml file>\fP
-This command is used to update the config file that ccsd is working with
-while the cman cluster is operational (i.e. online).  Run this on a single
-machine to update cluster.conf on all current cluster members.  This also
-notifies cman of the new config version.
-
-.TP 
-\fBupgrade\fP \fI<location>\fP
-This command is used to upgrade an old CCS format archive to the new
-xml format.  \fI<location>\fP is the location of the old archive,
-which can be either a block device archive or a file archive.  The
-converted configuration will be printed to stdout.
-
-.TP 
-\fBaddnode\fP [options] \fI<node> [<fenceoption=value>]...\fP
-Adds a new node to the cluster configuration file. Fencing device options
-are specified as key=value pairs (as many as required) and are entered into the
-configuration file as is. See the documentation for your fencing agent for more
-details (eg a powerswitch fence device may need to know which port the node is
-connected to).
-.br
-\fIOptions:\fP
-.br
-\-v <votes>        Number of votes for this node (mandatory)
-.br 
-\-n <nodeid>       Node id for this node (optional)
-.br
-\-i <interface>    Network interface to use for this node. Mandatory if the cluster 
-is using multicast as transport. Forbidden if not.
-.br
-\-m <multicast>    Multicast address for cluster. Only allowed on the first node to 
-be added to the file. Subsequent nodes will use either multicast or broadcast 
-depending on the properties of the first node.
-.br
-\-f <fencedevice>  Name of fence device to use for this node. The fence device 
-section must already have been added to the file, probably using the addfence command.
-.br
-\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
-.br
-\-o <file>         Output file. Defaults to the same as -c
-.br
-\-C                Don't run "ccs_tool update" after changing file. This will
-happen by default if the input file is the same as the output file.
-.br
-\-F                Force a "ccs_tool update" even if the input and output files
-are different.
-
-
-
-.TP 
-\fBdelnode\fP [options] \fI<node>\fP
-Delete a node from the cluster configuration file. Note: there is no 
-"edit" command so to change the properties of a node you must delete it
-and add it back in with the new properties.
-.br
-\fIOptions:\fP
-.br
-\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
-.br
-\-o <file>         Output file. Defaults to the same as -c
-.br
-\-C                Don't run "ccs_tool update" after changing file. This will
-happen by default if the input file is the same as the output file.
-.br
-\-F                Force a "ccs_tool update" even if the input and output files
-are different.
-
-
-
-.TP 
-\fBaddfence\fP [options] \fI<name> <agent> [<option>=<value>]...\fP
-Adds a new fence device section to the cluster configuration file. <agent> is the
-name of the fence agent that controls the device. the options following are entered
-as key-value pairs. See the fence agent documentation for details about these. eg:
-you may need to enter the IP address and username/password for a powerswitch fencing
-device.
-.br
-\fIOptions:\fP
-.br
-\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
-.br
-\-o <file>         Output file. Defaults to the same as -c
-.br
-\-C                Don't run "ccs_tool update" after changing file. This will
-happen by default if the input file is the same as the output file.
-.br
-\-F                Force a "ccs_tool update" even if the input and output files
-are different.
-
-.TP 
-\fBdelfence\fP [options] \fI<node>\fP
-Deletes a fencing device from the cluster configuration file.
-delfence will allow you to remove a fence device that is in use by nodes.
-This is to allow changes to be made, but be aware that it may produce an
-invalid configuration file if you don't add it back in again.
-.br
-\fIOptions:\fP
-.br
-\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
-.br
-\-o <file>         Output file. Defaults to the same as -c
-.br
-\-C                Don't run "ccs_tool update" after changing file. This will
-happen by default if the input file is the same as the output file.
-.br
-\-F                Force a "ccs_tool update" even if the input and output files
-are different.
-
-
-.TP 
-\fBlsnode [options] \fP
-List the nodes in the configuration file. This is (hopefully obviously) not
-necessarily the same as the nodes currently in the cluster, but it should
-be a superset.
-.br
-\fIOptions:\fP
-.br
-\-v                Verbose. Lists all the properties of the node, and the
-node-specific properties of the fence device too.
-.br
-\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
-
-
-.TP 
-\fBlsfence [options] \fP
-List all the fence devices in the cluster configuration file.
-.br
-\fIOptions:\fP
-.br
-\-v                Verbose. Lists all the properties of the fence device rather
-than just the names and agents.
-.br
-\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
-
-
-.TP 
-\fBcreate [options] \fP \fI<clustername>\fP
-Create a new, skeleton, configuration file. Note that "create" on its own will 
-not create a valid configuration file. Fence agents and nodes will need to be 
-added to it before handing it over to ccsd. The new configuration file will
-have a version number of 1. Subsequent addnode/delnode/addfence/delfence operations
-will increment the version number by 1 each time.
-.br
-\fIOptions:\fP
-.br
-.br
-\-c <file>         Config file to create. Defaults to /etc/cluster/cluster.conf
-
-.TP 
-\fBaddnodeids\fP
-Adds node ID numbers to all the nodes in cluster.conf. In RHEL4, node IDs were optional
-and assigned by cman when a node joined the cluster. In RHEL5 they must be pre-assigned
-in cluster.conf. This command will not change any node IDs that are already set in 
-cluster.conf, it will simply add unique node ID numbers to nodes that do not already
-have them.
-
-
-.SH "SEE ALSO"
-ccs(7), ccsd(8), cluster.conf(5)
diff --git a/config/tools/Makefile b/config/tools/Makefile
index 8b2d2fc..04cc742 100644
--- a/config/tools/Makefile
+++ b/config/tools/Makefile
@@ -1,4 +1,4 @@
 include ../../make/defines.mk
 include $(OBJDIR)/make/passthrough.mk
 
-SUBDIRS=ldap man
+SUBDIRS=ccs_tool ldap man
diff --git a/config/tools/ccs_tool/Makefile b/config/tools/ccs_tool/Makefile
new file mode 100644
index 0000000..428b9fa
--- /dev/null
+++ b/config/tools/ccs_tool/Makefile
@@ -0,0 +1,56 @@
+TARGET1 = ccs_tool
+TARGET2 = ccs_test
+
+SBINDIRT = $(TARGET1)
+SBINSYMT = $(TARGET2)
+
+include ../../../make/defines.mk
+
+ifdef legacy_code
+all: depends ${TARGET1} ${TARGET2}
+else
+all: ${TARGET1} ${TARGET2}
+endif
+
+include $(OBJDIR)/make/cobj.mk
+include $(OBJDIR)/make/clean.mk
+include $(OBJDIR)/make/install.mk
+include $(OBJDIR)/make/uninstall.mk
+
+OBJS =	ccs_tool.o \
+	editconf.o
+
+ifdef legacy_code
+OBJS += update.o
+endif
+
+CFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+CFLAGS += -I${cmanincdir} `xml2-config --cflags`
+CFLAGS += -I${ccsincdir} -I$(SRCDIR)/ccs/include
+CFLAGS += -I$(SRCDIR)/ccs/libccscompat
+CFLAGS += -I${incdir}
+
+LDFLAGS += -L${cmanlibdir} -lcman
+ifdef legacy_code
+LDFLAGS += -L$(OBJDIR)/ccs/libccscompat -lccscompat
+LDDEPS += $(OBJDIR)/ccs/libccscompat/libccscompat.a
+else
+LDFLAGS += -L${ccslibdir} -lccs
+endif
+LDFLAGS += `xml2-config --libs`
+LDFLAGS += -L${libdir}
+
+${TARGET1}: ${OBJS} ${LDDEPS}
+	$(CC) -o $@ $^ $(LDFLAGS)
+
+${TARGET2}: ${TARGET1}
+	ln -sf ${TARGET1} ${TARGET2}
+
+ifdef legacy_code
+depends:
+	$(MAKE) -C $(OBJDIR)/ccs/libccscompat all
+endif
+
+clean: generalclean
+
+-include $(OBJS:.o=.d)
diff --git a/config/tools/ccs_tool/ccs_tool.c b/config/tools/ccs_tool/ccs_tool.c
new file mode 100644
index 0000000..c05a07e
--- /dev/null
+++ b/config/tools/ccs_tool/ccs_tool.c
@@ -0,0 +1,353 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include "copyright.cf"
+#include "editconf.h"
+#ifdef LEGACY_CODE
+#include "update.h"
+#include "libccscompat.h"
+#else
+#include "ccs.h"
+#endif
+
+
+/*
+ * Old libccs retruned -error (mostly!) but didn't set errno (sigh)
+ * New libccs sets errno correctly
+ */
+static char *errstring(int retcode)
+{
+#ifdef LEGACY_CODE
+	return strerror(retcode);
+#else
+	return strerror(errno);
+#endif
+}
+
+static void tool_print_usage(FILE *stream);
+
+int globalverbose=0;
+
+static void test_print_usage(FILE *stream);
+
+static int test_main(int argc, char *argv[], int old_format){
+  int desc=0;
+  int i=0;
+  int error = 0;
+  int force = 0, blocking = 0;
+  char *str=NULL;
+  char *cluster_name = NULL;
+
+  if(argc <= 1){
+    test_print_usage(stderr);
+    exit(EXIT_FAILURE);
+  }
+
+  for(i=1; i < argc; i++){
+    if(!strcmp(argv[i], "-h")){
+      test_print_usage(stdout);
+      exit(EXIT_SUCCESS);
+    }
+    if(!strcmp(argv[i], "-V")){
+      printf("%s %s (built %s %s)\n", argv[0], RELEASE_VERSION, __DATE__, __TIME__);
+      printf("%s\n", REDHAT_COPYRIGHT);
+      exit(EXIT_SUCCESS);
+    }
+  }
+
+  if(!strcmp(argv[1], "connect")){
+    for(i=2; i < argc; i++){
+      if(!strcmp(argv[i], "force")){
+	printf("Force is set.\n");
+	force = 1;
+      } else if(!strcmp(argv[i], "block")){
+	printf("Blocking is set.\n");
+	blocking = 1;
+      } else {
+	cluster_name = argv[i];
+	printf("Setting cluster name to %s\n", cluster_name);
+      }
+    }
+    if(blocking && !force){
+      fprintf(stderr, "Blocking can only be used with \"force\".\n");
+      exit(EXIT_FAILURE);
+    }
+    if(force){
+      desc = ccs_force_connect(cluster_name, blocking);
+    } else {
+      if(cluster_name){
+	fprintf(stderr, "A cluster name can only be specified when using 'force'.\n");
+	exit(EXIT_FAILURE);
+      }
+      desc = ccs_connect();
+    }
+    if(desc < 0){
+      fprintf(stderr, "ccs_connect failed: %s\n", errstring(-desc));
+      exit(EXIT_FAILURE);
+    } else {
+      printf("Connect successful.\n");
+      printf(" Connection descriptor = %d\n", desc);
+#ifndef LEGACY_CODE
+      ccs_disconnect(desc);
+#endif
+    }
+  }
+  else if(!strcmp(argv[1], "disconnect")){
+    if(argc < 3){
+      fprintf(stderr, "Wrong number of arguments.\n");
+      exit(EXIT_FAILURE);
+    }
+#ifdef LEGACY_CODE
+    desc = atoi(argv[2]);
+#else
+    desc = ccs_connect();
+#endif
+    if((error = ccs_disconnect(desc))){
+      fprintf(stderr, "ccs_disconnect failed: %s\n", errstring(-error));
+      exit(EXIT_FAILURE);
+    } else {
+      printf("Disconnect successful.\n");
+    }
+  }
+  else if(!strcmp(argv[1], "get")){
+    if(argc < 4){
+      fprintf(stderr, "Wrong number of arguments.\n");
+      exit(EXIT_FAILURE);
+    }
+#ifdef LEGACY_CODE
+    desc = atoi(argv[2]);
+#else
+    desc = ccs_connect();
+#endif
+    if((desc < 0) || (error = ccs_get(desc, argv[3], &str))){
+      fprintf(stderr, "ccs_get failed: %s\n", errstring(-error));
+      exit(EXIT_FAILURE);
+    } else {
+	    if (old_format) {
+		    printf("Get successful.\n");
+		    printf(" Value = <%s>\n", str);
+	    }
+	    else {
+		    printf("%s\n", str);
+	    }
+      if(str)free(str);
+#ifndef LEGACY_CODE
+      ccs_disconnect(desc);
+#endif
+    }
+  }
+  else {
+    fprintf(stderr, "Unknown command: %s\n", argv[1]);
+    exit(EXIT_FAILURE);
+  }
+
+  exit(EXIT_SUCCESS);
+}
+
+static void test_print_usage(FILE *stream)
+{
+	fprintf(stream,
+	  "Usage:\n"
+	  "\n"
+	  "ccs_test [Options] <Command>\n"
+	  "\n"
+	  "Options:\n"
+	  "  -h                        Print usage.\n"
+	  "  -V                        Print version information.\n"
+	  "\n"
+	  "Commands:\n"
+	  "  connect <force> <block>   Connect to CCS and return connection descriptor.\n"
+	  "  disconnect <desc>         Disconnect from CCS.\n"
+	  "  get <desc> <request>      Get a value from CCS.\n"
+	  );
+}
+
+#ifndef LEGACY_CODE
+static int xpath_query(int argc, char **argv)
+{
+	int handle;
+	char *ret;
+	int i;
+
+	if (argc < 2) {
+		fprintf(stderr,
+			"Usage:\n"
+			"\n"
+			"ccs_tool query <xpath query>\n");
+		return 1;
+	}
+
+	/* Tell the library we want full XPath parsing */
+	fullxpath = 1;
+
+	handle = ccs_connect();
+
+	/* Process all the queries on the command-line */
+	for (i=1; i<argc; i++) {
+		if (!ccs_get(handle, argv[1], &ret)) {
+			printf("%s\n", ret);
+			free(ret);
+		}
+		else {
+			fprintf(stderr, "Query failed: %s\n", strerror(errno));
+			ccs_disconnect(handle);
+			return -1;
+		}
+	}
+	ccs_disconnect(handle);
+	return 0;
+}
+#endif
+
+static int tool_main(int argc, char *argv[])
+{
+  optind = 1;
+
+  if (argc < 2 || !strcmp(argv[optind], "-h")) {
+      tool_print_usage(stdout);
+      exit(EXIT_SUCCESS);
+  }
+  if (!strcmp(argv[optind], "-V")) {
+      printf("%s %s (built %s %s)\n", argv[0], RELEASE_VERSION,
+	     __DATE__, __TIME__);
+      printf("%s\n", REDHAT_COPYRIGHT);
+      exit(EXIT_SUCCESS);
+  }
+
+  if(optind < argc){
+    if(!strcmp(argv[optind], "-verbose")){
+      optind++;
+      globalverbose=1;
+    }
+    if(!strcmp(argv[optind], "help")){
+      tool_print_usage(stdout);
+      exit(EXIT_SUCCESS);
+    }
+#ifdef LEGACY_CODE
+    /* Update is meaningless now */
+    else if(!strcmp(argv[optind], "update")){
+      if(optind+1 >= argc){
+	fprintf(stderr, "Too few arguments.\n"
+		"Try 'ccs_tool help' for help.\n");
+	exit(EXIT_FAILURE);
+      }
+      if(update(argv[optind+1])){
+	fprintf(stderr, "\nFailed to update config file.\n");
+	exit(EXIT_FAILURE);
+      }
+      printf("\nUpdate complete.\n");
+    }
+    /* Do old ccs queries */
+    else if(!strcmp(argv[optind], "query")){
+	    char *new_argv[argc+2];
+	    int i;
+
+	    new_argv[0] = "ccs_test";
+	    new_argv[1] = "get";
+	    new_argv[2] = "0"; /* Dummy connection ID */
+	    for (i=2; i<argc; i++)
+		    new_argv[1+i] = argv[i];
+
+	    return test_main(argc+1, new_argv, 0);
+    }
+#else
+    else if(!strcmp(argv[optind], "query")){
+	    return xpath_query(argc-1, argv+1);
+    }
+#endif
+    else if(!strcmp(argv[optind], "addnode")){
+	    add_node(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "delnode")){
+	    del_node(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "addfence")){
+	    add_fence(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "delfence")){
+	    del_fence(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "lsnode")){
+	    list_nodes(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "lsfence")){
+	    list_fences(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "create")){
+	    create_skeleton(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "addnodeids")){
+	    add_nodeids(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+
+    else {
+      fprintf(stderr, "Unknown command, %s.\n"
+	      "Try 'ccs_tool help' for help.\n", argv[optind]);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    fprintf(stderr, "Too few arguments.\n"
+	    "Try 'ccs_tool help' for help.\n");
+    exit(EXIT_FAILURE);
+  }
+  exit(EXIT_SUCCESS);
+}
+
+static void tool_print_usage(FILE *stream){
+  fprintf(stream,
+	  "Usage:\n"
+	  "  ccs_tool [options] <command>\n"
+	  "\n"
+	  "Options:\n"
+	  "  -verbose            Make some operations print more details.\n"
+	  "  -h                  Print this usage and exit.\n"
+	  "  -V                  Print version information and exit.\n"
+	  "\n"
+	  "Commands:\n"
+	  "  help                Print this usage and exit.\n"
+#ifdef LEGACY_CODE
+	  "  update <xml file>   Tells ccsd to upgrade to new config file version.\n"
+	  "  query <ccs query>   Query the cluster configuration.\n"
+#else
+	  "  query <xpath query> Query the cluster configuration.\n"
+#endif
+	  "  addnode <node>      Add a node\n"
+          "  delnode <node>      Delete a node\n"
+          "  lsnode              List nodes\n"
+          "  lsfence             List fence devices\n"
+	  "  addfence <fencedev> Add a new fence device\n"
+	  "  delfence <fencedev> Delete a fence device\n"
+	  "  create              Create a skeleton config file\n"
+	  "  addnodeids          Assign node ID numbers to all nodes\n"
+	  "\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+	char *name = strdup(argv[0]);
+
+	/*
+	 * Don't be anal about the binary name.
+	 * We expect either 'ccs_tool' or 'ccs_test',
+	 * but interpret anything other than 'ccs_test'
+	 * as 'ccs_tool'.
+	 * That's not a bug, it's a feature.
+	 */
+
+	if (strcmp(basename(name), "ccs_test") == 0)
+		return test_main(argc, argv, 1);
+	else
+		return tool_main(argc, argv);
+}
diff --git a/config/tools/ccs_tool/editconf.c b/config/tools/ccs_tool/editconf.c
new file mode 100644
index 0000000..53b0ed6
--- /dev/null
+++ b/config/tools/ccs_tool/editconf.c
@@ -0,0 +1,1261 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <libxml/tree.h>
+
+#ifdef LEGACY_CODE
+#include "update.h"
+#endif
+
+#define MAX_NODES 256
+
+char *prog_name = "ccs_tool";
+
+#define die(fmt, args...) \
+do { \
+	fprintf(stderr, "%s: ", prog_name); \
+	fprintf(stderr, fmt "\n", ##args); \
+	exit(EXIT_FAILURE); \
+} while (0)
+
+
+struct option_info
+{
+	char *name;
+	char *altname;
+	char *votes;
+	char *nodeid;
+	char *mcast_addr;
+	char *fence_type;
+	char *configfile;
+	char *outputfile;
+	int  do_delete;
+	int  tell_ccsd;
+	int  force_ccsd;
+};
+
+static void config_usage(int rw)
+{
+	fprintf(stderr, " -c --configfile    Name of configuration file (" DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE ")\n");
+	if (rw)
+	{
+		fprintf(stderr, " -o --outputfile    Name of output file (defaults to same as --configfile)\n");
+		fprintf(stderr, " -C --no_ccs        Don't tell CCSD about this change\n");
+		fprintf(stderr, "                    default: run \"ccs_tool update\" if file is updated in place)\n");
+		fprintf(stderr, " -F --force_ccs     Force \"ccs_tool upgrade\" even if input & output files differ\n");
+	}
+}
+
+static void help_usage(void)
+{
+	fprintf(stderr, " -h --help          Display this help text\n");
+}
+
+static void list_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [options]\n", prog_name, name);
+	fprintf(stderr, " -v --verbose       Print all properties of the item\n");
+	config_usage(0);
+	help_usage();
+
+	exit(0);
+}
+
+static void create_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [-2] <clustername>\n", prog_name, name);
+	fprintf(stderr, " -2                 Create a 2-node cman cluster config file\n");
+	config_usage(0);
+	help_usage();
+	fprintf(stderr, "\n"
+	  "Note that \"create\" on its own will not create a valid configuration file.\n"
+	  "Fence agents and nodes will need to be added to it before handing it over\n"
+	  "to ccsd.\n"
+	  "\n"
+	  "eg:\n"
+	  "  ccs_tool create MyCluster\n"
+	  "  ccs_tool addfence apc fence_apc ipaddr=apc.domain.net user=apc password=apc\n"
+	  "  ccs_tool addnode node1 -n 1 -f apc port=1\n"
+	  "  ccs_tool addnode node2 -n 2 -f apc port=2\n"
+	  "  ccs_tool addnode node3 -n 3 -f apc port=3\n"
+	  "  ccs_tool addnode node4 -n 4 -f apc port=4\n"
+          "\n");
+
+	exit(0);
+}
+
+static void addfence_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [options] <name> <agent> [param=value]\n", prog_name, name);
+	config_usage(1);
+	help_usage();
+
+	exit(0);
+}
+
+static void delfence_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [options] <name>\n", prog_name, name);
+	config_usage(1);
+	help_usage();
+	fprintf(stderr, "\n");
+	fprintf(stderr, "%s will allow you to remove a fence device that is in use by nodes.\n", name);
+	fprintf(stderr, "This is to allow changes to be made, but be aware that it may produce an\n");
+	fprintf(stderr, "invalid configuration file if you don't add it back in again.\n");
+
+	exit(0);
+}
+
+static void delnode_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [options] <name>\n", prog_name, name);
+	config_usage(1);
+	help_usage();
+
+	exit(0);
+}
+
+static void addnodeid_usage(const char *name)
+{
+	fprintf(stderr, "Add node IDs to all nodes in the config file that don't have them.\n");
+	fprintf(stderr, "Nodes with IDs will not be afftected, so you can run this as many times\n");
+	fprintf(stderr, "as you like without doing any harm.\n");
+	fprintf(stderr, "It will optionally add a multicast address to the cluster config too.\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Usage: %s %s [options] <name>\n", prog_name, name);
+	fprintf(stderr, " -n --nodeid        Nodeid to start with (default 1)\n");
+	fprintf(stderr, " -m --multicast     Set or change the multicast address\n");
+	fprintf(stderr, " -v --verbose       Print nodeids that are assigned\n");
+	config_usage(1);
+	help_usage();
+
+	exit(0);
+}
+
+static void addnode_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [options] <nodename> [<fencearg>=<value>]...\n", prog_name, name);
+	fprintf(stderr, " -n --nodeid        Nodeid (required)\n");
+	fprintf(stderr, " -v --votes         Number of votes for this node (default 1)\n");
+	fprintf(stderr, " -a --altname       Alternative name/interface for multihomed hosts\n");
+	fprintf(stderr, " -f --fence_type    Type of fencing to use\n");
+	config_usage(1);
+	help_usage();
+
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Examples:\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Add a new node to default configuration file:\n");
+	fprintf(stderr, "  %s %s -n 1 -f manual ipaddr=newnode\n", prog_name, name);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Add a new node and dump config file to stdout rather than save it\n");
+	fprintf(stderr, "  %s %s -n 2 -f apc -o- newnode.temp.net port=1\n", prog_name, name);
+
+	exit(0);
+}
+
+/* Is it really ?
+ * Actually, we don't check that this is a valid multicast address(!),
+ * merely that it is a valid IP[46] address.
+ */
+static int valid_mcast_addr(char *mcast)
+{
+        struct addrinfo *ainfo;
+        struct addrinfo ahints;
+	int ret;
+
+        memset(&ahints, 0, sizeof(ahints));
+
+        ret = getaddrinfo(mcast, NULL, &ahints, &ainfo);
+	if (ret) {
+		freeaddrinfo(ainfo);
+		return 0;
+	}
+	return 1;
+}
+
+static void save_file(xmlDoc *doc, struct option_info *ninfo)
+{
+	char tmpfile[strlen(ninfo->outputfile)+5];
+	char oldfile[strlen(ninfo->outputfile)+5];
+	int using_stdout = 0;
+	mode_t old_mode;
+	int ret;
+
+	old_mode = umask(026);
+
+	if (strcmp(ninfo->outputfile, "-") == 0)
+		using_stdout = 1;
+
+	/*
+	 * Save it to a temp file before moving the old one out of the way
+	 */
+	if (!using_stdout)
+	{
+		snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", ninfo->outputfile);
+		snprintf(oldfile, sizeof(oldfile), "%s.old", ninfo->outputfile);
+	}
+	else
+	{
+		strcpy(tmpfile, ninfo->outputfile);
+	}
+
+	xmlKeepBlanksDefault(0);
+	ret = xmlSaveFormatFile(tmpfile, doc, 1);
+	if (ret == -1)
+		die("Error writing new config file %s", ninfo->outputfile);
+
+	if (!using_stdout)
+	{
+		if (rename(ninfo->outputfile, oldfile) == -1 && errno != ENOENT)
+			die("Can't move old config file out of the way\n");
+
+		if (rename(tmpfile, ninfo->outputfile))
+		{
+			perror("Error renaming new file to its real filename");
+
+			/* Drat, that failed, try to put the old one back */
+			if (rename(oldfile, ninfo->outputfile))
+				die("Can't move old config fileback in place - clean up after me please\n");
+		}
+	}
+
+#ifdef LEGACY_CODE
+	/* Try to tell ccsd if needed */
+	if ((strcmp(ninfo->configfile, ninfo->outputfile) == 0 && ninfo->tell_ccsd) ||
+	    ninfo->force_ccsd)
+	{
+		printf("running ccs_tool update...\n");
+		update(ninfo->outputfile);
+	}
+#endif
+
+	/* free the document */
+	xmlFreeDoc(doc);
+
+	umask(old_mode);
+}
+
+static void validate_int_arg(char argopt, char *arg)
+{
+	char *tmp;
+	int val;
+
+	val = strtol(arg, &tmp, 10);
+	if (tmp == arg || tmp != arg + strlen(arg))
+		die("argument to %c (%s) is not an integer", argopt, arg);
+
+	if (val < 0)
+		die("argument to %c cannot be negative", argopt);
+}
+
+/* Get the config_version string from the file */
+static xmlChar *find_version(xmlNode *root)
+{
+	if (xmlHasProp(root, BAD_CAST "config_version"))
+	{
+		xmlChar *ver;
+
+		ver = xmlGetProp(root, BAD_CAST "config_version");
+		return ver;
+	}
+	return NULL;
+}
+
+/* Get the cluster name string from the file */
+static xmlChar *cluster_name(xmlNode *root)
+{
+	if (xmlHasProp(root, BAD_CAST "name"))
+	{
+		xmlChar *ver;
+
+		ver = xmlGetProp(root, BAD_CAST "name");
+		return ver;
+	}
+	return NULL;
+}
+
+static void increment_version(xmlNode *root_element)
+{
+	int ver;
+	unsigned char *version_string;
+	char newver[32];
+
+	/* Increment version */
+	version_string = find_version(root_element);
+	if (!version_string)
+		die("Can't find \"config_version\" in config file\n");
+
+	ver = atoi((char *)version_string);
+	snprintf(newver, sizeof(newver), "%d", ++ver);
+	xmlSetProp(root_element, BAD_CAST "config_version", BAD_CAST newver);
+}
+
+static xmlNode *findnode(xmlNode *root, char *name)
+{
+	xmlNode *cur_node;
+
+	for (cur_node = root->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, name)==0)
+		{
+			return cur_node;
+		}
+	}
+	return NULL;
+}
+
+/* Return the fence type name (& node) for a cluster node */
+static xmlChar *get_fence_type(xmlNode *clusternode, xmlNode **fencenode)
+{
+	xmlNode *f;
+
+	f = findnode(clusternode, "fence");
+	if (f)
+	{
+		f = findnode(f, "method");
+		if (f)
+		{
+			f = findnode(f, "device");
+			*fencenode = f;
+			return xmlGetProp(f, BAD_CAST "name");
+		}
+	}
+	return NULL;
+}
+
+/* Check the fence type exists under <fencedevices> */
+static xmlNode *valid_fence_type(xmlNode *root, char *fencetype)
+{
+	xmlNode *devs;
+	xmlNode *cur_node;
+
+	devs = findnode(root, "fencedevices");
+	if (!devs)
+		return NULL;
+
+	for (cur_node = devs->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "fencedevice") == 0)
+		{
+			xmlChar *name = xmlGetProp(cur_node, BAD_CAST "name");
+			if (strcmp((char *)name, fencetype) == 0)
+				return cur_node;
+		}
+	}
+	return NULL;
+}
+
+/* Check the nodeid is not already in use by another node */
+static xmlNode *get_by_nodeid(xmlNode *root, int nodeid)
+{
+	xmlNode *cnodes;
+	xmlNode *cur_node;
+
+	cnodes = findnode(root, "clusternodes");
+	if (!cnodes)
+		return NULL;
+
+	for (cur_node = cnodes->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
+		{
+			xmlChar *idstring = xmlGetProp(cur_node, BAD_CAST "nodeid");
+			if (idstring && atoi((char *)idstring) == nodeid)
+				return cur_node;
+		}
+	}
+	return NULL;
+}
+
+
+/* Get the multicast address node.
+ */
+static xmlNode *find_multicast_addr(xmlNode *clusternodes)
+{
+	xmlNode *clnode = findnode(clusternodes, "cman");
+	if (clnode)
+	{
+		xmlNode *mcast = findnode(clnode, "multicast");
+		return mcast;
+	}
+	return NULL;
+}
+
+static xmlNode *find_node(xmlNode *clusternodes, char *nodename)
+{
+	xmlNode *cur_node;
+
+	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
+		{
+			xmlChar *name = xmlGetProp(cur_node, BAD_CAST "name");
+			if (strcmp((char *)name, nodename) == 0)
+				return cur_node;
+		}
+	}
+	return NULL;
+}
+
+/* Print name=value pairs for a (n XML) node.
+ * "ignore" is a string to ignore if present as a property (probably already printed on the main line)
+ */
+static int print_properties(xmlNode *node, char *prefix, char *ignore, char *ignore2)
+{
+	xmlAttr *attr;
+	int done_prefix = 0;
+
+	for (attr = node->properties; attr; attr = attr->next)
+	{
+		/* Don't print "name=" */
+		if (strcmp((char *)attr->name, "name") &&
+		    strcmp((char *)attr->name, ignore) &&
+		    strcmp((char *)attr->name, ignore2)
+			)
+		{
+			if (!done_prefix)
+			{
+				done_prefix = 1;
+				printf("%s", prefix);
+			}
+			printf(" %s=%s", attr->name, xmlGetProp(node, attr->name));
+		}
+	}
+	if (done_prefix)
+		printf("\n");
+	return done_prefix;
+}
+
+/* Add name=value pairs from the commandline as properties to a node */
+static void add_fence_args(xmlNode *fencenode, int argc, char **argv, int optind)
+{
+	int i;
+
+	for (i = optind; i<argc; i++)
+	{
+		char *prop;
+		char *value;
+		char *equals;
+
+		prop = strdup(argv[i]);
+		equals = strchr(prop, '=');
+		if (!equals)
+			die("option '%s' is not opt=value pair\n", prop);
+
+		value = equals+1;
+		*equals = '\0';
+
+		/* "name" is used for the fence type itself, so this is just
+		 *  to protect the user from their own stupidity
+		 */
+		if (strcmp(prop, "name") == 0)
+			die("Can't use \"name\" as a fence argument name\n");
+
+		xmlSetProp(fencenode, BAD_CAST prop, BAD_CAST value);
+		free(prop);
+	}
+}
+
+static void add_clusternode(xmlNode *root_element, struct option_info *ninfo,
+			    int argc, char **argv, int optind)
+{
+	xmlNode *clusternodes;
+	xmlNode *newnode;
+
+	xmlNode *newfence;
+	xmlNode *newfencemethod;
+	xmlNode *newfencedevice;
+
+	clusternodes = findnode(root_element, "clusternodes");
+	if (!clusternodes)
+		die("Can't find \"clusternodes\" in %s\n", ninfo->configfile);
+
+	/* Don't allow duplicate node names */
+	if (find_node(clusternodes, ninfo->name))
+		die("node %s already exists in %s\n", ninfo->name, ninfo->configfile);
+
+	/* Check for duplicate node ID */
+	if (!ninfo->nodeid)
+		die("nodeid not specified\n");
+
+	if (get_by_nodeid(root_element, atoi((char *)ninfo->nodeid)))
+		die("nodeid %s already in use\n", ninfo->nodeid);
+
+        /* Don't allow random fence types */
+	if (!valid_fence_type(root_element, ninfo->fence_type))
+		die("fence type '%s' not known\n", ninfo->fence_type);
+
+	/* Add the new node */
+	newnode = xmlNewNode(NULL, BAD_CAST "clusternode");
+	xmlSetProp(newnode, BAD_CAST "name", BAD_CAST ninfo->name);
+	xmlSetProp(newnode, BAD_CAST "votes", BAD_CAST ninfo->votes);
+	xmlSetProp(newnode, BAD_CAST "nodeid", BAD_CAST ninfo->nodeid);
+	xmlAddChild(clusternodes, newnode);
+
+	if (ninfo->altname)
+	{
+		xmlNode *altnode;
+
+		altnode = xmlNewNode(NULL, BAD_CAST "altname");
+		xmlSetProp(altnode, BAD_CAST "name", BAD_CAST ninfo->altname);
+		xmlAddChild(newnode, altnode);
+	}
+
+	/* Add the fence attributes */
+	newfence = xmlNewNode(NULL, BAD_CAST "fence");
+	newfencemethod = xmlNewNode(NULL, BAD_CAST "method");
+	xmlSetProp(newfencemethod, BAD_CAST "name", BAD_CAST "single");
+
+	newfencedevice = xmlNewNode(NULL, BAD_CAST "device");
+	xmlSetProp(newfencedevice, BAD_CAST "name", BAD_CAST ninfo->fence_type);
+
+	/* Add name=value options */
+	add_fence_args(newfencedevice, argc, argv, optind+1);
+
+	xmlAddChild(newnode, newfence);
+	xmlAddChild(newfence, newfencemethod);
+	xmlAddChild(newfencemethod, newfencedevice);
+}
+
+static xmlDoc *open_configfile(struct option_info *ninfo)
+{
+	xmlDoc *doc;
+
+	/* Init libxml */
+	xmlInitParser();
+	LIBXML_TEST_VERSION;
+
+	if (!ninfo->configfile)
+		ninfo->configfile = DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE;
+	if (!ninfo->outputfile)
+		ninfo->outputfile = ninfo->configfile;
+
+	/* Load XML document */
+	doc = xmlParseFile(ninfo->configfile);
+	if (doc == NULL)
+		die("Error: unable to parse requested configuration file\n");
+
+	return doc;
+
+}
+
+static void del_clusternode(xmlNode *root_element, struct option_info *ninfo)
+{
+	xmlNode *clusternodes;
+	xmlNode *oldnode;
+
+	clusternodes = findnode(root_element, "clusternodes");
+	if (!clusternodes)
+	{
+		fprintf(stderr, "Can't find \"clusternodes\" in %s\n", ninfo->configfile);
+		exit(1);
+	}
+
+	oldnode = find_node(clusternodes, ninfo->name);
+	if (!oldnode)
+	{
+		fprintf(stderr, "node %s does not exist in %s\n", ninfo->name, ninfo->configfile);
+		exit(1);
+	}
+
+	xmlUnlinkNode(oldnode);
+}
+
+struct option addnode_options[] =
+{
+      { "votes", required_argument, NULL, 'v'},
+      { "nodeid", required_argument, NULL, 'n'},
+      { "altname", required_argument, NULL, 'a'},
+      { "fence_type", required_argument, NULL, 'f'},
+      { "outputfile", required_argument, NULL, 'o'},
+      { "configfile", required_argument, NULL, 'c'},
+      { "no_ccs", no_argument, NULL, 'C'},
+      { "force_ccs", no_argument, NULL, 'F'},
+      { NULL, 0, NULL, 0 },
+};
+
+struct option delnode_options[] =
+{
+      { "outputfile", required_argument, NULL, 'o'},
+      { "configfile", required_argument, NULL, 'c'},
+      { "no_ccs", no_argument, NULL, 'C'},
+      { "force_ccs", no_argument, NULL, 'F'},
+      { NULL, 0, NULL, 0 },
+};
+
+struct option addfence_options[] =
+{
+      { "outputfile", required_argument, NULL, 'o'},
+      { "configfile", required_argument, NULL, 'c'},
+      { "no_ccs", no_argument, NULL, 'C'},
+      { "force_ccs", no_argument, NULL, 'F'},
+      { NULL, 0, NULL, 0 },
+};
+
+struct option addnodeid_options[] =
+{
+      { "outputfile", required_argument, NULL, 'o'},
+      { "configfile", required_argument, NULL, 'c'},
+      { "multicast", required_argument, NULL, 'm'},
+      { "nodeid", no_argument, NULL, 'n'},
+      { "verbose", no_argument, NULL, 'v'},
+      { NULL, 0, NULL, 0 },
+};
+
+struct option list_options[] =
+{
+      { "configfile", required_argument, NULL, 'c'},
+      { "verbose", no_argument, NULL, 'v'},
+      { NULL, 0, NULL, 0 },
+};
+
+
+static int next_nodeid(int startid, int *nodeids, int nodecount)
+{
+	int i;
+	int nextid = startid;
+
+retry:
+	for (i=0; i<nodecount; i++)
+	{
+		if (nodeids[i] == nextid)
+		{
+			nextid++;
+			goto retry;
+		}
+	}
+
+	return nextid;
+}
+
+void add_nodeids(int argc, char **argv)
+{
+	struct option_info ninfo;
+	unsigned char *nodenames[MAX_NODES];
+	xmlDoc *doc;
+	xmlNode *root_element;
+	xmlNode *clusternodes;
+	xmlNode *cur_node;
+	xmlNode *mcast;
+	int  verbose = 0;
+	int  opt;
+	int  i;
+	int  nodenumbers[MAX_NODES];
+	int  nodeidx;
+	int  totalnodes;
+	int  nextid;
+
+	memset(nodenames, 0, sizeof(nodenames));
+	memset(nodenumbers, 0, sizeof(nodenumbers));
+	memset(&ninfo, 0, sizeof(ninfo));
+	ninfo.nodeid = "1";
+
+	while ( (opt = getopt_long(argc, argv, "n:o:c:m:vh?", addnodeid_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'n':
+			validate_int_arg(opt, optarg);
+			ninfo.nodeid = strdup(optarg);
+			break;
+
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+
+		case 'o':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case 'm':
+			if (!valid_mcast_addr(optarg)) {
+				fprintf(stderr, "%s is not a valid multicast address\n", optarg);
+				return;
+			}
+			ninfo.mcast_addr = strdup(optarg);
+			break;
+
+		case 'v':
+			verbose++;
+			break;
+
+		case '?':
+		default:
+			addnodeid_usage(argv[0]);
+		}
+	}
+
+	doc = open_configfile(&ninfo);
+
+	root_element = xmlDocGetRootElement(doc);
+
+	increment_version(root_element);
+
+	/* Warn if the cluster doesn't have a multicast address */
+	mcast = find_multicast_addr(root_element);
+	if (!mcast & !ninfo.mcast_addr) {
+		fprintf(stderr, "\nWARNING: The cluster does not have a multicast address.\n");
+		fprintf(stderr, "A default will be assigned a run-time which might not suit your installation\n\n");
+	}
+
+	if (ninfo.mcast_addr) {
+		if (!mcast) {
+			xmlNode *cman = xmlNewNode(NULL, BAD_CAST "cman");
+			mcast = xmlNewNode(NULL, BAD_CAST "multicast");
+
+			xmlAddChild(cman, mcast);
+			xmlAddChild(root_element, cman);
+		}
+		xmlSetProp(mcast, BAD_CAST "addr", BAD_CAST ninfo.mcast_addr);
+	}
+
+	/* Get a list of nodes that /do/ have nodeids so we don't generate
+	   any duplicates */
+	nodeidx=0;
+	clusternodes = findnode(root_element, "clusternodes");
+	if (!clusternodes)
+		die("Can't find \"clusternodes\" in %s\n", ninfo.configfile);
+
+
+	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
+		{
+			xmlChar *name   = xmlGetProp(cur_node, BAD_CAST "name");
+			xmlChar *nodeid = xmlGetProp(cur_node, BAD_CAST "nodeid");
+			nodenames[nodeidx]  = name;
+			if (nodeid)
+				nodenumbers[nodeidx] = atoi((char*)nodeid);
+			nodeidx++;
+		}
+	}
+	totalnodes = nodeidx;
+
+	/* Loop round nodes adding nodeIDs where they don't exist. */
+	nextid = next_nodeid(atoi(ninfo.nodeid), nodenumbers, totalnodes);
+	for (i=0; i<totalnodes; i++)
+	{
+		if (nodenumbers[i] == 0)
+		{
+			nodenumbers[i] = nextid;
+			nextid = next_nodeid(nextid, nodenumbers, totalnodes);
+			if (verbose)
+				fprintf(stderr, "Node %s now has id %d\n", nodenames[i], nodenumbers[i]);
+		}
+	}
+
+	/* Now write them into the tree */
+	nodeidx = 0;
+	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
+		{
+			char tmp[80];
+			xmlChar *name = xmlGetProp(cur_node, BAD_CAST "name");
+
+			assert(strcmp((char*)nodenames[nodeidx], (char*)name) == 0);
+
+			sprintf(tmp, "%d", nodenumbers[nodeidx]);
+			xmlSetProp(cur_node, BAD_CAST "nodeid", BAD_CAST tmp);
+			nodeidx++;
+		}
+	}
+
+
+	/* Write it out */
+	save_file(doc, &ninfo);
+
+	/* Shutdown libxml */
+	xmlCleanupParser();
+}
+
+void add_node(int argc, char **argv)
+{
+	struct option_info ninfo;
+	int opt;
+	xmlDoc *doc;
+	xmlNode *root_element;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+	ninfo.tell_ccsd = 1;
+	ninfo.votes = "1";
+
+	while ( (opt = getopt_long(argc, argv, "v:n:a:f:o:c:CFh?", addnode_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'v':
+			validate_int_arg(opt, optarg);
+			ninfo.votes = optarg;
+			break;
+
+		case 'n':
+			validate_int_arg(opt, optarg);
+			ninfo.nodeid = optarg;
+			break;
+
+		case 'a':
+			ninfo.altname = strdup(optarg);
+			break;
+
+		case 'f':
+			ninfo.fence_type = strdup(optarg);
+			break;
+
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+
+		case 'o':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case 'C':
+			ninfo.tell_ccsd = 0;
+			break;
+
+		case 'F':
+			ninfo.force_ccsd = 1;
+			break;
+
+		case '?':
+		default:
+			addnode_usage(argv[0]);
+		}
+	}
+
+	/* Get node name parameter */
+	if (optind < argc)
+		ninfo.name = strdup(argv[optind]);
+	else
+		addnode_usage(argv[0]);
+
+	if (!ninfo.fence_type)
+		addnode_usage(argv[0]);
+
+
+	doc = open_configfile(&ninfo);
+
+	root_element = xmlDocGetRootElement(doc);
+
+	increment_version(root_element);
+
+	add_clusternode(root_element, &ninfo, argc, argv, optind);
+
+	/* Write it out */
+	save_file(doc, &ninfo);
+	/* Shutdown libxml */
+	xmlCleanupParser();
+
+}
+
+void del_node(int argc, char **argv)
+{
+	struct option_info ninfo;
+	int opt;
+	xmlDoc *doc;
+	xmlNode *root_element;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+	ninfo.tell_ccsd = 1;
+
+	while ( (opt = getopt_long(argc, argv, "o:c:CFh?", delnode_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+
+		case 'o':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case 'C':
+			ninfo.tell_ccsd = 0;
+			break;
+
+		case 'F':
+			ninfo.force_ccsd = 1;
+			break;
+
+		case '?':
+		default:
+			delnode_usage(argv[0]);
+		}
+	}
+
+	/* Get node name parameter */
+	if (optind < argc)
+		ninfo.name = strdup(argv[optind]);
+	else
+		delnode_usage(argv[0]);
+
+	doc = open_configfile(&ninfo);
+
+	root_element = xmlDocGetRootElement(doc);
+
+	increment_version(root_element);
+
+	del_clusternode(root_element, &ninfo);
+
+	/* Write it out */
+	save_file(doc, &ninfo);
+}
+
+void list_nodes(int argc, char **argv)
+{
+	xmlNode *cur_node;
+	xmlNode *root_element;
+	xmlNode *clusternodes;
+	xmlNode *fencenode = NULL;
+	xmlDocPtr doc;
+	xmlNode *mcast;
+	struct option_info ninfo;
+	int opt;
+	int verbose = 0;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+
+	while ( (opt = getopt_long(argc, argv, "c:vh?", list_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case '?':
+		default:
+			list_usage(argv[0]);
+		}
+	}
+	doc = open_configfile(&ninfo);
+
+	root_element = xmlDocGetRootElement(doc);
+
+
+	printf("\nCluster name: %s, config_version: %s\n\n",
+	       (char *)cluster_name(root_element),
+	       (char *)find_version(root_element));
+
+	clusternodes = findnode(root_element, "clusternodes");
+	if (!clusternodes)
+		die("Can't find \"clusternodes\" in %s\n", ninfo.configfile);
+
+	mcast = find_multicast_addr(root_element);
+	if (mcast)
+		printf("Multicast address for cluster: %s\n\n", xmlGetProp(mcast, BAD_CAST "addr"));
+
+	printf("Nodename                        Votes Nodeid Fencetype\n");
+	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
+		{
+			xmlChar *name   = xmlGetProp(cur_node, BAD_CAST "name");
+			xmlChar *votes  = xmlGetProp(cur_node, BAD_CAST "votes");
+			xmlChar *nodeid = xmlGetProp(cur_node, BAD_CAST "nodeid");
+			xmlChar *ftype  = get_fence_type(cur_node, &fencenode);
+
+			if (!nodeid)
+				nodeid=(unsigned char *)"0";
+			if (!votes)
+				votes = (unsigned char *)"1";
+
+			printf("%-32s %3d  %3d    %s\n", name, atoi((char *)votes),
+			       atoi((char *)nodeid),
+			       ftype?ftype:(xmlChar *)"");
+			if (verbose)
+			{
+				xmlNode *a = findnode(cur_node, "altname");
+				if (a)
+				{
+					printf(" altname %s=%s", "name", xmlGetProp(a, BAD_CAST "name"));
+					if (!print_properties(a, "","",""))
+						printf("\n");
+				}
+				print_properties(cur_node, "  Node properties: ", "votes", "nodeid");
+				print_properties(fencenode, "  Fence properties: ", "agent", "");
+			}
+
+		}
+	}
+}
+
+void create_skeleton(int argc, char **argv)
+{
+	xmlNode *root_element;
+	xmlNode *fencedevices;
+	xmlNode *clusternodes;
+	xmlNode *rm;
+	xmlNode *rm1;
+	xmlNode *rm2;
+	xmlDocPtr doc;
+	char *clustername;
+	struct option_info ninfo;
+	struct stat st;
+	int twonode = 0;
+	int opt;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+
+	while ( (opt = getopt_long(argc, argv, "c:2h?", list_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case '2':
+			twonode = 1;
+			break;
+
+		case '?':
+		default:
+			create_usage(argv[0]);
+		}
+	}
+	if (!ninfo.outputfile)
+		ninfo.outputfile = DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE;
+	ninfo.configfile = "-";
+
+	if (argc - optind < 1)
+		create_usage(argv[0]);
+
+	clustername = argv[optind];
+
+	if (stat(ninfo.outputfile, &st) == 0)
+		die("%s already exists", ninfo.outputfile);
+
+	/* Init libxml */
+	xmlInitParser();
+	LIBXML_TEST_VERSION;
+
+	doc = xmlNewDoc(BAD_CAST "1.0");
+	root_element = xmlNewNode(NULL, BAD_CAST "cluster");
+	xmlDocSetRootElement(doc, root_element);
+
+	xmlSetProp(root_element, BAD_CAST "name", BAD_CAST clustername);
+	xmlSetProp(root_element, BAD_CAST "config_version", BAD_CAST "1");
+
+	/* Generate extra bits for a 2node cman cluster */
+	if (twonode) {
+
+		xmlNode *cman = xmlNewNode(NULL, BAD_CAST "cman");
+		xmlSetProp(cman, BAD_CAST "two_node", BAD_CAST "1");
+		xmlSetProp(cman, BAD_CAST "expected_votes", BAD_CAST "1");
+		xmlAddChild(root_element, cman);
+	}
+
+	clusternodes = xmlNewNode(NULL, BAD_CAST "clusternodes");
+	fencedevices = xmlNewNode(NULL, BAD_CAST "fencedevices");
+	rm = xmlNewNode(NULL, BAD_CAST "rm");
+	rm1 = xmlNewNode(NULL, BAD_CAST "failoverdomains");
+
+	xmlAddChild(root_element, clusternodes);
+	xmlAddChild(root_element, fencedevices);
+	xmlAddChild(root_element, rm);
+
+	/* Create empty resource manager sections to keep GUI happy */
+	rm2 = xmlNewNode(NULL, BAD_CAST "resources");
+	xmlAddChild(rm, rm1);
+	xmlAddChild(rm, rm2);
+
+	save_file(doc, &ninfo);
+
+}
+
+void add_fence(int argc, char **argv)
+{
+	xmlNode *root_element;
+	xmlNode *fencedevices;
+	xmlNode *fencenode = NULL;
+	xmlDocPtr doc;
+	char *fencename;
+	char *agentname;
+	struct option_info ninfo;
+	int opt;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+	ninfo.tell_ccsd = 1;
+
+	while ( (opt = getopt_long(argc, argv, "c:o:CFh?", list_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+		case 'o':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case 'C':
+			ninfo.tell_ccsd = 0;
+			break;
+
+		case 'F':
+			ninfo.force_ccsd = 1;
+			break;
+
+		case '?':
+		default:
+			addfence_usage(argv[0]);
+		}
+	}
+
+	if (argc - optind < 2)
+		addfence_usage(argv[0]);
+
+	doc = open_configfile(&ninfo);
+	root_element = xmlDocGetRootElement(doc);
+
+	increment_version(root_element);
+
+	fencedevices = findnode(root_element, "fencedevices");
+	if (!fencedevices)
+		die("Can't find \"fencedevices\" %s\n", ninfo.configfile);
+
+	/* First param is the fence name - check it doesn't already exist */
+	fencename = argv[optind++];
+
+	if (valid_fence_type(root_element, fencename))
+		die("fence type %s already exists\n", fencename);
+
+	agentname = argv[optind++];
+
+	/* Add it */
+	fencenode = xmlNewNode(NULL, BAD_CAST "fencedevice");
+	xmlSetProp(fencenode, BAD_CAST "name", BAD_CAST fencename);
+	xmlSetProp(fencenode, BAD_CAST "agent", BAD_CAST agentname);
+
+	/* Add name=value options */
+	add_fence_args(fencenode, argc, argv, optind);
+
+	xmlAddChild(fencedevices, fencenode);
+
+	save_file(doc, &ninfo);
+}
+
+void del_fence(int argc, char **argv)
+{
+	xmlNode *root_element;
+	xmlNode *fencedevices;
+	xmlNode *fencenode;
+	xmlDocPtr doc;
+	char *fencename;
+	struct option_info ninfo;
+	int opt;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+	ninfo.tell_ccsd = 1;
+
+	while ( (opt = getopt_long(argc, argv, "c:o:CFhv?", list_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+		case 'o':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case 'C':
+			ninfo.tell_ccsd = 0;
+			break;
+
+		case 'F':
+			ninfo.force_ccsd = 1;
+			break;
+
+		case '?':
+		default:
+			delfence_usage(argv[0]);
+		}
+	}
+
+	if (argc - optind < 1)
+		delfence_usage(argv[0]);
+
+	fencename = argv[optind];
+
+	doc = open_configfile(&ninfo);
+	root_element = xmlDocGetRootElement(doc);
+	increment_version(root_element);
+
+	fencedevices = findnode(root_element, "fencedevices");
+	if (!fencedevices)
+		die("Can't find \"fencedevices\" in %s\n", ninfo.configfile);
+
+	fencenode = valid_fence_type(root_element, fencename);
+	if (!fencenode)
+		die("fence type %s does not exist\n", fencename);
+
+	xmlUnlinkNode(fencenode);
+
+	save_file(doc, &ninfo);
+}
+
+void list_fences(int argc, char **argv)
+{
+	xmlNode *cur_node;
+	xmlNode *root_element;
+	xmlNode *fencedevices;
+	xmlDocPtr doc;
+	struct option_info ninfo;
+	int opt;
+	int verbose=0;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+
+	while ( (opt = getopt_long(argc, argv, "c:hv?", list_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case '?':
+		default:
+			list_usage(argv[0]);
+		}
+	}
+	doc = open_configfile(&ninfo);
+	root_element = xmlDocGetRootElement(doc);
+
+	fencedevices = findnode(root_element, "fencedevices");
+	if (!fencedevices)
+		die("Can't find \"fencedevices\" in %s\n", ninfo.configfile);
+
+
+	printf("Name             Agent\n");
+	for (cur_node = fencedevices->children; cur_node; cur_node = cur_node->next)
+	{
+		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "fencedevice") == 0)
+		{
+			xmlChar *name  = xmlGetProp(cur_node, BAD_CAST "name");
+			xmlChar *agent = xmlGetProp(cur_node, BAD_CAST "agent");
+
+			printf("%-16s %s\n", name, agent);
+			if (verbose)
+				print_properties(cur_node, "  Properties: ", "agent", "");
+		}
+	}
+}
+
diff --git a/config/tools/ccs_tool/editconf.h b/config/tools/ccs_tool/editconf.h
new file mode 100644
index 0000000..1847e2c
--- /dev/null
+++ b/config/tools/ccs_tool/editconf.h
@@ -0,0 +1,8 @@
+void add_node(int argc, char **argv);
+void add_nodeids(int argc, char **argv);
+void add_fence(int argc, char **argv);
+void del_node(int argc, char **argv);
+void del_fence(int argc, char **argv);
+void list_nodes(int argc, char **argv);
+void list_fences(int argc, char **argv);
+void create_skeleton(int argc, char **argv);
diff --git a/config/tools/ccs_tool/update.c b/config/tools/ccs_tool/update.c
new file mode 100644
index 0000000..d8c1308
--- /dev/null
+++ b/config/tools/ccs_tool/update.c
@@ -0,0 +1,673 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "comm_headers.h"
+#include "libccscompat.h"
+#include "libcman.h"
+
+typedef struct member_list {
+  int count;
+  int pad;
+  cman_node_t *nodes;
+} member_list_t;
+
+static member_list_t *get_member_list(cman_handle_t handle);
+static void free_member_list(member_list_t *list);
+
+static int select_retry(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *xfds,
+			struct timeval *timeout);
+
+static ssize_t read_retry(int fd, void *buf, int count, struct timeval *timeout);
+
+static int ccs_open(cman_node_t node, uint16_t baseport, int timeout);
+static int ipv4_connect(struct in_addr *addr, uint16_t port, int timeout);
+static int ipv6_connect(struct in6_addr *addr, uint16_t port, int timeout);
+static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, int timeout);
+
+extern int globalverbose;
+
+int cluster_base_port = 50008;
+
+static int get_doc_version(xmlDocPtr ldoc)
+{
+  int i;
+  int error = 0;
+
+  xmlXPathObjectPtr  obj = NULL;
+  xmlXPathContextPtr ctx = NULL;
+  xmlNodePtr        node = NULL;
+
+  ctx = xmlXPathNewContext(ldoc);
+
+  if (!ctx) {
+    fprintf(stderr, "Unable to create new XPath context.\n");
+    error = -EIO;  /* ATTENTION -- what should this be? */
+    goto fail;
+  }
+
+  obj = xmlXPathEvalExpression((xmlChar *)"/cluster/@config_version", ctx);
+
+  if (!obj || !obj->nodesetval || (obj->nodesetval->nodeNr != 1)) {
+    fprintf(stderr, "Error while retrieving config_version.\n");
+    error = -ENODATA;
+    goto fail;
+  }
+
+  node = obj->nodesetval->nodeTab[0];
+
+  if (node->type != XML_ATTRIBUTE_NODE) {
+    fprintf(stderr, "Object returned is not of attribute type.\n");
+    error = -ENODATA;
+    goto fail;
+  }
+
+  if (!node->children->content || !strlen((char *)node->children->content)) {
+    error = -ENODATA;
+    goto fail;
+  }
+
+  for (i = 0; i < strlen((char *)node->children->content); i++) {
+    if (!isdigit(node->children->content[i])) {
+      fprintf(stderr, "config_version is not a valid integer.\n");
+      error = -EINVAL;
+      goto fail;
+    }
+  }
+
+  error = atoi((char *)node->children->content);
+
+fail:
+
+  if (ctx) {
+    xmlXPathFreeContext(ctx);
+  }
+
+  if (obj) {
+    xmlXPathFreeObject(obj);
+  }
+
+  return error;
+}
+
+
+int update(char *location)
+{
+  int error = 0;
+  int i, fd;
+  int cluster_fd = -1;
+  char true_location[256];
+  xmlDocPtr doc = NULL;
+  xmlChar *mem_doc;
+  int doc_size = 0;
+  char *buffer = NULL;
+  comm_header_t *ch = NULL, rch;
+  member_list_t *members = NULL;
+  cman_handle_t handle = NULL;
+  int desc;
+  char *v1_str,*v3_str;
+  int v1, v2, v3;
+
+  struct timeval tv;
+
+  if (location[0] != '/') {
+    memset(true_location, 0, 256);
+    if (!getcwd(true_location, 256)) {
+      fprintf(stderr, "Unable to get the current working directory.\n");
+      return -errno;
+    }
+    true_location[strlen(true_location)] = '/';
+    strncpy(true_location+strlen(true_location), location, 256-strlen(true_location));
+  } else {
+    strncpy(true_location, location, 256);
+  }
+
+  desc = ccs_connect();
+
+  if (desc < 0) {
+    fprintf(stderr, "Unable to connect to the CCS daemon: %s\n", strerror(-desc));
+    return desc;
+  }
+
+  if ((error = ccs_get(desc, "/cluster/@config_version", &v1_str))) {
+    fprintf(stderr, "Unable to get current config_version: %s\n", strerror(-error));
+    ccs_disconnect(desc);
+    return error;
+  }
+
+  ccs_disconnect(desc);
+
+  for (i = 0; i < strlen(v1_str); i++) {
+    if (!isdigit(v1_str[i])) {
+      fprintf(stderr, "config_version is not a valid integer.\n");
+      free(v1_str);
+      return -EINVAL;
+    }
+  }
+
+  v1 = atoi(v1_str);
+  free(v1_str);
+
+  doc = xmlParseFile(true_location);
+
+  if (!doc) {
+    fprintf(stderr, "Unable to parse %s\n", true_location);
+    return -EINVAL;
+  }
+
+  v2 = get_doc_version(doc);
+
+  if (v2 < 0) {
+    fprintf(stderr, "Unable to get the config_version from %s\n", location);
+    xmlFreeDoc(doc);
+    return -EINVAL;
+  }
+
+  if (v2 <= v1)  {
+    fprintf(stderr,
+	    "Proposed updated config file does not have greater version number.\n"
+	    "  Current config_version :: %d\n"
+	    "  Proposed config_version:: %d\n", v1, v2);
+    xmlFreeDoc(doc);
+    return -EINVAL;
+  }    
+
+  xmlDocDumpFormatMemory(doc, &mem_doc, &doc_size, 0);
+
+  if (!mem_doc) {
+    fprintf(stderr, "Unable to allocate memory for update document.\n");
+    xmlFreeDoc(doc);
+    return -ENOMEM;
+  }
+
+  xmlFreeDoc(doc);
+
+  buffer = malloc(doc_size + sizeof(comm_header_t));
+
+  if (!buffer) {
+    fprintf(stderr, "Unable to allocate memory for transfer buffer.\n");
+    free(mem_doc);
+    return -ENOMEM;
+  }
+
+  memset(buffer, 0, (doc_size + sizeof(comm_header_t)));
+  ch = (comm_header_t *)buffer;
+
+  memcpy(buffer+sizeof(comm_header_t), mem_doc, doc_size);
+  free(mem_doc);
+
+  ch->comm_type = COMM_UPDATE;
+  ch->comm_flags= COMM_UPDATE_NOTICE;
+  ch->comm_payload_size = doc_size;
+
+  handle = cman_admin_init(NULL);
+
+  cluster_fd = cman_get_fd(handle);
+
+  /* Should we test the cman handle of file descriptor to determine connectivity? */
+
+  if (cluster_fd < 0) {
+    fprintf(stderr, "Unable to connect to cluster infrastructure.\n");
+    return cluster_fd;
+  }
+
+  if (!cman_is_quorate(handle)) {
+    fprintf(stderr, "Unable to honor update request. Cluster is not quorate.\n");
+    return -EPERM;
+  }
+
+  members = get_member_list(handle);
+
+  swab_header(ch);
+  
+  for (i = 0; i < members->count; i++) {
+    if (members->nodes[i].cn_nodeid == 0)
+      continue;
+    if (members->nodes[i].cn_member == 0)
+      continue;
+
+    fd = ccs_open(members->nodes[i], cluster_base_port, 5);
+
+    if (fd < 0) {
+      fprintf(stderr, "Unable to open connection to %s: %s\n",
+	      members->nodes[i].cn_name, strerror(errno));
+      free(buffer);
+      free_member_list(members);
+      return -errno;
+    }
+
+    error = write(fd, buffer, sizeof(comm_header_t) + doc_size);
+
+    if (error < 0) {
+      fprintf(stderr, "Unable to send msg to %s: %s\n",
+	      members->nodes[i].cn_name, strerror(errno));
+      close(fd);
+      free(buffer);
+      free_member_list(members);
+      return -errno;
+    }
+
+    tv.tv_sec = 5;
+    tv.tv_usec = 0;
+
+    error = read_retry(fd, &rch, sizeof(comm_header_t), &tv);
+
+    swab_header(&rch);
+
+    if (error < 0) {
+      fprintf(stderr, "Failed to receive COMM_UPDATE_NOTICE_ACK from %s.\n",
+	      members->nodes[i].cn_name);
+      fprintf(stderr, "Hint: Check the log on %s for reason.\n",
+	      members->nodes[i].cn_name);
+      close(fd);
+      free(buffer);
+      free_member_list(members);
+      return -errno;
+    }
+
+    close(fd);
+  }
+
+  swab_header(ch);
+  
+  ch->comm_flags = COMM_UPDATE_COMMIT;
+
+  swab_header(ch);
+
+  for (i=0; i < members->count; i++) {
+    if (members->nodes[i].cn_nodeid == 0)
+      continue;
+    if (members->nodes[i].cn_member == 0)
+      continue;
+
+    fd = ccs_open(members->nodes[i], cluster_base_port, 5);
+    if(fd < 0){
+      fprintf(stderr, "Unable to open connection to %s: %s\n",
+	      members->nodes[i].cn_name, strerror(errno));
+      free(buffer);
+      free_member_list(members);
+      return -errno;
+    }
+
+    error = write(fd, buffer, sizeof(comm_header_t));
+
+    if (error < 0) {
+      fprintf(stderr, "Unable to send msg to %s: %s\n",
+	      members->nodes[i].cn_name, strerror(errno));
+      close(fd);
+      free(buffer);
+      free_member_list(members);
+      return -errno;
+    }
+
+    tv.tv_sec = 5;
+    tv.tv_usec = 0;
+
+    error = read_retry(fd, &rch, sizeof(comm_header_t), &tv);
+
+    swab_header(&rch);
+
+    if (error < 0) {
+      fprintf(stderr, "Failed to receive COMM_UPDATE_COMMIT_ACK from %s.\n",
+	      members->nodes[i].cn_name);
+      fprintf(stderr, "Hint: Check the log on %s for reason.\n",
+	      members->nodes[i].cn_name);
+      close(fd);
+      free(buffer);
+      free_member_list(members);
+      return -errno;
+    }
+
+    close(fd);
+    error = 0;
+  }
+
+  free(buffer);
+  free_member_list(members);
+
+  /* If we can't connect here, it doesn't mean the update failed **
+  ** It means that we simply can't report the change in version  */
+  desc = ccs_connect();
+
+  if (desc < 0) {
+    fprintf(stderr, "Unable to connect to the CCS daemon: %s\n", strerror(-desc));
+    return 0;
+  }
+
+  if ((error = ccs_get(desc, "/cluster/@config_version", &v3_str))) {
+    ccs_disconnect(desc);
+    return 0;
+  }
+
+  v3 = atoi(v3_str);
+  free(v3_str);
+
+  ccs_disconnect(desc);
+
+  if (v2 == v3) {
+    cman_version_t cman_ver;
+    printf("Config file updated from version %d to %d\n", v1, v2);
+    cman_get_version(handle, &cman_ver);
+    cman_ver.cv_config = v2;
+    if (cman_set_version(handle, &cman_ver)) {
+	    perror("Failed to tell cman of new version number");
+    }
+  } else {
+    fprintf(stderr, "Warning:: Simultaneous update requests detected.\n"
+	    "  You have lost the race.\n"
+	    "  Old config version :: %d\n"
+	    "  Proposed config version :: %d\n"
+	    "  Winning config version  :: %d\n\n"
+	    "Check " DEFAULT_CONFIG_DIR "/" DEFAULT_CONFIG_FILE " to ensure it contains the desired contents.\n", v1, v2, v3);
+    return -EAGAIN;
+  }
+
+  return 0;
+}
+
+
+static member_list_t *get_member_list(cman_handle_t handle)
+{
+  int count = 0;
+
+  member_list_t *list = NULL;
+  cman_node_t *nodes = NULL;
+
+  do
+  {
+
+    if (nodes != NULL) {
+      free(nodes);
+    }
+
+    count = cman_get_node_count(handle);
+
+    if (count <= 0) {
+      return NULL;
+    }
+
+    if (list == NULL) {
+      list = malloc(sizeof(*list));
+    }
+
+    if (list == NULL) {
+      return NULL;
+    }
+
+    nodes = malloc(sizeof(*nodes) * count);
+
+    if (nodes == NULL) {
+      free(list);
+      return NULL;
+    }
+
+    memset(list, 0, sizeof(*list));
+    memset(nodes, 0, sizeof(*nodes) * count);
+
+    cman_get_nodes(handle, count, &list->count, nodes);
+
+  } while (list->count != count);
+
+  list->count = count;
+  list->nodes = nodes;
+
+  return list;
+}
+
+
+static void free_member_list(member_list_t *list)
+{
+  if (list != NULL) {
+    if (list->nodes != NULL) {
+      free(list->nodes);
+    }
+    free(list);
+  }
+}
+
+
+static int select_retry(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *xfds,
+			struct timeval *timeout)
+{
+  int rv;
+
+  while (1) {
+    rv = select(max_fd, rfds, wfds, xfds, timeout);
+    if ((rv == -1) && (errno == EINTR)) {
+      /* return on EBADF/EINVAL/ENOMEM; continue on EINTR */
+      continue;
+    }
+    return rv;
+  }
+}
+
+
+static ssize_t read_retry(int fd, void *buf, int count, struct timeval *timeout)
+{
+  int n, total = 0, remain = count, rv = 0;
+  fd_set rfds, xfds;
+
+  while (total < count) 
+  {
+    FD_ZERO(&rfds);
+    FD_SET(fd, &rfds);
+    FD_ZERO(&xfds);
+    FD_SET(fd, &xfds);
+
+    /*
+     * Select on the socket, in case it closes while we're not
+     * looking...
+     */
+    rv = select_retry(fd + 1, &rfds, NULL, &xfds, timeout);
+    if (rv == -1) {
+      return -1;
+    }
+    else if (rv == 0) {
+      errno = ETIMEDOUT;
+      return -1;
+    }
+
+    if (FD_ISSET(fd, &xfds)) {
+      errno = EPIPE;
+      return -1;
+    }
+
+    /* 
+     * Attempt to read off the socket 
+     */
+    n = read(fd, buf + (off_t) total, remain);
+
+    /*
+     * When we know our socket was select()ed and we receive 0 bytes
+     * when we read, the socket was closed.
+     */
+    if ((n == 0) && (rv == 1)) {
+      errno = EPIPE;
+      return -1;
+    }
+
+    if (n == -1) {
+      if ((errno == EAGAIN) || (errno == EINTR)) {
+	/* 
+	 * Not ready? Wait for data to become available
+	 */
+	continue;
+      }
+
+      /* Other errors: EPIPE, EINVAL, etc */
+      return -1;
+    }
+
+    total += n;
+    remain -= n;
+  }
+
+  return total;
+}
+
+
+static int ccs_open(cman_node_t node, uint16_t port, int timeout)
+{
+  struct in_addr *addr;
+  struct in6_addr *addr6;
+  int fd, family;
+  char buf[INET6_ADDRSTRLEN];
+
+  if (globalverbose) {
+    memset(buf, 0, sizeof(buf));
+    printf("Processing node: %s\n", node.cn_name);
+  }
+
+  family = ((struct sockaddr *)&(node.cn_address.cna_address))->sa_family;
+
+  if (family == AF_INET6) {
+
+    addr6 = &(((struct sockaddr_in6 *)&(node.cn_address.cna_address))->sin6_addr);
+
+    if (globalverbose) {
+      inet_ntop(family, addr6, buf, sizeof(buf));
+      printf(" family: ipv6\n address: %s\n", buf);
+    }
+
+    if ((fd = ipv6_connect(addr6, port, timeout)) < 0) {
+      return -1;
+    }
+
+  } else {
+
+    addr = &(((struct sockaddr_in *)&(node.cn_address.cna_address))->sin_addr);
+
+    if (globalverbose) {
+      inet_ntop(family, addr, buf, sizeof(buf));
+      printf(" family: ipv4\n address: %s\n", buf);
+    }
+
+    if ((fd = ipv4_connect(addr, port, timeout)) < 0) {
+      return -1;
+    }
+
+  }
+
+  return fd;
+}
+
+
+static int ipv4_connect(struct in_addr *addr, uint16_t port, int timeout)
+{
+  struct sockaddr_in sin;
+
+  int fd;
+
+  if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+    return -1;
+  }
+
+  sin.sin_family = AF_INET;
+  sin.sin_port = htons(port);
+
+  memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
+
+  if (connect_nb(fd, (struct sockaddr *)&sin, sizeof(sin), timeout) < 0) {
+    close(fd);
+    return -1;
+  }
+
+  return fd;
+}
+
+
+static int ipv6_connect(struct in6_addr *addr, uint16_t port, int timeout)
+{
+  struct sockaddr_in6 sin6;
+
+  int fd;
+
+  if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
+    return -1;
+  }
+
+  memset(&sin6, 0, sizeof(sin6));
+
+  sin6.sin6_family = AF_INET6;
+  sin6.sin6_port = htons(port);
+  sin6.sin6_flowinfo = 0;
+
+  memcpy(&sin6.sin6_addr, addr, sizeof(sin6.sin6_addr));
+
+  if (connect_nb(fd, (struct sockaddr *)&sin6, sizeof(sin6), timeout)) {
+    close(fd);
+    return -1;
+  }
+
+  return fd;
+}
+
+
+static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, int timeout)
+{
+  int err;
+  int ret;
+  int flags = 1;
+  unsigned l;
+  fd_set rfds, wfds;
+
+  struct timeval tv;
+
+  if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0) {
+    return -1;
+  }
+
+  flags = fcntl(fd, F_GETFL, 0);
+  fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+  ret = connect(fd, addr, len);
+
+  if ((ret < 0) && (errno != EINPROGRESS)) {
+    return -1;
+  }
+
+  if (ret != 0) {
+    FD_ZERO(&rfds);
+    FD_SET(fd, &rfds);
+    FD_ZERO(&wfds);
+    FD_SET(fd, &wfds);
+
+    tv.tv_sec = timeout;
+    tv.tv_usec = 0;
+
+    if (select_retry((fd + 1), &rfds, &wfds, NULL, &tv) == 0) {
+      errno = ETIMEDOUT;
+      return -1;
+    }
+
+    if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds)) {
+      l = sizeof(err);
+      if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &l) < 0) {
+	close(fd);
+	return -1;
+      }
+
+      if (err != 0) {
+	close(fd);
+	errno = err;
+	return -1;
+      }
+
+      fcntl(fd, F_SETFL, flags);
+      return 0;
+    }
+  }
+
+  errno = EIO;
+  return -1;
+}
diff --git a/config/tools/ccs_tool/update.h b/config/tools/ccs_tool/update.h
new file mode 100644
index 0000000..2f41aa4
--- /dev/null
+++ b/config/tools/ccs_tool/update.h
@@ -0,0 +1,6 @@
+#ifndef __UPDATE_DOT_H__
+#define __UPDATE_DOT_H__
+
+int update(char *location);
+
+#endif /* __UPDATE_DOT_H__ */
diff --git a/config/tools/man/Makefile b/config/tools/man/Makefile
index ee4d874..c40d94b 100644
--- a/config/tools/man/Makefile
+++ b/config/tools/man/Makefile
@@ -1,4 +1,10 @@
-TARGET= confdb2ldif.8
+TARGET= ccs_tool.8 \
+	confdb2ldif.8
 
 include ../../../make/defines.mk
+
+ifdef legacy_code
+TARGET += ccs_test.8
+endif
+
 include $(OBJDIR)/make/man.mk
diff --git a/config/tools/man/ccs_test.8 b/config/tools/man/ccs_test.8
new file mode 100644
index 0000000..9dce13c
--- /dev/null
+++ b/config/tools/man/ccs_test.8
@@ -0,0 +1,132 @@
+.TH ccs_test 8
+
+.SH NAME
+ccs_test - CCS daemon (ccsd) diagnostic tool
+
+.SH SYNOPSIS
+.B ccs_test
+[\fBoptions\fP]
+<\fBcommand\fP>
+
+.SH DESCRIPTION
+\fBccs_test\fP is part of the Cluster Configuration System (CCS).  It is a
+diagnostic tool that reads cluster.conf information to test ccsd.
+
+.SH OPTIONS
+.TP
+\fB-h\fP
+Help.  Print out the usage syntax and exit.
+.TP
+\fB-V\fP
+Print the version information and exit.
+
+.SH COMMANDS
+.TP
+\fBconnect\fP \fI[force]\fP \fI[block]\fP \fI[cluster name]\fP
+This command creates a connection to ccsd.  It returns a descriptor, which
+is used as an parameter to other commands.
+
+The 'force' key-word is used to establish a connection to ccsd in the
+absence of a quorate cluster manager.
+
+The 'block' key-word is used (with the 'force' key-word) to tell ccsd to
+keep broadcasting for a valid configuration file until one is found.
+
+The 'cluster name' is used (with the 'force' key-word) to specify that
+only configuration files containing the given cluster name are valid
+possibilities.
+
+.TP
+\fBget\fP \fI<desc>\fP \fI<request>\fP
+Get the results of a given request.  The 'desc' is the number returned
+from the \fBconnect\fP command.  The 'request' is a valid Xpath request.
+
+If 'request' results in multiple matches, the first will be returned.
+Subsequent calls with the same 'request' will result in the subsequent
+matches.  Once all the matches have been returned, a subsequent call
+will begin again with the first result.
+
+.TP
+\fBget_list\fP \fI<desc>\fP \fI<request>\fP
+Similar to the \fBget\fP command.  However, issuing subsequent calls
+with the same 'request' will result in all matches being returned (one
+at a time), then null, then starting over with the first result.
+
+.TP
+\fBset\fP \fI<desc>\fP \fI<path>\fP \fI<value>\fP
+Sets a particular 'path' to the given 'value'.  Not yet implemented.
+
+.TP
+\fBget_state\fP \fI<desc>\fP
+Get the state associated with a given connection.
+
+.TP
+\fBset_state\fP \fI<desc>\fP \fI<ncwp>\fP
+Set the current working path (cwp) to 'ncwp' for a given connection.
+
+.SH EXAMPLES
+.SS To connect to ccsd:
+
+> ccs_test connect
+
+Connect successful.
+ Connection descriptor = 0
+
+Or, if the cluster is not yet quorate and the name of the cluster is 'mycluster':
+
+> ccs_test connect force block mycluster
+
+Connect successful.
+ Connection descriptor = 0
+
+.SS To get the cluster name from ccsd:
+
+> ccs_test get 0 /cluster/@name
+
+Get successful.
+ Value = <mycluster>
+
+.SS To get the connection state:
+
+> ccs_test get_state 0
+
+Get state successful.
+ Current working path:
+ Previous query      : /cluster/@name
+
+
+.SS To set the connection state:
+
+> ccs_test set_state 0 /cluster
+
+Set state successful.
+
+
+.SS After setting the connection state, note the change:
+
+> ccs_test get_state 0
+
+Get state successful.
+ Current working path: /cluster
+ Previous query      : /cluster/@name
+
+.SS After setting the connection state, you can now query with an absolute or relative path:
+
+> ccs_test get 0 @name
+
+Get successful.
+ Value = <brassow>
+
+> ccs_test get 0 /cluster/@name
+
+Get successful.
+ Value = <brassow>
+
+.SS To disconnect:
+
+> ccs_test disconnect 0
+
+Disconnect successful.
+
+.SH SEE ALSO
+ccs(7), ccsd(8), cluster.conf(5)
diff --git a/config/tools/man/ccs_tool.8 b/config/tools/man/ccs_tool.8
new file mode 100644
index 0000000..ef13406
--- /dev/null
+++ b/config/tools/man/ccs_tool.8
@@ -0,0 +1,185 @@
+.TH "ccs_tool" "8" "" "" ""
+.SH "NAME"
+ccs_tool \- The tool used to make online updates of CCS config files.
+
+.SH "SYNOPSIS"
+.B ccs_tool
+[\fIOPTION\fR].. <\fBcommand\fP>
+
+.SH "DESCRIPTION"
+
+\fBccs_tool\fP is part of the Cluster Configuration System (CCS).  It is
+used to make online updates to cluster.conf.  It can also be used to
+upgrade old style (GFS <= 6.0) CCS archives to the new xml cluster.conf
+format.
+
+.SH "OPTIONS"
+.TP 
+\fB\-h\fP
+Help.  Print out the usage.
+.TP 
+\fB\-V\fP
+Print the version information.
+
+sub\-commands have their own options, see below for more detail
+.SH "COMMANDS"
+.TP 
+\fBupdate\fP \fI<xml file>\fP
+This command is used to update the config file that ccsd is working with
+while the cman cluster is operational (i.e. online).  Run this on a single
+machine to update cluster.conf on all current cluster members.  This also
+notifies cman of the new config version.
+
+.TP 
+\fBupgrade\fP \fI<location>\fP
+This command is used to upgrade an old CCS format archive to the new
+xml format.  \fI<location>\fP is the location of the old archive,
+which can be either a block device archive or a file archive.  The
+converted configuration will be printed to stdout.
+
+.TP 
+\fBaddnode\fP [options] \fI<node> [<fenceoption=value>]...\fP
+Adds a new node to the cluster configuration file. Fencing device options
+are specified as key=value pairs (as many as required) and are entered into the
+configuration file as is. See the documentation for your fencing agent for more
+details (eg a powerswitch fence device may need to know which port the node is
+connected to).
+.br
+\fIOptions:\fP
+.br
+\-v <votes>        Number of votes for this node (mandatory)
+.br 
+\-n <nodeid>       Node id for this node (optional)
+.br
+\-i <interface>    Network interface to use for this node. Mandatory if the cluster 
+is using multicast as transport. Forbidden if not.
+.br
+\-m <multicast>    Multicast address for cluster. Only allowed on the first node to 
+be added to the file. Subsequent nodes will use either multicast or broadcast 
+depending on the properties of the first node.
+.br
+\-f <fencedevice>  Name of fence device to use for this node. The fence device 
+section must already have been added to the file, probably using the addfence command.
+.br
+\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
+.br
+\-o <file>         Output file. Defaults to the same as -c
+.br
+\-C                Don't run "ccs_tool update" after changing file. This will
+happen by default if the input file is the same as the output file.
+.br
+\-F                Force a "ccs_tool update" even if the input and output files
+are different.
+
+
+
+.TP 
+\fBdelnode\fP [options] \fI<node>\fP
+Delete a node from the cluster configuration file. Note: there is no 
+"edit" command so to change the properties of a node you must delete it
+and add it back in with the new properties.
+.br
+\fIOptions:\fP
+.br
+\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
+.br
+\-o <file>         Output file. Defaults to the same as -c
+.br
+\-C                Don't run "ccs_tool update" after changing file. This will
+happen by default if the input file is the same as the output file.
+.br
+\-F                Force a "ccs_tool update" even if the input and output files
+are different.
+
+
+
+.TP 
+\fBaddfence\fP [options] \fI<name> <agent> [<option>=<value>]...\fP
+Adds a new fence device section to the cluster configuration file. <agent> is the
+name of the fence agent that controls the device. the options following are entered
+as key-value pairs. See the fence agent documentation for details about these. eg:
+you may need to enter the IP address and username/password for a powerswitch fencing
+device.
+.br
+\fIOptions:\fP
+.br
+\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
+.br
+\-o <file>         Output file. Defaults to the same as -c
+.br
+\-C                Don't run "ccs_tool update" after changing file. This will
+happen by default if the input file is the same as the output file.
+.br
+\-F                Force a "ccs_tool update" even if the input and output files
+are different.
+
+.TP 
+\fBdelfence\fP [options] \fI<node>\fP
+Deletes a fencing device from the cluster configuration file.
+delfence will allow you to remove a fence device that is in use by nodes.
+This is to allow changes to be made, but be aware that it may produce an
+invalid configuration file if you don't add it back in again.
+.br
+\fIOptions:\fP
+.br
+\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
+.br
+\-o <file>         Output file. Defaults to the same as -c
+.br
+\-C                Don't run "ccs_tool update" after changing file. This will
+happen by default if the input file is the same as the output file.
+.br
+\-F                Force a "ccs_tool update" even if the input and output files
+are different.
+
+
+.TP 
+\fBlsnode [options] \fP
+List the nodes in the configuration file. This is (hopefully obviously) not
+necessarily the same as the nodes currently in the cluster, but it should
+be a superset.
+.br
+\fIOptions:\fP
+.br
+\-v                Verbose. Lists all the properties of the node, and the
+node-specific properties of the fence device too.
+.br
+\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
+
+
+.TP 
+\fBlsfence [options] \fP
+List all the fence devices in the cluster configuration file.
+.br
+\fIOptions:\fP
+.br
+\-v                Verbose. Lists all the properties of the fence device rather
+than just the names and agents.
+.br
+\-c <file>         Config file to use. Defaults to /etc/cluster/cluster.conf
+
+
+.TP 
+\fBcreate [options] \fP \fI<clustername>\fP
+Create a new, skeleton, configuration file. Note that "create" on its own will 
+not create a valid configuration file. Fence agents and nodes will need to be 
+added to it before handing it over to ccsd. The new configuration file will
+have a version number of 1. Subsequent addnode/delnode/addfence/delfence operations
+will increment the version number by 1 each time.
+.br
+\fIOptions:\fP
+.br
+.br
+\-c <file>         Config file to create. Defaults to /etc/cluster/cluster.conf
+
+.TP 
+\fBaddnodeids\fP
+Adds node ID numbers to all the nodes in cluster.conf. In RHEL4, node IDs were optional
+and assigned by cman when a node joined the cluster. In RHEL5 they must be pre-assigned
+in cluster.conf. This command will not change any node IDs that are already set in 
+cluster.conf, it will simply add unique node ID numbers to nodes that do not already
+have them.
+
+
+.SH "SEE ALSO"
+ccs(7), ccsd(8), cluster.conf(5)


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-08-14 15:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-08-14 16:00 master - config: move ccs/ccs_tool to config/tools/ccs_tool Fabio M. Di Nitto

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).