diff --git a/cib/cibio.h b/cib/cibio.h
index 2c53abdf04..b9cd7e1988 100644
--- a/cib/cibio.h
+++ b/cib/cibio.h
@@ -1,55 +1,54 @@
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #ifndef CIB_IO__H
 #  define CIB_IO__H
 
 #  include <stdio.h>
 #  include <sys/types.h>
 #  include <unistd.h>
 
 #  include <stdlib.h>
 #  include <errno.h>
 #  include <fcntl.h>
 
 #  include <crm/common/xml.h>
 #  include <crm/common/mainloop.h>
 
 extern gboolean initialized;
 extern xmlNode *the_cib;
 extern xmlNode *node_search;
 extern xmlNode *resource_search;
 extern xmlNode *constraint_search;
 extern xmlNode *status_search;
 
 extern xmlNode *get_the_CIB(void);
 
 extern int initializeCib(xmlNode * cib);
 extern gboolean uninitializeCib(void);
-extern xmlNode *createEmptyCib(void);
 extern gboolean verifyCibXml(xmlNode * cib);
 extern xmlNode *readCibXml(char *buffer);
 extern xmlNode *readCibXmlFile(const char *dir, const char *file, gboolean discard_status);
 extern int activateCibBuffer(char *buffer, const char *filename);
 extern int activateCibXml(xmlNode * doc, gboolean to_disk, const char *op);
 extern crm_trigger_t *cib_writer;
 extern gboolean cib_writes_enabled;
 
 /* extern xmlNode *server_get_cib_copy(void); */
 
 #endif
diff --git a/cib/io.c b/cib/io.c
index b3ddf601e9..58f2b3ae51 100644
--- a/cib/io.c
+++ b/cib/io.c
@@ -1,844 +1,840 @@
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <dirent.h>
 
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 
 #include <crm/crm.h>
 
 #include <cibio.h>
 #include <crm/cib.h>
 #include <crm/common/util.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/util.h>
 #include <crm/cluster.h>
 
 #define CIB_SERIES "cib"
 #define CIB_SERIES_MAX 100
 #define CIB_SERIES_BZIP FALSE /* Must be false due to the way archived
                                * copies are created - ie. with calls to
                                * link()
                                */
 
 extern const char *cib_root;
 
 #define CIB_WRITE_PARANOIA	0
 
 const char *local_resource_path[] = {
     XML_CIB_TAG_STATUS,
 };
 
 const char *resource_path[] = {
     XML_CIB_TAG_RESOURCES,
 };
 
 const char *node_path[] = {
     XML_CIB_TAG_NODES,
 };
 
 const char *constraint_path[] = {
     XML_CIB_TAG_CONSTRAINTS,
 };
 
 crm_trigger_t *cib_writer = NULL;
 gboolean initialized = FALSE;
 xmlNode *node_search = NULL;
 xmlNode *resource_search = NULL;
 xmlNode *constraint_search = NULL;
 xmlNode *status_search = NULL;
 
 extern int cib_status;
 
 int set_connected_peers(xmlNode * xml_obj);
 void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data);
 int write_cib_contents(gpointer p);
 extern void cib_cleanup(void);
 
 static gboolean
 validate_cib_digest(xmlNode * local_cib, const char *sigfile)
 {
     char *digest = NULL;
     char *expected = NULL;
     gboolean passed = FALSE;
     FILE *expected_strm = NULL;
     int start = 0, length = 0, read_len = 0;
 
     CRM_ASSERT(sigfile != NULL);
 
     expected_strm = fopen(sigfile, "r");
     if (expected_strm == NULL && errno == ENOENT) {
         crm_warn("No on-disk digest present");
         return TRUE;
 
     } else if (expected_strm == NULL) {
         crm_perror(LOG_ERR, "Could not open signature file %s for reading", sigfile);
         goto bail;
     }
 
     if (local_cib != NULL) {
         digest = calculate_on_disk_digest(local_cib);
     }
 
     start = ftell(expected_strm);
     fseek(expected_strm, 0L, SEEK_END);
     length = ftell(expected_strm);
     fseek(expected_strm, 0L, start);
 
     CRM_ASSERT(length >= 0);
     CRM_ASSERT(start == ftell(expected_strm));
 
     if (length > 0) {
         crm_trace("Reading %d bytes from file", length);
         expected = calloc(1, (length + 1));
         read_len = fread(expected, 1, length, expected_strm);   /* Coverity: False positive */
         CRM_ASSERT(read_len == length);
     }
     fclose(expected_strm);
 
   bail:
     if (expected == NULL) {
         crm_err("On-disk digest is empty");
 
     } else if (safe_str_eq(expected, digest)) {
         crm_trace("Digest comparision passed: %s", digest);
         passed = TRUE;
 
     } else {
         crm_err("Digest comparision failed: expected %s (%s), calculated %s",
                 expected, sigfile, digest);
     }
 
     free(digest);
     free(expected);
     return passed;
 }
 
 static int
 write_cib_digest(xmlNode * local_cib, const char *digest_file, int fd, char *digest)
 {
     int rc = 0;
     char *local_digest = NULL;
     FILE *digest_strm = fdopen(fd, "w");
 
     if (digest_strm == NULL) {
         crm_perror(LOG_ERR, "Cannot open signature file %s for writing", digest_file);
         return -1;
     }
 
     if (digest == NULL) {
         local_digest = calculate_on_disk_digest(local_cib);
         CRM_ASSERT(digest != NULL);
         digest = local_digest;
     }
 
     rc = fprintf(digest_strm, "%s", digest);
     if (rc < 0) {
         crm_perror(LOG_ERR, "Cannot write to signature file %s", digest_file);
     }
 
     CRM_ASSERT(digest_strm != NULL);
     if (fflush(digest_strm) != 0) {
         crm_perror(LOG_ERR, "Couldnt flush the contents of %s", digest_file);
         rc = -1;
     }
 
     if (fsync(fileno(digest_strm)) < 0) {
         crm_perror(LOG_ERR, "Couldnt sync the contents of %s", digest_file);
         rc = -1;
     }
 
     fclose(digest_strm);
     free(local_digest);
     return rc;
 }
 
 static gboolean
 validate_on_disk_cib(const char *filename, xmlNode ** on_disk_cib)
 {
     int s_res = -1;
     struct stat buf;
     gboolean passed = TRUE;
     xmlNode *root = NULL;
 
     CRM_ASSERT(filename != NULL);
 
     s_res = stat(filename, &buf);
     if (s_res == 0) {
         char *sigfile = NULL;
         size_t fnsize;
 
         crm_trace("Reading cluster configuration from: %s", filename);
         root = filename2xml(filename);
 
         fnsize = strlen(filename) + 5;
         sigfile = calloc(1, fnsize);
         snprintf(sigfile, fnsize, "%s.sig", filename);
         if (validate_cib_digest(root, sigfile) == FALSE) {
             passed = FALSE;
         }
         free(sigfile);
     }
 
     if (on_disk_cib != NULL) {
         *on_disk_cib = root;
     } else {
         free_xml(root);
     }
 
     return passed;
 }
 
 static gboolean
 on_disk_cib_corrupt(const char *filename)
 {
     int s_res = -1;
     struct stat buf;
     gboolean corrupt = FALSE;
 
     CRM_ASSERT(filename != NULL);
 
     s_res = stat(filename, &buf);
     if (s_res == 0) {
         if (buf.st_size == 0) {
             crm_warn("Cluster configuration file %s is corrupt: size is zero", filename);
             corrupt = TRUE;
         }
     }
 
     return corrupt;
 }
 
 static int
 cib_rename(const char *old, const char *new)
 {
     int rc = 0;
     int automatic_fd = 0;
     char *automatic = NULL;
 
     if (new == NULL) {
         umask(S_IWGRP | S_IWOTH | S_IROTH);
 
         automatic = g_strdup_printf("%s/cib.auto.XXXXXX", cib_root);
         automatic_fd = mkstemp(automatic);
         new = automatic;
 
         crm_err("Archiving corrupt or unusable file %s as %s", old, automatic);
     }
 
     rc = rename(old, new);
     if (rc < 0) {
         crm_perror(LOG_ERR, "Couldn't rename %s as %s - Disabling disk writes and continuing", old,
                    new);
         cib_writes_enabled = FALSE;
     }
     if (automatic_fd > 0) {
         close(automatic_fd);
     }
     free(automatic);
     return rc;
 }
 
 /*
  * It is the callers responsibility to free the output of this function
  */
 
 static xmlNode *
 retrieveCib(const char *filename, const char *sigfile, gboolean archive_invalid)
 {
     struct stat buf;
     xmlNode *root = NULL;
 
     crm_info("Reading cluster configuration from: %s (digest: %s)", filename, sigfile);
 
     if (stat(filename, &buf) != 0) {
         crm_warn("Cluster configuration not found: %s", filename);
         return NULL;
     }
 
     root = filename2xml(filename);
     if (root == NULL) {
         crm_err("%s exists but does NOT contain valid XML. ", filename);
         crm_warn("Continuing but %s will NOT used.", filename);
 
     } else if (validate_cib_digest(root, sigfile) == FALSE) {
         crm_err("Checksum of %s failed!  Configuration contents ignored!", filename);
         crm_err("Usually this is caused by manual changes, "
                 "please refer to http://clusterlabs.org/wiki/FAQ#cib_changes_detected");
         crm_warn("Continuing but %s will NOT used.", filename);
         free_xml(root);
         root = NULL;
 
         if (archive_invalid) {
             /* Archive the original files so the contents are not lost */
             cib_rename(filename, NULL);
             cib_rename(sigfile, NULL);
         }
     }
     return root;
 }
 
 static int cib_archive_filter(const struct dirent * a)
 {
     int rc = 0;
     /* Looking for regular files (d_type = 8) starting with 'cib-' and not ending in .sig */
     struct stat s;
     char *a_path = g_strdup_printf("%s/%s", cib_root, a->d_name);
 
     if(stat(a_path, &s) != 0) {
         rc = errno;
         crm_trace("%s - stat failed: %s (%d)", a->d_name, pcmk_strerror(rc), rc);
         rc = 0;
 
     } else if ((s.st_mode & S_IFREG) != S_IFREG) {
         crm_trace("%s - wrong type (%d)", a->d_name, a->d_type);
 
     } else if(strstr(a->d_name, "cib-") != a->d_name) {
         crm_trace("%s - wrong prefix", a->d_name);
 
     } else if(strstr(a->d_name, ".sig") != NULL) {
         crm_trace("%s - wrong suffix", a->d_name);
 
     } else {
         crm_debug("%s - candidate", a->d_name);
         rc = 1;
     }
 
     free(a_path);
     return rc;
 }
 
 static int cib_archive_sort(const struct dirent ** a, const struct dirent **b)
 {
     /* Order by creation date - most recently created file first */
     int rc = 0;
     struct stat buf;
 
     time_t a_age = 0;
     time_t b_age = 0;
 
     char *a_path = g_strdup_printf("%s/%s", cib_root, a[0]->d_name);
     char *b_path = g_strdup_printf("%s/%s", cib_root, b[0]->d_name);
 
     if(stat(a_path, &buf) == 0) {
         a_age = buf.st_ctime;
     }
     if(stat(b_path, &buf) == 0) {
         b_age = buf.st_ctime;
     }
 
     free(a_path);
     free(b_path);
 
     if(a_age > b_age) {
         rc = 1;
     } else if(a_age < b_age) {
         rc = -1;
     }
 
     crm_trace("%s (%u) vs. %s (%u) : %d", a[0]->d_name, a_age, b[0]->d_name, b_age, rc);
     return rc;
 }
 
 xmlNode *
 readCibXmlFile(const char *dir, const char *file, gboolean discard_status)
 {
     struct dirent **namelist = NULL;
 
     int lpc = 0;
     char *sigfile = NULL;
     char *filename = NULL;
     const char *name = NULL;
     const char *value = NULL;
     const char *validation = NULL;
     const char *use_valgrind = getenv("PCMK_valgrind_enabled");
 
     xmlNode *root = NULL;
     xmlNode *status = NULL;
 
     if (!crm_is_writable(dir, file, CRM_DAEMON_USER, NULL, FALSE)) {
         cib_status = -EACCES;
         return NULL;
     }
 
     filename = crm_concat(dir, file, '/');
     sigfile = crm_concat(filename, "sig", '.');
 
     cib_status = pcmk_ok;
     root = retrieveCib(filename, sigfile, TRUE);
     free(filename);
     free(sigfile);
 
     if (root == NULL) {
         crm_warn("Primary configuration corrupt or unusable, trying backups in %s", cib_root);
         lpc = scandir(cib_root, &namelist, cib_archive_filter, cib_archive_sort);
         if (lpc < 0) {
             crm_perror(LOG_NOTICE, "scandir(%s) failed", cib_root);
         }
     }
 
     while (root == NULL && lpc > 1) {
         crm_debug("Testing %d candidates", lpc);
 
         lpc--;
 
         filename = g_strdup_printf("%s/%s", cib_root, namelist[lpc]->d_name);
         sigfile = crm_concat(filename, "sig", '.');
 
         root = retrieveCib(filename, sigfile, FALSE);
         if(root) {
             crm_notice("Continuing with last valid configuration archive: %s", filename);
         }
 
         free(namelist[lpc]);
         free(filename);
         free(sigfile);
     }
     free(namelist);
 
     if (root == NULL) {
-        root = createEmptyCib();
-        crm_xml_add(root, XML_ATTR_GENERATION, "0");
-        crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
-        crm_xml_add(root, XML_ATTR_GENERATION_ADMIN, "0");
-        crm_xml_add(root, XML_ATTR_VALIDATION, xml_latest_schema());
+        root = createEmptyCib(0);
         crm_warn("Continuing with an empty configuration.");
     }
 
     if (cib_writes_enabled && use_valgrind) {
         if (crm_is_true(use_valgrind) || strstr(use_valgrind, "cib")) {
             cib_writes_enabled = FALSE;
             crm_err("*********************************************************");
             crm_err("*** Disabling disk writes to avoid confusing Valgrind ***");
             crm_err("*********************************************************");
         }
     }
 
     status = find_xml_node(root, XML_CIB_TAG_STATUS, FALSE);
     if (discard_status && status != NULL) {
         /* strip out the status section if there is one */
         free_xml(status);
         status = NULL;
     }
     if (status == NULL) {
         create_xml_node(root, XML_CIB_TAG_STATUS);
     }
 
     /* Do this before DTD validation happens */
 
     /* fill in some defaults */
     name = XML_ATTR_GENERATION_ADMIN;
     value = crm_element_value(root, name);
     if (value == NULL) {
         crm_warn("No value for %s was specified in the configuration.", name);
         crm_warn("The reccomended course of action is to shutdown,"
                  " run crm_verify and fix any errors it reports.");
         crm_warn("We will default to zero and continue but may get"
                  " confused about which configuration to use if"
                  " multiple nodes are powered up at the same time.");
         crm_xml_add_int(root, name, 0);
     }
 
     name = XML_ATTR_GENERATION;
     value = crm_element_value(root, name);
     if (value == NULL) {
         crm_xml_add_int(root, name, 0);
     }
 
     name = XML_ATTR_NUMUPDATES;
     value = crm_element_value(root, name);
     if (value == NULL) {
         crm_xml_add_int(root, name, 0);
     }
 
     /* unset these and require the DC/CCM to update as needed */
     xml_remove_prop(root, XML_ATTR_DC_UUID);
 
     if (discard_status) {
         crm_log_xml_trace(root, "[on-disk]");
     }
 
     validation = crm_element_value(root, XML_ATTR_VALIDATION);
     if (validate_xml(root, NULL, TRUE) == FALSE) {
         crm_err("CIB does not validate with %s", crm_str(validation));
         cib_status = -pcmk_err_schema_validation;
 
     } else if (validation == NULL) {
         int version = 0;
 
         update_validation(&root, &version, 0, FALSE, FALSE);
         if (version > 0) {
             crm_notice("Enabling %s validation on"
                        " the existing (sane) configuration", get_schema_name(version));
         } else {
             crm_err("CIB does not validate with any known DTD or schema");
             cib_status = -pcmk_err_schema_validation;
         }
     }
 
     return root;
 }
 
 /*
  * The caller should never free the return value
  */
 xmlNode *
 get_the_CIB(void)
 {
     return the_cib;
 }
 
 gboolean
 uninitializeCib(void)
 {
     xmlNode *tmp_cib = the_cib;
 
     if (tmp_cib == NULL) {
         crm_debug("The CIB has already been deallocated.");
         return FALSE;
     }
 
     initialized = FALSE;
     the_cib = NULL;
     node_search = NULL;
     resource_search = NULL;
     constraint_search = NULL;
     status_search = NULL;
 
     crm_debug("Deallocating the CIB.");
 
     free_xml(tmp_cib);
 
     crm_debug("The CIB has been deallocated.");
 
     return TRUE;
 }
 
 /*
  * This method will not free the old CIB pointer or the new one.
  * We rely on the caller to have saved a pointer to the old CIB
  *   and to free the old/bad one depending on what is appropriate.
  */
 gboolean
 initializeCib(xmlNode * new_cib)
 {
     if (new_cib == NULL) {
         return FALSE;
     }
 
     the_cib = new_cib;
     initialized = TRUE;
     return TRUE;
 }
 
 static void
 sync_directory(const char *name)
 {
     int fd = 0;
     DIR *directory = NULL;
 
     directory = opendir(name);
     if (directory == NULL) {
         crm_perror(LOG_ERR, "Could not open %s for syncing", name);
         return;
     }
 
     fd = dirfd(directory);
     if (fd < 0) {
         crm_perror(LOG_ERR, "Could not obtain file descriptor for %s", name);
 
     } else if (fsync(fd) < 0) {
         crm_perror(LOG_ERR, "Could not sync %s", name);
     }
 
     if (closedir(directory) < 0) {
         crm_perror(LOG_ERR, "Could not close %s after fsync", name);
     }
 }
 
 /*
  * This method will free the old CIB pointer on success and the new one
  * on failure.
  */
 int
 activateCibXml(xmlNode * new_cib, gboolean to_disk, const char *op)
 {
     xmlNode *saved_cib = the_cib;
 
     CRM_ASSERT(new_cib != saved_cib);
     if (initializeCib(new_cib) == FALSE) {
         free_xml(new_cib);
         crm_err("Ignoring invalid or NULL CIB");
 
         if (saved_cib != NULL) {
             crm_warn("Reverting to last known CIB");
             if (initializeCib(saved_cib) == FALSE) {
                 /* oh we are so dead  */
                 crm_crit("Couldn't re-initialize the old CIB!");
                 exit(1);
             }
 
         } else {
             crm_crit("Could not write out new CIB and no saved" " version to revert to");
         }
         return -ENODATA;
     }
 
     free_xml(saved_cib);
     if (cib_writes_enabled && cib_status == pcmk_ok && to_disk) {
         crm_debug("Triggering CIB write for %s op", op);
         mainloop_set_trigger(cib_writer);
     }
 
     return pcmk_ok;
 }
 
 static void
 cib_diskwrite_complete(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
 {
     if (signo) {
         crm_notice("Disk write process terminated with signal %d (pid=%d, core=%d)", signo, pid,
                    core);
 
     } else  {
         do_crm_log(exitcode == 0 ? LOG_TRACE : LOG_ERR, "Disk write process exited (pid=%d, rc=%d)",
                    pid, exitcode);
     }
 
     if (exitcode != 0 && cib_writes_enabled) {
         crm_err("Disabling disk writes after write failure");
         cib_writes_enabled = FALSE;
     }
 
     mainloop_trigger_complete(cib_writer);
 }
 
 int
 write_cib_contents(gpointer p)
 {
     int exit_rc = pcmk_ok;
     char *digest = NULL;
     xmlNode *cib_status_root = NULL;
 
     xmlNode *cib_local = NULL;
     xmlNode *cib_tmp = NULL;
 
     int tmp_cib_fd = 0;
     int tmp_digest_fd = 0;
     char *tmp_cib = NULL;
     char *tmp_digest = NULL;
 
     char *digest_file = NULL;
     char *primary_file = NULL;
 
     char *backup_file = NULL;
     char *backup_digest = NULL;
 
     const char *epoch = NULL;
     const char *admin_epoch = NULL;
 
     if (p) {
         /* Synchronous write out */
         cib_local = copy_xml(p);
 
     } else {
         int pid = 0;
         int bb_state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
 
         /* Turn it off before the fork() to avoid:
          * - 2 processes writing to the same shared mem
          * - the child needing to disable it
          *   (which would close it from underneath the parent)
          * This way, the shared mem files are already closed
          */
         qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
 
         pid = fork();
         if (pid < 0) {
             crm_perror(LOG_ERR, "Disabling disk writes after fork failure");
             cib_writes_enabled = FALSE;
             return FALSE;
         }
 
         if (pid) {
             /* Parent */
             mainloop_child_add(pid, 0, "disk-writer", NULL, cib_diskwrite_complete);
             if (bb_state == QB_LOG_STATE_ENABLED) {
                 /* Re-enable now that it it safe */
                 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
             }
 
             return -1;          /* -1 means 'still work to do' */
         }
 
         /* A-synchronous write out after a fork() */
 
         /* In theory we can scribble on "the_cib" here and not affect the parent
          * But lets be safe anyway
          */
         cib_local = copy_xml(the_cib);
     }
 
     epoch = crm_element_value(cib_local, XML_ATTR_GENERATION);
     admin_epoch = crm_element_value(cib_local, XML_ATTR_GENERATION_ADMIN);
 
     primary_file = crm_concat(cib_root, "cib.xml", '/');
     digest_file = crm_concat(primary_file, "sig", '.');
 
     /* Always write out with num_updates=0 */
     crm_xml_add(cib_local, XML_ATTR_NUMUPDATES, "0");
 
     /* check the admin didnt modify it underneath us */
     if (on_disk_cib_corrupt(primary_file) == FALSE
         && validate_on_disk_cib(primary_file, NULL) == FALSE) {
         crm_err("%s was manually modified while the cluster was active!", primary_file);
         exit_rc = pcmk_err_cib_modified;
         goto cleanup;
 
     } else {
         int rc = 0;
         int seq = get_last_sequence(cib_root, CIB_SERIES);
 
         backup_file = generate_series_filename(cib_root, CIB_SERIES, seq, CIB_SERIES_BZIP);
         backup_digest = crm_concat(backup_file, "sig", '.');
 
         unlink(backup_file);
         unlink(backup_digest);
 
         rc = link(primary_file, backup_file);
         if (rc < 0) {
             rc = errno;
             switch(rc) {
                 case ENOENT:
                     /* No file to back up */
                     goto writeout;
                     break;
                 default:
                     exit_rc = pcmk_err_cib_backup;
                     crm_err("Cannot link %s to %s: %s (%d)", primary_file, backup_file, pcmk_strerror(rc), rc);
             }
             goto cleanup;
         }
 
         rc = link(digest_file, backup_digest);
         if (rc < 0 && errno != ENOENT) {
             exit_rc = pcmk_err_cib_backup;
             crm_perror(LOG_ERR, "Cannot link %s to %s", digest_file, backup_digest);
             goto cleanup;
         }
         write_last_sequence(cib_root, CIB_SERIES, seq + 1, CIB_SERIES_MAX);
         sync_directory(cib_root);
 
         crm_info("Archived previous version as %s", backup_file);
     }
 
   writeout:
     /* Given that we discard the status section on startup
      *   there is no point writing it out in the first place
      *   since users just get confused by it
      *
      * So delete the status section before we write it out
      */
     crm_debug("Writing CIB to disk");
     if (p == NULL) {
         cib_status_root = find_xml_node(cib_local, XML_CIB_TAG_STATUS, TRUE);
         CRM_LOG_ASSERT(cib_status_root != NULL);
 
         if (cib_status_root != NULL) {
             free_xml(cib_status_root);
         }
     }
 
     tmp_cib = g_strdup_printf("%s/cib.XXXXXX", cib_root);
     tmp_digest = g_strdup_printf("%s/cib.XXXXXX", cib_root);
 
     umask(S_IWGRP | S_IWOTH | S_IROTH);
 
     tmp_cib_fd = mkstemp(tmp_cib);
     if (tmp_cib_fd < 0 || write_xml_fd(cib_local, tmp_cib, tmp_cib_fd, FALSE) <= 0) {
         crm_err("Changes couldn't be written to %s", tmp_cib);
         exit_rc = pcmk_err_cib_save;
         goto cleanup;
     }
 
     /* Must calculate the digest after writing as write_xml_file() updates the last-written field */
     digest = calculate_on_disk_digest(cib_local);
     crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
              admin_epoch ? admin_epoch : "0", epoch ? epoch : "0", digest);
 
     tmp_digest_fd = mkstemp(tmp_digest);
     if (tmp_digest_fd < 0 || write_cib_digest(cib_local, tmp_digest, tmp_digest_fd, digest) <= 0) {
         crm_err("Digest couldn't be written to %s", tmp_digest);
         exit_rc = pcmk_err_cib_save;
         goto cleanup;
     }
     crm_debug("Wrote digest %s to disk", digest);
     cib_tmp = retrieveCib(tmp_cib, tmp_digest, FALSE);
     CRM_ASSERT(cib_tmp != NULL);
     sync_directory(cib_root);
 
     crm_debug("Activating %s", tmp_cib);
     cib_rename(tmp_cib, primary_file);
     cib_rename(tmp_digest, digest_file);
     sync_directory(cib_root);
 
   cleanup:
     free(backup_digest);
     free(primary_file);
     free(backup_file);
     free(digest_file);
     free(digest);
     free(tmp_digest);
     free(tmp_cib);
 
     free_xml(cib_tmp);
     free_xml(cib_local);
 
     if (p == NULL) {
         /* exit() could potentially affect the parent by closing things it shouldn't
          * Use _exit instead
          */
         _exit(exit_rc);
     }
     return exit_rc;
 }
 
 void
 GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data)
 {
     int *active = user_data;
 
     if (safe_str_eq(value, ONLINESTATUS)) {
         (*active)++;
 
     } else if (safe_str_eq(value, JOINSTATUS)) {
         (*active)++;
     }
 }
diff --git a/include/crm/cib/util.h b/include/crm/cib/util.h
index 70097c1506..9a97bf9cde 100644
--- a/include/crm/cib/util.h
+++ b/include/crm/cib/util.h
@@ -1,70 +1,70 @@
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #ifndef CIB_UTIL__H
 #  define CIB_UTIL__H
 
 /* Utility functions */
 const char *get_object_path(const char *object_type);
 const char *get_object_parent(const char *object_type);
 xmlNode *get_object_root(const char *object_type, xmlNode * the_root);
 xmlNode *create_cib_fragment_adv(xmlNode * update, const char *section, const char *source);
 
-xmlNode *createEmptyCib(void);
+xmlNode *createEmptyCib(int admin_epoch);
 gboolean verifyCibXml(xmlNode * cib);
 
 gboolean cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates);
 
 int update_attr_delegate(cib_t * the_cib, int call_options,
                          const char *section, const char *node_uuid,
                          const char *set_type, const char *set_name,
                          const char *attr_id, const char *attr_name,
                          const char *attr_value, gboolean to_console,
                          const char *user_name, const char *node_type);
 
 int find_nvpair_attr_delegate(cib_t * the_cib, const char *attr,
                               const char *section, const char *node_uuid,
                               const char *set_type, const char *set_name,
                               const char *attr_id, const char *attr_name,
                               gboolean to_console, char **value, const char *user_name);
 
 int read_attr_delegate(cib_t * the_cib,
                        const char *section, const char *node_uuid,
                        const char *set_type, const char *set_name,
                        const char *attr_id, const char *attr_name,
                        char **attr_value, gboolean to_console, const char *user_name);
 
 int delete_attr_delegate(cib_t * the_cib, int options,
                          const char *section, const char *node_uuid,
                          const char *set_type, const char *set_name,
                          const char *attr_id, const char *attr_name,
                          const char *attr_value, gboolean to_console, const char *user_name);
 
 int query_node_uuid(cib_t * the_cib, const char *uname, char **uuid, int *is_remote_node);
 
 int query_node_uname(cib_t * the_cib, const char *uuid, char **uname);
 
 int set_standby(cib_t * the_cib, const char *uuid, const char *scope, const char *standby_value);
 
 xmlNode *get_cib_copy(cib_t * cib);
 xmlNode *cib_get_generation(cib_t * cib);
 
 void cib_metadata(void);
 const char *cib_pref(GHashTable * options, const char *name);
 int cib_apply_patch_event(xmlNode * event, xmlNode * input, xmlNode ** output, int level);
 
 #endif
diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c
index 4ea8a71610..a175843d87 100644
--- a/lib/cib/cib_ops.c
+++ b/lib/cib/cib_ops.c
@@ -1,836 +1,836 @@
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <time.h>
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <crm/crm.h>
 #include <crm/cib/internal.h>
 #include <crm/msg_xml.h>
 
 #include <crm/common/xml.h>
 
 int
 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *obj_root = NULL;
     int result = pcmk_ok;
 
     crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     CRM_CHECK(*answer == NULL, free_xml(*answer));
     *answer = NULL;
 
     if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
         section = NULL;
     }
 
     obj_root = get_object_root(section, existing_cib);
 
     if (obj_root == NULL) {
         result = -ENXIO;
 
     } else if (options & cib_no_children) {
         const char *tag = TYPE(obj_root);
         xmlNode *shallow = create_xml_node(*answer, tag);
 
         copy_in_properties(shallow, obj_root);
         *answer = shallow;
 
     } else {
         *answer = obj_root;
     }
 
     if (result == pcmk_ok && *answer == NULL) {
         crm_err("Error creating query response");
         result = -ENOMSG;
     }
 
     return result;
 }
 
 int
 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     int result = pcmk_ok;
 
     crm_trace("Processing \"%s\" event", op);
     *answer = NULL;
     free_xml(*result_cib);
-    *result_cib = createEmptyCib();
+    *result_cib = createEmptyCib(0);
 
     copy_in_properties(*result_cib, existing_cib);
     cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
 
     return result;
 }
 
 int
 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                     xmlNode ** answer)
 {
     int rc = 0;
     int new_version = 0;
     int current_version = 0;
     int max_version = 0;
     const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
     const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
 
     *answer = NULL;
     crm_trace("Processing \"%s\" event with max=%s", op, max);
 
     if (value != NULL) {
         current_version = get_schema_version(value);
     }
 
     if (max) {
         max_version = get_schema_version(max);
     }
 
     rc = update_validation(result_cib, &new_version, max_version, TRUE, TRUE);
     if (new_version > current_version) {
         cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
         cib_update_counter(*result_cib, XML_ATTR_GENERATION, TRUE);
         cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
         return pcmk_ok;
     }
 
     return rc;
 }
 
 int
 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     int result = pcmk_ok;
 
     crm_trace("Processing \"%s\" event for epoch=%s",
               op, crm_str(crm_element_value(existing_cib, XML_ATTR_GENERATION)));
 
     *answer = NULL;
     cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
 
     return result;
 }
 
 int
 cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset)
 {
     char *new_value = NULL;
     char *old_value = NULL;
     int int_value = -1;
 
     if (reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
         old_value = crm_element_value_copy(xml_obj, field);
     }
     if (old_value != NULL) {
         new_value = calloc(1, 128);
         int_value = atoi(old_value);
         sprintf(new_value, "%d", ++int_value);
     } else {
         new_value = strdup("1");
     }
 
     crm_trace("%s %d(%s)->%s", field, int_value, crm_str(old_value), crm_str(new_value));
     crm_xml_add(xml_obj, field, new_value);
 
     free(new_value);
     free(old_value);
 
     return pcmk_ok;
 }
 
 int
 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                     xmlNode ** answer)
 {
     const char *tag = NULL;
     int result = pcmk_ok;
 
     crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     *answer = NULL;
 
     if (input == NULL) {
         return -EINVAL;
     }
 
     tag = crm_element_name(input);
 
     if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
         section = NULL;
 
     } else if (safe_str_eq(tag, section)) {
         section = NULL;
     }
 
     if (safe_str_eq(tag, XML_TAG_CIB)) {
         int updates = 0;
         int epoch = 0;
         int admin_epoch = 0;
 
         int replace_updates = 0;
         int replace_epoch = 0;
         int replace_admin_epoch = 0;
 
         const char *reason = NULL;
         const char *peer = crm_element_value(req, F_ORIG);
         const char *digest = crm_element_value(req, XML_ATTR_DIGEST);
 
         if (digest) {
             const char *version = crm_element_value(req, XML_ATTR_CRM_VERSION);
             char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
                                                                  version ? version :
                                                                  CRM_FEATURE_SET);
 
             if (safe_str_neq(digest_verify, digest)) {
                 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
                         digest_verify, digest);
                 reason = "digest mismatch";
 
             } else {
                 crm_info("Digest matched on replace from %s: %s", peer, digest);
             }
             free(digest_verify);
 
         } else {
             crm_trace("No digest to verify");
         }
 
         cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
         cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
 
         if (replace_admin_epoch < admin_epoch) {
             reason = XML_ATTR_GENERATION_ADMIN;
 
         } else if (replace_admin_epoch > admin_epoch) {
             /* no more checks */
 
         } else if (replace_epoch < epoch) {
             reason = XML_ATTR_GENERATION;
 
         } else if (replace_epoch > epoch) {
             /* no more checks */
 
         } else if (replace_updates < updates) {
             reason = XML_ATTR_NUMUPDATES;
         }
 
         if (reason != NULL) {
             crm_warn("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
                      " current %s is greater than the replacement",
                      replace_admin_epoch, replace_epoch,
                      replace_updates, peer, admin_epoch, epoch, updates, reason);
             result = -pcmk_err_old_data;
         } else {
             crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
                      admin_epoch, epoch, updates,
                      replace_admin_epoch, replace_epoch, replace_updates, peer);
         }
 
         free_xml(*result_cib);
         *result_cib = copy_xml(input);
 
     } else {
         xmlNode *obj_root = NULL;
         gboolean ok = TRUE;
 
         obj_root = get_object_root(section, *result_cib);
         ok = replace_xml_child(NULL, obj_root, input, FALSE);
         if (ok == FALSE) {
             crm_trace("No matching object to replace");
             result = -ENXIO;
         }
     }
 
     return result;
 }
 
 int
 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *obj_root = NULL;
 
     crm_trace("Processing \"%s\" event", op);
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     if (input == NULL) {
         crm_err("Cannot perform modification with no data");
         return -EINVAL;
     }
 
     obj_root = get_object_root(section, *result_cib);
     if(safe_str_eq(crm_element_name(input), section)) {
         xmlNode *child = NULL;
         for(child = __xml_first_child(input); child; child = __xml_next(child)) {
             if (replace_xml_child(NULL, obj_root, child, TRUE) == FALSE) {
                 crm_trace("No matching object to delete: %s=%s", child->name, ID(child));
             }
         }
 
     } else if (replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
             crm_trace("No matching object to delete: %s=%s", input->name, ID(input));
     }
 
     return pcmk_ok;
 }
 
 int
 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *obj_root = NULL;
 
     crm_trace("Processing \"%s\" event", op);
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     if (input == NULL) {
         crm_err("Cannot perform modification with no data");
         return -EINVAL;
     }
 
     obj_root = get_object_root(section, *result_cib);
     if (obj_root == NULL) {
         xmlNode *tmp_section = NULL;
         const char *path = get_object_parent(section);
 
         if (path == NULL) {
             return -EINVAL;
         }
 
         tmp_section = create_xml_node(NULL, section);
         cib_process_xpath(CIB_OP_CREATE, 0, path, NULL, tmp_section, NULL, result_cib, answer);
         free_xml(tmp_section);
 
         obj_root = get_object_root(section, *result_cib);
     }
 
     CRM_CHECK(obj_root != NULL, return -EINVAL);
 
     if (update_xml_child(obj_root, input) == FALSE) {
         if (options & cib_can_create) {
             add_node_copy(obj_root, input);
         } else {
             return -ENXIO;
         }
     }
 
     if(options & cib_mixed_update) {
         int max = 0, lpc;
         xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
 
         if (xpathObj) {
             max = numXpathResults(xpathObj);
             crm_log_xml_trace(*result_cib, "Mixed result");
         }
 
         for (lpc = 0; lpc < max; lpc++) {
             xmlNode *match = getXpathResult(xpathObj, lpc);
             crm_debug("Destroying %s", (char *)xmlGetNodePath(match));
             free_xml(match);
         }
 
         freeXpathObject(xpathObj);
     }
     return pcmk_ok;
 }
 
 static int
 update_cib_object(xmlNode * parent, xmlNode * update)
 {
     int result = pcmk_ok;
     xmlNode *target = NULL;
     xmlNode *a_child = NULL;
     const char *replace = NULL;
     const char *object_id = NULL;
     const char *object_name = NULL;
 
     CRM_CHECK(update != NULL, return -EINVAL);
     CRM_CHECK(parent != NULL, return -EINVAL);
 
     object_name = crm_element_name(update);
     CRM_CHECK(object_name != NULL, return -EINVAL);
 
     object_id = ID(update);
     crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
 
     if (object_id == NULL) {
         /*  placeholder object */
         target = find_xml_node(parent, object_name, FALSE);
 
     } else {
         target = find_entity(parent, object_name, object_id);
     }
 
     if (target == NULL) {
         target = create_xml_node(parent, object_name);
     }
 
     crm_trace("Found node <%s id=%s> to update", crm_str(object_name), crm_str(object_id));
 
     replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
     if (replace != NULL) {
         xmlNode *remove = NULL;
         int last = 0, lpc = 0, len = 0;
 
         len = strlen(replace);
         while (lpc <= len) {
             if (replace[lpc] == ',' || replace[lpc] == 0) {
                 char *replace_item = NULL;
 
                 if (last == lpc) {
                     /* nothing to do */
                     last = lpc + 1;
                     goto incr;
                 }
 
                 replace_item = calloc(1, lpc - last + 1);
                 memcpy(replace_item, replace + last, lpc - last);
 
                 remove = find_xml_node(target, replace_item, FALSE);
                 if (remove != NULL) {
                     crm_trace("Replacing node <%s> in <%s>",
                               replace_item, crm_element_name(target));
                     free_xml(remove);
                     remove = NULL;
                 }
                 free(replace_item);
                 last = lpc + 1;
             }
   incr:
             lpc++;
         }
         xml_remove_prop(update, XML_CIB_ATTR_REPLACE);
         xml_remove_prop(target, XML_CIB_ATTR_REPLACE);
     }
 
     copy_in_properties(target, update);
 
     crm_trace("Processing children of <%s id=%s>", crm_str(object_name), crm_str(object_id));
 
     for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
         int tmp_result = 0;
 
         crm_trace("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
 
         tmp_result = update_cib_object(target, a_child);
 
         /*  only the first error is likely to be interesting */
         if (tmp_result != pcmk_ok) {
             crm_err("Error updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
 
             if (result == pcmk_ok) {
                 result = tmp_result;
             }
         }
     }
 
     crm_trace("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id));
 
     return result;
 }
 
 static int
 add_cib_object(xmlNode * parent, xmlNode * new_obj)
 {
     int result = pcmk_ok;
     const char *object_name = NULL;
     const char *object_id = NULL;
     xmlNode *equiv_node = NULL;
 
     if (new_obj != NULL) {
         object_name = crm_element_name(new_obj);
     }
     object_id = crm_element_value(new_obj, XML_ATTR_ID);
 
     crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
 
     if (new_obj == NULL || object_name == NULL) {
         result = -EINVAL;
 
     } else if (parent == NULL) {
         result = -EINVAL;
 
     } else if (object_id == NULL) {
         /*  placeholder object */
         equiv_node = find_xml_node(parent, object_name, FALSE);
 
     } else {
         equiv_node = find_entity(parent, object_name, object_id);
     }
 
     if (result != pcmk_ok) {
         ;                       /* do nothing */
 
     } else if (equiv_node != NULL) {
         result = -ENOTUNIQ;
 
     } else {
         result = update_cib_object(parent, new_obj);
     }
 
     return result;
 }
 
 int
 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *failed = NULL;
     int result = pcmk_ok;
     xmlNode *update_section = NULL;
 
     crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
     if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
         section = NULL;
 
     } else if (safe_str_eq(XML_TAG_CIB, section)) {
         section = NULL;
 
     } else if (safe_str_eq(crm_element_name(input), XML_TAG_CIB)) {
         section = NULL;
     }
 
     CRM_CHECK(strcasecmp(CIB_OP_CREATE, op) == 0, return -EINVAL);
 
     if (input == NULL) {
         crm_err("Cannot perform modification with no data");
         return -EINVAL;
     }
 
     if (section == NULL) {
         return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
                                   answer);
     }
 
     failed = create_xml_node(NULL, XML_TAG_FAILED);
 
     update_section = get_object_root(section, *result_cib);
     if (safe_str_eq(crm_element_name(input), section)) {
         xmlNode *a_child = NULL;
 
         for (a_child = __xml_first_child(input); a_child != NULL; a_child = __xml_next(a_child)) {
             result = add_cib_object(update_section, a_child);
             if (update_results(failed, a_child, op, result)) {
                 break;
             }
         }
 
     } else {
         result = add_cib_object(update_section, input);
         update_results(failed, input, op, result);
     }
 
     if (xml_has_children(failed)) {
         CRM_CHECK(result != pcmk_ok, result = -EINVAL);
     }
 
     if (result != pcmk_ok) {
         crm_log_xml_err(failed, "CIB Update failures");
         *answer = failed;
 
     } else {
         free_xml(failed);
     }
 
     return result;
 }
 
 int
 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     const char *originator = NULL;
 
     if (req != NULL) {
         originator = crm_element_value(req, F_ORIG);
     }
 
     crm_trace("Processing \"%s\" event from %s %s",
               op, originator, is_set(options, cib_force_diff)?"(global update)":"");
 
     free_xml(*result_cib);
     *result_cib = copy_xml(existing_cib);
     return xml_apply_patchset(*result_cib, input, TRUE);
 }
 
 gboolean
 cib_config_changed(xmlNode * last, xmlNode * next, xmlNode ** diff)
 {
     int lpc = 0, max = 0;
     gboolean config_changes = FALSE;
     xmlXPathObject *xpathObj = NULL;
 
     CRM_ASSERT(diff != NULL);
 
     if (*diff == NULL && last != NULL && next != NULL) {
         *diff = diff_xml_object(last, next, FALSE);
     }
 
     if (*diff == NULL) {
         goto done;
     }
 
     xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
     if (numXpathResults(xpathObj) > 0) {
         config_changes = TRUE;
         goto done;
     }
     freeXpathObject(xpathObj);
 
     /*
      * Do not check XML_TAG_DIFF_ADDED "//" XML_TAG_CIB
      * This always contains every field and would produce a false positive
      * every time if the checked value existed
      */
     xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
     max = numXpathResults(xpathObj);
 
     for (lpc = 0; lpc < max; lpc++) {
         xmlNode *top = getXpathResult(xpathObj, lpc);
 
         if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
             config_changes = TRUE;
             goto done;
         }
         if (crm_element_value(top, XML_ATTR_GENERATION_ADMIN) != NULL) {
             config_changes = TRUE;
             goto done;
         }
 
         if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
             config_changes = TRUE;
             goto done;
         }
         if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
             config_changes = TRUE;
             goto done;
         }
         if (crm_element_value(top, "remote-clear-port") != NULL) {
             config_changes = TRUE;
             goto done;
         }
         if (crm_element_value(top, "remote-tls-port") != NULL) {
             config_changes = TRUE;
             goto done;
         }
     }
 
   done:
     freeXpathObject(xpathObj);
     return config_changes;
 }
 
 int
 cib_process_xpath(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     int lpc = 0;
     int max = 0;
     int rc = pcmk_ok;
     gboolean is_query = safe_str_eq(op, CIB_OP_QUERY);
 
     xmlXPathObjectPtr xpathObj = NULL;
 
     crm_trace("Processing \"%s\" event", op);
 
     if (is_query) {
         xpathObj = xpath_search(existing_cib, section);
     } else {
         xpathObj = xpath_search(*result_cib, section);
     }
 
     max = numXpathResults(xpathObj);
 
     if (max < 1 && safe_str_eq(op, CIB_OP_DELETE)) {
         crm_debug("%s was already removed", section);
 
     } else if (max < 1) {
         crm_debug("%s: %s does not exist", op, section);
         rc = -ENXIO;
 
     } else if (is_query) {
         if (max > 1) {
             *answer = create_xml_node(NULL, "xpath-query");
         }
     }
 
     for (lpc = 0; lpc < max; lpc++) {
         xmlChar *path = NULL;
         xmlNode *match = getXpathResult(xpathObj, lpc);
 
         if (match == NULL) {
             continue;
         }
 
         path = xmlGetNodePath(match);
         crm_debug("Processing %s op for %s (%s)", op, section, path);
         free(path);
 
         if (safe_str_eq(op, CIB_OP_DELETE)) {
             free_xml(match);
             if ((options & cib_multiple) == 0) {
                 break;
             }
 
         } else if (safe_str_eq(op, CIB_OP_MODIFY)) {
             if (update_xml_child(match, input) == FALSE) {
                 rc = -ENXIO;
             } else if ((options & cib_multiple) == 0) {
                 break;
             }
 
         } else if (safe_str_eq(op, CIB_OP_CREATE)) {
             add_node_copy(match, input);
             break;
 
         } else if (safe_str_eq(op, CIB_OP_QUERY)) {
 
             if (options & cib_no_children) {
                 const char *tag = TYPE(match);
                 xmlNode *shallow = create_xml_node(*answer, tag);
 
                 copy_in_properties(shallow, match);
 
                 if (*answer == NULL) {
                     *answer = shallow;
                 }
 
             } else if (options & cib_xpath_address) {
 
                 int path_len = 0;
                 char *path = NULL;
                 xmlNode *parent = match;
 
                 while (parent && parent->type == XML_ELEMENT_NODE) {
                     int extra = 1;
                     char *new_path = NULL;
                     const char *id = crm_element_value(parent, XML_ATTR_ID);
 
                     extra += strlen((const char *)parent->name);
                     if (id) {
                         extra += 8;     /* [@id=""] */
                         extra += strlen(id);
                     }
 
                     path_len += extra;
                     new_path = malloc(path_len + 1);
                     if(new_path == NULL) {
                         break;
 
                     } else if (id) {
                         snprintf(new_path, path_len + 1, "/%s[@id='%s']%s", parent->name, id,
                                  path ? path : "");
                     } else {
                         snprintf(new_path, path_len + 1, "/%s%s", parent->name, path ? path : "");
                     }
                     free(path);
                     path = new_path;
                     parent = parent->parent;
                 }
                 crm_trace("Got: %s\n", path);
 
                 if (*answer == NULL) {
                     *answer = create_xml_node(NULL, "xpath-query");
                 }
                 parent = create_xml_node(*answer, "xpath-query-path");
                 crm_xml_add(parent, XML_ATTR_ID, path);
                 free(path);
 
             } else if (*answer) {
                 add_node_copy(*answer, match);
 
             } else {
                 *answer = match;
             }
 
         } else if (safe_str_eq(op, CIB_OP_REPLACE)) {
             xmlNode *parent = match->parent;
 
             free_xml(match);
             if (input != NULL) {
                 add_node_copy(parent, input);
             }
 
             if ((options & cib_multiple) == 0) {
                 break;
             }
         }
     }
 
     freeXpathObject(xpathObj);
     return rc;
 }
 
 /* remove this function */
 gboolean
 update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code)
 {
     xmlNode *xml_node = NULL;
     gboolean was_error = FALSE;
     const char *error_msg = NULL;
 
     if (return_code != pcmk_ok) {
         error_msg = pcmk_strerror(return_code);
 
         was_error = TRUE;
         xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
         add_node_copy(xml_node, target);
 
         crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
         crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
         crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
         crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
 
         crm_warn("Action %s failed: %s (cde=%d)", operation, error_msg, return_code);
     }
 
     return was_error;
 }
diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c
index c34770807e..5bad02fc30 100644
--- a/lib/cib/cib_utils.c
+++ b/lib/cib/cib_utils.c
@@ -1,830 +1,836 @@
 /*
  * Copyright (c) 2004 International Business Machines
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 #include <crm_internal.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
 #include <sys/utsname.h>
 
 #include <glib.h>
 
 #include <crm/crm.h>
 #include <crm/cib/internal.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/pengine/rules.h>
 
 struct config_root_s {
     const char *name;
     const char *parent;
     const char *path;
 };
 
  /*
   * "//crm_config" will also work in place of "/cib/configuration/crm_config"
   * The / prefix means find starting from the root, whereas the // prefix means
   * find anywhere and risks multiple matches
   */
 /* *INDENT-OFF* */
 struct config_root_s known_paths[] = {
     { NULL,			NULL,                 "//cib" },
     { XML_TAG_CIB,		NULL,                 "//cib" },
     { XML_CIB_TAG_STATUS,       "/cib",               "//cib/status" },
     { XML_CIB_TAG_CONFIGURATION,"/cib",               "//cib/configuration" },
     { XML_CIB_TAG_CRMCONFIG,    "/cib/configuration", "//cib/configuration/crm_config" },
     { XML_CIB_TAG_NODES,        "/cib/configuration", "//cib/configuration/nodes" },
     { XML_CIB_TAG_DOMAINS,      "/cib/configuration", "//cib/configuration/domains" },
     { XML_CIB_TAG_RESOURCES,    "/cib/configuration", "//cib/configuration/resources" },
     { XML_CIB_TAG_CONSTRAINTS,  "/cib/configuration", "//cib/configuration/constraints" },
     { XML_CIB_TAG_OPCONFIG,	"/cib/configuration", "//cib/configuration/op_defaults" },
     { XML_CIB_TAG_RSCCONFIG,	"/cib/configuration", "//cib/configuration/rsc_defaults" },
     { XML_CIB_TAG_ACLS,		"/cib/configuration", "//cib/configuration/acls" },
     { XML_TAG_FENCING_TOPOLOGY,	"/cib/configuration", "//cib/configuration/fencing-topology" },
     { XML_CIB_TAG_SECTION_ALL,  NULL,                 "//cib" },
 };
 /* *INDENT-ON* */
 
 int
 cib_compare_generation(xmlNode * left, xmlNode * right)
 {
     int lpc = 0;
 
     const char *attributes[] = {
         XML_ATTR_GENERATION_ADMIN,
         XML_ATTR_GENERATION,
         XML_ATTR_NUMUPDATES,
     };
 
     crm_log_xml_trace(left, "left");
     crm_log_xml_trace(right, "right");
 
     for (lpc = 0; lpc < DIMOF(attributes); lpc++) {
         int int_elem_l = -1;
         int int_elem_r = -1;
         const char *elem_r = NULL;
         const char *elem_l = crm_element_value(left, attributes[lpc]);
 
         if (right != NULL) {
             elem_r = crm_element_value(right, attributes[lpc]);
         }
 
         if (elem_l != NULL) {
             int_elem_l = crm_parse_int(elem_l, NULL);
         }
         if (elem_r != NULL) {
             int_elem_r = crm_parse_int(elem_r, NULL);
         }
 
         if (int_elem_l < int_elem_r) {
             crm_trace("%s (%s < %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r));
             return -1;
 
         } else if (int_elem_l > int_elem_r) {
             crm_trace("%s (%s > %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r));
             return 1;
         }
     }
 
     return 0;
 }
 
 /* Deprecated - doesn't expose -EACCES */
 xmlNode *
 get_cib_copy(cib_t * cib)
 {
     xmlNode *xml_cib;
     int options = cib_scope_local | cib_sync_call;
     int rc = cib->cmds->query(cib, NULL, &xml_cib, options);
 
     if (rc == -EACCES) {
         return NULL;
 
     } else if (rc != pcmk_ok) {
         crm_err("Couldnt retrieve the CIB");
         free_xml(xml_cib);
         return NULL;
 
     } else if (xml_cib == NULL) {
         crm_err("The CIB result was empty");
         free_xml(xml_cib);
         return NULL;
     }
 
     if (safe_str_eq(crm_element_name(xml_cib), XML_TAG_CIB)) {
         return xml_cib;
     }
     free_xml(xml_cib);
     return NULL;
 }
 
 xmlNode *
 cib_get_generation(cib_t * cib)
 {
     xmlNode *the_cib = NULL;
     xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
 
     cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
     if (the_cib != NULL) {
         copy_in_properties(generation, the_cib);
         free_xml(the_cib);
     }
 
     return generation;
 }
 
 gboolean
 cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
 {
     *epoch = -1;
     *updates = -1;
     *admin_epoch = -1;
 
     if (cib == NULL) {
         return FALSE;
 
     } else {
         crm_element_value_int(cib, XML_ATTR_GENERATION, epoch);
         crm_element_value_int(cib, XML_ATTR_NUMUPDATES, updates);
         crm_element_value_int(cib, XML_ATTR_GENERATION_ADMIN, admin_epoch);
     }
     return TRUE;
 }
 
 gboolean
 cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
                          int *_admin_epoch, int *_epoch, int *_updates)
 {
     int add[] = { 0, 0, 0 };
     int del[] = { 0, 0, 0 };
 
     xml_patch_versions(diff, add, del);
 
     *admin_epoch = add[0];
     *epoch = add[1];
     *updates = add[2];
 
     *_admin_epoch = del[0];
     *_epoch = del[1];
     *_updates = del[2];
 
     return TRUE;
 }
 
 /*
  * The caller should never free the return value
  */
 
 const char *
 get_object_path(const char *object_type)
 {
     int lpc = 0;
     int max = DIMOF(known_paths);
 
     for (; lpc < max; lpc++) {
         if ((object_type == NULL && known_paths[lpc].name == NULL)
             || safe_str_eq(object_type, known_paths[lpc].name)) {
             return known_paths[lpc].path;
         }
     }
     return NULL;
 }
 
 const char *
 get_object_parent(const char *object_type)
 {
     int lpc = 0;
     int max = DIMOF(known_paths);
 
     for (; lpc < max; lpc++) {
         if (safe_str_eq(object_type, known_paths[lpc].name)) {
             return known_paths[lpc].parent;
         }
     }
     return NULL;
 }
 
 xmlNode *
 get_object_root(const char *object_type, xmlNode * the_root)
 {
     const char *xpath = get_object_path(object_type);
 
     if (xpath == NULL) {
         return the_root;        /* or return NULL? */
     }
 
     return get_xpath_object(xpath, the_root, LOG_DEBUG_4);
 }
 
 /*
  * It is the callers responsibility to free both the new CIB (output)
  *     and the new CIB (input)
  */
 xmlNode *
-createEmptyCib(void)
+createEmptyCib(int admin_epoch)
 {
     xmlNode *cib_root = NULL, *config = NULL;
 
     cib_root = create_xml_node(NULL, XML_TAG_CIB);
+    crm_xml_add(cib_root, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
+    crm_xml_add(cib_root, XML_ATTR_VALIDATION, xml_latest_schema());
+
+    crm_xml_add_int(cib_root, XML_ATTR_GENERATION, admin_epoch);
+    crm_xml_add_int(cib_root, XML_ATTR_NUMUPDATES, 0);
+    crm_xml_add_int(cib_root, XML_ATTR_GENERATION_ADMIN, 0);
 
     config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
     create_xml_node(cib_root, XML_CIB_TAG_STATUS);
 
     create_xml_node(config, XML_CIB_TAG_CRMCONFIG);
     create_xml_node(config, XML_CIB_TAG_NODES);
     create_xml_node(config, XML_CIB_TAG_RESOURCES);
     create_xml_node(config, XML_CIB_TAG_CONSTRAINTS);
 
     return cib_root;
 }
 
 static bool
 cib_acl_enabled(xmlNode *xml, const char *user)
 {
     bool rc = FALSE;
 
 #if ENABLE_ACL
     if(pcmk_acl_required(user)) {
         const char *value = NULL;
         GHashTable *options = g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
 
         cib_read_config(options, xml);
         value = cib_pref(options, "enable-acl");
         rc = crm_is_true(value);
         g_hash_table_destroy(options);
     }
 
     crm_debug("CIB ACL is %s", rc ? "enabled" : "disabled");
 #endif
     return rc;
 }
 
 int
 cib_perform_op(const char *op, int call_options, cib_op_t * fn, gboolean is_query,
                const char *section, xmlNode * req, xmlNode * input,
                gboolean manage_counters, gboolean * config_changed,
                xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output)
 {
     int rc = pcmk_ok;
     gboolean check_dtd = TRUE;
     xmlNode *top = NULL;
     xmlNode *scratch = NULL;
     xmlNode *local_diff = NULL;
 
     const char *new_version = NULL;
     static struct qb_log_callsite *diff_cs = NULL;
     const char *user = crm_element_value(req, F_CIB_USER);
 
     crm_trace("Begin %s%s op", is_query ? "read-only " : "", op);
 
     CRM_CHECK(output != NULL, return -ENOMSG);
     CRM_CHECK(result_cib != NULL, return -ENOMSG);
     CRM_CHECK(config_changed != NULL, return -ENOMSG);
 
     if(output) {
         *output = NULL;
     }
 
     *result_cib = NULL;
     *config_changed = FALSE;
 
     if (fn == NULL) {
         return -EINVAL;
     }
 
     if (is_query) {
         xmlNode *cib_ro = current_cib;
         xmlNode *cib_filtered = NULL;
 
         if(cib_acl_enabled(cib_ro, user)) {
             if(xml_acl_filtered_copy(user, current_cib, current_cib, &cib_filtered)) {
                 if (cib_filtered == NULL) {
                     crm_debug("Pre-filtered the entire cib");
                     return -EACCES;
                 }
                 cib_ro = cib_filtered;
                 crm_log_xml_trace(cib_ro, "filtered");
             }
         }
 
         rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
 
         if(output == NULL || *output == NULL) {
             /* nothing */
 
         } else if(cib_filtered == *output) {
             cib_filtered = NULL; /* Let them have this copy */
 
         } else if(*output == current_cib) {
             /* They already know not to free it */
 
         } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
             /* We're about to free the document of which *output is a part */
             *output = copy_xml(*output);
 
         } else if((*output)->doc == current_cib->doc) {
             /* Give them a copy they can free */
             *output = copy_xml(*output);
         }
 
         free_xml(cib_filtered);
         return rc;
     }
 
 
     if (is_set(call_options, cib_zero_copy)) {
         /* Conditional on v2 patch style */
 
         scratch = current_cib;
 
         /* Create a shallow copy of current_cib for the version details */
         current_cib = create_xml_node(NULL, (const char *)scratch->name);
         copy_in_properties(current_cib, scratch);
         top = current_cib;
 
         xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
         rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
 
     } else {
         scratch = copy_xml(current_cib);
         xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
         rc = (*fn) (op, call_options, section, req, input, current_cib, &scratch, output);
 
         if(xml_tracking_changes(scratch) == FALSE) {
             crm_trace("Inferring changes after %s op", op);
             xml_track_changes(scratch, user, current_cib, cib_acl_enabled(current_cib, user));
             xml_calculate_changes(current_cib, scratch);
         }
         CRM_CHECK(current_cib != scratch, return -EINVAL);
     }
 
     xml_acl_disable(scratch); /* Allow the system to make any additional changes */
 
     if (rc == pcmk_ok && scratch == NULL) {
         rc = -EINVAL;
         goto done;
 
     } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
         crm_trace("ACL rejected part or all of the proposed changes");
         rc = -EACCES;
         goto done;
 
     } else if (rc != pcmk_ok) {
         goto done;
     }
 
     if (scratch) {
         new_version = crm_element_value(scratch, XML_ATTR_CRM_VERSION);
 
         if (new_version && compare_version(new_version, CRM_FEATURE_SET) > 0) {
             crm_err("Discarding update with feature set '%s' greater than our own '%s'",
                     new_version, CRM_FEATURE_SET);
             rc = -EPROTONOSUPPORT;
             goto done;
         }
     }
 
     if (current_cib) {
         int old = 0;
         int new = 0;
 
         crm_element_value_int(scratch, XML_ATTR_GENERATION_ADMIN, &new);
         crm_element_value_int(current_cib, XML_ATTR_GENERATION_ADMIN, &old);
 
         if (old > new) {
             crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
                     XML_ATTR_GENERATION_ADMIN, old, new, call_options);
             crm_log_xml_warn(req, "Bad Op");
             crm_log_xml_warn(input, "Bad Data");
             rc = -pcmk_err_old_data;
 
         } else if (old == new) {
             crm_element_value_int(scratch, XML_ATTR_GENERATION, &new);
             crm_element_value_int(current_cib, XML_ATTR_GENERATION, &old);
             if (old > new) {
                 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
                         XML_ATTR_GENERATION, old, new, call_options);
                 crm_log_xml_warn(req, "Bad Op");
                 crm_log_xml_warn(input, "Bad Data");
                 rc = -pcmk_err_old_data;
             }
         }
     }
 
     crm_trace("Massaging CIB contents");
     strip_text_nodes(scratch);
     fix_plus_plus_recursive(scratch);
 
     if (is_set(call_options, cib_zero_copy)) {
         /* At this point, current_cib is just the 'cib' tag and its properties,
          *
          * The v1 format would barf on this, but we know the v2 patch
          * format only needs it for the top-level version fields
          */
         local_diff = xml_create_patchset(2, current_cib, scratch, (bool*)config_changed, manage_counters, FALSE);
 
     } else {
         static time_t expires = 0;
         time_t tm_now = time(NULL);
         bool with_digest = FALSE;
 
         if (expires < tm_now) {
             expires = tm_now + 60;  /* Validate clients are correctly applying v2-style diffs at most once a minute */
             with_digest = TRUE;
         }
 
         local_diff = xml_create_patchset(0, current_cib, scratch, (bool*)config_changed, manage_counters, with_digest);
     }
 
     if (diff_cs == NULL) {
         diff_cs = qb_log_callsite_get(__PRETTY_FUNCTION__, __FILE__, "diff-validation", LOG_DEBUG, __LINE__, crm_trace_nonlog);
     }
 
     if(local_diff) {
         xml_log_patchset(LOG_INFO, __FUNCTION__, local_diff);
         crm_log_xml_trace(local_diff, "raw patch");
     }
 
     if (is_not_set(call_options, cib_zero_copy) /* The original to compare against doesn't exist */
         && local_diff
         && crm_is_callsite_active(diff_cs, LOG_TRACE, 0)) {
 
         /* Validate the calculated patch set */
         int test_rc, format = 1;
         xmlNode * c = copy_xml(current_cib);
 
         crm_element_value_int(local_diff, "format", &format);
         test_rc = xml_apply_patchset(c, local_diff, manage_counters);
 
         if(test_rc != pcmk_ok) {
             save_xml_to_file(c,           "PatchApply:calculated", NULL);
             save_xml_to_file(current_cib, "PatchApply:input", NULL);
             save_xml_to_file(scratch,     "PatchApply:actual", NULL);
             save_xml_to_file(local_diff,  "PatchApply:diff", NULL);
             crm_err("v%d patchset error, patch failed to apply: %s (%d)", format, pcmk_strerror(test_rc), test_rc);
         }
         free_xml(c);
     }
 
     xml_log_changes(LOG_TRACE, __FUNCTION__, scratch);
     xml_accept_changes(scratch);
 
     if (safe_str_eq(section, XML_CIB_TAG_STATUS)) {
         /* Throttle the amount of costly validation we perform due to status updates
          * a) we don't really care whats in the status section
          * b) we don't validate any of it's contents at the moment anyway
          */
         check_dtd = FALSE;
     }
 
     /* === scratch must not be modified after this point ===
      * Exceptions, anything in:
 
      static filter_t filter[] = {
      { 0, XML_ATTR_ORIGIN },
      { 0, XML_CIB_ATTR_WRITTEN },
      { 0, XML_ATTR_UPDATE_ORIG },
      { 0, XML_ATTR_UPDATE_CLIENT },
      { 0, XML_ATTR_UPDATE_USER },
      };
      */
 
     if (*config_changed && is_not_set(call_options, cib_no_mtime)) {
         char *now_str = NULL;
         time_t now = time(NULL);
         const char *schema = crm_element_value(scratch, XML_ATTR_VALIDATION);
 
         now_str = ctime(&now);
         now_str[24] = EOS;      /* replace the newline */
         crm_xml_replace(scratch, XML_CIB_ATTR_WRITTEN, now_str);
 
         if (schema) {
             static int minimum_schema = 0;
             int current_schema = get_schema_version(schema);
 
             if (minimum_schema == 0) {
                 minimum_schema = get_schema_version("pacemaker-1.1");
             }
 
             /* Does the CIB support the "update-*" attributes... */
             if (current_schema >= minimum_schema) {
                 const char *origin = crm_element_value(req, F_ORIG);
 
                 CRM_LOG_ASSERT(origin != NULL);
                 crm_xml_replace(scratch, XML_ATTR_UPDATE_ORIG, origin);
                 crm_xml_replace(scratch, XML_ATTR_UPDATE_CLIENT,
                                 crm_element_value(req, F_CIB_CLIENTNAME));
 #if ENABLE_ACL
                 crm_xml_replace(scratch, XML_ATTR_UPDATE_USER, crm_element_value(req, F_CIB_USER));
 #endif
             }
         }
     }
 
     crm_trace("Perform validation: %s", check_dtd ? "true" : "false");
     if (rc == pcmk_ok && check_dtd && validate_xml(scratch, NULL, TRUE) == FALSE) {
         const char *current_dtd = crm_element_value(scratch, XML_ATTR_VALIDATION);
 
         crm_warn("Updated CIB does not validate against %s schema/dtd", crm_str(current_dtd));
         rc = -pcmk_err_schema_validation;
     }
 
   done:
 
     *result_cib = scratch;
 #if ENABLE_ACL
     if(rc != pcmk_ok && cib_acl_enabled(current_cib, user)) {
         if(xml_acl_filtered_copy(user, current_cib, scratch, result_cib)) {
             if (*result_cib == NULL) {
                 crm_debug("Pre-filtered the entire cib result");
             }
             free_xml(scratch);
         }
     }
 #endif
 
     if(diff) {
         *diff = local_diff;
     } else {
         free_xml(local_diff);
     }
 
     free_xml(top);
     crm_trace("Done");
     return rc;
 }
 
 xmlNode *
 cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section,
               xmlNode * data, int call_options, const char *user_name)
 {
     xmlNode *op_msg = create_xml_node(NULL, "cib_command");
 
     CRM_CHECK(op_msg != NULL, return NULL);
     CRM_CHECK(token != NULL, return NULL);
 
     crm_xml_add(op_msg, F_XML_TAGNAME, "cib_command");
 
     crm_xml_add(op_msg, F_TYPE, T_CIB);
     crm_xml_add(op_msg, F_CIB_CALLBACK_TOKEN, token);
     crm_xml_add(op_msg, F_CIB_OPERATION, op);
     crm_xml_add(op_msg, F_CIB_HOST, host);
     crm_xml_add(op_msg, F_CIB_SECTION, section);
     crm_xml_add_int(op_msg, F_CIB_CALLID, call_id);
 #if ENABLE_ACL
     if (user_name) {
         crm_xml_add(op_msg, F_CIB_USER, user_name);
     }
 #endif
     crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
     crm_xml_add_int(op_msg, F_CIB_CALLOPTS, call_options);
 
     if (data != NULL) {
         add_message_xml(op_msg, F_CIB_CALLDATA, data);
     }
 
     if (call_options & cib_inhibit_bcast) {
         CRM_CHECK((call_options & cib_scope_local), return NULL);
     }
     return op_msg;
 }
 
 void
 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
 {
     xmlNode *output = NULL;
     cib_callback_client_t *blob = NULL;
     cib_callback_client_t local_blob;
 
     local_blob.id = NULL;
     local_blob.callback = NULL;
     local_blob.user_data = NULL;
     local_blob.only_success = FALSE;
 
     if (msg != NULL) {
         crm_element_value_int(msg, F_CIB_RC, &rc);
         crm_element_value_int(msg, F_CIB_CALLID, &call_id);
         output = get_message_xml(msg, F_CIB_CALLDATA);
     }
 
     blob = g_hash_table_lookup(cib_op_callback_table, GINT_TO_POINTER(call_id));
 
     if (blob != NULL) {
         local_blob = *blob;
         blob = NULL;
 
         remove_cib_op_callback(call_id, FALSE);
 
     } else {
         crm_trace("No callback found for call %d", call_id);
         local_blob.callback = NULL;
     }
 
     if (cib == NULL) {
         crm_debug("No cib object supplied");
     }
 
     if (rc == -pcmk_err_diff_resync) {
         /* This is an internal value that clients do not and should not care about */
         rc = pcmk_ok;
     }
 
     if (local_blob.callback != NULL && (rc == pcmk_ok || local_blob.only_success == FALSE)) {
         crm_trace("Invoking callback %s for call %d", crm_str(local_blob.id), call_id);
         local_blob.callback(msg, call_id, rc, output, local_blob.user_data);
 
     } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
         crm_warn("CIB command failed: %s", pcmk_strerror(rc));
         crm_log_xml_debug(msg, "Failed CIB Update");
     }
 
     if (cib && cib->op_callback != NULL) {
         crm_trace("Invoking global callback for call %d", call_id);
         cib->op_callback(msg, call_id, rc, output);
     }
     crm_trace("OP callback activated.");
 }
 
 void
 cib_native_notify(gpointer data, gpointer user_data)
 {
     xmlNode *msg = user_data;
     cib_notify_client_t *entry = data;
     const char *event = NULL;
 
     if (msg == NULL) {
         crm_warn("Skipping callback - NULL message");
         return;
     }
 
     event = crm_element_value(msg, F_SUBTYPE);
 
     if (entry == NULL) {
         crm_warn("Skipping callback - NULL callback client");
         return;
 
     } else if (entry->callback == NULL) {
         crm_warn("Skipping callback - NULL callback");
         return;
 
     } else if (safe_str_neq(entry->event, event)) {
         crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
         return;
     }
 
     crm_trace("Invoking callback for %p/%s event...", entry, event);
     entry->callback(event, msg);
     crm_trace("Callback invoked...");
 }
 
 pe_cluster_option cib_opts[] = {
     /* name, old-name, validate, default, description */
     {"enable-acl", NULL, "boolean", NULL, "false", &check_boolean,
      "Enable CIB ACL", NULL}
     ,
 };
 
 void
 cib_metadata(void)
 {
     config_metadata("Cluster Information Base", "1.0",
                     "Cluster Information Base Options",
                     "This is a fake resource that details the options that can be configured for the Cluster Information Base.",
                     cib_opts, DIMOF(cib_opts));
 }
 
 void
 verify_cib_options(GHashTable * options)
 {
     verify_all_options(options, cib_opts, DIMOF(cib_opts));
 }
 
 const char *
 cib_pref(GHashTable * options, const char *name)
 {
     return get_cluster_pref(options, cib_opts, DIMOF(cib_opts), name);
 }
 
 gboolean
 cib_read_config(GHashTable * options, xmlNode * current_cib)
 {
     xmlNode *config = NULL;
     crm_time_t *now = NULL;
 
     if (options == NULL || current_cib == NULL) {
         return FALSE;
     }
 
     now = crm_time_new(NULL);
 
     g_hash_table_remove_all(options);
 
     config = get_object_root(XML_CIB_TAG_CRMCONFIG, current_cib);
     if (config) {
         unpack_instance_attributes(current_cib, config, XML_CIB_TAG_PROPSET, NULL, options,
                                    CIB_OPTIONS_FIRST, FALSE, now);
     }
 
     verify_cib_options(options);
 
     crm_time_free(now);
 
     return TRUE;
 }
 
 int
 cib_apply_patch_event(xmlNode * event, xmlNode * input, xmlNode ** output, int level)
 {
     int rc = pcmk_err_generic;
 
     xmlNode *diff = NULL;
 
     CRM_ASSERT(event);
     CRM_ASSERT(input);
     CRM_ASSERT(output);
 
     crm_element_value_int(event, F_CIB_RC, &rc);
     diff = get_message_xml(event, F_CIB_UPDATE_RESULT);
 
     if (rc < pcmk_ok || diff == NULL) {
         return rc;
     }
 
     if (level > LOG_CRIT) {
         xml_log_patchset(level, "Config update", diff);
     }
 
     if (input != NULL) {
         rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output, NULL);
 
         if (rc != pcmk_ok) {
             crm_debug("Update didn't apply: %s (%d) %p", pcmk_strerror(rc), rc, *output);
 
             if (rc == -pcmk_err_old_data) {
                 crm_trace("Masking error, we already have the supplied update");
                 return pcmk_ok;
             }
             free_xml(*output); *output = NULL;
 
             return rc;
         }
     }
 
     return rc;
 }
 
 gboolean
 cib_internal_config_changed(xmlNode * diff)
 {
     gboolean changed = FALSE;
     xmlXPathObject *xpathObj = NULL;
 
     if (diff == NULL) {
         return FALSE;
     }
 
     xpathObj = xpath_search(diff, "//" XML_CIB_TAG_CRMCONFIG);
     if (numXpathResults(xpathObj) > 0) {
         changed = TRUE;
     }
 
     freeXpathObject(xpathObj);
 
     return changed;
 }
 
 int
 cib_internal_op(cib_t * cib, const char *op, const char *host,
                 const char *section, xmlNode * data,
                 xmlNode ** output_data, int call_options, const char *user_name)
 {
     int (*delegate) (cib_t * cib, const char *op, const char *host,
                      const char *section, xmlNode * data,
                      xmlNode ** output_data, int call_options, const char *user_name) =
         cib->delegate_fn;
 
 #if ENABLE_ACL
     if(user_name == NULL) {
         user_name = getenv("CIB_user");
     }
 #endif
 
     return delegate(cib, op, host, section, data, output_data, call_options, user_name);
 }
diff --git a/tools/cib_shadow.c b/tools/cib_shadow.c
index e68d8eaa9d..ea4716c9d9 100644
--- a/tools/cib_shadow.c
+++ b/tools/cib_shadow.c
@@ -1,624 +1,620 @@
 
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <unistd.h>
 
 #include <sys/param.h>
 #include <crm/crm.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 
 #include <crm/common/ipc.h>
 
 #include <crm/cib.h>
 
 int exit_code = pcmk_ok;
 GMainLoop *mainloop = NULL;
 
 const char *host = NULL;
 void usage(const char *cmd, int exit_status);
 
 int command_options = cib_sync_call;
 const char *cib_action = NULL;
 
 cib_t *real_cib = NULL;
 
 int dump_data_element(int depth, char **buffer, int *max, int *offset, const char *prefix,
                       xmlNode * data, gboolean formatted);
 
 void print_xml_diff(FILE * where, xmlNode * diff);
 
 static int force_flag = 0;
 static int batch_flag = 0;
 
 static int
 print_spaces(char *buffer, int depth, int max)
 {
     int lpc = 0;
     int spaces = 2 * depth;
 
     max--;
 
     /* <= so that we always print 1 space - prevents problems with syslog */
     for (lpc = 0; lpc <= spaces && lpc < max; lpc++) {
         if (sprintf(buffer + lpc, "%c", ' ') < 1) {
             return -1;
         }
     }
     return lpc;
 }
 
 static char *
 get_shadow_prompt(const char *name)
 {
     return g_strdup_printf("shadow[%.40s] # ", name);
 }
 
 static void
 shadow_setup(char *name, gboolean do_switch)
 {
     const char *prompt = getenv("PS1");
     const char *shell = getenv("SHELL");
     char *new_prompt = get_shadow_prompt(name);
 
     printf("Setting up shadow instance\n");
 
     if (safe_str_eq(new_prompt, prompt)) {
         /* nothing to do */
         goto done;
 
     } else if (batch_flag == FALSE && shell != NULL) {
         setenv("PS1", new_prompt, 1);
         setenv("CIB_shadow", name, 1);
         printf("Type Ctrl-D to exit the crm_shadow shell\n");
 
         if (strstr(shell, "bash")) {
             execl(shell, shell, "--norc", "--noprofile", NULL);
         } else {
             execl(shell, shell, "--noprofile", NULL);
         }
 
     } else if (do_switch) {
         printf("To switch to the named shadow instance, paste the following into your shell:\n");
 
     } else {
         printf
             ("A new shadow instance was created.  To begin using it paste the following into your shell:\n");
     }
     printf("  CIB_shadow=%s ; export CIB_shadow\n", name);
 
   done:
     free(new_prompt);
 }
 
 static void
 shadow_teardown(char *name)
 {
     const char *prompt = getenv("PS1");
     char *our_prompt = get_shadow_prompt(name);
 
     if (prompt != NULL && strstr(prompt, our_prompt)) {
         printf("Now type Ctrl-D to exit the crm_shadow shell\n");
 
     } else {
         printf
             ("Please remember to unset the CIB_shadow variable by pasting the following into your shell:\n");
         printf("  unset CIB_shadow\n");
     }
     free(our_prompt);
 }
 
 /* *INDENT-OFF* */
 static struct crm_option long_options[] = {
     /* Top-level Options */
     {"help",    0, 0, '?', "\t\tThis text"},
     {"version", 0, 0, '$', "\t\tVersion information"  },
     {"verbose", 0, 0, 'V', "\t\tIncrease debug output"},
 
     {"-spacer-",	1, 0, '-', "\nQueries:"},
     {"which",   no_argument,       NULL, 'w', "\t\tIndicate the active shadow copy"},
     {"display", no_argument,       NULL, 'p', "\t\tDisplay the contents of the active shadow copy"},
     {"edit",    no_argument,       NULL, 'E', "\t\tEdit the contents of the active shadow copy with your favorite $EDITOR"},
     {"diff",    no_argument,       NULL, 'd', "\t\tDisplay the changes in the active shadow copy\n"},
     {"file",    no_argument,       NULL, 'F', "\t\tDisplay the location of the active shadow copy file\n"},
 
     {"-spacer-",	1, 0, '-', "\nCommands:"},
     {"create",		required_argument, NULL, 'c', "\tCreate the named shadow copy of the active cluster configuration"},
     {"create-empty",	required_argument, NULL, 'e', "Create the named shadow copy with an empty cluster configuration"},
     {"commit",  required_argument, NULL, 'C', "\tUpload the contents of the named shadow copy to the cluster"},
     {"delete",  required_argument, NULL, 'D', "\tDelete the contents of the named shadow copy"},
     {"reset",   required_argument, NULL, 'r', "\tRecreate the named shadow copy from the active cluster configuration"},
     {"switch",  required_argument, NULL, 's', "\t(Advanced) Switch to the named shadow copy"},
 
     {"-spacer-",	1, 0, '-', "\nAdditional Options:"},
     {"force",	no_argument, NULL, 'f', "\t\t(Advanced) Force the action to be performed"},
     {"batch",   no_argument, NULL, 'b', "\t\t(Advanced) Don't spawn a new shell" },
     {"all",     no_argument, NULL, 'a', "\t\t(Advanced) Upload the entire CIB, including status, with --commit" },
 
     {"-spacer-",	1, 0, '-', "\nExamples:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', "Create a blank shadow configuration:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_shadow --create-empty myShadow", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Create a shadow configuration from the running cluster:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_shadow --create myShadow", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Display the current shadow configuration:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_shadow --display", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Discard the current shadow configuration (named myShadow):", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_shadow --delete myShadow", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Upload the current shadow configuration (named myShadow) to the running cluster:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_shadow --commit myShadow", pcmk_option_example},
 
     {0, 0, 0, 0}
 };
 /* *INDENT-ON* */
 
 int
 main(int argc, char **argv)
 {
     int rc = 0;
     int flag;
     int argerr = 0;
     static int command = '?';
     char *shadow = NULL;
     char *shadow_file = NULL;
     gboolean full_upload = FALSE;
     gboolean dangerous_cmd = FALSE;
     struct stat buf;
     int option_index = 0;
 
     crm_log_cli_init("crm_shadow");
     crm_set_options(NULL, "(query|command) [modifiers]", long_options,
                     "Perform configuration changes in a sandbox before updating the live cluster."
                     "\n\nSets up an environment in which configuration tools (cibadmin, crm_resource, etc) work"
                     " offline instead of against a live cluster, allowing changes to be previewed and tested"
                     " for side-effects.\n");
 
     if (argc < 2) {
         crm_help('?', EX_USAGE);
     }
 
     while (1) {
         flag = crm_get_option(argc, argv, &option_index);
         if (flag == -1 || flag == 0)
             break;
 
         switch (flag) {
             case 'a':
                 full_upload = TRUE;
                 break;
             case 'd':
             case 'E':
             case 'p':
             case 'w':
             case 'F':
                 command = flag;
                 free(shadow);
                 shadow = NULL;
                 {
                     const char *env = getenv("CIB_shadow");
                     if(env) {
                         shadow = strdup(env);
                     } else {
                         fprintf(stderr, "No active shadow configuration defined\n");
                         crm_exit(ENOENT);
                     }
                 }
                 break;
             case 'e':
             case 'c':
             case 's':
             case 'r':
                 command = flag;
                 free(shadow);
                 shadow = strdup(optarg);
                 break;
             case 'C':
             case 'D':
                 command = flag;
                 dangerous_cmd = TRUE;
                 free(shadow);
                 shadow = strdup(optarg);
                 break;
             case 'V':
                 command_options = command_options | cib_verbose;
                 crm_bump_log_level(argc, argv);
                 break;
             case '$':
             case '?':
                 crm_help(flag, EX_OK);
                 break;
             case 'f':
                 command_options |= cib_quorum_override;
                 force_flag = 1;
                 break;
             case 'b':
                 batch_flag = 1;
                 break;
             default:
                 printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
                 ++argerr;
                 break;
         }
     }
 
     if (optind < argc) {
         printf("non-option ARGV-elements: ");
         while (optind < argc)
             printf("%s ", argv[optind++]);
         printf("\n");
         crm_help('?', EX_USAGE);
     }
 
     if (optind > argc) {
         ++argerr;
     }
 
     if (argerr) {
         crm_help('?', EX_USAGE);
     }
 
     if (command == 'w') {
         /* which shadow instance is active? */
         const char *local = getenv("CIB_shadow");
 
         if (local == NULL) {
             fprintf(stderr, "No shadow instance provided\n");
             rc = -ENXIO;
             goto done;
         }
         fprintf(stdout, "%s\n", local);
         rc = 0;
         goto done;
     }
 
     if (shadow == NULL) {
         fprintf(stderr, "No shadow instance provided\n");
         fflush(stderr);
         rc = -EINVAL;
         goto done;
 
     } else if (command != 's' && command != 'c') {
         const char *local = getenv("CIB_shadow");
 
         if (local != NULL && safe_str_neq(local, shadow) && force_flag == FALSE) {
             fprintf(stderr,
                     "The supplied shadow instance (%s) is not the same as the active one (%s).\n"
                     "  To prevent accidental destruction of the cluster,"
                     " the --force flag is required in order to proceed.\n", shadow, local);
             fflush(stderr);
             rc = EX_USAGE;
             goto done;
         }
     }
 
     if (dangerous_cmd && force_flag == FALSE) {
         fprintf(stderr, "The supplied command is considered dangerous."
                 "  To prevent accidental destruction of the cluster,"
                 " the --force flag is required in order to proceed.\n");
         fflush(stderr);
         rc = EX_USAGE;
         goto done;
     }
 
     shadow_file = get_shadow_file(shadow);
     if (command == 'D') {
         /* delete the file */
         rc = stat(shadow_file, &buf);
         if (rc == 0) {
             rc = unlink(shadow_file);
             if (rc != 0) {
                 fprintf(stderr, "Could not remove shadow instance '%s': %s\n", shadow,
                         strerror(errno));
                 goto done;
             }
         }
 
         shadow_teardown(shadow);
         goto done;
 
     } else if (command == 'F') {
         printf("%s\n", shadow_file);
         rc = 0;
         goto done;
     }
 
     if (command == 'd' || command == 'r' || command == 'c' || command == 'C') {
         real_cib = cib_new_no_shadow();
         rc = real_cib->cmds->signon(real_cib, crm_system_name, cib_command);
         if (rc != pcmk_ok) {
             fprintf(stderr, "Signon to CIB failed: %s\n", pcmk_strerror(rc));
             goto done;
         }
     }
 
     rc = stat(shadow_file, &buf);
 
     if (command == 'e' || command == 'c') {
         if (rc == 0 && force_flag == FALSE) {
             fprintf(stderr, "A shadow instance '%s' already exists.\n"
                     "  To prevent accidental destruction of the cluster,"
                     " the --force flag is required in order to proceed.\n", shadow);
             rc = -ENOTUNIQ;
             goto done;
         }
 
     } else if (rc != 0) {
         fprintf(stderr, "Could not access shadow instance '%s': %s\n", shadow, strerror(errno));
         rc = -ENXIO;
         goto done;
     }
 
     rc = pcmk_ok;
     if (command == 'c' || command == 'e' || command == 'r') {
         xmlNode *output = NULL;
 
         /* create a shadow instance based on the current cluster config */
         if (command == 'c' || command == 'r') {
             rc = real_cib->cmds->query(real_cib, NULL, &output, command_options);
             if (rc != pcmk_ok) {
                 fprintf(stderr, "Could not connect to the CIB: %s\n", pcmk_strerror(rc));
                 goto done;
             }
 
         } else {
-            output = createEmptyCib();
-            crm_xml_add(output, XML_ATTR_GENERATION, "0");
-            crm_xml_add(output, XML_ATTR_NUMUPDATES, "0");
-            crm_xml_add(output, XML_ATTR_GENERATION_ADMIN, "0");
-            crm_xml_add(output, XML_ATTR_VALIDATION, xml_latest_schema());
+            output = createEmptyCib(1);
         }
 
         rc = write_xml_file(output, shadow_file, FALSE);
         free_xml(output);
 
         if (rc < 0) {
             fprintf(stderr, "Could not %s the shadow instance '%s': %s\n",
                     command == 'r' ? "reset" : "create",
                     shadow, strerror(errno));
             goto done;
         }
         shadow_setup(shadow, FALSE);
         rc = pcmk_ok;
 
     } else if (command == 'E') {
         const char *err = NULL;
         char *editor = getenv("EDITOR");
 
         if (editor == NULL) {
             fprintf(stderr, "No value for $EDITOR defined\n");
             rc = -EINVAL;
             goto done;
         }
 
         execlp(editor, "--", shadow_file, NULL);
         err = strerror(errno);
         fprintf(stderr, "Could not invoke $EDITOR (%s %s): %s\n", editor, shadow_file, err);
         rc = -EINVAL;
         goto done;
 
     } else if (command == 's') {
         shadow_setup(shadow, TRUE);
         rc = 0;
         goto done;
 
     } else if (command == 'P') {
         /* display the current contents */
         char *output_s = NULL;
         xmlNode *output = filename2xml(shadow_file);
 
         output_s = dump_xml_formatted(output);
         printf("%s", output_s);
 
         free(output_s);
         free_xml(output);
 
     } else if (command == 'd') {
         /* diff against cluster */
         xmlNode *diff = NULL;
         xmlNode *old_config = NULL;
         xmlNode *new_config = filename2xml(shadow_file);
 
         rc = real_cib->cmds->query(real_cib, NULL, &old_config, command_options);
 
         if (rc != pcmk_ok) {
             fprintf(stderr, "Could not query the CIB: %s\n", pcmk_strerror(rc));
             goto done;
         }
 
         diff = diff_xml_object(old_config, new_config, FALSE);
         if (diff != NULL) {
             print_xml_diff(stdout, diff);
             rc = 1;
             goto done;
         }
         rc = 0;
         goto done;
 
     } else if (command == 'C') {
         /* commit to the cluster */
         xmlNode *input = filename2xml(shadow_file);
 
         if (full_upload) {
             rc = real_cib->cmds->replace(real_cib, NULL, input, command_options);
         } else {
             xmlNode *config = first_named_child(input, XML_CIB_TAG_CONFIGURATION);
 
             rc = real_cib->cmds->replace(real_cib, XML_CIB_TAG_CONFIGURATION, config,
                                          command_options);
         }
 
         if (rc != pcmk_ok) {
             fprintf(stderr, "Could not commit shadow instance '%s' to the CIB: %s\n",
                     shadow, pcmk_strerror(rc));
             return rc;
         }
         shadow_teardown(shadow);
         free_xml(input);
     }
   done:
     free(shadow_file);
     free(shadow);
     return crm_exit(rc);
 }
 
 #define bhead(buffer, offset) ((*buffer) + (*offset))
 #define bremain(max, offset) ((*max) - (*offset))
 #define update_buffer_head(len) do {		\
 	int total = (*offset) + len + 1;	\
 	if(total >= (*max)) { /* too late */	\
 	    (*buffer) = EOS; return -1;		\
 	} else if(((*max) - total) < 256) {	\
 	    (*max) *= 10;			\
 	    *buffer = realloc(*buffer, (*max));	\
 	}					\
 	(*offset) += len;			\
     } while(0)
 
 int
 dump_data_element(int depth, char **buffer, int *max, int *offset, const char *prefix,
                   xmlNode * data, gboolean formatted)
 {
     int printed = 0;
     int has_children = 0;
     xmlNode *child = NULL;
     const char *name = NULL;
 
     CRM_CHECK(data != NULL, return 0);
 
     name = crm_element_name(data);
 
     CRM_CHECK(name != NULL, return 0);
     CRM_CHECK(buffer != NULL && *buffer != NULL, return 0);
 
     crm_trace("Dumping %s...", name);
 
     if (prefix) {
         printed = snprintf(bhead(buffer, offset), bremain(max, offset), "%s", prefix);
         update_buffer_head(printed);
     }
 
     if (formatted) {
         printed = print_spaces(bhead(buffer, offset), depth, bremain(max, offset));
         update_buffer_head(printed);
     }
 
     printed = snprintf(bhead(buffer, offset), bremain(max, offset), "<%s", name);
     update_buffer_head(printed);
 
     if (data) {
         xmlAttrPtr xIter = NULL;
 
         for (xIter = data->properties; xIter; xIter = xIter->next) {
             const char *prop_name = (const char *)xIter->name;
             const char *prop_value = crm_element_value(data, prop_name);
 
             crm_trace("Dumping <%s %s=\"%s\"...", name, prop_name, prop_value);
             printed =
                 snprintf(bhead(buffer, offset), bremain(max, offset), " %s=\"%s\"", prop_name,
                          prop_value);
             update_buffer_head(printed);
         }
     }
 
     has_children = xml_has_children(data);
     printed = snprintf(bhead(buffer, offset), bremain(max, offset), "%s>%s",
                        has_children == 0 ? "/" : "", formatted ? "\n" : "");
     update_buffer_head(printed);
 
     if (has_children == 0) {
         return 0;
     }
 
     for (child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
         if (dump_data_element(depth + 1, buffer, max, offset, prefix, child, formatted) < 0) {
             return -1;
         }
     }
 
     if (prefix) {
         printed = snprintf(bhead(buffer, offset), bremain(max, offset), "%s", prefix);
         update_buffer_head(printed);
     }
 
     if (formatted) {
         printed = print_spaces(bhead(buffer, offset), depth, bremain(max, offset));
         update_buffer_head(printed);
     }
 
     printed =
         snprintf(bhead(buffer, offset), bremain(max, offset), "</%s>%s", name,
                  formatted ? "\n" : "");
     update_buffer_head(printed);
     crm_trace("Dumped %s...", name);
 
     return has_children;
 }
 
 void
 print_xml_diff(FILE * where, xmlNode * diff)
 {
     char *buffer = NULL;
     xmlNode *child = NULL;
     int max = 1024, len = 0;
     gboolean is_first = TRUE;
     xmlNode *added = find_xml_node(diff, "diff-added", FALSE);
     xmlNode *removed = find_xml_node(diff, "diff-removed", FALSE);
 
     is_first = TRUE;
     for (child = __xml_first_child(removed); child != NULL; child = __xml_next(child)) {
         len = 0;
         max = 1024;
         free(buffer);
         buffer = calloc(1, max);
 
         if (is_first) {
             is_first = FALSE;
         } else {
             fprintf(where, " --- \n");
         }
 
         CRM_CHECK(dump_data_element(0, &buffer, &max, &len, "-", child, TRUE) >= 0, continue);
         fprintf(where, "%s", buffer);
     }
 
     is_first = TRUE;
     for (child = __xml_first_child(added); child != NULL; child = __xml_next(child)) {
         len = 0;
         max = 1024;
         free(buffer);
         buffer = calloc(1, max);
 
         if (is_first) {
             is_first = FALSE;
         } else {
             fprintf(where, " +++ \n");
         }
 
         CRM_CHECK(dump_data_element(0, &buffer, &max, &len, "+", child, TRUE) >= 0, continue);
         fprintf(where, "%s", buffer);
     }
 }
diff --git a/tools/cibadmin.c b/tools/cibadmin.c
index 49ac9807ec..458d45962c 100644
--- a/tools/cibadmin.c
+++ b/tools/cibadmin.c
@@ -1,591 +1,584 @@
 
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 
 #include <crm/crm.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/ipc.h>
 #include <crm/cib/internal.h>
 
 int exit_code = pcmk_ok;
 int message_timer_id = -1;
 int message_timeout_ms = 30;
 
 GMainLoop *mainloop = NULL;
 
 const char *host = NULL;
 void usage(const char *cmd, int exit_status);
 int do_init(void);
 int do_work(xmlNode * input, int command_options, xmlNode ** output);
 
 gboolean admin_message_timeout(gpointer data);
 void cib_connection_destroy(gpointer user_data);
 void cibadmin_op_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data);
 
 int command_options = 0;
 const char *cib_user = NULL;
 const char *cib_action = NULL;
 
 typedef struct str_list_s {
     int num_items;
     char *value;
     struct str_list_s *next;
 } str_list_t;
 
 char *obj_type = NULL;
 char *status = NULL;
 char *migrate_from = NULL;
 char *migrate_res = NULL;
 char *subtype = NULL;
 char *reset = NULL;
 
 int request_id = 0;
 int operation_status = 0;
 cib_t *the_cib = NULL;
 gboolean force_flag = FALSE;
 gboolean quiet = FALSE;
 int bump_log_num = 0;
 
 /* *INDENT-OFF* */
 static struct crm_option long_options[] = {
     {"help",    0, 0, '?', "\tThis text"},
     {"version", 0, 0, '$', "\tVersion information"  },
     {"verbose", 0, 0, 'V', "\tIncrease debug output\n"},
 
     {"-spacer-",    0, 0, '-', "Commands:"},
     {"upgrade",     0, 0, 'u', "\tUpgrade the configuration to the latest syntax"},
     {"query",       0, 0, 'Q', "\tQuery the contents of the CIB"},
     {"erase",       0, 0, 'E', "\tErase the contents of the whole CIB"},
     {"bump",        0, 0, 'B', "\tIncrease the CIB's epoch value by 1"},
     {"create",      0, 0, 'C', "\tCreate an object in the CIB.  Will fail if the object already exists."},
     {"modify",      0, 0, 'M', "\tFind the object somewhere in the CIB's XML tree and update it.  Fails if the object does not exist unless -c is specified"},
     {"patch",	    0, 0, 'P', "\tSupply an update in the form of an xml diff (See also: crm_diff)"},
     {"replace",     0, 0, 'R', "\tRecursivly replace an object in the CIB"},
     {"delete",      0, 0, 'D', "\tDelete the first object matching the supplied criteria, Eg. <op id=\"rsc1_op1\" name=\"monitor\"/>"},
     {"-spacer-",    0, 0, '-', "\n\tThe tagname and all attributes must match in order for the element to be deleted\n"},
     {"delete-all",  0, 0, 'd', "When used with --xpath, remove all matching objects in the configuration instead of just the first one"},
     {"empty",       0, 0, 'a', "\tOutput an empty CIB"},
     {"md5-sum",	    0, 0, '5', "\tCalculate the on-disk CIB digest"},
     {"md5-sum-versioned",  0, 0, '6', "Calculate an on-the-wire versioned CIB digest"},
     {"blank",       0, 0, '-', NULL, 1},
 
     {"-spacer-",1, 0, '-', "\nAdditional options:"},
     {"force",	    0, 0, 'f'},
     {"timeout",	    1, 0, 't', "Time (in seconds) to wait before declaring the operation failed"},
     {"user",	    1, 0, 'U', "Run the command with permissions of the named user (valid only for the root and "CRM_DAEMON_USER" accounts)"},
     {"sync-call",   0, 0, 's', "Wait for call to complete before returning"},
     {"local",	    0, 0, 'l', "\tCommand takes effect locally.  Should only be used for queries"},
     {"allow-create",0, 0, 'c', "(Advanced) Allow the target of a --modify,-M operation to be created if they do not exist"},
     {"no-children", 0, 0, 'n', "(Advanced) When querying an object, do not return include its children in the result\n"},
     {"no-bcast",    0, 0, 'b', NULL, 1},
 
     {"-spacer-",    0, 0, '-', "Data:"},
     {"xml-text",    1, 0, 'X', "Retrieve XML from the supplied string"},
     {"xml-file",    1, 0, 'x', "Retrieve XML from the named file"},
     {"xml-pipe",    0, 0, 'p', "Retrieve XML from stdin\n"},
 
     {"scope",       1, 0, 'o', "Limit the scope of the operation to a specific section of the CIB."},
     {"-spacer-",    0, 0, '-', "\tValid values are: nodes, resources, constraints, crm_config, rsc_defaults, op_defaults, status"},
 
     {"xpath",       1, 0, 'A', "A valid XPath to use instead of --scope,-o"},
     {"node-path",   0, 0, 'e',  "When performing XPath queries, return the address of any matches found."},
     {"-spacer-",    0, 0, '-', " Eg: /cib/configuration/resources/master[@id='ms_RH1_SCS']/primitive[@id='prm_RH1_SCS']", pcmk_option_paragraph},
     {"node",	    1, 0, 'N', "(Advanced) Send command to the specified host\n"},
     {"-space-",	    0, 0, '!', NULL, 1},
 
     {"-spacer-",    0, 0, '-', "\nExamples:\n"},
     {"-spacer-",    0, 0, '-', "Query the configuration from the local node:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --query --local", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Query the just the cluster options configuration:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --query --scope crm_config", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Query all 'target-role' settings:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --query --xpath \"//nvpair[@name='target-role']\"", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Remove all 'is-managed' settings:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --delete-all --xpath \"//nvpair[@name='is-managed']\"", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Remove the resource named 'old':", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --delete --xml-text '<primitive id=\"old\"/>'", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Remove all resources from the configuration:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --replace --scope resources --xml-text '<resources/>'", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Replace the complete configuration with the contents of $HOME/pacemaker.xml:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --replace --xml-file $HOME/pacemaker.xml", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Replace the constraints section of the configuration with the contents of $HOME/constraints.xml:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --replace --scope constraints --xml-file $HOME/constraints.xml", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Increase the configuration version to prevent old configurations from being loaded accidentally:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --modify --xml-text '<cib admin_epoch=\"admin_epoch++\"/>'", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "Edit the configuration with your favorite $EDITOR:", pcmk_option_paragraph},
     {"-spacer-",    0, 0, '-', " cibadmin --query > $HOME/local.xml", pcmk_option_example},
     {"-spacer-",    0, 0, '-', " $EDITOR $HOME/local.xml", pcmk_option_example},
     {"-spacer-",    0, 0, '-', " cibadmin --replace --xml-file $HOME/local.xml", pcmk_option_example},
 
     {"-spacer-",    0, 0, '-', "SEE ALSO:"},
     {"-spacer-",    0, 0, '-', " crm(8), pcs(8), crm_shadow(8)"},
 
     /* Legacy options */
     {"host",	     1, 0, 'h', NULL, 1},
 
     {0, 0, 0, 0}
 };
 /* *INDENT-ON* */
 
 static void
 print_xml_output(xmlNode * xml)
 {
     char *buffer;
 
     if (!xml) {
         return;
     } else if (xml->type != XML_ELEMENT_NODE) {
         return;
     }
 
     if (command_options & cib_xpath_address) {
         const char *id = crm_element_value(xml, XML_ATTR_ID);
 
         if (safe_str_eq((const char *)xml->name, "xpath-query")) {
             xmlNode *child = NULL;
 
             for (child = xml->children; child; child = child->next) {
                 print_xml_output(child);
             }
 
         } else {
             printf("%s\n", id);
         }
 
     } else {
         buffer = dump_xml_formatted(xml);
         fprintf(stdout, "%s", crm_str(buffer));
         free(buffer);
     }
 }
 
 int
 main(int argc, char **argv)
 {
     int argerr = 0;
     int flag;
     const char *source = NULL;
     char *admin_input_xml = NULL;
     char *admin_input_file = NULL;
     gboolean dangerous_cmd = FALSE;
     gboolean admin_input_stdin = FALSE;
     xmlNode *output = NULL;
     xmlNode *input = NULL;
 
     int option_index = 0;
 
     crm_xml_init(); /* Sets buffer allocation strategy */
     crm_system_name = strdup("cibadmin");
     crm_set_options(NULL, "command [options] [data]", long_options,
                     "Provides direct access to the cluster configuration."
                     "\n\nAllows the configuration, or sections of it, to be queried, modified, replaced and deleted."
                     "\n\nWhere necessary, XML data will be obtained using the -X, -x, or -p options\n");
 
     if (argc < 2) {
         crm_help('?', EX_USAGE);
     }
 
     while (1) {
         flag = crm_get_option(argc, argv, &option_index);
         if (flag == -1)
             break;
 
         switch (flag) {
             case 't':
                 message_timeout_ms = atoi(optarg);
                 if (message_timeout_ms < 1) {
                     message_timeout_ms = 30;
                 }
                 break;
             case 'A':
                 obj_type = strdup(optarg);
                 command_options |= cib_xpath;
                 break;
             case 'e':
                 command_options |= cib_xpath_address;
                 break;
             case 'u':
                 cib_action = CIB_OP_UPGRADE;
                 dangerous_cmd = TRUE;
                 break;
             case 'E':
                 cib_action = CIB_OP_ERASE;
                 dangerous_cmd = TRUE;
                 break;
             case 'Q':
                 cib_action = CIB_OP_QUERY;
                 quiet = TRUE;
                 break;
             case 'P':
                 cib_action = CIB_OP_APPLY_DIFF;
                 break;
             case 'U':
                 cib_user = optarg;
                 break;
             case 'M':
                 cib_action = CIB_OP_MODIFY;
                 break;
             case 'R':
                 cib_action = CIB_OP_REPLACE;
                 break;
             case 'C':
                 cib_action = CIB_OP_CREATE;
                 break;
             case 'D':
                 cib_action = CIB_OP_DELETE;
                 break;
             case '5':
                 cib_action = "md5-sum";
                 break;
             case '6':
                 cib_action = "md5-sum-versioned";
                 break;
             case 'c':
                 command_options |= cib_can_create;
                 break;
             case 'n':
                 command_options |= cib_no_children;
                 break;
             case 'B':
                 cib_action = CIB_OP_BUMP;
                 break;
             case 'V':
                 command_options = command_options | cib_verbose;
                 bump_log_num++;
                 break;
             case '?':
             case '$':
             case '!':
                 crm_help(flag, EX_OK);
                 break;
             case 'o':
                 crm_trace("Option %c => %s", flag, optarg);
                 obj_type = strdup(optarg);
                 break;
             case 'X':
                 crm_trace("Option %c => %s", flag, optarg);
                 admin_input_xml = strdup(optarg);
                 break;
             case 'x':
                 crm_trace("Option %c => %s", flag, optarg);
                 admin_input_file = strdup(optarg);
                 break;
             case 'p':
                 admin_input_stdin = TRUE;
                 break;
             case 'N':
             case 'h':
                 host = strdup(optarg);
                 break;
             case 'l':
                 command_options |= cib_scope_local;
                 break;
             case 'd':
                 cib_action = CIB_OP_DELETE;
                 command_options |= cib_multiple;
                 dangerous_cmd = TRUE;
                 break;
             case 'b':
                 dangerous_cmd = TRUE;
                 command_options |= cib_inhibit_bcast;
                 command_options |= cib_scope_local;
                 break;
             case 's':
                 command_options |= cib_sync_call;
                 break;
             case 'f':
                 force_flag = TRUE;
                 command_options |= cib_quorum_override;
                 break;
             case 'a':
-                output = createEmptyCib();
-                crm_xml_add(output, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
-                if (optind >= argc) {
-                    crm_xml_add(output, XML_ATTR_VALIDATION, xml_latest_schema());
-                } else {
+                output = createEmptyCib(1);
+                if (optind < argc) {
                     crm_xml_add(output, XML_ATTR_VALIDATION, argv[optind]);
                 }
-                crm_xml_add_int(output, XML_ATTR_GENERATION_ADMIN, 1);
-                crm_xml_add_int(output, XML_ATTR_GENERATION, 0);
-                crm_xml_add_int(output, XML_ATTR_NUMUPDATES, 0);
-
                 admin_input_xml = dump_xml_formatted(output);
                 fprintf(stdout, "%s\n", crm_str(admin_input_xml));
                 goto bail;
                 break;
             default:
                 printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
                 ++argerr;
                 break;
         }
     }
-    
+
     if (bump_log_num > 0) {
         quiet = FALSE;
     }
     crm_log_init(NULL, LOG_CRIT, FALSE, FALSE, argc, argv, quiet);
     while (bump_log_num > 0) {
         crm_bump_log_level(argc, argv);
         bump_log_num--;
     }
 
     if (optind < argc) {
         printf("non-option ARGV-elements: ");
         while (optind < argc)
             printf("%s ", argv[optind++]);
         printf("\n");
         crm_help('?', EX_USAGE);
     }
 
     if (optind > argc || cib_action == NULL) {
         ++argerr;
     }
 
     if (argerr) {
         crm_help('?', EX_USAGE);
     }
 
     if (dangerous_cmd && force_flag == FALSE) {
         fprintf(stderr, "The supplied command is considered dangerous."
                 "  To prevent accidental destruction of the cluster,"
                 " the --force flag is required in order to proceed.\n");
         fflush(stderr);
         exit_code = -EINVAL;
         goto bail;
     }
 
     if (admin_input_file != NULL) {
         input = filename2xml(admin_input_file);
         source = admin_input_file;
 
     } else if (admin_input_xml != NULL) {
         source = "input string";
         input = string2xml(admin_input_xml);
 
     } else if (admin_input_stdin) {
         source = "STDIN";
         input = stdin2xml();
     }
 
     if (input != NULL) {
         crm_log_xml_debug(input, "[admin input]");
 
     } else if (source) {
         fprintf(stderr, "Couldn't parse input from %s.\n", source);
         exit_code = -EINVAL;
         goto bail;
     }
 
     if (safe_str_eq(cib_action, "md5-sum")) {
         char *digest = NULL;
 
         if (input == NULL) {
             fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
             exit_code = -EINVAL;
             goto bail;
         }
 
         digest = calculate_on_disk_digest(input);
         fprintf(stderr, "Digest: ");
         fprintf(stdout, "%s\n", crm_str(digest));
         free(digest);
         goto bail;
 
     } else if (safe_str_eq(cib_action, "md5-sum-versioned")) {
         char *digest = NULL;
         const char *version = NULL;
 
         if (input == NULL) {
             fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
             exit_code = -EINVAL;
             goto bail;
         }
 
         version = crm_element_value(input, XML_ATTR_CRM_VERSION);
         digest = calculate_xml_versioned_digest(input, FALSE, TRUE, version);
         fprintf(stderr, "Versioned (%s) digest: ", version);
         fprintf(stdout, "%s\n", crm_str(digest));
         free(digest);
         goto bail;
     }
 
     exit_code = do_init();
     if (exit_code != pcmk_ok) {
         crm_err("Init failed, could not perform requested operations");
         fprintf(stderr, "Init failed, could not perform requested operations\n");
         return crm_exit(-exit_code);
     }
 
     exit_code = do_work(input, command_options, &output);
     if (exit_code > 0) {
         /* wait for the reply by creating a mainloop and running it until
          * the callbacks are invoked...
          */
         request_id = exit_code;
 
         the_cib->cmds->register_callback(the_cib, request_id, message_timeout_ms, FALSE, NULL,
                                          "cibadmin_op_callback", cibadmin_op_callback);
 
         mainloop = g_main_new(FALSE);
 
         crm_trace("%s waiting for reply from the local CIB", crm_system_name);
 
         crm_info("Starting mainloop");
         g_main_run(mainloop);
 
     } else if (exit_code < 0) {
         crm_err("Call failed: %s", pcmk_strerror(exit_code));
         fprintf(stderr, "Call failed: %s\n", pcmk_strerror(exit_code));
         operation_status = exit_code;
 
         if (exit_code == -pcmk_err_schema_validation) {
             if (crm_str_eq(cib_action, CIB_OP_UPGRADE, TRUE)) {
                 xmlNode *obj = NULL;
                 int version = 0, rc = 0;
 
                 rc = the_cib->cmds->query(the_cib, NULL, &obj, command_options);
                 if (rc == pcmk_ok) {
                     update_validation(&obj, &version, 0, TRUE, FALSE);
                 }
 
             } else if (output) {
                 validate_xml_verbose(output);
             }
         }
     }
 
     if (output != NULL) {
         print_xml_output(output);
         free_xml(output);
     }
 
     crm_trace("%s exiting normally", crm_system_name);
 
     free_xml(input);
     free(admin_input_xml);
     free(admin_input_file);
     flag = the_cib->cmds->signoff(the_cib);
     cib_delete(the_cib);
 
     if(exit_code == pcmk_ok) {
         exit_code = flag;
     }
   bail:
     return crm_exit(exit_code);
 }
 
 int
 do_work(xmlNode * input, int call_options, xmlNode ** output)
 {
     /* construct the request */
     the_cib->call_timeout = message_timeout_ms;
     if (strcasecmp(CIB_OP_REPLACE, cib_action) == 0
         && safe_str_eq(crm_element_name(input), XML_TAG_CIB)) {
         xmlNode *status = get_object_root(XML_CIB_TAG_STATUS, input);
 
         if (status == NULL) {
             create_xml_node(input, XML_CIB_TAG_STATUS);
         }
     }
 
     if (cib_action != NULL) {
         crm_trace("Passing \"%s\" to variant_op...", cib_action);
         return cib_internal_op(the_cib, cib_action, host, obj_type, input, output, call_options, cib_user);
 
     } else {
         crm_err("You must specify an operation");
     }
     return -EINVAL;
 }
 
 int
 do_init(void)
 {
     int rc = pcmk_ok;
 
     the_cib = cib_new();
     rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
     if (rc != pcmk_ok) {
         crm_err("Signon to CIB failed: %s", pcmk_strerror(rc));
         fprintf(stderr, "Signon to CIB failed: %s\n", pcmk_strerror(rc));
     }
 
     return rc;
 }
 
 void
 cib_connection_destroy(gpointer user_data)
 {
     crm_err("Connection to the CIB terminated... exiting");
     g_main_quit(mainloop);
     return;
 }
 
 void
 cibadmin_op_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     exit_code = rc;
 
     if (rc != 0) {
         crm_warn("Call %s failed (%d): %s", cib_action, rc, pcmk_strerror(rc));
         fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, pcmk_strerror(rc));
         print_xml_output(output);
 
     } else if (safe_str_eq(cib_action, CIB_OP_QUERY) && output == NULL) {
         crm_err("Output expected in query response");
         crm_log_xml_err(msg, "no output");
 
     } else if (output == NULL) {
         crm_info("Call passed");
 
     } else {
         crm_info("Call passed");
         print_xml_output(output);
     }
 
     if (call_id == request_id) {
         g_main_quit(mainloop);
 
     } else {
         crm_info("Message was not the response we were looking for (%d vs. %d", call_id,
                  request_id);
     }
 }