diff --git a/cib/messages.c b/cib/messages.c
index 9167c3cab9..c51af1058a 100644
--- a/cib/messages.c
+++ b/cib/messages.c
@@ -1,509 +1,506 @@
 /*
  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #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>
 #include <crm/common/ipcs.h>
 #include <crm/cluster/internal.h>
 
 #include <cibio.h>
 #include <cibmessages.h>
 #include <callbacks.h>
 
 /* Maximum number of diffs to ignore while waiting for a resync */
 #define MAX_DIFF_RETRY 5
 
 gboolean cib_is_master = FALSE;
 
 xmlNode *the_cib = NULL;
 extern const char *cib_our_uname;
 int revision_check(xmlNode * cib_update, xmlNode * cib_copy, int flags);
 int get_revision(xmlNode * xml_obj, int cur_revision);
 
 int updateList(xmlNode * local_cib, xmlNode * update_command, xmlNode * failed,
                int operation, const char *section);
 
 gboolean update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code);
 
 int cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset);
 
 int sync_our_cib(xmlNode * request, gboolean all);
 
 extern xmlNode *cib_msg_copy(const xmlNode * msg, gboolean with_data);
 extern gboolean cib_shutdown_flag;
 
 int
 cib_process_shutdown_req(const char *op, int options, const char *section, xmlNode * req,
                          xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                          xmlNode ** answer)
 {
-    int result = pcmk_ok;
     const char *host = crm_element_value(req, F_ORIG);
 
     *answer = NULL;
 
     if (crm_element_value(req, F_CIB_ISREPLY) == NULL) {
-        crm_info("Shutdown REQ from %s", host);
-        return pcmk_ok;
-
-    } else if (cib_shutdown_flag) {
-        crm_info("Shutdown ACK from %s", host);
-        terminate_cib(__FUNCTION__, 0);
+        crm_info("Peer %s is requesting to shut down", host);
         return pcmk_ok;
+    }
 
-    } else {
-        crm_err("Shutdown ACK from %s - not shutting down", host);
-        result = -EINVAL;
+    if (cib_shutdown_flag == FALSE) {
+        crm_err("Peer %s mistakenly thinks we wanted to shut down", host);
+        return -EINVAL;
     }
 
-    return result;
+    crm_info("Peer %s has acknowledged our shutdown request", host);
+    terminate_cib(__FUNCTION__, 0);
+    return pcmk_ok;
 }
 
 int
 cib_process_default(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;
 
     if (op == NULL) {
         result = -EINVAL;
         crm_err("No operation specified");
 
     } else if (strcasecmp(CRM_OP_NOOP, op) == 0) {
         ;
 
     } else {
         result = -EPROTONOSUPPORT;
         crm_err("Action [%s] is not supported by the CIB", op);
     }
     return result;
 }
 
 int
 cib_process_readwrite(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);
 
     if (safe_str_eq(op, CIB_OP_ISMASTER)) {
         if (cib_is_master == TRUE) {
             result = pcmk_ok;
         } else {
             result = -EPERM;
         }
         return result;
     }
 
     if (safe_str_eq(op, CIB_OP_MASTER)) {
         if (cib_is_master == FALSE) {
             crm_info("We are now in R/W mode");
             cib_is_master = TRUE;
         } else {
             crm_debug("We are still in R/W mode");
         }
 
     } else if (cib_is_master) {
         crm_info("We are now in R/O mode");
         cib_is_master = FALSE;
     }
 
     return result;
 }
 
 /* Set to 1 when a sync is requested, incremented when a diff is ignored,
  * reset to 0 when a sync is received
  */
 static int sync_in_progress = 0;
 
 void
 send_sync_request(const char *host)
 {
     xmlNode *sync_me = create_xml_node(NULL, "sync-me");
 
     crm_info("Requesting re-sync from %s", (host? host : "all peers"));
     sync_in_progress = 1;
 
     crm_xml_add(sync_me, F_TYPE, "cib");
     crm_xml_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
     crm_xml_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
 
     send_cluster_message(host ? crm_get_peer(0, host) : NULL, crm_msg_cib, sync_me, FALSE);
     free_xml(sync_me);
 }
 
 int
 cib_process_ping(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     const char *host = crm_element_value(req, F_ORIG);
     const char *seq = crm_element_value(req, F_CIB_PING_ID);
     char *digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
 
     static struct qb_log_callsite *cs = NULL;
 
     crm_trace("Processing \"%s\" event %s from %s", op, seq, host);
     *answer = create_xml_node(NULL, XML_CRM_TAG_PING);
 
     crm_xml_add(*answer, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
     crm_xml_add(*answer, XML_ATTR_DIGEST, digest);
     crm_xml_add(*answer, F_CIB_PING_ID, seq);
 
     if (cs == NULL) {
         cs = qb_log_callsite_get(__func__, __FILE__, __FUNCTION__, LOG_TRACE, __LINE__, crm_trace_nonlog);
     }
     if (cs && cs->targets) {
         /* Append additional detail so the reciever can log the differences */
         add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
 
     } else {
         /* Always include at least the version details */
         const char *tag = TYPE(the_cib);
         xmlNode *shallow = create_xml_node(NULL, tag);
 
         copy_in_properties(shallow, the_cib);
         add_message_xml(*answer, F_CIB_CALLDATA, shallow);
         free_xml(shallow);
     }
 
     crm_info("Reporting our current digest to %s: %s for %s.%s.%s (%p %d)",
              host, digest,
              crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN),
              crm_element_value(existing_cib, XML_ATTR_GENERATION),
              crm_element_value(existing_cib, XML_ATTR_NUMUPDATES),
              existing_cib,
              cs && cs->targets);
 
     free(digest);
 
     return pcmk_ok;
 }
 
 int
 cib_process_sync(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     return sync_our_cib(req, TRUE);
 }
 
 int
 cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                            xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     int rc = pcmk_ok;
 
     *answer = NULL;
 
     if(crm_element_value(req, F_CIB_SCHEMA_MAX)) {
         return cib_process_upgrade(
             op, options, section, req, input, existing_cib, result_cib, answer);
 
     } else {
         int new_version = 0;
         int current_version = 0;
         xmlNode *scratch = copy_xml(existing_cib);
         const char *host = crm_element_value(req, F_ORIG);
         const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
 
         crm_trace("Processing \"%s\" event", op);
         if (value != NULL) {
             current_version = get_schema_version(value);
         }
 
         rc = update_validation(&scratch, &new_version, 0, TRUE, TRUE);
         if (new_version > current_version) {
             xmlNode *up = create_xml_node(NULL, __FUNCTION__);
 
             rc = pcmk_ok;
             crm_notice("Upgrade request from %s verified", host);
 
             crm_xml_add(up, F_TYPE, "cib");
             crm_xml_add(up, F_CIB_OPERATION, CIB_OP_UPGRADE);
             crm_xml_add(up, F_CIB_SCHEMA_MAX, get_schema_name(new_version));
             crm_xml_add(up, F_CIB_DELEGATED, host);
             crm_xml_add(up, F_CIB_CLIENTID, crm_element_value(req, F_CIB_CLIENTID));
             crm_xml_add(up, F_CIB_CALLOPTS, crm_element_value(req, F_CIB_CALLOPTS));
             crm_xml_add(up, F_CIB_CALLID, crm_element_value(req, F_CIB_CALLID));
 
             if (cib_legacy_mode() && cib_is_master) {
                 rc = cib_process_upgrade(
                     op, options, section, up, input, existing_cib, result_cib, answer);
 
             } else {
                 send_cluster_message(NULL, crm_msg_cib, up, FALSE);
             }
 
             free_xml(up);
 
         } else if(rc == pcmk_ok) {
             rc = -pcmk_err_schema_unchanged;
         }
 
         free_xml(scratch);
     }
     return rc;
 }
 
 int
 cib_process_sync_one(const char *op, int options, const char *section, xmlNode * req,
                      xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                      xmlNode ** answer)
 {
     return sync_our_cib(req, FALSE);
 }
 
 int
 cib_server_process_diff(const char *op, int options, const char *section, xmlNode * req,
                         xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                         xmlNode ** answer)
 {
     int rc = pcmk_ok;
 
     if (sync_in_progress > MAX_DIFF_RETRY) {
         /* Don't ignore diffs forever; the last request may have been lost.
          * If the diff fails, we'll ask for another full resync.
          */
         sync_in_progress = 0;
     }
 
     /* The master should never ignore a diff */
     if (sync_in_progress && !cib_is_master) {
         int diff_add_updates = 0;
         int diff_add_epoch = 0;
         int diff_add_admin_epoch = 0;
 
         int diff_del_updates = 0;
         int diff_del_epoch = 0;
         int diff_del_admin_epoch = 0;
 
         cib_diff_version_details(input,
                                  &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
                                  &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
 
         sync_in_progress++;
         crm_notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
                    diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
                    diff_add_admin_epoch, diff_add_epoch, diff_add_updates);
         return -pcmk_err_diff_resync;
     }
 
     rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer);
     crm_trace("result: %s (%d), %s", pcmk_strerror(rc), rc, cib_is_master?"master":"slave");
 
     if (rc == -pcmk_err_diff_resync && cib_is_master == FALSE) {
         free_xml(*result_cib);
         *result_cib = NULL;
         send_sync_request(NULL);
 
     } else if (rc == -pcmk_err_diff_resync) {
         rc = -pcmk_err_diff_failed;
         if (options & cib_force_diff) {
             crm_warn("Not requesting full refresh in R/W mode");
         }
 
     } else if ((rc != pcmk_ok) && !cib_is_master && cib_legacy_mode()) {
         crm_warn("Requesting full CIB refresh because update failed: %s"
                  CRM_XS " rc=%d", pcmk_strerror(rc), rc);
         xml_log_patchset(LOG_INFO, __FUNCTION__, input);
         free_xml(*result_cib);
         *result_cib = NULL;
         send_sync_request(NULL);
     }
 
     return rc;
 }
 
 int
 cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req,
                         xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                         xmlNode ** answer)
 {
     const char *tag = crm_element_name(input);
     int rc =
         cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
     if (rc == pcmk_ok && safe_str_eq(tag, XML_TAG_CIB)) {
         sync_in_progress = 0;
     }
     return rc;
 }
 
 static int
 delete_cib_object(xmlNode * parent, xmlNode * delete_spec)
 {
     const char *object_name = NULL;
     const char *object_id = NULL;
     xmlNode *equiv_node = NULL;
     int result = pcmk_ok;
 
     if (delete_spec != NULL) {
         object_name = crm_element_name(delete_spec);
     }
     object_id = crm_element_value(delete_spec, XML_ATTR_ID);
 
     crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
 
     if (delete_spec == 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) {
         ;                       /* nothing */
 
     } else if (equiv_node == NULL) {
         result = pcmk_ok;
 
     } else if (xml_has_children(delete_spec) == FALSE) {
         /*  only leaves are deleted */
         crm_debug("Removing leaf: <%s id=%s>", crm_str(object_name), crm_str(object_id));
         free_xml(equiv_node);
         equiv_node = NULL;
 
     } else {
         xmlNode *child = NULL;
 
         for (child = __xml_first_child(delete_spec); child != NULL; child = __xml_next(child)) {
             int tmp_result = delete_cib_object(equiv_node, child);
 
             /*  only the first error is likely to be interesting */
             if (tmp_result != pcmk_ok && result == pcmk_ok) {
                 result = tmp_result;
             }
         }
     }
 
     return result;
 }
 
 int
 cib_process_delete_absolute(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_DELETE, op) == 0, return -EINVAL);
 
     if (input == NULL) {
         crm_err("Cannot perform modification with no data");
         return -EINVAL;
     }
 
     failed = create_xml_node(NULL, XML_TAG_FAILED);
 
     update_section = get_object_root(section, *result_cib);
     result = delete_cib_object(update_section, input);
     update_results(failed, input, op, result);
 
     if ((result == pcmk_ok) && xml_has_children(failed)) {
         result = -EINVAL;
     }
 
     if (result != pcmk_ok) {
         crm_log_xml_err(failed, "CIB Update failures");
         *answer = failed;
 
     } else {
         free_xml(failed);
     }
 
     return result;
 }
 
 int
 sync_our_cib(xmlNode * request, gboolean all)
 {
     int result = pcmk_ok;
     char *digest = NULL;
     const char *host = crm_element_value(request, F_ORIG);
     const char *op = crm_element_value(request, F_CIB_OPERATION);
 
     xmlNode *replace_request = cib_msg_copy(request, FALSE);
 
     CRM_CHECK(the_cib != NULL,;);
     CRM_CHECK(replace_request != NULL,;);
 
     crm_debug("Syncing CIB to %s", all ? "all peers" : host);
     if (all == FALSE && host == NULL) {
         crm_log_xml_err(request, "bad sync");
     }
 
     /* remove the "all == FALSE" condition
      *
      * sync_from was failing, the local client wasn't being notified
      *    because it didn't know it was a reply
      * setting this does not prevent the other nodes from applying it
      *    if all == TRUE
      */
     if (host != NULL) {
         crm_xml_add(replace_request, F_CIB_ISREPLY, host);
     }
     if (all) {
         xml_remove_prop(replace_request, F_CIB_HOST);
     }
 
     crm_xml_add(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE);
     crm_xml_add(replace_request, "original_" F_CIB_OPERATION, op);
     crm_xml_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
 
     crm_xml_add(replace_request, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
     digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
     crm_xml_add(replace_request, XML_ATTR_DIGEST, digest);
 
     add_message_xml(replace_request, F_CIB_CALLDATA, the_cib);
 
     if (send_cluster_message
         (all ? NULL : crm_get_peer(0, host), crm_msg_cib, replace_request, FALSE) == FALSE) {
         result = -ENOTCONN;
     }
     free_xml(replace_request);
     free(digest);
     return result;
 }