diff --git a/include/crm/common/internal.h b/include/crm/common/internal.h
index d33f041a5d..c9ee488755 100644
--- a/include/crm/common/internal.h
+++ b/include/crm/common/internal.h
@@ -1,146 +1,151 @@
 /*
  * Copyright 2015-2018 Andrew Beekhof <andrew@beekhof.net>
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef CRM_COMMON_INTERNAL__H
 #define CRM_COMMON_INTERNAL__H
 
 #include <glib.h>       /* for gboolean */
 #include <dirent.h>     /* for struct dirent */
 #include <unistd.h>     /* for getpid() */
 #include <sys/types.h>  /* for uid_t and gid_t */
 
 #include <crm/common/logging.h>
 
 /* internal I/O utilities (from io.c) */
 
 char *generate_series_filename(const char *directory, const char *series, int sequence,
                                gboolean bzip);
 int get_last_sequence(const char *directory, const char *series);
 void write_last_sequence(const char *directory, const char *series, int sequence, int max);
 int crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid);
 
 bool pcmk__daemon_can_write(const char *dir, const char *file);
 void crm_sync_directory(const char *name);
 
 char *crm_read_contents(const char *filename);
 int crm_write_sync(int fd, const char *contents);
 int crm_set_nonblocking(int fd);
 const char *crm_get_tmpdir(void);
 
 
 /* internal procfs utilities (from procfs.c) */
 
 int crm_procfs_process_info(struct dirent *entry, char *name, int *pid);
 int crm_procfs_pid_of(const char *name);
 unsigned int crm_procfs_num_cores(void);
 
 
 /* internal XML schema functions (from xml.c) */
 
 void crm_schema_init(void);
 void crm_schema_cleanup(void);
 
 
 /* internal functions related to process IDs (from pid.c) */
 
 int crm_pid_active(long pid, const char *daemon);
 long crm_pidfile_inuse(const char *filename, long mypid, const char *daemon);
 long crm_read_pidfile(const char *filename);
 int crm_lock_pidfile(const char *filename, const char *name);
 
 
 /* interal functions related to resource operations (from operations.c) */
 
 char *generate_op_key(const char *rsc_id, const char *op_type,
                       guint interval_ms);
 char *generate_notify_key(const char *rsc_id, const char *notify_type,
                           const char *op_type);
 char *generate_transition_magic(const char *transition_key, int op_status,
                                 int op_rc);
 char *generate_transition_key(int action, int transition_id, int target_rc,
                               const char *node);
 void filter_action_parameters(xmlNode *param_set, const char *version);
 xmlNode *create_operation_update(xmlNode *parent, lrmd_event_data_t *event,
                                  const char *caller_version, int target_rc,
                                  const char *node, const char *origin,
                                  int level);
 
 
+// miscellaneous utilities (from utils.c)
+
+const char *pcmk_message_name(const char *name);
+
+
 /* internal generic string functions (from strings.c) */
 
 long long crm_int_helper(const char *text, char **end_text);
 guint crm_parse_ms(const char *text);
 bool crm_starts_with(const char *str, const char *prefix);
 gboolean crm_ends_with(const char *s, const char *match);
 gboolean crm_ends_with_ext(const char *s, const char *match);
 char *add_list_element(char *list, const char *value);
 bool crm_compress_string(const char *data, int length, int max, char **result,
                          unsigned int *result_len);
 gint crm_alpha_sort(gconstpointer a, gconstpointer b);
 
 static inline char *
 crm_concat(const char *prefix, const char *suffix, char join)
 {
     CRM_ASSERT(prefix && suffix);
     return crm_strdup_printf("%s%c%s", prefix, join, suffix);
 }
 
 static inline int
 crm_strlen_zero(const char *s)
 {
     return !s || *s == '\0';
 }
 
 static inline char *
 crm_getpid_s()
 {
     return crm_strdup_printf("%lu", (unsigned long) getpid());
 }
 
 /* convenience functions for failure-related node attributes */
 
 #define CRM_FAIL_COUNT_PREFIX   "fail-count"
 #define CRM_LAST_FAILURE_PREFIX "last-failure"
 
 /*!
  * \internal
  * \brief Generate a failure-related node attribute name for a resource
  *
  * \param[in] prefix       Start of attribute name
  * \param[in] rsc_id       Resource name
  * \param[in] op           Operation name
  * \param[in] interval_ms  Operation interval
  *
  * \return Newly allocated string with attribute name
  *
  * \note Failure attributes are named like PREFIX-RSC#OP_INTERVAL (for example,
  *       "fail-count-myrsc#monitor_30000"). The '#' is used because it is not
  *       a valid character in a resource ID, to reliably distinguish where the
  *       operation name begins. The '_' is used simply to be more comparable to
  *       action labels like "myrsc_monitor_30000".
  */
 static inline char *
 crm_fail_attr_name(const char *prefix, const char *rsc_id, const char *op,
                    guint interval_ms)
 {
     CRM_CHECK(prefix && rsc_id && op, return NULL);
     return crm_strdup_printf("%s-%s#%s_%u", prefix, rsc_id, op, interval_ms);
 }
 
 static inline char *
 crm_failcount_name(const char *rsc_id, const char *op, guint interval_ms)
 {
     return crm_fail_attr_name(CRM_FAIL_COUNT_PREFIX, rsc_id, op, interval_ms);
 }
 
 static inline char *
 crm_lastfailure_name(const char *rsc_id, const char *op, guint interval_ms)
 {
     return crm_fail_attr_name(CRM_LAST_FAILURE_PREFIX, rsc_id, op, interval_ms);
 }
 
 #endif /* CRM_COMMON_INTERNAL__H */
diff --git a/lib/cluster/cpg.c b/lib/cluster/cpg.c
index 1e33a42610..c1a36353c5 100644
--- a/lib/cluster/cpg.c
+++ b/lib/cluster/cpg.c
@@ -1,659 +1,649 @@
 /*
- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
+ * Copyright 2004-2018 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
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 #include <bzlib.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 
 #include <crm/common/ipc.h>
 #include <crm/cluster/internal.h>
 #include <crm/common/mainloop.h>
 #include <sys/utsname.h>
 
 #include <qb/qbipcc.h>
 #include <qb/qbutil.h>
 
 #include <corosync/corodefs.h>
 #include <corosync/corotypes.h>
 #include <corosync/hdb.h>
 #include <corosync/cpg.h>
 
 #include <crm/msg_xml.h>
 
 cpg_handle_t pcmk_cpg_handle = 0; /* TODO: Remove, use cluster.cpg_handle */
 
 static bool cpg_evicted = FALSE;
 gboolean(*pcmk_cpg_dispatch_fn) (int kind, const char *from, const char *data) = NULL;
 
 #define cs_repeat(counter, max, code) do {		\
 	code;						\
 	if(rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {  \
 	    counter++;					\
 	    crm_debug("Retrying operation after %ds", counter);	\
 	    sleep(counter);				\
 	} else {                                        \
             break;                                      \
         }                                               \
     } while(counter < max)
 
 void
 cluster_disconnect_cpg(crm_cluster_t *cluster)
 {
     pcmk_cpg_handle = 0;
     if (cluster->cpg_handle) {
         crm_trace("Disconnecting CPG");
         cpg_leave(cluster->cpg_handle, &cluster->group);
         cpg_finalize(cluster->cpg_handle);
         cluster->cpg_handle = 0;
 
     } else {
         crm_info("No CPG connection");
     }
 }
 
 uint32_t get_local_nodeid(cpg_handle_t handle)
 {
     int rc = CS_OK;
     int retries = 0;
     static uint32_t local_nodeid = 0;
     cpg_handle_t local_handle = handle;
     cpg_callbacks_t cb = { };
 
     if(local_nodeid != 0) {
         return local_nodeid;
     }
 
     if(handle == 0) {
         crm_trace("Creating connection");
         cs_repeat(retries, 5, rc = cpg_initialize(&local_handle, &cb));
     }
 
     if (rc == CS_OK) {
         retries = 0;
         crm_trace("Performing lookup");
         cs_repeat(retries, 5, rc = cpg_local_get(local_handle, &local_nodeid));
     }
 
     if (rc != CS_OK) {
         crm_err("Could not get local node id from the CPG API: %s (%d)", ais_error2text(rc), rc);
     }
     if(handle == 0) {
         crm_trace("Closing connection");
         cpg_finalize(local_handle);
     }
     crm_debug("Local nodeid is %u", local_nodeid);
     return local_nodeid;
 }
 
 
 GListPtr cs_message_queue = NULL;
 int cs_message_timer = 0;
 
 static ssize_t crm_cs_flush(gpointer data);
 
 static gboolean
 crm_cs_flush_cb(gpointer data)
 {
     cs_message_timer = 0;
     crm_cs_flush(data);
     return FALSE;
 }
 
 #define CS_SEND_MAX 200
 static ssize_t
 crm_cs_flush(gpointer data)
 {
     int sent = 0;
     ssize_t rc = 0;
     int queue_len = 0;
     static unsigned int last_sent = 0;
     cpg_handle_t *handle = (cpg_handle_t *)data;
 
     if (*handle == 0) {
         crm_trace("Connection is dead");
         return pcmk_ok;
     }
 
     queue_len = g_list_length(cs_message_queue);
     if ((queue_len % 1000) == 0 && queue_len > 1) {
         crm_err("CPG queue has grown to %d", queue_len);
 
     } else if (queue_len == CS_SEND_MAX) {
         crm_warn("CPG queue has grown to %d", queue_len);
     }
 
     if (cs_message_timer) {
         /* There is already a timer, wait until it goes off */
         crm_trace("Timer active %d", cs_message_timer);
         return pcmk_ok;
     }
 
     while (cs_message_queue && sent < CS_SEND_MAX) {
         struct iovec *iov = cs_message_queue->data;
 
         errno = 0;
         rc = cpg_mcast_joined(*handle, CPG_TYPE_AGREED, iov, 1);
 
         if (rc != CS_OK) {
             break;
         }
 
         sent++;
         last_sent++;
         crm_trace("CPG message sent, size=%llu",
                   (unsigned long long) iov->iov_len);
 
         cs_message_queue = g_list_remove(cs_message_queue, iov);
         free(iov->iov_base);
         free(iov);
     }
 
     queue_len -= sent;
     if (sent > 1 || cs_message_queue) {
         crm_info("Sent %d CPG messages  (%d remaining, last=%u): %s (%lld)",
                  sent, queue_len, last_sent, ais_error2text(rc),
                  (long long) rc);
     } else {
         crm_trace("Sent %d CPG messages  (%d remaining, last=%u): %s (%lld)",
                   sent, queue_len, last_sent, ais_error2text(rc),
                   (long long) rc);
     }
 
     if (cs_message_queue) {
         uint32_t delay_ms = 100;
         if(rc != CS_OK) {
             /* Proportionally more if sending failed but cap at 1s */
             delay_ms = QB_MIN(1000, CS_SEND_MAX + (10 * queue_len));
         }
         cs_message_timer = g_timeout_add(delay_ms, crm_cs_flush_cb, data);
     }
 
     return rc;
 }
 
 gboolean
 send_cpg_iov(struct iovec * iov)
 {
     static unsigned int queued = 0;
 
     queued++;
     crm_trace("Queueing CPG message %u (%llu bytes)",
               queued, (unsigned long long) iov->iov_len);
     cs_message_queue = g_list_append(cs_message_queue, iov);
     crm_cs_flush(&pcmk_cpg_handle);
     return TRUE;
 }
 
 static int
 pcmk_cpg_dispatch(gpointer user_data)
 {
     int rc = 0;
     crm_cluster_t *cluster = (crm_cluster_t*) user_data;
 
     rc = cpg_dispatch(cluster->cpg_handle, CS_DISPATCH_ONE);
     if (rc != CS_OK) {
         crm_err("Connection to the CPG API failed: %s (%d)", ais_error2text(rc), rc);
         cluster->cpg_handle = 0;
         return -1;
 
     } else if(cpg_evicted) {
         crm_err("Evicted from CPG membership");
         return -1;
     }
     return 0;
 }
 
 char *
 pcmk_message_common_cs(cpg_handle_t handle, uint32_t nodeid, uint32_t pid, void *content,
                         uint32_t *kind, const char **from)
 {
     char *data = NULL;
     AIS_Message *msg = (AIS_Message *) content;
 
     if(handle) {
         // Do filtering and field massaging
         uint32_t local_nodeid = get_local_nodeid(handle);
         const char *local_name = get_local_node_name();
 
         if (msg->sender.id > 0 && msg->sender.id != nodeid) {
             crm_err("Nodeid mismatch from %d.%d: claimed nodeid=%u", nodeid, pid, msg->sender.id);
             return NULL;
 
         } else if (msg->host.id != 0 && (local_nodeid != msg->host.id)) {
             /* Not for us */
             crm_trace("Not for us: %u != %u", msg->host.id, local_nodeid);
             return NULL;
         } else if (msg->host.size != 0 && safe_str_neq(msg->host.uname, local_name)) {
             /* Not for us */
             crm_trace("Not for us: %s != %s", msg->host.uname, local_name);
             return NULL;
         }
 
         msg->sender.id = nodeid;
         if (msg->sender.size == 0) {
             crm_node_t *peer = crm_get_peer(nodeid, NULL);
 
             if (peer == NULL) {
                 crm_err("Peer with nodeid=%u is unknown", nodeid);
 
             } else if (peer->uname == NULL) {
                 crm_err("No uname for peer with nodeid=%u", nodeid);
 
             } else {
                 crm_notice("Fixing uname for peer with nodeid=%u", nodeid);
                 msg->sender.size = strlen(peer->uname);
                 memset(msg->sender.uname, 0, MAX_NAME);
                 memcpy(msg->sender.uname, peer->uname, msg->sender.size);
             }
         }
     }
 
     crm_trace("Got new%s message (size=%d, %d, %d)",
               msg->is_compressed ? " compressed" : "",
               ais_data_len(msg), msg->size, msg->compressed_size);
 
     if (kind != NULL) {
         *kind = msg->header.id;
     }
     if (from != NULL) {
         *from = msg->sender.uname;
     }
 
     if (msg->is_compressed && msg->size > 0) {
         int rc = BZ_OK;
         char *uncompressed = NULL;
         unsigned int new_size = msg->size + 1;
 
         if (check_message_sanity(msg, NULL) == FALSE) {
             goto badmsg;
         }
 
         crm_trace("Decompressing message data");
         uncompressed = calloc(1, new_size);
         rc = BZ2_bzBuffToBuffDecompress(uncompressed, &new_size, msg->data, msg->compressed_size, 1, 0);
 
         if (rc != BZ_OK) {
             crm_err("Decompression failed: %s " CRM_XS " bzerror=%d",
                     bz2_strerror(rc), rc);
             free(uncompressed);
             goto badmsg;
         }
 
         CRM_ASSERT(rc == BZ_OK);
         CRM_ASSERT(new_size == msg->size);
 
         data = uncompressed;
 
     } else if (check_message_sanity(msg, data) == FALSE) {
         goto badmsg;
 
     } else if (safe_str_eq("identify", data)) {
         char *pid_s = crm_getpid_s();
 
         send_cluster_text(crm_class_cluster, pid_s, TRUE, NULL, crm_msg_ais);
         free(pid_s);
         return NULL;
 
     } else {
         data = strdup(msg->data);
     }
 
     // Is this necessary?
     crm_get_peer(msg->sender.id, msg->sender.uname);
 
     crm_trace("Payload: %.200s", data);
     return data;
 
   badmsg:
     crm_err("Invalid message (id=%d, dest=%s:%s, from=%s:%s.%d):"
             " min=%d, total=%d, size=%d, bz2_size=%d",
             msg->id, ais_dest(&(msg->host)), msg_type2text(msg->host.type),
             ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
             msg->sender.pid, (int)sizeof(AIS_Message),
             msg->header.size, msg->size, msg->compressed_size);
 
     free(data);
     return NULL;
 }
 
 void
 pcmk_cpg_membership(cpg_handle_t handle,
                     const struct cpg_name *groupName,
                     const struct cpg_address *member_list, size_t member_list_entries,
                     const struct cpg_address *left_list, size_t left_list_entries,
                     const struct cpg_address *joined_list, size_t joined_list_entries)
 {
     int i;
     gboolean found = FALSE;
     static int counter = 0;
     uint32_t local_nodeid = get_local_nodeid(handle);
 
     for (i = 0; i < left_list_entries; i++) {
         crm_node_t *peer = crm_find_peer(left_list[i].nodeid, NULL);
 
         crm_info("Node %u left group %s (peer=%s, counter=%d.%d)",
                  left_list[i].nodeid, groupName->value,
                  (peer? peer->uname : "<none>"), counter, i);
         if (peer) {
             crm_update_peer_proc(__FUNCTION__, peer, crm_proc_cpg, OFFLINESTATUS);
         }
     }
 
     for (i = 0; i < joined_list_entries; i++) {
         crm_info("Node %u joined group %s (counter=%d.%d)",
                  joined_list[i].nodeid, groupName->value, counter, i);
     }
 
     for (i = 0; i < member_list_entries; i++) {
         crm_node_t *peer = crm_get_peer(member_list[i].nodeid, NULL);
 
         crm_info("Node %u still member of group %s (peer=%s, counter=%d.%d)",
                  member_list[i].nodeid, groupName->value,
                  (peer? peer->uname : "<none>"), counter, i);
 
         /* Anyone that is sending us CPG messages must also be a _CPG_ member.
          * But it's _not_ safe to assume it's in the quorum membership.
          * We may have just found out it's dead and are processing the last couple of messages it sent
          */
         peer = crm_update_peer_proc(__FUNCTION__, peer, crm_proc_cpg, ONLINESTATUS);
         if(peer && peer->state && crm_is_peer_active(peer) == FALSE) {
             time_t now = time(NULL);
 
             /* Co-opt the otherwise unused votes field */
             if(peer->votes == 0) {
                 peer->votes = now;
 
             } else if(now > (60 + peer->votes)) {
                 /* On the other hand, if we're still getting messages, at a
                  * certain point we need to acknowledge our internal cache is
                  * probably wrong. Use 1 minute.
                  */
                 crm_err("Node %s[%u] appears to be online even though we think it is dead", peer->uname, peer->id);
                 if (crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_MEMBER, 0)) {
                     peer->votes = 0;
                 }
             }
         }
 
         if (local_nodeid == member_list[i].nodeid) {
             found = TRUE;
         }
     }
 
     if (!found) {
         crm_err("We're not part of CPG group '%s' anymore!", groupName->value);
         cpg_evicted = TRUE;
     }
 
     counter++;
 }
 
 gboolean
 cluster_connect_cpg(crm_cluster_t *cluster)
 {
     int rc = -1;
     int fd = 0;
     int retries = 0;
     uint32_t id = 0;
     crm_node_t *peer = NULL;
     cpg_handle_t handle = 0;
+    const char *message_name = pcmk_message_name(crm_system_name);
 
     struct mainloop_fd_callbacks cpg_fd_callbacks = {
         .dispatch = pcmk_cpg_dispatch,
         .destroy = cluster->destroy,
     };
 
     cpg_callbacks_t cpg_callbacks = {
         .cpg_deliver_fn = cluster->cpg.cpg_deliver_fn,
         .cpg_confchg_fn = cluster->cpg.cpg_confchg_fn,
         /* .cpg_deliver_fn = pcmk_cpg_deliver, */
         /* .cpg_confchg_fn = pcmk_cpg_membership, */
     };
 
     cpg_evicted = FALSE;
     cluster->group.length = 0;
     cluster->group.value[0] = 0;
 
     /* group.value is char[128] */
-    strncpy(cluster->group.value, crm_system_name?crm_system_name:"unknown", 127);
+    strncpy(cluster->group.value, message_name, 127);
     cluster->group.value[127] = 0;
     cluster->group.length = 1 + QB_MIN(127, strlen(cluster->group.value));
 
     cs_repeat(retries, 30, rc = cpg_initialize(&handle, &cpg_callbacks));
     if (rc != CS_OK) {
         crm_err("Could not connect to the Cluster Process Group API: %d", rc);
         goto bail;
     }
 
     id = get_local_nodeid(handle);
     if (id == 0) {
         crm_err("Could not get local node id from the CPG API");
         goto bail;
 
     }
     cluster->nodeid = id;
 
     retries = 0;
     cs_repeat(retries, 30, rc = cpg_join(handle, &cluster->group));
     if (rc != CS_OK) {
-        crm_err("Could not join the CPG group '%s': %d", crm_system_name, rc);
+        crm_err("Could not join the CPG group '%s': %d", message_name, rc);
         goto bail;
     }
 
     rc = cpg_fd_get(handle, &fd);
     if (rc != CS_OK) {
         crm_err("Could not obtain the CPG API connection: %d", rc);
         goto bail;
     }
 
     pcmk_cpg_handle = handle;
     cluster->cpg_handle = handle;
     mainloop_add_fd("corosync-cpg", G_PRIORITY_MEDIUM, fd, cluster, &cpg_fd_callbacks);
 
   bail:
     if (rc != CS_OK) {
         cpg_finalize(handle);
         return FALSE;
     }
 
     peer = crm_get_peer(id, NULL);
     crm_update_peer_proc(__FUNCTION__, peer, crm_proc_cpg, ONLINESTATUS);
     return TRUE;
 }
 
 gboolean
 send_cluster_message_cs(xmlNode * msg, gboolean local, crm_node_t * node, enum crm_ais_msg_types dest)
 {
     gboolean rc = TRUE;
     char *data = NULL;
 
     data = dump_xml_unformatted(msg);
     rc = send_cluster_text(crm_class_cluster, data, local, node, dest);
     free(data);
     return rc;
 }
 
 gboolean
 send_cluster_text(enum crm_ais_msg_class msg_class, const char *data,
                   gboolean local, crm_node_t *node, enum crm_ais_msg_types dest)
 {
     static int msg_id = 0;
     static int local_pid = 0;
     static int local_name_len = 0;
     static const char *local_name = NULL;
 
     char *target = NULL;
     struct iovec *iov;
     AIS_Message *msg = NULL;
     enum crm_ais_msg_types sender = text2msg_type(crm_system_name);
 
     switch (msg_class) {
         case crm_class_cluster:
             break;
         default:
             crm_err("Invalid message class: %d", msg_class);
             return FALSE;
     }
 
     CRM_CHECK(dest != crm_msg_ais, return FALSE);
 
     if(local_name == NULL) {
         local_name = get_local_node_name();
     }
     if(local_name_len == 0 && local_name) {
         local_name_len = strlen(local_name);
     }
 
     if (data == NULL) {
         data = "";
     }
 
     if (local_pid == 0) {
         local_pid = getpid();
     }
 
     if (sender == crm_msg_none) {
         sender = local_pid;
     }
 
     msg = calloc(1, sizeof(AIS_Message));
 
     msg_id++;
     msg->id = msg_id;
     msg->header.id = msg_class;
     msg->header.error = CS_OK;
 
     msg->host.type = dest;
     msg->host.local = local;
 
     if (node) {
         if (node->uname) {
             target = strdup(node->uname);
             msg->host.size = strlen(node->uname);
             memset(msg->host.uname, 0, MAX_NAME);
             memcpy(msg->host.uname, node->uname, msg->host.size);
         } else {
             target = crm_strdup_printf("%u", node->id);
         }
         msg->host.id = node->id;
     } else {
         target = strdup("all");
     }
 
     msg->sender.id = 0;
     msg->sender.type = sender;
     msg->sender.pid = local_pid;
     msg->sender.size = local_name_len;
     memset(msg->sender.uname, 0, MAX_NAME);
     if(local_name && msg->sender.size) {
         memcpy(msg->sender.uname, local_name, msg->sender.size);
     }
 
     msg->size = 1 + strlen(data);
     msg->header.size = sizeof(AIS_Message) + msg->size;
 
     if (msg->size < CRM_BZ2_THRESHOLD) {
         msg = realloc_safe(msg, msg->header.size);
         memcpy(msg->data, data, msg->size);
 
     } else {
         char *compressed = NULL;
         unsigned int new_size = 0;
         char *uncompressed = strdup(data);
 
         if (crm_compress_string(uncompressed, msg->size, 0, &compressed, &new_size)) {
 
             msg->header.size = sizeof(AIS_Message) + new_size;
             msg = realloc_safe(msg, msg->header.size);
             memcpy(msg->data, compressed, new_size);
 
             msg->is_compressed = TRUE;
             msg->compressed_size = new_size;
 
         } else {
             msg = realloc_safe(msg, msg->header.size);
             memcpy(msg->data, data, msg->size);
         }
 
         free(uncompressed);
         free(compressed);
     }
 
     iov = calloc(1, sizeof(struct iovec));
     iov->iov_base = msg;
     iov->iov_len = msg->header.size;
 
     if (msg->compressed_size) {
         crm_trace("Queueing CPG message %u to %s (%llu bytes, %d bytes compressed payload): %.200s",
                   msg->id, target, (unsigned long long) iov->iov_len,
                   msg->compressed_size, data);
     } else {
         crm_trace("Queueing CPG message %u to %s (%llu bytes, %d bytes payload): %.200s",
                   msg->id, target, (unsigned long long) iov->iov_len,
                   msg->size, data);
     }
     free(target);
 
     send_cpg_iov(iov);
 
     return TRUE;
 }
 
 enum crm_ais_msg_types
 text2msg_type(const char *text)
 {
     int type = crm_msg_none;
 
     CRM_CHECK(text != NULL, return type);
+    text = pcmk_message_name(text);
     if (safe_str_eq(text, "ais")) {
         type = crm_msg_ais;
     } else if (safe_str_eq(text, CRM_SYSTEM_CIB)) {
         type = crm_msg_cib;
-    } else if (safe_str_eq(text, CRM_SYSTEM_CRMD)) {
-        type = crm_msg_crmd;
-    } else if (safe_str_eq(text, CRM_SYSTEM_DC)) {
+    } else if (safe_str_eq(text, CRM_SYSTEM_CRMD)
+               || safe_str_eq(text, CRM_SYSTEM_DC)) {
         type = crm_msg_crmd;
     } else if (safe_str_eq(text, CRM_SYSTEM_TENGINE)) {
         type = crm_msg_te;
     } else if (safe_str_eq(text, CRM_SYSTEM_PENGINE)) {
         type = crm_msg_pe;
     } else if (safe_str_eq(text, CRM_SYSTEM_LRMD)) {
         type = crm_msg_lrmd;
     } else if (safe_str_eq(text, CRM_SYSTEM_STONITHD)) {
         type = crm_msg_stonithd;
     } else if (safe_str_eq(text, "stonith-ng")) {
         type = crm_msg_stonith_ng;
     } else if (safe_str_eq(text, "attrd")) {
         type = crm_msg_attrd;
 
     } else {
         /* This will normally be a transient client rather than
          * a cluster daemon.  Set the type to the pid of the client
          */
         int scan_rc = sscanf(text, "%d", &type);
 
         if (scan_rc != 1 || type <= crm_msg_stonith_ng) {
             /* Ensure it's sane */
             type = crm_msg_none;
         }
     }
     return type;
 }
diff --git a/lib/common/utils.c b/lib/common/utils.c
index 61c8bef9ac..a67e58a262 100644
--- a/lib/common/utils.c
+++ b/lib/common/utils.c
@@ -1,1353 +1,1394 @@
 /*
  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 #include <dlfcn.h>
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/utsname.h>
 
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <pwd.h>
 #include <time.h>
 #include <libgen.h>
 #include <signal.h>
 
 #include <qb/qbdefs.h>
 
 #include <crm/crm.h>
 #include <crm/services.h>
 #include <crm/msg_xml.h>
 #include <crm/cib/internal.h>
 #include <crm/common/xml.h>
 #include <crm/common/util.h>
 #include <crm/common/ipc.h>
 #include <crm/common/iso8601.h>
 #include <crm/common/mainloop.h>
 #include <libxml2/libxml/relaxng.h>
 
 #ifndef MAXLINE
 #  define MAXLINE 512
 #endif
 
 #ifdef HAVE_GETOPT_H
 #  include <getopt.h>
 #endif
 
 #ifndef PW_BUFFER_LEN
 #  define PW_BUFFER_LEN		500
 #endif
 
 CRM_TRACE_INIT_DATA(common);
 
 gboolean crm_config_error = FALSE;
 gboolean crm_config_warning = FALSE;
 char *crm_system_name = NULL;
 
 int node_score_red = 0;
 int node_score_green = 0;
 int node_score_yellow = 0;
 
 static struct crm_option *crm_long_options = NULL;
 static const char *crm_app_description = NULL;
 static char *crm_short_options = NULL;
 static const char *crm_app_usage = NULL;
 
 gboolean
 check_time(const char *value)
 {
     if (crm_get_msec(value) < 5000) {
         return FALSE;
     }
     return TRUE;
 }
 
 gboolean
 check_timer(const char *value)
 {
     if (crm_get_msec(value) < 0) {
         return FALSE;
     }
     return TRUE;
 }
 
 gboolean
 check_boolean(const char *value)
 {
     int tmp = FALSE;
 
     if (crm_str_to_boolean(value, &tmp) != 1) {
         return FALSE;
     }
     return TRUE;
 }
 
 gboolean
 check_number(const char *value)
 {
     errno = 0;
     if (value == NULL) {
         return FALSE;
 
     } else if (safe_str_eq(value, CRM_MINUS_INFINITY_S)) {
 
     } else if (safe_str_eq(value, CRM_INFINITY_S)) {
 
     } else {
         crm_int_helper(value, NULL);
     }
 
     if (errno != 0) {
         return FALSE;
     }
     return TRUE;
 }
 
 gboolean
 check_positive_number(const char* value)
 {
     if (safe_str_eq(value, CRM_INFINITY_S) || (crm_int_helper(value, NULL))) {
         return TRUE;
     }
     return FALSE;
 }
 
 gboolean
 check_quorum(const char *value)
 {
     if (safe_str_eq(value, "stop")) {
         return TRUE;
 
     } else if (safe_str_eq(value, "freeze")) {
         return TRUE;
 
     } else if (safe_str_eq(value, "ignore")) {
         return TRUE;
 
     } else if (safe_str_eq(value, "suicide")) {
         return TRUE;
     }
     return FALSE;
 }
 
 gboolean
 check_script(const char *value)
 {
     struct stat st;
 
     if(safe_str_eq(value, "/dev/null")) {
         return TRUE;
     }
 
     if(stat(value, &st) != 0) {
         crm_err("Script %s does not exist", value);
         return FALSE;
     }
 
     if(S_ISREG(st.st_mode) == 0) {
         crm_err("Script %s is not a regular file", value);
         return FALSE;
     }
 
     if( (st.st_mode & (S_IXUSR | S_IXGRP )) == 0) {
         crm_err("Script %s is not executable", value);
         return FALSE;
     }
 
     return TRUE;
 }
 
 gboolean
 check_utilization(const char *value)
 {
     char *end = NULL;
     long number = strtol(value, &end, 10);
 
     if(end && end[0] != '%') {
         return FALSE;
     } else if(number < 0) {
         return FALSE;
     }
 
     return TRUE;
 }
 
 void
 crm_args_fini()
 {
     free(crm_short_options);
     crm_short_options = NULL;
 }
 
 int
 char2score(const char *score)
 {
     int score_f = 0;
 
     if (score == NULL) {
 
     } else if (safe_str_eq(score, CRM_MINUS_INFINITY_S)) {
         score_f = -CRM_SCORE_INFINITY;
 
     } else if (safe_str_eq(score, CRM_INFINITY_S)) {
         score_f = CRM_SCORE_INFINITY;
 
     } else if (safe_str_eq(score, CRM_PLUS_INFINITY_S)) {
         score_f = CRM_SCORE_INFINITY;
 
     } else if (safe_str_eq(score, "red")) {
         score_f = node_score_red;
 
     } else if (safe_str_eq(score, "yellow")) {
         score_f = node_score_yellow;
 
     } else if (safe_str_eq(score, "green")) {
         score_f = node_score_green;
 
     } else {
         score_f = crm_parse_int(score, NULL);
         if (score_f > 0 && score_f > CRM_SCORE_INFINITY) {
             score_f = CRM_SCORE_INFINITY;
 
         } else if (score_f < 0 && score_f < -CRM_SCORE_INFINITY) {
             score_f = -CRM_SCORE_INFINITY;
         }
     }
 
     return score_f;
 }
 
 char *
 score2char_stack(int score, char *buf, size_t len)
 {
     if (score >= CRM_SCORE_INFINITY) {
         strncpy(buf, CRM_INFINITY_S, 9);
     } else if (score <= -CRM_SCORE_INFINITY) {
         strncpy(buf, CRM_MINUS_INFINITY_S , 10);
     } else {
         return crm_itoa_stack(score, buf, len);
     }
 
     return buf;
 }
 
 char *
 score2char(int score)
 {
     if (score >= CRM_SCORE_INFINITY) {
         return strdup(CRM_INFINITY_S);
 
     } else if (score <= -CRM_SCORE_INFINITY) {
         return strdup(CRM_MINUS_INFINITY_S);
     }
     return crm_itoa(score);
 }
 
 const char *
 cluster_option(GHashTable * options, gboolean(*validate) (const char *),
                const char *name, const char *old_name, const char *def_value)
 {
     const char *value = NULL;
     char *new_value = NULL;
 
     CRM_ASSERT(name != NULL);
 
     if (options) {
         value = g_hash_table_lookup(options, name);
 
         if ((value == NULL) && old_name) {
             value = g_hash_table_lookup(options, old_name);
             if (value != NULL) {
                 crm_config_warn("Support for legacy name '%s' for cluster option '%s'"
                                 " is deprecated and will be removed in a future release",
                                 old_name, name);
 
                 // Inserting copy with current name ensures we only warn once
                 new_value = strdup(value);
                 g_hash_table_insert(options, strdup(name), new_value);
                 value = new_value;
             }
         }
 
         if (value && validate && (validate(value) == FALSE)) {
             crm_config_err("Resetting cluster option '%s' to default: value '%s' is invalid",
                            name, value);
             value = NULL;
         }
 
         if (value) {
             return value;
         }
     }
 
     // No value found, use default
     value = def_value;
 
     if (value == NULL) {
         crm_trace("No value or default provided for cluster option '%s'",
                   name);
         return NULL;
     }
 
     if (validate) {
         CRM_CHECK(validate(value) != FALSE,
                   crm_err("Bug: default value for cluster option '%s' is invalid", name);
                   return NULL);
     }
 
     crm_trace("Using default value '%s' for cluster option '%s'",
               value, name);
     if (options) {
         new_value = strdup(value);
         g_hash_table_insert(options, strdup(name), new_value);
         value = new_value;
     }
     return value;
 }
 
 const char *
 get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name)
 {
     const char *value = NULL;
 
     for (int lpc = 0; lpc < len; lpc++) {
         if (safe_str_eq(name, option_list[lpc].name)) {
             value = cluster_option(options,
                                    option_list[lpc].is_valid,
                                    option_list[lpc].name,
                                    option_list[lpc].alt_name,
                                    option_list[lpc].default_value);
             return value;
         }
     }
     CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
     return NULL;
 }
 
 void
 config_metadata(const char *name, const char *version, const char *desc_short,
                 const char *desc_long, pe_cluster_option * option_list, int len)
 {
     int lpc = 0;
 
     fprintf(stdout, "<?xml version=\"1.0\"?>"
             "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
             "<resource-agent name=\"%s\">\n"
             "  <version>%s</version>\n"
             "  <longdesc lang=\"en\">%s</longdesc>\n"
             "  <shortdesc lang=\"en\">%s</shortdesc>\n"
             "  <parameters>\n", name, version, desc_long, desc_short);
 
     for (lpc = 0; lpc < len; lpc++) {
         if (option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) {
             continue;
         }
         fprintf(stdout, "    <parameter name=\"%s\" unique=\"0\">\n"
                 "      <shortdesc lang=\"en\">%s</shortdesc>\n"
                 "      <content type=\"%s\" default=\"%s\"/>\n"
                 "      <longdesc lang=\"en\">%s%s%s</longdesc>\n"
                 "    </parameter>\n",
                 option_list[lpc].name,
                 option_list[lpc].description_short,
                 option_list[lpc].type,
                 option_list[lpc].default_value,
                 option_list[lpc].description_long ? option_list[lpc].
                 description_long : option_list[lpc].description_short,
                 option_list[lpc].values ? "  Allowed values: " : "",
                 option_list[lpc].values ? option_list[lpc].values : "");
     }
     fprintf(stdout, "  </parameters>\n</resource-agent>\n");
 }
 
 void
 verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len)
 {
     int lpc = 0;
 
     for (lpc = 0; lpc < len; lpc++) {
         cluster_option(options,
                        option_list[lpc].is_valid,
                        option_list[lpc].name,
                        option_list[lpc].alt_name, option_list[lpc].default_value);
     }
 }
 
 char *
 generate_hash_key(const char *crm_msg_reference, const char *sys)
 {
     char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_');
 
     crm_trace("created hash key: (%s)", hash_key);
     return hash_key;
 }
 
 
 int
 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
 {
     int rc = pcmk_ok;
     char *buffer = NULL;
     struct passwd pwd;
     struct passwd *pwentry = NULL;
 
     buffer = calloc(1, PW_BUFFER_LEN);
     rc = getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
     if (pwentry) {
         if (uid) {
             *uid = pwentry->pw_uid;
         }
         if (gid) {
             *gid = pwentry->pw_gid;
         }
         crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
 
     } else {
         rc = rc? -rc : -EINVAL;
         crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
     }
 
     free(buffer);
     return rc;
 }
 
 static int
 crm_version_helper(const char *text, char **end_text)
 {
     int atoi_result = -1;
 
     CRM_ASSERT(end_text != NULL);
 
     errno = 0;
 
     if (text != NULL && text[0] != 0) {
         atoi_result = (int)strtol(text, end_text, 10);
 
         if (errno == EINVAL) {
             crm_err("Conversion of '%s' %c failed", text, text[0]);
             atoi_result = -1;
         }
     }
     return atoi_result;
 }
 
 /*
  * version1 < version2 : -1
  * version1 = version2 :  0
  * version1 > version2 :  1
  */
 int
 compare_version(const char *version1, const char *version2)
 {
     int rc = 0;
     int lpc = 0;
     char *ver1_copy = NULL, *ver2_copy = NULL;
     char *rest1 = NULL, *rest2 = NULL;
 
     if (version1 == NULL && version2 == NULL) {
         return 0;
     } else if (version1 == NULL) {
         return -1;
     } else if (version2 == NULL) {
         return 1;
     }
 
     ver1_copy = strdup(version1);
     ver2_copy = strdup(version2);
     rest1 = ver1_copy;
     rest2 = ver2_copy;
 
     while (1) {
         int digit1 = 0;
         int digit2 = 0;
 
         lpc++;
 
         if (rest1 == rest2) {
             break;
         }
 
         if (rest1 != NULL) {
             digit1 = crm_version_helper(rest1, &rest1);
         }
 
         if (rest2 != NULL) {
             digit2 = crm_version_helper(rest2, &rest2);
         }
 
         if (digit1 < digit2) {
             rc = -1;
             break;
 
         } else if (digit1 > digit2) {
             rc = 1;
             break;
         }
 
         if (rest1 != NULL && rest1[0] == '.') {
             rest1++;
         }
         if (rest1 != NULL && rest1[0] == 0) {
             rest1 = NULL;
         }
 
         if (rest2 != NULL && rest2[0] == '.') {
             rest2++;
         }
         if (rest2 != NULL && rest2[0] == 0) {
             rest2 = NULL;
         }
     }
 
     free(ver1_copy);
     free(ver2_copy);
 
     if (rc == 0) {
         crm_trace("%s == %s (%d)", version1, version2, lpc);
     } else if (rc < 0) {
         crm_trace("%s < %s (%d)", version1, version2, lpc);
     } else if (rc > 0) {
         crm_trace("%s > %s (%d)", version1, version2, lpc);
     }
 
     return rc;
 }
 
 gboolean do_stderr = FALSE;
 
 #ifndef NUMCHARS
 #  define	NUMCHARS	"0123456789."
 #endif
 
 #ifndef WHITESPACE
 #  define	WHITESPACE	" \t\n\r\f"
 #endif
 
 guint
 crm_parse_interval_spec(const char *input)
 {
     long long msec = 0;
 
     if (input == NULL) {
         return 0;
 
     } else if (input[0] != 'P') {
         long long tmp = crm_get_msec(input);
 
         if(tmp > 0) {
             msec = tmp;
         }
 
     } else {
         crm_time_t *period_s = crm_time_parse_duration(input);
 
         msec = 1000 * crm_time_get_seconds(period_s);
         crm_time_free(period_s);
     }
 
     return (msec <= 0)? 0 : ((msec >= G_MAXUINT)? G_MAXUINT : (guint) msec);
 }
 
 long long
 crm_get_msec(const char *input)
 {
     const char *cp = input;
     const char *units;
     long long multiplier = 1000;
     long long divisor = 1;
     long long msec = -1;
     char *end_text = NULL;
 
     /* double dret; */
 
     if (input == NULL) {
         return msec;
     }
 
     cp += strspn(cp, WHITESPACE);
     units = cp + strspn(cp, NUMCHARS);
     units += strspn(units, WHITESPACE);
 
     if (strchr(NUMCHARS, *cp) == NULL) {
         return msec;
     }
 
     if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) {
         multiplier = 1;
         divisor = 1;
     } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) {
         multiplier = 1;
         divisor = 1000;
     } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) {
         multiplier = 1000;
         divisor = 1;
     } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) {
         multiplier = 60 * 1000;
         divisor = 1;
     } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) {
         multiplier = 60 * 60 * 1000;
         divisor = 1;
     } else if (*units != EOS && *units != '\n' && *units != '\r') {
         return msec;
     }
 
     msec = crm_int_helper(cp, &end_text);
     if (msec > LLONG_MAX/multiplier) {
         /* arithmetics overflow while multiplier/divisor mutually exclusive */
         return LLONG_MAX;
     }
     msec *= multiplier;
     msec /= divisor;
     /* dret += 0.5; */
     /* msec = (long long)dret; */
     return msec;
 }
 
 extern bool crm_is_daemon;
 
 /* coverity[+kill] */
 void
 crm_abort(const char *file, const char *function, int line,
           const char *assert_condition, gboolean do_core, gboolean do_fork)
 {
     int rc = 0;
     int pid = 0;
     int status = 0;
 
     /* Implied by the parent's error logging below */
     /* crm_write_blackbox(0); */
 
     if(crm_is_daemon == FALSE) {
         /* This is a command line tool - do not fork */
 
         /* crm_add_logfile(NULL);   * Record it to a file? */
         crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */
         do_fork = FALSE;         /* Just crash if needed */
     }
 
     if (do_core == FALSE) {
         crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition);
         return;
 
     } else if (do_fork) {
         pid = fork();
 
     } else {
         crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition);
     }
 
     if (pid == -1) {
         crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s",
                  function, file, line, assert_condition);
         return;
 
     } else if(pid == 0) {
         /* Child process */
         abort();
         return;
     }
 
     /* Parent process */
     crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s",
             function, pid, file, line, assert_condition);
     crm_write_blackbox(SIGTRAP, NULL);
 
     do {
         rc = waitpid(pid, &status, 0);
         if(rc == pid) {
             return; /* Job done */
         }
 
     } while(errno == EINTR);
 
     if (errno == ECHILD) {
         /* crm_mon does this */
         crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid);
         return;
     }
     crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid);
 }
 
 void
 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
 {
     int rc;
     long pid;
     const char *devnull = "/dev/null";
 
     if (daemonize == FALSE) {
         return;
     }
 
     /* Check before we even try... */
     rc = crm_pidfile_inuse(pidfile, 1, name);
     if(rc < pcmk_ok && rc != -ENOENT) {
         pid = crm_read_pidfile(pidfile);
         crm_err("%s: already running [pid %ld in %s]", name, pid, pidfile);
         printf("%s: already running [pid %ld in %s]\n", name, pid, pidfile);
         crm_exit(CRM_EX_ERROR);
     }
 
     pid = fork();
     if (pid < 0) {
         fprintf(stderr, "%s: could not start daemon\n", name);
         crm_perror(LOG_ERR, "fork");
         crm_exit(CRM_EX_OSERR);
 
     } else if (pid > 0) {
         crm_exit(CRM_EX_OK);
     }
 
     rc = crm_lock_pidfile(pidfile, name);
     if(rc < pcmk_ok) {
         crm_err("Could not lock '%s' for %s: %s (%d)", pidfile, name, pcmk_strerror(rc), rc);
         printf("Could not lock '%s' for %s: %s (%d)\n", pidfile, name, pcmk_strerror(rc), rc);
         crm_exit(CRM_EX_ERROR);
     }
 
     umask(S_IWGRP | S_IWOTH | S_IROTH);
 
     close(STDIN_FILENO);
     (void)open(devnull, O_RDONLY);      /* Stdin:  fd 0 */
     close(STDOUT_FILENO);
     (void)open(devnull, O_WRONLY);      /* Stdout: fd 1 */
     close(STDERR_FILENO);
     (void)open(devnull, O_WRONLY);      /* Stderr: fd 2 */
 }
 
 char *
 crm_meta_name(const char *field)
 {
     int lpc = 0;
     int max = 0;
     char *crm_name = NULL;
 
     CRM_CHECK(field != NULL, return NULL);
     crm_name = crm_concat(CRM_META, field, '_');
 
     /* Massage the names so they can be used as shell variables */
     max = strlen(crm_name);
     for (; lpc < max; lpc++) {
         switch (crm_name[lpc]) {
             case '-':
                 crm_name[lpc] = '_';
                 break;
         }
     }
     return crm_name;
 }
 
 const char *
 crm_meta_value(GHashTable * hash, const char *field)
 {
     char *key = NULL;
     const char *value = NULL;
 
     key = crm_meta_name(field);
     if (key) {
         value = g_hash_table_lookup(hash, key);
         free(key);
     }
 
     return value;
 }
 
 static struct option *
 crm_create_long_opts(struct crm_option *long_options)
 {
     struct option *long_opts = NULL;
 
 #ifdef HAVE_GETOPT_H
     int index = 0, lpc = 0;
 
     /*
      * A previous, possibly poor, choice of '?' as the short form of --help
      * means that getopt_long() returns '?' for both --help and for "unknown option"
      *
      * This dummy entry allows us to differentiate between the two in crm_get_option()
      * and exit with the correct error code
      */
     long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
     long_opts[index].name = "__dummmy__";
     long_opts[index].has_arg = 0;
     long_opts[index].flag = 0;
     long_opts[index].val = '_';
     index++;
 
     for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
         if (long_options[lpc].name[0] == '-') {
             continue;
         }
 
         long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
         /*fprintf(stderr, "Creating %d %s = %c\n", index,
          * long_options[lpc].name, long_options[lpc].val);      */
         long_opts[index].name = long_options[lpc].name;
         long_opts[index].has_arg = long_options[lpc].has_arg;
         long_opts[index].flag = long_options[lpc].flag;
         long_opts[index].val = long_options[lpc].val;
         index++;
     }
 
     /* Now create the list terminator */
     long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
     long_opts[index].name = NULL;
     long_opts[index].has_arg = 0;
     long_opts[index].flag = 0;
     long_opts[index].val = 0;
 #endif
 
     return long_opts;
 }
 
 void
 crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options,
                 const char *app_desc)
 {
     if (short_options) {
         crm_short_options = strdup(short_options);
 
     } else if (long_options) {
         int lpc = 0;
         int opt_string_len = 0;
         char *local_short_options = NULL;
 
         for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
             if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
                 local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
                 local_short_options[opt_string_len++] = long_options[lpc].val;
                 /* getopt(3) says: Two colons mean an option takes an optional arg; */
                 if (long_options[lpc].has_arg == optional_argument) {
                     local_short_options[opt_string_len++] = ':';
                 }
                 if (long_options[lpc].has_arg >= required_argument) {
                     local_short_options[opt_string_len++] = ':';
                 }
                 local_short_options[opt_string_len] = 0;
             }
         }
         crm_short_options = local_short_options;
         crm_trace("Generated short option string: '%s'", local_short_options);
     }
 
     if (long_options) {
         crm_long_options = long_options;
     }
     if (app_desc) {
         crm_app_description = app_desc;
     }
     if (app_usage) {
         crm_app_usage = app_usage;
     }
 }
 
 int
 crm_get_option(int argc, char **argv, int *index)
 {
     return crm_get_option_long(argc, argv, index, NULL);
 }
 
 int
 crm_get_option_long(int argc, char **argv, int *index, const char **longname)
 {
 #ifdef HAVE_GETOPT_H
     static struct option *long_opts = NULL;
 
     if (long_opts == NULL && crm_long_options) {
         long_opts = crm_create_long_opts(crm_long_options);
     }
 
     *index = 0;
     if (long_opts) {
         int flag = getopt_long(argc, argv, crm_short_options, long_opts, index);
 
         switch (flag) {
             case 0:
                 if (long_opts[*index].val) {
                     return long_opts[*index].val;
                 } else if (longname) {
                     *longname = long_opts[*index].name;
                 } else {
                     crm_notice("Unhandled option --%s", long_opts[*index].name);
                     return flag;
                 }
             case -1:           /* End of option processing */
                 break;
             case ':':
                 crm_trace("Missing argument");
                 crm_help('?', CRM_EX_USAGE);
                 break;
             case '?':
                 crm_help('?', (*index? CRM_EX_OK : CRM_EX_USAGE));
                 break;
         }
         return flag;
     }
 #endif
 
     if (crm_short_options) {
         return getopt(argc, argv, crm_short_options);
     }
 
     return -1;
 }
 
 crm_exit_t
 crm_help(char cmd, crm_exit_t exit_code)
 {
     int i = 0;
     FILE *stream = (exit_code ? stderr : stdout);
 
     if (cmd == 'v' || cmd == '$') {
         fprintf(stream, "Pacemaker %s\n", PACEMAKER_VERSION);
         fprintf(stream, "Written by Andrew Beekhof\n");
         goto out;
     }
 
     if (cmd == '!') {
         fprintf(stream, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
         goto out;
     }
 
     fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description);
 
     if (crm_app_usage) {
         fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage);
     }
 
     if (crm_long_options) {
         fprintf(stream, "Options:\n");
         for (i = 0; crm_long_options[i].name != NULL; i++) {
             if (crm_long_options[i].flags & pcmk_option_hidden) {
 
             } else if (crm_long_options[i].flags & pcmk_option_paragraph) {
                 fprintf(stream, "%s\n\n", crm_long_options[i].desc);
 
             } else if (crm_long_options[i].flags & pcmk_option_example) {
                 fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc);
 
             } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) {
                 fprintf(stream, "%s\n", crm_long_options[i].desc);
 
             } else {
                 /* is val printable as char ? */
                 if (crm_long_options[i].val && crm_long_options[i].val <= UCHAR_MAX) {
                     fprintf(stream, " -%c,", crm_long_options[i].val);
                 } else {
                     fputs("    ", stream);
                 }
                 fprintf(stream, " --%s%s\t%s\n", crm_long_options[i].name,
                         crm_long_options[i].has_arg == optional_argument ? "[=value]" :
                         crm_long_options[i].has_arg == required_argument ? "=value" : "",
                         crm_long_options[i].desc ? crm_long_options[i].desc : "");
             }
         }
 
     } else if (crm_short_options) {
         fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description);
         for (i = 0; crm_short_options[i] != 0; i++) {
             int has_arg = no_argument /* 0 */;
 
             if (crm_short_options[i + 1] == ':') {
                 if (crm_short_options[i + 2] == ':')
                     has_arg = optional_argument /* 2 */;
                 else
                     has_arg = required_argument /* 1 */;
             }
 
             fprintf(stream, " -%c %s\n", crm_short_options[i],
                     has_arg == optional_argument ? "[value]" :
                     has_arg == required_argument ? "{value}" : "");
             i += has_arg;
         }
     }
 
     fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT);
 
   out:
     return crm_exit(exit_code);
 }
 
 void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro,
         qb_ipcs_service_t **ipcs_rw,
         qb_ipcs_service_t **ipcs_shm,
         struct qb_ipcs_service_handlers *ro_cb,
         struct qb_ipcs_service_handlers *rw_cb)
 {
     *ipcs_ro = mainloop_add_ipc_server(cib_channel_ro, QB_IPC_NATIVE, ro_cb);
     *ipcs_rw = mainloop_add_ipc_server(cib_channel_rw, QB_IPC_NATIVE, rw_cb);
     *ipcs_shm = mainloop_add_ipc_server(cib_channel_shm, QB_IPC_SHM, rw_cb);
 
     if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) {
         crm_err("Failed to create the CIB manager: exiting and inhibiting respawn");
         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled");
         crm_exit(CRM_EX_FATAL);
     }
 }
 
 void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
         qb_ipcs_service_t *ipcs_rw,
         qb_ipcs_service_t *ipcs_shm)
 {
     qb_ipcs_destroy(ipcs_ro);
     qb_ipcs_destroy(ipcs_rw);
     qb_ipcs_destroy(ipcs_shm);
 }
 
 qb_ipcs_service_t *
 crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
 {
     return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb);
 }
 
 void
 attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
 {
     *ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, cb);
 
     if (*ipcs == NULL) {
         crm_err("Failed to create pacemaker-attrd server: exiting and inhibiting respawn");
         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
         crm_exit(CRM_EX_FATAL);
     }
 }
 
 void
 stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
 {
     *ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, cb);
 
     if (*ipcs == NULL) {
         crm_err("Failed to create fencer: exiting and inhibiting respawn.");
         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
         crm_exit(CRM_EX_FATAL);
     }
 }
 
 bool
 pcmk_acl_required(const char *user) 
 {
 #if ENABLE_ACL
     if(user == NULL || strlen(user) == 0) {
         crm_trace("no user set");
         return FALSE;
 
     } else if (strcmp(user, CRM_DAEMON_USER) == 0) {
         return FALSE;
 
     } else if (strcmp(user, "root") == 0) {
         return FALSE;
     }
     crm_trace("acls required for %s", user);
     return TRUE;
 #else
     crm_trace("acls not supported");
     return FALSE;
 #endif
 }
 
 #if ENABLE_ACL
 char *
 uid2username(uid_t uid)
 {
     struct passwd *pwent = getpwuid(uid);
 
     if (pwent == NULL) {
         crm_perror(LOG_ERR, "Cannot get password entry of uid: %d", uid);
         return NULL;
 
     } else {
         return strdup(pwent->pw_name);
     }
 }
 
 const char *
 crm_acl_get_set_user(xmlNode * request, const char *field, const char *peer_user)
 {
     /* field is only checked for backwards compatibility */
     static const char *effective_user = NULL;
     const char *requested_user = NULL;
     const char *user = NULL;
 
     if(effective_user == NULL) {
         effective_user = uid2username(geteuid());
     }
 
     requested_user = crm_element_value(request, XML_ACL_TAG_USER);
     if(requested_user == NULL) {
         requested_user = crm_element_value(request, field);
     }
 
     if (is_privileged(effective_user) == FALSE) {
         /* We're not running as a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
         user = effective_user;
 
     } else if(peer_user == NULL && requested_user == NULL) {
         /* No user known or requested, use 'effective_user' and make sure one is set for the request */
         user = effective_user;
 
     } else if(peer_user == NULL) {
         /* No user known, trusting 'requested_user' */
         user = requested_user;
 
     } else if (is_privileged(peer_user) == FALSE) {
         /* The peer is not a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
         user = peer_user;
 
     } else if (requested_user == NULL) {
         /* Even if we're privileged, make sure there is always a value set */
         user = peer_user;
 
     } else {
         /* Legal delegation to 'requested_user' */
         user = requested_user;
     }
 
     // This requires pointer comparison, not string comparison
     if(user != crm_element_value(request, XML_ACL_TAG_USER)) {
         crm_xml_add(request, XML_ACL_TAG_USER, user);
     }
 
     if(field != NULL && user != crm_element_value(request, field)) {
         crm_xml_add(request, field, user);
     }
 
     return requested_user;
 }
 
 void
 determine_request_user(const char *user, xmlNode * request, const char *field)
 {
     /* Get our internal validation out of the way first */
     CRM_CHECK(user != NULL && request != NULL && field != NULL, return);
 
     /* If our peer is a privileged user, we might be doing something on behalf of someone else */
     if (is_privileged(user) == FALSE) {
         /* We're not a privileged user, set or overwrite any existing value for $field */
         crm_xml_replace(request, field, user);
 
     } else if (crm_element_value(request, field) == NULL) {
         /* Even if we're privileged, make sure there is always a value set */
         crm_xml_replace(request, field, user);
 
 /*  } else { Legal delegation */
     }
 
     crm_trace("Processing msg as user '%s'", crm_element_value(request, field));
 }
 #endif
 
 void *
 find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
 {
     char *error;
     void *a_function;
 
     if (*handle == NULL) {
         *handle = dlopen(lib, RTLD_LAZY);
     }
 
     if (!(*handle)) {
         crm_err("%sCould not open %s: %s", fatal ? "Fatal: " : "", lib, dlerror());
         if (fatal) {
             crm_exit(CRM_EX_FATAL);
         }
         return NULL;
     }
 
     a_function = dlsym(*handle, fn);
     if (a_function == NULL) {
         error = dlerror();
         crm_err("%sCould not find %s in %s: %s", fatal ? "Fatal: " : "", fn, lib, error);
         if (fatal) {
             crm_exit(CRM_EX_FATAL);
         }
     }
 
     return a_function;
 }
 
 void *
 convert_const_pointer(const void *ptr)
 {
     /* Worst function ever */
     return (void *)ptr;
 }
 
 #ifdef HAVE_UUID_UUID_H
 #  include <uuid/uuid.h>
 #endif
 
 char *
 crm_generate_uuid(void)
 {
     unsigned char uuid[16];
     char *buffer = malloc(37);  /* Including NUL byte */
 
     uuid_generate(uuid);
     uuid_unparse(uuid, buffer);
     return buffer;
 }
 
+/*!
+ * \brief Get name to be used as identifier for cluster messages
+ *
+ * \param[in] name  Actual system name to check
+ *
+ * \return Non-NULL cluster message identifier corresponding to name
+ *
+ * \note The Pacemaker daemons were renamed in version 2.0.0, but the old names
+ *       must continue to be used as the identifier for cluster messages, so
+ *       that mixed-version clusters are possible during a rolling upgrade.
+ */
+const char *
+pcmk_message_name(const char *name)
+{
+    if (name == NULL) {
+        return "unknown";
+
+    } else if (!strcmp(name, "pacemaker-attrd")) {
+        return "attrd";
+
+    } else if (!strcmp(name, "pacemaker-based")) {
+        return CRM_SYSTEM_CIB;
+
+    } else if (!strcmp(name, "pacemaker-controld")) {
+        return CRM_SYSTEM_CRMD;
+
+    } else if (!strcmp(name, "pacemaker-execd")) {
+        return CRM_SYSTEM_LRMD;
+
+    } else if (!strcmp(name, "pacemaker-fenced")) {
+        return "stonith-ng";
+
+    } else if (!strcmp(name, "pacemaker-schedulerd")) {
+        return CRM_SYSTEM_PENGINE;
+
+    } else {
+        return name;
+    }
+}
+
 /*!
  * \brief Check whether a string represents a cluster daemon name
  *
  * \param[in] name  String to check
  *
  * \return TRUE if name is standard client name used by daemons, FALSE otherwise
  */
 bool
 crm_is_daemon_name(const char *name)
 {
-    return (name &&
-            (!strcmp(name, CRM_SYSTEM_CRMD)
+    name = pcmk_message_name(name);
+    return (!strcmp(name, CRM_SYSTEM_CRMD)
             || !strcmp(name, CRM_SYSTEM_STONITHD)
-            || !strcmp(name, T_ATTRD)
+            || !strcmp(name, "stonith-ng")
+            || !strcmp(name, "attrd")
             || !strcmp(name, CRM_SYSTEM_CIB)
             || !strcmp(name, CRM_SYSTEM_MCP)
             || !strcmp(name, CRM_SYSTEM_DC)
             || !strcmp(name, CRM_SYSTEM_TENGINE)
-            || !strcmp(name, CRM_SYSTEM_LRMD)));
+            || !strcmp(name, CRM_SYSTEM_LRMD));
 }
 
 #include <md5.h>
 
 char *
 crm_md5sum(const char *buffer)
 {
     int lpc = 0, len = 0;
     char *digest = NULL;
     unsigned char raw_digest[MD5_DIGEST_SIZE];
 
     if (buffer == NULL) {
         buffer = "";
     }
     len = strlen(buffer);
 
     crm_trace("Beginning digest of %d bytes", len);
     digest = malloc(2 * MD5_DIGEST_SIZE + 1);
     if(digest) {
         md5_buffer(buffer, len, raw_digest);
         for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
             sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
         }
         digest[(2 * MD5_DIGEST_SIZE)] = 0;
         crm_trace("Digest %s.", digest);
 
     } else {
         crm_err("Could not create digest");
     }
     return digest;
 }
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 void
 crm_gnutls_global_init(void)
 {
     signal(SIGPIPE, SIG_IGN);
     gnutls_global_init();
 }
 #endif
 
 char *
 crm_generate_ra_key(const char *standard, const char *provider, const char *type)
 {
     if (!standard && !provider && !type) {
         return NULL;
     }
 
     return crm_strdup_printf("%s%s%s:%s",
                              (standard? standard : ""),
                              (provider? ":" : ""), (provider? provider : ""),
                              (type? type : ""));
 }
 
 /*!
  * \brief Check whether a resource standard requires a provider to be specified
  *
  * \param[in] standard  Standard name
  *
  * \return TRUE if standard requires a provider, FALSE otherwise
  */
 bool
 crm_provider_required(const char *standard)
 {
     CRM_CHECK(standard != NULL, return FALSE);
 
     /* @TODO
      * - this should probably be case-sensitive, but isn't,
      *   for backward compatibility
      * - it might be nice to keep standards' capabilities (supports provider,
      *   can be promotable, etc.) as structured data somewhere
      */
     if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF)) {
         return TRUE;
     }
     return FALSE;
 }
 
 /*!
  * \brief Parse a "standard[:provider]:type" agent specification
  *
  * \param[in]  spec      Agent specification
  * \param[out] standard  Newly allocated memory containing agent standard (or NULL)
  * \param[out] provider  Newly allocated memory containing agent provider (or NULL)
  * \param[put] type      Newly allocated memory containing agent type (or NULL)
  *
  * \return pcmk_ok if the string could be parsed, -EINVAL otherwise
  *
  * \note It is acceptable for the type to contain a ':' if the standard supports
  *       that. For example, systemd supports the form "systemd:UNIT@A:B".
  * \note It is the caller's responsibility to free the returned values.
  */
 int
 crm_parse_agent_spec(const char *spec, char **standard, char **provider,
                      char **type)
 {
     char *colon;
 
     CRM_CHECK(spec && standard && provider && type, return -EINVAL);
     *standard = NULL;
     *provider = NULL;
     *type = NULL;
 
     colon = strchr(spec, ':');
     if ((colon == NULL) || (colon == spec)) {
         return -EINVAL;
     }
 
     *standard = strndup(spec, colon - spec);
     spec = colon + 1;
 
     if (crm_provider_required(*standard)) {
         colon = strchr(spec, ':');
         if ((colon == NULL) || (colon == spec)) {
             free(*standard);
             return -EINVAL;
         }
         *provider = strndup(spec, colon - spec);
         spec = colon + 1;
     }
 
     if (*spec == '\0') {
         free(*standard);
         free(*provider);
         return -EINVAL;
     }
 
     *type = strdup(spec);
     return pcmk_ok;
 }
diff --git a/lib/lrmd/proxy_common.c b/lib/lrmd/proxy_common.c
index 41c0cce9fd..cd3bb26301 100644
--- a/lib/lrmd/proxy_common.c
+++ b/lib/lrmd/proxy_common.c
@@ -1,308 +1,308 @@
 /*
  * Copyright 2015-2018 David Vossel <davidvossel@gmail.com>
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <glib.h>
 #include <unistd.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/services.h>
 #include <crm/common/mainloop.h>
 
 #include <crm/pengine/status.h>
 #include <crm/cib.h>
 #include <crm/lrmd.h>
 
 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
 GHashTable *proxy_table = NULL;
 
 static void
 remote_proxy_notify_destroy(lrmd_t *lrmd, const char *session_id)
 {
     /* sending to the remote node that an ipc connection has been destroyed */
     xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
     crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_DESTROY);
     crm_xml_add(msg, F_LRMD_IPC_SESSION, session_id);
     lrmd_internal_proxy_send(lrmd, msg);
     free_xml(msg);
 }
 
 /*!
  * \brief Send an acknowledgment of a remote proxy shutdown request.
  *
  * \param[in] lrmd  Connection to proxy
  */
 void
 remote_proxy_ack_shutdown(lrmd_t *lrmd)
 {
     xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
     crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_ACK);
     lrmd_internal_proxy_send(lrmd, msg);
     free_xml(msg);
 }
 
 /*!
  * \brief We're not going to shutdown as response to
  *        a remote proxy shutdown request.
  *
  * \param[in] lrmd  Connection to proxy
  */
 void
 remote_proxy_nack_shutdown(lrmd_t *lrmd)
 {
     xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
     crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_NACK);
     lrmd_internal_proxy_send(lrmd, msg);
     free_xml(msg);
 }
 
 void
 remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
 {
     /* sending to the remote node an event msg. */
     xmlNode *event = create_xml_node(NULL, T_LRMD_IPC_PROXY);
     crm_xml_add(event, F_LRMD_IPC_OP, LRMD_IPC_OP_EVENT);
     crm_xml_add(event, F_LRMD_IPC_SESSION, proxy->session_id);
     add_message_xml(event, F_LRMD_IPC_MSG, msg);
     crm_log_xml_explicit(event, "EventForProxy");
     lrmd_internal_proxy_send(proxy->lrm, event);
     free_xml(event);
 }
 
 void
 remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
 {
     /* sending to the remote node a response msg. */
     xmlNode *response = create_xml_node(NULL, T_LRMD_IPC_PROXY);
     crm_xml_add(response, F_LRMD_IPC_OP, LRMD_IPC_OP_RESPONSE);
     crm_xml_add(response, F_LRMD_IPC_SESSION, proxy->session_id);
     crm_xml_add_int(response, F_LRMD_IPC_MSG_ID, msg_id);
     add_message_xml(response, F_LRMD_IPC_MSG, msg);
     lrmd_internal_proxy_send(proxy->lrm, response);
     free_xml(response);
 }
 
 static void
 remote_proxy_end_session(remote_proxy_t *proxy)
 {
     if (proxy == NULL) {
         return;
     }
     crm_trace("ending session ID %s", proxy->session_id);
 
     if (proxy->source) {
         mainloop_del_ipc_client(proxy->source);
     }
 }
 
 void
 remote_proxy_free(gpointer data)
 {
     remote_proxy_t *proxy = data;
 
     crm_trace("freed proxy session ID %s", proxy->session_id);
     free(proxy->node_name);
     free(proxy->session_id);
     free(proxy);
 }
 
 int
 remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
 {
     // Async responses from cib and friends to clients via pacemaker-remoted
     xmlNode *xml = NULL;
     uint32_t flags = 0;
     remote_proxy_t *proxy = userdata;
 
     xml = string2xml(buffer);
     if (xml == NULL) {
         crm_warn("Received a NULL msg from IPC service.");
         return 1;
     }
 
     flags = crm_ipc_buffer_flags(proxy->ipc);
     if (flags & crm_ipc_proxied_relay_response) {
         crm_trace("Passing response back to %.8s on %s: %.200s - request id: %d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id);
         remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
         proxy->last_request_id = 0;
 
     } else {
         crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
         remote_proxy_relay_event(proxy, xml);
     }
     free_xml(xml);
     return 1;
 }
 
 
 void
 remote_proxy_disconnected(gpointer userdata)
 {
     remote_proxy_t *proxy = userdata;
 
     crm_trace("destroying %p", proxy);
 
     proxy->source = NULL;
     proxy->ipc = NULL;
 
     if(proxy->lrm) {
         remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
         proxy->lrm = NULL;
     }
 
     g_hash_table_remove(proxy_table, proxy->session_id);
 }
 
 remote_proxy_t *
 remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
                  const char *node_name, const char *session_id, const char *channel)
 {
     remote_proxy_t *proxy = NULL;
 
     if(channel == NULL) {
         crm_err("No channel specified to proxy");
         remote_proxy_notify_destroy(lrmd, session_id);
         return NULL;
     }
 
     proxy = calloc(1, sizeof(remote_proxy_t));
 
     proxy->node_name = strdup(node_name);
     proxy->session_id = strdup(session_id);
     proxy->lrm = lrmd;
 
-    if (safe_str_eq(crm_system_name, CRM_SYSTEM_CRMD)
-        && safe_str_eq(channel, CRM_SYSTEM_CRMD)) {
+    if (!strcmp(pcmk_message_name(crm_system_name), CRM_SYSTEM_CRMD)
+        && !strcmp(pcmk_message_name(channel), CRM_SYSTEM_CRMD)) {
         // The controller doesn't need to connect to itself
         proxy->is_local = TRUE;
 
     } else {
         proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
         proxy->ipc = mainloop_get_ipc_client(proxy->source);
         if (proxy->source == NULL) {
             remote_proxy_free(proxy);
             remote_proxy_notify_destroy(lrmd, session_id);
             return NULL;
         }
     }
 
     crm_trace("new remote proxy client established to %s on %s, session id %s",
               channel, node_name, session_id);
     g_hash_table_insert(proxy_table, proxy->session_id, proxy);
 
     return proxy;
 }
 
 void
 remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
 {
     const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
     const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
     int msg_id = 0;
 
     /* sessions are raw ipc connections to IPC,
      * all we do is proxy requests/responses exactly
      * like they are given to us at the ipc level. */
 
     CRM_CHECK(op != NULL, return);
     CRM_CHECK(session != NULL, return);
 
     crm_element_value_int(msg, F_LRMD_IPC_MSG_ID, &msg_id);
     /* This is msg from remote ipc client going to real ipc server */
 
     if (safe_str_eq(op, LRMD_IPC_OP_DESTROY)) {
         remote_proxy_end_session(proxy);
 
     } else if (safe_str_eq(op, LRMD_IPC_OP_REQUEST)) {
         int flags = 0;
         xmlNode *request = get_message_xml(msg, F_LRMD_IPC_MSG);
         const char *name = crm_element_value(msg, F_LRMD_IPC_CLIENT);
 
         CRM_CHECK(request != NULL, return);
 
         if (proxy == NULL) {
             /* proxy connection no longer exists */
             remote_proxy_notify_destroy(lrmd, session);
             return;
         }
 
         // Controller requests MUST be handled by the controller, not us
         CRM_CHECK(proxy->is_local == FALSE,
                   remote_proxy_end_session(proxy); return);
 
         if (crm_ipc_connected(proxy->ipc) == FALSE) {
             remote_proxy_end_session(proxy);
             return;
         }
         proxy->last_request_id = 0;
         crm_element_value_int(msg, F_LRMD_IPC_MSG_FLAGS, &flags);
         crm_xml_add(request, XML_ACL_TAG_ROLE, "pacemaker-remote");
 
 #if ENABLE_ACL
         CRM_ASSERT(node_name);
         crm_acl_get_set_user(request, F_LRMD_IPC_USER, node_name);
 #endif
 
         if(is_set(flags, crm_ipc_proxied)) {
             const char *type = crm_element_value(request, F_TYPE);
             int rc = 0;
 
             if (safe_str_eq(type, T_ATTRD)
                 && crm_element_value(request, F_ATTRD_HOST) == NULL) {
                 crm_xml_add(request, F_ATTRD_HOST, proxy->node_name);
             }
 
             rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
 
             if(rc < 0) {
                 xmlNode *op_reply = create_xml_node(NULL, "nack");
 
                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
 
                 /* Send a n'ack so the caller doesn't block */
                 crm_xml_add(op_reply, "function", __FUNCTION__);
                 crm_xml_add_int(op_reply, "line", __LINE__);
                 crm_xml_add_int(op_reply, "rc", rc);
                 remote_proxy_relay_response(proxy, op_reply, msg_id);
                 free_xml(op_reply);
 
             } else {
                 crm_trace("Relayed %s request %d from %s to %s for %s",
                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
                 proxy->last_request_id = msg_id;
             }
 
         } else {
             int rc = pcmk_ok;
             xmlNode *op_reply = NULL;
             // @COMPAT pacemaker_remoted <= 1.1.10
 
             crm_trace("Relaying %s request %d from %s to %s for %s",
                       op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
 
             rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
             if(rc < 0) {
                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
             } else {
                 crm_trace("Relayed %s request %d from %s to %s for %s",
                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
             }
 
             if(op_reply) {
                 remote_proxy_relay_response(proxy, op_reply, msg_id);
                 free_xml(op_reply);
             }
         }
     } else {
         crm_err("Unknown proxy operation: %s", op);
     }
 }