diff --git a/fencing/main.c b/fencing/main.c
index 407d51f68e..41b3cb5b46 100644
--- a/fencing/main.c
+++ b/fencing/main.c
@@ -1,1075 +1,1076 @@
 /* 
  * Copyright (C) 2009 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/utsname.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/ipc.h>
 #include <crm/cluster/internal.h>
 
 #include <crm/stonith-ng.h>
 #include <crm/fencing/internal.h>
 #include <crm/common/xml.h>
 
 #include <crm/common/mainloop.h>
 
 #include <crm/cib/internal.h>
 
 #include <internal.h>
 
 #include <standalone_config.h>
 
 char *stonith_our_uname = NULL;
 
 GMainLoop *mainloop = NULL;
 GHashTable *client_list = NULL;
 
 gboolean stand_alone = FALSE;
 gboolean no_cib_connect = FALSE;
 gboolean stonith_shutdown_flag = FALSE;
 
 qb_ipcs_service_t *ipcs = NULL;
 
 static void stonith_shutdown(int nsig);
 static void stonith_cleanup(void);
 
 static int32_t
 st_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
 {
     crm_trace("Connecting %p for uid=%d gid=%d", c, uid, gid);
     if(stonith_shutdown_flag) {
         crm_info("Ignoring new client [%d] during shutdown", crm_ipcs_client_pid(c));
         return -EPERM;
     }
     return 0;
 }
 
 static void
 st_ipc_created(qb_ipcs_connection_t *c)
 {
     stonith_client_t *new_client = NULL;
 
 #if 0
     struct qb_ipcs_stats srv_stats;
 
     qb_ipcs_stats_get(s1, &srv_stats, QB_FALSE);
     qb_log(LOG_INFO, "Connection created (active:%d, closed:%d)",
            srv_stats.active_connections,
            srv_stats.closed_connections);
 #endif
 
     new_client = calloc(1, sizeof(stonith_client_t));
     new_client->channel = c;
     new_client->pid = crm_ipcs_client_pid(c);
     new_client->channel_name = strdup("ipc");
 
     CRM_CHECK(new_client->id == NULL, free(new_client->id));
     new_client->id = crm_generate_uuid();
     crm_trace("Created channel %p for client %s", c, new_client->id);
 
     /* make sure we can find ourselves later for sync calls
      * redirected to the master instance
      */
     g_hash_table_insert(client_list, new_client->id, new_client);
     qb_ipcs_context_set(c, new_client);
     CRM_ASSERT(qb_ipcs_context_get(c) != NULL);
 }
 
 /* Exit code means? */
 static int32_t
 st_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size)
 {
     uint32_t id = 0;
     uint32_t flags = 0;
     xmlNode *request = NULL;
     stonith_client_t *client = (stonith_client_t*)qb_ipcs_context_get(c);
 
     request = crm_ipcs_recv(c, data, size, &id, &flags);
     if (request == NULL) {
         crm_ipcs_send_ack(c, id, "nack", __FUNCTION__, __LINE__);
         return 0;
     }
     
     CRM_CHECK(client != NULL, goto cleanup);
 
     if(client->name == NULL) {
         const char *value = crm_element_value(request, F_STONITH_CLIENTNAME);
         if(value == NULL) {
             value = "unknown";
         }
         client->name = g_strdup_printf("%s.%u", value, client->pid);
     }
 
     CRM_CHECK(client->id != NULL, crm_err("Invalid client: %p/%s", client, client->name); goto cleanup);
 
     if(flags & crm_ipc_client_response) {
         CRM_LOG_ASSERT(client->request_id == 0); /* This means the client has two synchronous events in-flight */
         client->request_id = id;                 /* Reply only to the last one */
     }
     
     crm_xml_add(request, F_STONITH_CLIENTID, client->id);
     crm_xml_add(request, F_STONITH_CLIENTNAME, client->name);
     crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);
 
     crm_log_xml_trace(request, "Client[inbound]");
     stonith_command(client, id, flags, request, NULL);
 
   cleanup:
     if(client == NULL || client->id == NULL) {
         crm_log_xml_notice(request, "Invalid client");
     }
 
     free_xml(request);
     return 0;
 }
 
 /* Error code means? */
 static int32_t
 st_ipc_closed(qb_ipcs_connection_t *c)
 {
     stonith_client_t *client = (stonith_client_t*)qb_ipcs_context_get(c);
 
 #if 0
     qb_ipcs_stats_get(s1, &srv_stats, QB_FALSE);
     qb_ipcs_connection_stats_get(c, &stats, QB_FALSE);
     qb_log(LOG_INFO, "Connection to pid:%d destroyed (active:%d, closed:%d)",
            stats.client_pid,
            srv_stats.active_connections,
            srv_stats.closed_connections);
 
     qb_log(LOG_DEBUG, " Requests %"PRIu64"", stats.requests);
     qb_log(LOG_DEBUG, " Responses %"PRIu64"", stats.responses);
     qb_log(LOG_DEBUG, " Events %"PRIu64"", stats.events);
     qb_log(LOG_DEBUG, " Send retries %"PRIu64"", stats.send_retries);
     qb_log(LOG_DEBUG, " Recv retries %"PRIu64"", stats.recv_retries);
     qb_log(LOG_DEBUG, " FC state %d", stats.flow_control_state);
     qb_log(LOG_DEBUG, " FC count %"PRIu64"", stats.flow_control_count);
 #endif
 
     if (client == NULL) {
         crm_err("No client");
         return 0;
     }
 
     crm_trace("Cleaning up after client disconnect: %p/%s/%s", client, crm_str(client->name), client->id);
     if(client->id != NULL) {
         g_hash_table_remove(client_list, client->id);
     }
 
     /* 0 means: yes, go ahead and destroy the connection */
     return 0;
 }
 
 static void
 st_ipc_destroy(qb_ipcs_connection_t *c)
 {
     stonith_client_t *client = (stonith_client_t*)qb_ipcs_context_get(c);
 
     /* Make sure the connection is fully cleaned up */
     st_ipc_closed(c);
 
     if(client == NULL) {
         crm_trace("Nothing to destroy");
         return;
     }
 
     crm_trace("Destroying %s (%p)", client->name, client);
 
     free(client->name);
     free(client->id);
     free(client);
     crm_trace("Done");
 
     return;
 }
 
 static void
 stonith_peer_callback(xmlNode * msg, void* private_data)
 {
     const char *remote_peer = crm_element_value(msg, F_ORIG);
     const char *op = crm_element_value(msg, F_STONITH_OPERATION);
 
     if(crm_str_eq(op, "poke", TRUE)) {
         return;
     }
 
     crm_log_xml_trace(msg, "Peer[inbound]");
     stonith_command(NULL, 0, 0, msg, remote_peer);
 }
 
 #if SUPPORT_HEARTBEAT
 static void
 stonith_peer_hb_callback(HA_Message * msg, void* private_data)
 {
     xmlNode *xml = convert_ha_message(NULL, msg, __FUNCTION__);
     stonith_peer_callback(xml, private_data);
     free_xml(xml);
 }
 static void
 stonith_peer_hb_destroy(gpointer user_data)
 {
     if(stonith_shutdown_flag) {
         crm_info("Heartbeat disconnection complete... exiting");
     } else {
         crm_err("Heartbeat connection lost!  Exiting.");
     }
     stonith_shutdown(0);
 }
 #endif
 
 
 #if SUPPORT_COROSYNC
 static gboolean stonith_peer_ais_callback(int kind, const char *from, const char *data)
 {
     xmlNode *xml = NULL;
 
     if(kind == crm_class_cluster) {
         xml = string2xml(data);
         if(xml == NULL) {
             goto bail;
         }
         crm_xml_add(xml, F_ORIG, from);
         /* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
         stonith_peer_callback(xml, NULL);
     }
 
     free_xml(xml);
     return TRUE;
 
   bail:
     crm_err("Invalid XML: '%.120s'", data);
     return TRUE;
 
 }
 
 static void
 stonith_peer_ais_destroy(gpointer user_data)
 {
     crm_err("AIS connection terminated");
     stonith_shutdown(0);
 }
 #endif
 
 void do_local_reply(xmlNode *notify_src, const char *client_id,
              gboolean sync_reply, gboolean from_peer)
 {
     /* send callback to originating child */
     stonith_client_t *client_obj = NULL;
     int local_rc = pcmk_ok;
 
     crm_trace("Sending response");
 
     if(client_id != NULL) {
         client_obj = g_hash_table_lookup(client_list, client_id);
     } else {
         crm_trace("No client to sent the response to."
                     "  F_STONITH_CLIENTID not set.");
     }
 
     crm_trace("Sending callback to request originator");
     if(client_obj == NULL) {
         local_rc = -1;
 
     } else {
         int rid = 0;
 
         if(sync_reply) {
             CRM_LOG_ASSERT(client_obj->request_id);
 
             rid = client_obj->request_id;
             client_obj->request_id = 0;
 
             crm_trace("Sending response %d to %s %s",
                       rid, client_obj->name, from_peer?"(originator of delegated request)":"");
 
         } else {
             crm_trace("Sending an event to %s %s",
                       client_obj->name, from_peer?"(originator of delegated request)":"");
         }
 
         local_rc = crm_ipcs_send(client_obj->channel, rid, notify_src, !sync_reply);
     }
 
     if(local_rc < pcmk_ok && client_obj != NULL) {
         crm_warn("%sSync reply to %s failed: %s",
                  sync_reply?"":"A-",
                  client_obj?client_obj->name:"<unknown>", pcmk_strerror(local_rc));
     }
 }
 
 long long get_stonith_flag(const char *name)
 {
     if(safe_str_eq(name, T_STONITH_NOTIFY_FENCE)) {
         return 0x01;
 
     } else if(safe_str_eq(name, STONITH_OP_DEVICE_ADD)) {
         return 0x04;
 
     } else if(safe_str_eq(name, STONITH_OP_DEVICE_DEL)) {
         return 0x10;
    }
     return 0;
 }
 
 static void
 stonith_notify_client(gpointer key, gpointer value, gpointer user_data)
 {
 
     xmlNode *update_msg = user_data;
     stonith_client_t *client = value;
     const char *type = NULL;
 
     CRM_CHECK(client != NULL, return);
     CRM_CHECK(update_msg != NULL, return);
 
     type = crm_element_value(update_msg, F_SUBTYPE);
     CRM_CHECK(type != NULL, crm_log_xml_err(update_msg, "notify"); return);
 
     if(client->channel == NULL) {
         crm_trace("Skipping client with NULL channel");
         return;
 
     } else if(client->name == NULL) {
         crm_trace("Skipping unnammed client / comamnd channel");
         return;
     }
 
     if(client->flags & get_stonith_flag(type)) {
         int rc = crm_ipcs_send(client->channel, 0, update_msg, crm_ipc_server_event|crm_ipc_server_error);
         if(rc <= 0) {
             crm_warn("%s notification of client %s.%.6s failed: %s (%d)",
                      type, client->name, client->id, pcmk_strerror(rc), rc);
         } else {
             crm_trace("Sent %s notification to client %s.%.6s", type, client->name, client->id);
         }
     }
 }
 
 void
 do_stonith_async_timeout_update(const char *client_id, const char *call_id, int timeout)
 {
     stonith_client_t *client = NULL;
     xmlNode *notify_data = NULL;
 
     if (!timeout || !call_id || !client_id) {
         return;
     }
 
     client = g_hash_table_lookup(client_list, client_id);
     if (!client) {
         return;
     }
 
     notify_data = create_xml_node(NULL, T_STONITH_TIMEOUT_VALUE);
     crm_xml_add(notify_data, F_TYPE, T_STONITH_TIMEOUT_VALUE);
     crm_xml_add(notify_data, F_STONITH_CALLID, call_id);
     crm_xml_add_int(notify_data, F_STONITH_TIMEOUT, timeout);
 
     crm_trace("timeout update is %d for client %s and call id %s", timeout, client_id, call_id);
 
     if (client->channel) {
         crm_ipcs_send(client->channel, 0, notify_data, crm_ipc_server_event);
     }
 
     free_xml(notify_data);
 }
 
 void
 do_stonith_notify(int options, const char *type, int result, xmlNode *data)
 {
     /* TODO: Standardize the contents of data */
     xmlNode *update_msg = create_xml_node(NULL, "notify");
 
     CRM_CHECK(type != NULL, ;);
 
     crm_xml_add(update_msg, F_TYPE, T_STONITH_NOTIFY);
     crm_xml_add(update_msg, F_SUBTYPE, type);
     crm_xml_add(update_msg, F_STONITH_OPERATION, type);
     crm_xml_add_int(update_msg, F_STONITH_RC, result);
 
     if(data != NULL) {
         add_message_xml(update_msg, F_STONITH_CALLDATA, data);
     }
 
     crm_trace("Notifying clients");
     g_hash_table_foreach(client_list, stonith_notify_client, update_msg);
     free_xml(update_msg);
     crm_trace("Notify complete");
 }
 
 static stonith_key_value_t *parse_device_list(const char *devices)
 {
     int lpc = 0;
     int max = 0;
     int last = 0;
     stonith_key_value_t *output = NULL;
 
     if(devices == NULL) {
         return output;
     }
 
     max = strlen(devices);
     for(lpc = 0; lpc <= max; lpc++) {
         if(devices[lpc] == ',' || devices[lpc] == 0) {
             char *line = NULL;
 
             line = calloc(1, 2 + lpc - last);
             snprintf(line, 1 + lpc - last, "%s", devices+last);
             output = stonith_key_value_add(output, NULL, line);
             free(line);
 
             last = lpc + 1;
         }
     }
 
     return output;
 }
 
 static void topology_remove_helper(const char *node, int level)
 {
     int rc;
     char *desc = NULL;
     xmlNode *data = create_xml_node(NULL, F_STONITH_LEVEL);
     xmlNode *notify_data = create_xml_node(NULL, STONITH_OP_LEVEL_DEL);
 
     crm_xml_add(data, "origin", __FUNCTION__);
     crm_xml_add_int(data, XML_ATTR_ID, level);
     crm_xml_add(data, F_STONITH_TARGET, node);
 
     rc = stonith_level_remove(data, &desc);
 
     crm_xml_add(notify_data, F_STONITH_DEVICE, desc);
     crm_xml_add_int(notify_data, F_STONITH_ACTIVE, g_hash_table_size(topology));
 
     do_stonith_notify(0, STONITH_OP_LEVEL_DEL, rc, notify_data);
 
     free_xml(notify_data);
     free_xml(data);
     free(desc);
 }
 
 static void topology_register_helper(const char *node, int level, stonith_key_value_t *device_list) 
 {
     int rc;
     char *desc = NULL;
     xmlNode *notify_data = create_xml_node(NULL, STONITH_OP_LEVEL_ADD);
     xmlNode *data = create_level_registration_xml(node, level, device_list);
 
     rc = stonith_level_register(data, &desc);
 
     crm_xml_add(notify_data, F_STONITH_DEVICE, desc);
     crm_xml_add_int(notify_data, F_STONITH_ACTIVE, g_hash_table_size(topology));
 
     do_stonith_notify(0, STONITH_OP_LEVEL_ADD, rc, notify_data);
 
     free_xml(notify_data);
     free_xml(data);
     free(desc);
 }
 
 static void remove_cib_device(xmlXPathObjectPtr xpathObj)
 {
     int max = 0, lpc = 0;
 
     if(xpathObj && xpathObj->nodesetval) {
         max = xpathObj->nodesetval->nodeNr;
     }
 
     for(lpc = 0; lpc < max; lpc++) {
         const char *rsc_id = NULL;
         const char *standard = NULL;
         xmlNode *match = getXpathResult(xpathObj, lpc);
         CRM_CHECK(match != NULL, continue);
 
         standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
 
         if (safe_str_neq(standard, "stonith")) {
             continue;
         }
 
         rsc_id = crm_element_value(match, XML_ATTR_ID);
 
         stonith_device_remove(rsc_id, TRUE);
     }
 }
 
 static void remove_fencing_topology(xmlXPathObjectPtr xpathObj)
 {
     int max = 0, lpc = 0;
 
     if(xpathObj && xpathObj->nodesetval) {
         max = xpathObj->nodesetval->nodeNr;
     }
 
     for(lpc = 0; lpc < max; lpc++) {
         xmlNode *match = getXpathResult(xpathObj, lpc);
         CRM_CHECK(match != NULL, continue);
 
         if(crm_element_value(match, XML_DIFF_MARKER)) {
             /* Deletion */
             int index = 0;
             const char *target = crm_element_value(match, XML_ATTR_STONITH_TARGET);
 
             crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
             if(target == NULL) {
                 crm_err("Invalid fencing target in element %s", ID(match));
 
             } else if(index <= 0) {
                 crm_err("Invalid level for %s in element %s", target, ID(match));
 
             } else {
                 topology_remove_helper(target, index);
             }
      /* } else { Deal with modifications during the 'addition' stage */
         }
     }
 }
 
 static void register_cib_device(xmlXPathObjectPtr xpathObj, gboolean force)
 {
     int max = 0, lpc = 0;
 
     if(xpathObj && xpathObj->nodesetval) {
         max = xpathObj->nodesetval->nodeNr;
     }
 
     for(lpc = 0; lpc < max; lpc++) {
         const char *rsc_id = NULL;
         const char *agent = NULL;
         const char *standard = NULL;
         const char *provider = NULL;
         stonith_key_value_t *params = NULL;
         xmlNode *match = getXpathResult(xpathObj, lpc);
         xmlNode *attributes;
         xmlNode *attr;
         xmlNode *data;
 
         CRM_CHECK(match != NULL, continue);
 
         standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
         agent = crm_element_value(match, XML_EXPR_ATTR_TYPE);
         provider = crm_element_value(match, XML_AGENT_ATTR_PROVIDER);
 
         if (safe_str_neq(standard, "stonith") || !agent) {
             continue;
         }
 
         rsc_id = crm_element_value(match, XML_ATTR_ID);
         attributes = find_xml_node(match, XML_TAG_ATTR_SETS, FALSE);
 
         for (attr = __xml_first_child(attributes); attr; attr = __xml_next(attr)) {
             const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
             const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
 
             if (!name || !value) {
                 continue;
             }
             params = stonith_key_value_add(params, name, value);
         }
 
         data = create_device_registration_xml(rsc_id,
             provider,
             agent,
             params);
 
         if(force == FALSE && crm_element_value(match, XML_DIFF_MARKER)) {
             stonith_device_register(data, NULL, TRUE);
         } else {
             stonith_device_remove(rsc_id, TRUE);
             stonith_device_register(data, NULL, TRUE);
         }
     }
 }
 
 static void register_fencing_topology(xmlXPathObjectPtr xpathObj, gboolean force)
 {
     int max = 0, lpc = 0;
 
     if(xpathObj && xpathObj->nodesetval) {
         max = xpathObj->nodesetval->nodeNr;
     }
 
     for(lpc = 0; lpc < max; lpc++) {
         int index = 0;
         const char *target;
         const char *dev_list;
         stonith_key_value_t *devices = NULL;
         xmlNode *match = getXpathResult(xpathObj, lpc);
         CRM_CHECK(match != NULL, continue);
 
         crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
         target = crm_element_value(match, XML_ATTR_STONITH_TARGET);
         dev_list = crm_element_value(match, XML_ATTR_STONITH_DEVICES);
         devices = parse_device_list(dev_list);
 
         crm_trace("Updating %s[%d] (%s) to %s", target, index, ID(match), dev_list);
 
         if(target == NULL) {
             crm_err("Invalid fencing target in element %s", ID(match));
 
         } else if(index <= 0) {
             crm_err("Invalid level for %s in element %s", target, ID(match));
 
         } else if(force == FALSE && crm_element_value(match, XML_DIFF_MARKER)) {
             /* Addition */
             topology_register_helper(target, index, devices);
 
         } else { /* Modification */
             /* Remove then re-add */
             topology_remove_helper(target, index);
             topology_register_helper(target, index, devices);
         }
 
         stonith_key_value_freeall(devices, 1, 1);
     }
 }
 
 /* Fencing 
 <diff crm_feature_set="3.0.6">
   <diff-removed>
     <fencing-topology>
       <fencing-level id="f-p1.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="removed:top"/>
       <fencing-level id="f-p1.2" target="pcmk-1" index="2" devices="power" __crm_diff_marker__="removed:top"/>
       <fencing-level devices="disk,network" id="f-p2.1"/>
     </fencing-topology>
   </diff-removed>
   <diff-added>
     <fencing-topology>
       <fencing-level id="f-p.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="added:top"/>
       <fencing-level id="f-p2.1" target="pcmk-2" index="1" devices="disk,something"/>
       <fencing-level id="f-p3.1" target="pcmk-2" index="2" devices="power" __crm_diff_marker__="added:top"/>
     </fencing-topology>
   </diff-added>
 </diff>
 */
 
 static void
 fencing_topology_init(xmlNode * msg)
 {
     xmlXPathObjectPtr xpathObj = NULL;
     const char *xpath = "//" XML_TAG_FENCING_LEVEL;
 
     crm_trace("Pushing in stonith topology");
 
     /* Grab everything */
     xpathObj = xpath_search(msg, xpath);
 
     register_fencing_topology(xpathObj, TRUE);
 
     if(xpathObj) {
         xmlXPathFreeObject(xpathObj);
     }
 }
 
 static void
 cib_stonith_devices_init(xmlNode *msg)
 {
     xmlXPathObjectPtr xpathObj = NULL;
     const char *xpath = "//" XML_CIB_TAG_RESOURCE;
 
     crm_trace("Pushing in stonith devices");
 
     /* Grab everything */
     xpathObj = xpath_search(msg, xpath);
 
     if(xpathObj) {
         register_cib_device(xpathObj, TRUE);
         xmlXPathFreeObject(xpathObj);
     }
 }
 
 static void
 update_cib_stonith_devices(const char *event, xmlNode * msg)
 {
 
     const char *xpath_add = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_RESOURCE;
     const char *xpath_del = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_RESOURCE;
     xmlXPathObjectPtr xpath_obj = NULL;
 
     /* process deletions */
     xpath_obj = xpath_search(msg, xpath_del);
     if (xpath_obj) {
         remove_cib_device(xpath_obj);
         xmlXPathFreeObject(xpath_obj);
     }
 
     /* process additions */
     xpath_obj = xpath_search(msg, xpath_add);
     if (xpath_obj) {
         register_cib_device(xpath_obj, FALSE);
         xmlXPathFreeObject(xpath_obj);
     }
 }
 
 static void
 update_fencing_topology(const char *event, xmlNode * msg)
 {
     const char *xpath;
     xmlXPathObjectPtr xpathObj = NULL;
 
     /* Process deletions (only) */
     xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_FENCING_LEVEL;
     xpathObj = xpath_search(msg, xpath);
 
     remove_fencing_topology(xpathObj);
 
     if(xpathObj) {
         xmlXPathFreeObject(xpathObj);
     }
 
     /* Process additions and changes */
     xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_TAG_FENCING_LEVEL;
     xpathObj = xpath_search(msg, xpath);
 
     register_fencing_topology(xpathObj, FALSE);
 
     if(xpathObj) {
         xmlXPathFreeObject(xpathObj);
     }
 }
 
 static void
 update_cib_cache_cb(const char *event, xmlNode * msg)
 {
     update_fencing_topology(event, msg);
     update_cib_stonith_devices(event, msg);
 }
 
 static void
 init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     fencing_topology_init(msg);
     cib_stonith_devices_init(msg);
 }
 
 static void
 stonith_shutdown(int nsig)
 {
     stonith_shutdown_flag = TRUE;
     crm_info("Terminating with  %d clients", g_hash_table_size(client_list));
     if(mainloop != NULL && g_main_is_running(mainloop)) {
         g_main_quit(mainloop);
     } else {
         stonith_cleanup();
         exit(EX_OK);
     }
 }
 
 cib_t *cib = NULL;
 
 static void
 stonith_cleanup(void) 
 {
     if(cib) {
         cib->cmds->signoff(cib);
     }
 
     if(ipcs) {
         qb_ipcs_destroy(ipcs);
     }
     crm_peer_destroy();
     g_hash_table_destroy(client_list);
     free(stonith_our_uname);
 #if HAVE_LIBXML2
     crm_xml_cleanup();
 #endif
 }
 
 /* *INDENT-OFF* */
 static struct crm_option long_options[] = {
     {"stand-alone",         0, 0, 's'},
     {"stand-alone-w-cpg",   0, 0, 'c'},
     {"verbose",     0, 0, 'V'},
     {"version",     0, 0, '$'},
     {"help",        0, 0, '?'},
 
     {0, 0, 0, 0}
 };
 /* *INDENT-ON* */
 
 static void
 setup_cib(void)
 {
     static void *cib_library = NULL;
     static cib_t *(*cib_new_fn)(void) = NULL;
     static const char *(*cib_err_fn)(int) = NULL;
 
     int rc, retries = 0;
 
     if(cib_library == NULL) {
         cib_library = dlopen(CIB_LIBRARY, RTLD_LAZY);
     }
     if(cib_library && cib_new_fn == NULL) {
         cib_new_fn = dlsym(cib_library, "cib_new");
     }
     if(cib_library && cib_err_fn == NULL) {
         cib_err_fn = dlsym(cib_library, "pcmk_strerror");
     }
     if(cib_new_fn != NULL) {
         cib = (*cib_new_fn)();
     }
 
     if(cib == NULL) {
         crm_err("No connection to the CIB");
         return;
     }
 
     do {
         sleep(retries);
         rc = cib->cmds->signon(cib, CRM_SYSTEM_CRMD, cib_command);
     } while(rc == -ENOTCONN && ++retries < 5);
 
     if (rc != pcmk_ok) {
         crm_err("Could not connect to the CIB service: %d %p", rc, cib_err_fn);
 
     } else if (pcmk_ok != cib->cmds->add_notify_callback(
                    cib, T_CIB_DIFF_NOTIFY, update_cib_cache_cb)) {
         crm_err("Could not set CIB notification callback");
 
     } else {
         rc = cib->cmds->query(cib, NULL, NULL, cib_scope_local);
         add_cib_op_callback(cib, rc, FALSE, NULL, init_cib_cache_cb);
         crm_notice("Watching for stonith topology changes");
     }
 }
 
 struct qb_ipcs_service_handlers ipc_callbacks =
 {
     .connection_accept = st_ipc_accept,
     .connection_created = st_ipc_created,
     .msg_process = st_ipc_dispatch,
     .connection_closed = st_ipc_closed,
     .connection_destroyed = st_ipc_destroy
 };
 
 static void
 st_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
 {
     /* 
      * This is a hack until we can send to a nodeid and/or we fix node name lookups
      * These messages are ignored in stonith_peer_callback()
      */
         xmlNode *query = create_xml_node(NULL, "stonith_command");
 
         crm_xml_add(query, F_XML_TAGNAME, "stonith_command");
         crm_xml_add(query, F_TYPE, T_STONITH_NG);
         crm_xml_add(query, F_STONITH_OPERATION, "poke");
 
         crm_debug("Broadcasting our uname because of node %u", node->id);
         send_cluster_message(NULL, crm_msg_stonith_ng, query, FALSE);
 
         free_xml(query);
 }
 
 int
 main(int argc, char ** argv)
 {
     int flag;
     int rc = 0;
     int lpc = 0;
     int argerr = 0;
     int option_index = 0;
     crm_cluster_t cluster;
     const char *actions[] = { "reboot", "off", "list", "monitor", "status" };
 
     crm_log_init("stonith-ng", LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
     crm_set_options(NULL, "mode [options]", long_options,
         "Provides a summary of cluster's current state."
         "\n\nOutputs varying levels of detail in a number of different formats.\n");
 
     while (1) {
         flag = crm_get_option(argc, argv, &option_index);
         if (flag == -1) {
             break;
         }
 
         switch(flag) {
         case 'V':
             crm_bump_log_level(argc, argv);
             break;
         case 's':
             stand_alone = TRUE;
             break;
         case 'c':
             stand_alone = FALSE;
             no_cib_connect = TRUE;
             break;
         case '$':
         case '?':
             crm_help(flag, EX_OK);
             break;
         default:
             ++argerr;
             break;
         }
     }
 
     if(argc - optind == 1 && safe_str_eq("metadata", argv[optind])) {
         printf("<?xml version=\"1.0\"?><!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n");
         printf("<resource-agent name=\"stonithd\">\n");
         printf(" <version>1.0</version>\n");
         printf(" <longdesc lang=\"en\">This is a fake resource that details the instance attributes handled by stonithd.</longdesc>\n");
         printf(" <shortdesc lang=\"en\">Options available for all stonith resources</shortdesc>\n");
         printf(" <parameters>\n");
 
         printf("  <parameter name=\"stonith-timeout\" unique=\"0\">\n");
         printf("    <shortdesc lang=\"en\">How long to wait for the STONITH action to complete per a stonith device.</shortdesc>\n");
         printf("    <longdesc lang=\"en\">Overrides the stonith-timeout cluster property</longdesc>\n");
         printf("    <content type=\"time\" default=\"60s\"/>\n");
         printf("  </parameter>\n");
 
         printf("  <parameter name=\"priority\" unique=\"0\">\n");
         printf("    <shortdesc lang=\"en\">The priority of the stonith resource. The lower the number, the higher the priority.</shortdesc>\n");
         printf("    <content type=\"integer\" default=\"0\"/>\n");
         printf("  </parameter>\n");
 
         printf("  <parameter name=\"%s\" unique=\"0\">\n", STONITH_ATTR_HOSTARG);
         printf("    <shortdesc lang=\"en\">Advanced use only: An alternate parameter to supply instead of 'port'</shortdesc>\n");
         printf("    <longdesc lang=\"en\">Some devices do not support the standard 'port' parameter or may provide additional ones.\n"
                "Use this to specify an alternate, device-specific, parameter that should indicate the machine to be fenced.\n"
                "A value of 'none' can be used to tell the cluster not to supply any additional parameters.\n"
                "     </longdesc>\n");
         printf("    <content type=\"string\" default=\"port\"/>\n");
         printf("  </parameter>\n");
 
         printf("  <parameter name=\"%s\" unique=\"0\">\n", STONITH_ATTR_HOSTMAP);
         printf("    <shortdesc lang=\"en\">A mapping of host names to ports numbers for devices that do not support host names.</shortdesc>\n");
         printf("    <longdesc lang=\"en\">Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2</longdesc>\n");
         printf("    <content type=\"string\" default=\"\"/>\n");
         printf("  </parameter>\n");
 
         printf("  <parameter name=\"%s\" unique=\"0\">\n", STONITH_ATTR_HOSTLIST);
         printf("    <shortdesc lang=\"en\">A list of machines controlled by this device (Optional unless %s=static-list).</shortdesc>\n", STONITH_ATTR_HOSTCHECK);
         printf("    <content type=\"string\" default=\"\"/>\n");
         printf("  </parameter>\n");
 
         printf("  <parameter name=\"%s\" unique=\"0\">\n", STONITH_ATTR_HOSTCHECK);
         printf("    <shortdesc lang=\"en\">How to determin which machines are controlled by the device.</shortdesc>\n");
         printf("    <longdesc lang=\"en\">Allowed values: dynamic-list (query the device), static-list (check the %s attribute), none (assume every device can fence every machine)</longdesc>\n", STONITH_ATTR_HOSTLIST);
         printf("    <content type=\"string\" default=\"dynamic-list\"/>\n");
         printf("  </parameter>\n");
 
         for(lpc = 0; lpc < DIMOF(actions); lpc++) {
             printf("  <parameter name=\"pcmk_%s_action\" unique=\"0\">\n", actions[lpc]);
             printf("    <shortdesc lang=\"en\">Advanced use only: An alternate command to run instead of '%s'</shortdesc>\n", actions[lpc]);
             printf("    <longdesc lang=\"en\">Some devices do not support the standard commands or may provide additional ones.\n"
                    "Use this to specify an alternate, device-specific, command that implements the '%s' action.</longdesc>\n", actions[lpc]);
             printf("    <content type=\"string\" default=\"%s\"/>\n", actions[lpc]);
             printf("  </parameter>\n");
         }
 
         printf(" </parameters>\n");
         printf("</resource-agent>\n");
         return 0;
     }
 
     if (optind != argc) {
         ++argerr;
     }
 
     if (argerr) {
         crm_help('?', EX_USAGE);
     }
 
     mainloop_add_signal(SIGTERM, stonith_shutdown);
 
     crm_peer_init();
     client_list = g_hash_table_new(crm_str_hash, g_str_equal);
 
     if(stand_alone == FALSE) {
 #if SUPPORT_HEARTBEAT
+        cluster.hb_conn = NULL;
         cluster.hb_dispatch = stonith_peer_hb_callback;
         cluster.destroy = stonith_peer_hb_destroy;
 #endif
 
         if(is_openais_cluster()) {
 #if SUPPORT_COROSYNC
             cluster.destroy = stonith_peer_ais_destroy;
             cluster.cs_dispatch = stonith_peer_ais_callback;
 #endif
         }
 
         if(crm_cluster_connect(&cluster) == FALSE) {
             crm_crit("Cannot sign in to the cluster... terminating");
             exit(100);
         } else {
             stonith_our_uname = cluster.uname;
         }
         stonith_our_uname = cluster.uname;
 
         if (no_cib_connect == FALSE) {
             setup_cib();
         }
 
     } else {
         stonith_our_uname = strdup("localhost");
     }
 
     crm_set_status_callback(&st_peer_update_callback);
 
     device_list = g_hash_table_new_full(
         crm_str_hash, g_str_equal, NULL, free_device);
 
     topology = g_hash_table_new_full(
         crm_str_hash, g_str_equal, NULL, free_topology_entry);
 
     ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, &ipc_callbacks);
 
 #if SUPPORT_STONITH_CONFIG
     if (((stand_alone == TRUE)) && !(standalone_cfg_read_file(STONITH_NG_CONF_FILE))) {
         standalone_cfg_commit();
     }
 #endif
 
     if(ipcs != NULL) {
         /* Create the mainloop and run it... */
         mainloop = g_main_new(FALSE);
         crm_info("Starting %s mainloop", crm_system_name);
 
         g_main_run(mainloop);
 
     } else {
         crm_err("Couldnt start all communication channels, exiting.");
     }
 
     stonith_cleanup();
 
 #if SUPPORT_HEARTBEAT
     if(cluster.hb_conn) {
         cluster.hb_conn->llc_ops->delete(cluster.hb_conn);
     }
 #endif
 
     crm_info("Done");
     qb_log_fini();
 
     return rc;
 }
 
diff --git a/lib/cluster/cluster.c b/lib/cluster/cluster.c
index ad09700ba7..874e101345 100644
--- a/lib/cluster/cluster.c
+++ b/lib/cluster/cluster.c
@@ -1,665 +1,667 @@
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  * 
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  * 
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 #include <dlfcn.h>
 
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 
 #include <crm/common/ipc.h>
 #include <crm/cluster/internal.h>
 
 CRM_TRACE_INIT_DATA(cluster);
 
 #if SUPPORT_HEARTBEAT
 void *hb_library = NULL;
 #endif
 
 static GHashTable *crm_uuid_cache = NULL;
 static GHashTable *crm_uname_cache = NULL;
 
 static char *
 get_heartbeat_uuid(uint32_t unused, const char *uname)
 {
     char *uuid_calc = NULL;
 
 #if SUPPORT_HEARTBEAT
     cl_uuid_t uuid_raw;
     const char *unknown = "00000000-0000-0000-0000-000000000000";
 
     if (heartbeat_cluster == NULL) {
         crm_warn("No connection to heartbeat, using uuid=uname");
         return NULL;
     }
 
     if (heartbeat_cluster->llc_ops->get_uuid_by_name(heartbeat_cluster, uname, &uuid_raw) ==
         HA_FAIL) {
         crm_err("get_uuid_by_name() call failed for host %s", uname);
         free(uuid_calc);
         return NULL;
     }
 
     uuid_calc = calloc(1, 50);
     cl_uuid_unparse(&uuid_raw, uuid_calc);
 
     if (safe_str_eq(uuid_calc, unknown)) {
         crm_warn("Could not calculate UUID for %s", uname);
         free(uuid_calc);
         return NULL;
     }
 #endif
     return uuid_calc;
 }
 
 static gboolean
 uname_is_uuid(void)
 {
     static const char *uuid_pref = NULL;
 
     if (uuid_pref == NULL) {
         uuid_pref = getenv("PCMK_uname_is_uuid");
     }
 
     if (uuid_pref == NULL) {
         /* true is legacy mode */
         uuid_pref = "false";
     }
 
     return crm_is_true(uuid_pref);
 }
 
 int
 get_corosync_id(int id, const char *uuid)
 {
     if (id == 0 && !uname_is_uuid() && is_corosync_cluster()) {
         id = crm_atoi(uuid, "0");
     }
 
     return id;
 }
 
 char *
 get_corosync_uuid(uint32_t id, const char *uname)
 {
     if (!uname_is_uuid() && is_corosync_cluster()) {
         if (id <= 0) {
             /* Try the membership cache... */
             crm_node_t *node = g_hash_table_lookup(crm_peer_cache, uname);
 
             if (node != NULL) {
                 id = node->id;
             }
         }
 
         if (id > 0) {
             int len = 32;
             char *buffer = NULL;
 
             buffer = calloc(1, (len + 1));
             if (buffer != NULL) {
                 snprintf(buffer, len, "%u", id);
             }
 
             return buffer;
 
         } else {
             crm_warn("Node %s is not yet known by corosync", uname);
         }
 
     } else if (uname != NULL) {
         return strdup(uname);
     }
 
     return NULL;
 }
 
 void
 set_node_uuid(const char *uname, const char *uuid)
 {
     CRM_CHECK(uuid != NULL, return);
     CRM_CHECK(uname != NULL, return);
 
     if (crm_uuid_cache == NULL) {
         crm_uuid_cache = g_hash_table_new_full(crm_str_hash, g_str_equal,
                                                g_hash_destroy_str, g_hash_destroy_str);
     }
 
     g_hash_table_insert(crm_uuid_cache, strdup(uname), strdup(uuid));
 }
 
 const char *
 get_node_uuid(uint32_t id, const char *uname)
 {
     char *uuid = NULL;
     enum cluster_type_e type = get_cluster_type();
 
     if (crm_uuid_cache == NULL) {
         crm_uuid_cache = g_hash_table_new_full(crm_str_hash, g_str_equal,
                                                g_hash_destroy_str, g_hash_destroy_str);
     }
 
     /* avoid blocking heartbeat calls where possible */
     if (uname) {
         uuid = g_hash_table_lookup(crm_uuid_cache, uname);
     }
     if (uuid != NULL) {
         return uuid;
     }
 
     switch (type) {
         case pcmk_cluster_corosync:
             uuid = get_corosync_uuid(id, uname);
             break;
 
         case pcmk_cluster_cman:
         case pcmk_cluster_classic_ais:
             if (uname) {
                 uuid = strdup(uname);
             }
             break;
 
         case pcmk_cluster_heartbeat:
             uuid = get_heartbeat_uuid(id, uname);
             break;
 
         case pcmk_cluster_unknown:
         case pcmk_cluster_invalid:
             crm_err("Unsupported cluster type");
             break;
     }
 
     if (uuid == NULL) {
         return NULL;
     }
 
     if (uname) {
         g_hash_table_insert(crm_uuid_cache, strdup(uname), uuid);
         return g_hash_table_lookup(crm_uuid_cache, uname);
     }
 
     /* Memory leak! */
     CRM_LOG_ASSERT(uuid != NULL);
     return uuid;
 }
 
 gboolean
 crm_cluster_connect(crm_cluster_t *cluster)
 {
     enum cluster_type_e type = get_cluster_type();
 
     crm_notice("Connecting to cluster infrastructure: %s", name_for_cluster_type(type));
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         crm_peer_init();
         return init_cs_connection(cluster);
     }
 #endif
 
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         int rv;
 
         /* coverity[var_deref_op] False positive */
         if (cluster->hb_conn == NULL) {
             /* No object passed in, create a new one. */
             ll_cluster_t *(*new_cluster) (const char *llctype) =
                 find_library_function(&hb_library, HEARTBEAT_LIBRARY, "ll_cluster_new", 1);
 
             cluster->hb_conn = (*new_cluster) ("heartbeat");
             /* dlclose(handle); */
 
         } else {
             /* Object passed in. Disconnect first, then reconnect below. */
             cluster->hb_conn->llc_ops->signoff(cluster->hb_conn, FALSE);
         }
 
         /* make sure we are disconnected first with the old object, if any. */
         if (heartbeat_cluster && heartbeat_cluster != cluster->hb_conn) {
             heartbeat_cluster->llc_ops->signoff(heartbeat_cluster, FALSE);
         }
 
         CRM_ASSERT(cluster->hb_conn != NULL);
         heartbeat_cluster = cluster->hb_conn;
 
         rv = register_heartbeat_conn(cluster);
         if (rv) {
             /* we'll benefit from a bigger queue length on heartbeat side.
              * Otherwise, if peers send messages faster than we can consume
              * them right now, heartbeat messaging layer will kick us out once
              * it's (small) default queue fills up :(
              * If we fail to adjust the sendq length, that's not yet fatal, though.
              */
             if (HA_OK != heartbeat_cluster->llc_ops->set_sendq_len(heartbeat_cluster, 1024)) {
                 crm_warn("Cannot set sendq length: %s", heartbeat_cluster->llc_ops->errmsg(heartbeat_cluster));
             }
         }
         return rv;
     }
 #endif
     crm_info("Unsupported cluster stack: %s", getenv("HA_cluster_type"));
     return FALSE;
 }
 
 void
 crm_cluster_disconnect(crm_cluster_t *cluster)
 {
     enum cluster_type_e type = get_cluster_type();
     const char *type_str = name_for_cluster_type(type);
 
     crm_info("Disconnecting from cluster infrastructure: %s", type_str);
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         crm_peer_destroy();
         terminate_cs_connection();
         crm_info("Disconnected from %s", type_str);
         return;
     }
 #endif
 
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         if (cluster == NULL) {
             crm_info("No cluster connection");
             return;
 
         } else if (cluster->hb_conn) {
             cluster->hb_conn->llc_ops->signoff(cluster->hb_conn, FALSE);
             cluster->hb_conn = NULL;
             crm_info("Disconnected from %s", type_str);
             return;
 
         } else {
             crm_info("No %s connection", type_str);
             return;
         }
     }
 #endif
     crm_info("Unsupported cluster stack: %s", getenv("HA_cluster_type"));
 }
 
 gboolean
 send_cluster_message(crm_node_t *node, enum crm_ais_msg_types service, xmlNode * data,
                      gboolean ordered)
 {
 
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         return send_ais_message(data, FALSE, node, service);
     }
 #endif
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
-        return send_ha_message(heartbeat_cluster, data, node->uname, ordered);
+        return send_ha_message(heartbeat_cluster, data, node ? node->uname : NULL, ordered);
     }
 #endif
     return FALSE;
 }
 
 void
 empty_uuid_cache(void)
 {
     if (crm_uuid_cache != NULL) {
         g_hash_table_destroy(crm_uuid_cache);
         crm_uuid_cache = NULL;
     }
 }
 
 void
 unget_uuid(const char *uname)
 {
     if (crm_uuid_cache == NULL) {
         return;
     }
     g_hash_table_remove(crm_uuid_cache, uname);
 }
 
 const char *
 get_uuid(const char *uname)
 {
     return get_node_uuid(0, uname);
 }
 
 char *
 get_local_node_name(void)
 {
     int rc;
     char *name = NULL;
     struct utsname res;
     enum cluster_type_e stack = get_cluster_type();
 
     switch(stack) {
 
 #if SUPPORT_CMAN
         case pcmk_cluster_cman:
             name = cman_node_name(0 /* AKA. CMAN_NODEID_US */);
             break;
 #endif
 
 #if SUPPORT_COROSYNC
 # if !SUPPORT_PLUGIN
         case pcmk_cluster_corosync:
             name = corosync_node_name(0, 0);
             break;
 # endif
 #endif
         case pcmk_cluster_heartbeat:
         case pcmk_cluster_classic_ais:
             rc = uname(&res);
             if(rc == 0) {
                 name = strdup(res.nodename);
             }
             break;
         default:
             crm_err("Unknown cluster type: %s (%d)", name_for_cluster_type(stack), stack);
     }
 
     if(name == NULL) {
         crm_err("Could not obtain the local %s node name", name_for_cluster_type(stack));
         exit(100);
     }
     return name;
 }
 
 char *
 get_node_name(uint32_t nodeid)
 {
     char *name = NULL;
     enum cluster_type_e stack = get_cluster_type();
 
     switch (stack) {
         case pcmk_cluster_heartbeat:
             break;
 
 #if SUPPORT_PLUGIN
         case pcmk_cluster_classic_ais:
             name = classic_node_name(nodeid);
             break;
 #else
+#if SUPPORT_COROSYNC
         case pcmk_cluster_corosync:
             name = corosync_node_name(0, nodeid);
             break;
 #endif
+#endif
 
 #if SUPPORT_CMAN
         case pcmk_cluster_cman:
             name = cman_node_name(nodeid);
             break;
 #endif
 
         default:
             crm_err("Unknown cluster type: %s (%d)", name_for_cluster_type(stack), stack);
     }
     
     if(name == NULL) {
         crm_notice("Could not obtain a node name for %s nodeid %u",
                    name_for_cluster_type(stack), nodeid);
     }
     return name;
 }
 
 /* Only used by update_failcount() in te_utils.c */
 const char *
 get_uname(const char *uuid)
 {
     char *uname = NULL;
 
     if (crm_uname_cache == NULL) {
         crm_uname_cache = g_hash_table_new_full(crm_str_hash, g_str_equal,
                                                 g_hash_destroy_str, g_hash_destroy_str);
     }
 
     CRM_CHECK(uuid != NULL, return NULL);
 
     /* avoid blocking calls where possible */
     uname = g_hash_table_lookup(crm_uname_cache, uuid);
     if (uname != NULL) {
         crm_trace("%s = %s (cached)", uuid, uname);
         return uname;
     }
 
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         if (!uname_is_uuid() && is_corosync_cluster()) {
             uint32_t id = crm_int_helper(uuid, NULL);
             crm_node_t *node = g_hash_table_lookup(crm_peer_id_cache, GUINT_TO_POINTER(id));
 
             if(node && node->uname) {
                 uname = strdup(node->uname);
             }
 
         } else {
             uname = strdup(uuid);
         }
     }
 #endif
 
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         if (heartbeat_cluster != NULL) {
             cl_uuid_t uuid_raw;
             char *uuid_copy = strdup(uuid);
 
             cl_uuid_parse(uuid_copy, &uuid_raw);
             uname = malloc( MAX_NAME);
 
             if (heartbeat_cluster->llc_ops->get_name_by_uuid(
                     heartbeat_cluster, &uuid_raw, uname, MAX_NAME) == HA_FAIL) {
                 crm_err("Could not calculate uname for %s", uuid);
                 free(uuid_copy);
                 free(uname);
                 uname = NULL;
             }
         }
     }
 #endif
 
     if (uname) {
         crm_trace("Storing %s = %s", uuid, uname);
         g_hash_table_insert(crm_uname_cache, strdup(uuid), uname);
     }
     return uname;
 }
 
 void
 set_uuid(xmlNode * node, const char *attr, const char *uname)
 {
     const char *uuid_calc = get_uuid(uname);
 
     crm_xml_add(node, attr, uuid_calc);
     return;
 }
 
 const char *
 name_for_cluster_type(enum cluster_type_e type)
 {
     switch (type) {
         case pcmk_cluster_classic_ais:
             return "classic openais (with plugin)";
         case pcmk_cluster_cman:
             return "cman";
         case pcmk_cluster_corosync:
             return "corosync";
         case pcmk_cluster_heartbeat:
             return "heartbeat";
         case pcmk_cluster_unknown:
             return "unknown";
         case pcmk_cluster_invalid:
             return "invalid";
     }
     crm_err("Invalid cluster type: %d", type);
     return "invalid";
 }
 
 /* Do not expose these two */
 int set_cluster_type(enum cluster_type_e type);
 static enum cluster_type_e cluster_type = pcmk_cluster_unknown;
 
 int
 set_cluster_type(enum cluster_type_e type)
 {
     if (cluster_type == pcmk_cluster_unknown) {
         crm_info("Cluster type set to: %s", name_for_cluster_type(type));
         cluster_type = type;
         return 0;
 
     } else if (cluster_type == type) {
         return 0;
 
     } else if (pcmk_cluster_unknown == type) {
         cluster_type = type;
         return 0;
     }
 
     crm_err("Cluster type already set to %s, ignoring %s",
             name_for_cluster_type(cluster_type), name_for_cluster_type(type));
     return -1;
 }
 
 enum cluster_type_e
 get_cluster_type(void)
 {
     if (cluster_type == pcmk_cluster_unknown) {
         const char *cluster = getenv("HA_cluster_type");
 
         cluster_type = pcmk_cluster_invalid;
         if (cluster) {
             crm_info("Cluster type is: '%s'", cluster);
 
         } else {
 #if SUPPORT_COROSYNC
             cluster_type = find_corosync_variant();
             if (cluster_type == pcmk_cluster_unknown) {
                 cluster = "heartbeat";
                 crm_info("Assuming a 'heartbeat' based cluster");
             } else {
                 cluster = name_for_cluster_type(cluster_type);
                 crm_info("Detected an active '%s' cluster", cluster);
             }
 #else
             cluster = "heartbeat";
 #endif
         }
 
         if (safe_str_eq(cluster, "heartbeat")) {
 #if SUPPORT_HEARTBEAT
             cluster_type = pcmk_cluster_heartbeat;
 #else
             cluster_type = pcmk_cluster_invalid;
 #endif
         } else if (safe_str_eq(cluster, "openais")
                    || safe_str_eq(cluster, "classic openais (with plugin)")) {
 #if SUPPORT_COROSYNC
             cluster_type = pcmk_cluster_classic_ais;
 #else
             cluster_type = pcmk_cluster_invalid;
 #endif
         } else if (safe_str_eq(cluster, "corosync")) {
 #if SUPPORT_COROSYNC
             cluster_type = pcmk_cluster_corosync;
 #else
             cluster_type = pcmk_cluster_invalid;
 #endif
         } else if (safe_str_eq(cluster, "cman")) {
 #if SUPPORT_CMAN
             cluster_type = pcmk_cluster_cman;
 #else
             cluster_type = pcmk_cluster_invalid;
 #endif
         } else {
             cluster_type = pcmk_cluster_invalid;
         }
 
         if (cluster_type == pcmk_cluster_invalid) {
             crm_notice
                 ("This installation of Pacemaker does not support the '%s' cluster infrastructure.  Terminating.",
                  cluster);
             exit(100);
         }
     }
     return cluster_type;
 }
 
 gboolean
 is_cman_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_cman;
 }
 
 gboolean
 is_corosync_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_corosync;
 }
 
 gboolean
 is_classic_ais_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_classic_ais;
 }
 
 gboolean
 is_openais_cluster(void)
 {
     enum cluster_type_e type = get_cluster_type();
 
     if (type == pcmk_cluster_classic_ais) {
         return TRUE;
     } else if (type == pcmk_cluster_corosync) {
         return TRUE;
     } else if (type == pcmk_cluster_cman) {
         return TRUE;
     }
     return FALSE;
 }
 
 gboolean
 is_heartbeat_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_heartbeat;
 }
 
 gboolean
 node_name_is_valid(const char *key, const char *name) 
 {
     int octet;
 
     if(name == NULL) {
         crm_trace("%s is empty", key);
         return FALSE;
 
     } else if(sscanf(name, "%d.%d.%d.%d", &octet, &octet, &octet, &octet) == 4) {
         crm_trace("%s contains an ipv4 address, ignoring: %s", key, name);
         return FALSE;
 
     } else if(strstr(name, ":") != NULL) {
         crm_trace("%s contains an ipv6 address, ignoring: %s", key, name);
         return FALSE;
     }
     crm_trace("%s is valid", key);
     return TRUE;
 }
diff --git a/tools/attrd.c b/tools/attrd.c
index f6eec8dbf7..7f05d3852f 100644
--- a/tools/attrd.c
+++ b/tools/attrd.c
@@ -1,916 +1,917 @@
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <grp.h>
 
 #include <crm/crm.h>
 #include <crm/cib/internal.h>
 #include <crm/msg_xml.h>
 #include <crm/common/ipc.h>
 #include <crm/cluster/internal.h>
 #include <crm/common/mainloop.h>
 
 #include <crm/common/xml.h>
 
 #include <crm/attrd.h>
 
 #define OPTARGS	"hV"
 #if SUPPORT_HEARTBEAT
 ll_cluster_t *attrd_cluster_conn;
 #endif
 
 GMainLoop *mainloop = NULL;
 char *attrd_uname = NULL;
 char *attrd_uuid = NULL;
 gboolean need_shutdown = FALSE;
 
 GHashTable *attr_hash = NULL;
 cib_t *cib_conn = NULL;
 
 typedef struct attrd_client_s {
     char *user;
 } attrd_client_t;
 
 typedef struct attr_hash_entry_s {
     char *uuid;
     char *id;
     char *set;
     char *section;
 
     char *value;
     char *stored_value;
 
     int timeout;
     char *dampen;
     guint timer_id;
 
     char *user;
 
 } attr_hash_entry_t;
 
 void attrd_local_callback(xmlNode * msg);
 gboolean attrd_timer_callback(void *user_data);
 gboolean attrd_trigger_update(attr_hash_entry_t * hash_entry);
 void attrd_perform_update(attr_hash_entry_t * hash_entry);
 
 static void
 free_hash_entry(gpointer data)
 {
     attr_hash_entry_t *entry = data;
 
     if (entry == NULL) {
         return;
     }
     free(entry->id);
     free(entry->set);
     free(entry->dampen);
     free(entry->section);
     free(entry->uuid);
     free(entry->value);
     free(entry->stored_value);
     free(entry->user);
     free(entry);
 }
 
 static int32_t
 attrd_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
 {
     attrd_client_t *new_client = NULL;
 #if ENABLE_ACL
     struct group *crm_grp = NULL;
 #endif
 
     crm_trace("Connecting %p for connection from %d by uid=%d gid=%d",
               c, crm_ipcs_client_pid(c), uid, gid);
     if (need_shutdown) {
         crm_info("Ignoring connection request during shutdown");
         return FALSE;
     }
 
     new_client = calloc(1, sizeof(attrd_client_t));
 
 #if ENABLE_ACL
     crm_grp = getgrnam(CRM_DAEMON_GROUP);
     if (crm_grp) {
         qb_ipcs_connection_auth_set(c, -1, crm_grp->gr_gid, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
     }
 
     new_client->user = uid2username(uid);
 #endif
 
     qb_ipcs_context_set(c, new_client);
 
     return 0;
 }
 
 static void
 attrd_ipc_created(qb_ipcs_connection_t *c)
 {
     crm_trace("Client %p connected from %d", c, crm_ipcs_client_pid(c));
 }
 
 /* Exit code means? */
 static int32_t
 attrd_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size)
 {
     uint32_t id = 0;
     uint32_t flags = 0;
 #if ENABLE_ACL
     attrd_client_t *client = qb_ipcs_context_get(c);
 #endif
     xmlNode *msg = crm_ipcs_recv(c, data, size, &id, &flags);
 
     if(flags & crm_ipc_client_response) {
         crm_trace("Ack'ing msg from %d (%p)", crm_ipcs_client_pid(c), c);
         crm_ipcs_send_ack(c, id, "ack", __FUNCTION__, __LINE__);
     }
 
     if (msg == NULL) {
         crm_debug("No msg from %d (%p)", crm_ipcs_client_pid(c), c);
         return 0;
     }
 
 #if ENABLE_ACL
     determine_request_user(client->user, msg, F_ATTRD_USER);
 #endif
 
     crm_trace("Processing msg from %d (%p)", crm_ipcs_client_pid(c), c);
     crm_log_xml_trace(msg, __PRETTY_FUNCTION__);
     
     attrd_local_callback(msg);
     
     free_xml(msg);
     return 0;
 }
 
 /* Error code means? */
 static int32_t
 attrd_ipc_closed(qb_ipcs_connection_t *c) 
 {
     crm_trace("Connection %p from %d closed", c, crm_ipcs_client_pid(c));
     return 0;
 }
 
 static void
 attrd_ipc_destroy(qb_ipcs_connection_t *c) 
 {
     attrd_client_t *client = qb_ipcs_context_get(c);
 
     if (client == NULL) {
         return;
     }
 
     crm_trace("Destroying %p", c);
     free(client->user);
     free(client);
     crm_trace("Free'd the attrd client");
 
     return;
 }
 
 struct qb_ipcs_service_handlers ipc_callbacks = 
 {
     .connection_accept = attrd_ipc_accept,
     .connection_created = attrd_ipc_created,
     .msg_process = attrd_ipc_dispatch,
     .connection_closed = attrd_ipc_closed,
     .connection_destroyed = attrd_ipc_destroy
 };
 
 static void
 attrd_shutdown(int nsig)
 {
     need_shutdown = TRUE;
     crm_info("Exiting");
     if (mainloop != NULL && g_main_is_running(mainloop)) {
         g_main_quit(mainloop);
     } else {
         exit(0);
     }
 }
 
 static void
 usage(const char *cmd, int exit_status)
 {
     FILE *stream;
 
     stream = exit_status ? stderr : stdout;
 
     fprintf(stream, "usage: %s [-srkh] [-c configure file]\n", cmd);
 /* 	fprintf(stream, "\t-d\tsets debug level\n"); */
 /* 	fprintf(stream, "\t-s\tgets daemon status\n"); */
 /* 	fprintf(stream, "\t-r\trestarts daemon\n"); */
 /* 	fprintf(stream, "\t-k\tstops daemon\n"); */
 /* 	fprintf(stream, "\t-h\thelp message\n"); */
     fflush(stream);
 
     exit(exit_status);
 }
 
 static void
 stop_attrd_timer(attr_hash_entry_t * hash_entry)
 {
     if (hash_entry != NULL && hash_entry->timer_id != 0) {
         crm_trace("Stopping %s timer", hash_entry->id);
         g_source_remove(hash_entry->timer_id);
         hash_entry->timer_id = 0;
     }
 }
 
 static void
 log_hash_entry(int level, attr_hash_entry_t * entry, const char *text)
 {
     do_crm_log(level, "%s: Set: %s, Name: %s, Value: %s, Timeout: %s",
                text, entry->section, entry->id, entry->value, entry->dampen);
 }
 
 static attr_hash_entry_t *
 find_hash_entry(xmlNode * msg)
 {
     const char *value = NULL;
     const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE);
     attr_hash_entry_t *hash_entry = NULL;
 
     if (attr == NULL) {
         crm_info("Ignoring message with no attribute name");
         return NULL;
     }
 
     hash_entry = g_hash_table_lookup(attr_hash, attr);
 
     if (hash_entry == NULL) {
         /* create one and add it */
         crm_info("Creating hash entry for %s", attr);
         hash_entry = calloc(1, sizeof(attr_hash_entry_t));
         hash_entry->id = strdup(attr);
 
         g_hash_table_insert(attr_hash, hash_entry->id, hash_entry);
         hash_entry = g_hash_table_lookup(attr_hash, attr);
         CRM_CHECK(hash_entry != NULL, return NULL);
     }
 
     value = crm_element_value(msg, F_ATTRD_SET);
     if (value != NULL) {
         free(hash_entry->set);
         hash_entry->set = strdup(value);
         crm_debug("\t%s->set: %s", attr, value);
     }
 
     value = crm_element_value(msg, F_ATTRD_SECTION);
     if (value == NULL) {
         value = XML_CIB_TAG_STATUS;
     }
     free(hash_entry->section);
     hash_entry->section = strdup(value);
     crm_trace("\t%s->section: %s", attr, value);
 
     value = crm_element_value(msg, F_ATTRD_DAMPEN);
     if (value != NULL) {
         free(hash_entry->dampen);
         hash_entry->dampen = strdup(value);
 
         hash_entry->timeout = crm_get_msec(value);
         crm_trace("\t%s->timeout: %s", attr, value);
     }
 #if ENABLE_ACL
     free(hash_entry->user);
 
     value = crm_element_value(msg, F_ATTRD_USER);
     if (value != NULL) {
         hash_entry->user = strdup(value);
         crm_trace("\t%s->user: %s", attr, value);
     }
 #endif
 
     log_hash_entry(LOG_DEBUG_2, hash_entry, "Found (and updated) entry:");
     return hash_entry;
 }
 
 #if SUPPORT_HEARTBEAT
 static void
 attrd_ha_connection_destroy(gpointer user_data)
 {
     crm_trace("Invoked");
     if (need_shutdown) {
         /* we signed out, so this is expected */
         crm_info("Heartbeat disconnection complete");
         return;
     }
 
     crm_crit("Lost connection to heartbeat service!");
     if (mainloop != NULL && g_main_is_running(mainloop)) {
         g_main_quit(mainloop);
         return;
     }
     exit(EX_OK);
 }
 
 static void
 attrd_ha_callback(HA_Message * msg, void *private_data)
 {
     attr_hash_entry_t *hash_entry = NULL;
     xmlNode *xml = convert_ha_message(NULL, msg, __FUNCTION__);
     const char *from = crm_element_value(xml, F_ORIG);
     const char *op = crm_element_value(xml, F_ATTRD_TASK);
     const char *host = crm_element_value(xml, F_ATTRD_HOST);
     const char *ignore = crm_element_value(xml, F_ATTRD_IGNORE_LOCALLY);
 
     if (host != NULL && safe_str_eq(host, attrd_uname)) {
         crm_info("Update relayed from %s", from);
         attrd_local_callback(xml);
 
     } else if (ignore == NULL || safe_str_neq(from, attrd_uname)) {
         crm_info("%s message from %s", op, from);
         hash_entry = find_hash_entry(xml);
         stop_attrd_timer(hash_entry);
         attrd_perform_update(hash_entry);
     }
     free_xml(xml);
 }
 
 #endif
 
 #if SUPPORT_COROSYNC
 static gboolean
 attrd_ais_dispatch(int kind, const char *from, const char *data)
 {
     xmlNode *xml = NULL;
 
     if (kind == crm_class_cluster) {
         xml = string2xml(data);
         if (xml == NULL) {
             crm_err("Bad message received: '%.120s'", data);
         }
     }
 
     if (xml != NULL) {
         attr_hash_entry_t *hash_entry = NULL;
         const char *op = crm_element_value(xml, F_ATTRD_TASK);
         const char *host = crm_element_value(xml, F_ATTRD_HOST);
         const char *ignore = crm_element_value(xml, F_ATTRD_IGNORE_LOCALLY);
 
         /* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
         crm_xml_add(xml, F_ORIG, from);
 
         if (host != NULL && safe_str_eq(host, attrd_uname)) {
             crm_notice("Update relayed from %s", from);
             attrd_local_callback(xml);
 
         } else if (ignore == NULL || safe_str_neq(from, attrd_uname)) {
             crm_trace("%s message from %s", op, from);
             hash_entry = find_hash_entry(xml);
             stop_attrd_timer(hash_entry);
             attrd_perform_update(hash_entry);
         }
 
         free_xml(xml);
     }
 
     return TRUE;
 }
 
 static void
 attrd_ais_destroy(gpointer unused)
 {
     if (need_shutdown) {
         /* we signed out, so this is expected */
         crm_info("Corosync disconnection complete");
         return;
     }
 
     crm_crit("Lost connection to Corosync service!");
     if (mainloop != NULL && g_main_is_running(mainloop)) {
         g_main_quit(mainloop);
         return;
     }
     exit(EX_USAGE);
 }
 #endif
 
 static void
 attrd_cib_connection_destroy(gpointer user_data)
 {
     cib_t *conn = user_data;
     conn->cmds->signoff(conn); /* Ensure IPC is cleaned up */
 
     if (need_shutdown) {
         crm_info("Connection to the CIB terminated...");
 
     } else {
         /* eventually this will trigger a reconnect, not a shutdown */
         crm_err("Connection to the CIB terminated...");
         exit(1);
     }
 
     return;
 }
 
 static void
 update_for_hash_entry(gpointer key, gpointer value, gpointer user_data)
 {
     attr_hash_entry_t *entry = value;
 
     if (entry->value != NULL) {
         attrd_timer_callback(value);
     }
 }
 
 static void
 local_update_for_hash_entry(gpointer key, gpointer value, gpointer user_data)
 {
     attr_hash_entry_t *entry = value;
 
     if (entry->timer_id == 0) {
         crm_trace("Performing local-only update after replace for %s", entry->id);
         attrd_perform_update(entry);
  /* } else {
   *     just let the timer expire and attrd_timer_callback() will do the right thing
   */
     }
 }
 
 static void
 do_cib_replaced(const char *event, xmlNode * msg)
 {
     crm_info("Updating all attributes after %s event", event);
     g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL);
 }
 
 static gboolean
 cib_connect(void *user_data)
 {
     static int attempts = 1;
     static int max_retry = 20;
     gboolean was_err = FALSE;
     static cib_t *local_conn = NULL;
 
     if (local_conn == NULL) {
         local_conn = cib_new();
     }
 
     if (was_err == FALSE) {
         int rc = -ENOTCONN;
 
         if (attempts < max_retry) {
             crm_debug("CIB signon attempt %d", attempts);
             rc = local_conn->cmds->signon(local_conn, T_ATTRD, cib_command);
         }
 
         if (rc != pcmk_ok && attempts > max_retry) {
             crm_err("Signon to CIB failed: %s", pcmk_strerror(rc));
             was_err = TRUE;
 
         } else if (rc != pcmk_ok) {
             attempts++;
             return TRUE;
         }
     }
 
     crm_info("Connected to the CIB after %d signon attempts", attempts);
 
     if (was_err == FALSE) {
         int rc =
             local_conn->cmds->set_connection_dnotify(local_conn, attrd_cib_connection_destroy);
         if (rc != pcmk_ok) {
             crm_err("Could not set dnotify callback");
             was_err = TRUE;
         }
     }
 
     if (was_err == FALSE) {
         if (pcmk_ok !=
             local_conn->cmds->add_notify_callback(local_conn, T_CIB_REPLACE_NOTIFY,
                                                   do_cib_replaced)) {
             crm_err("Could not set CIB notification callback");
             was_err = TRUE;
         }
     }
 
     if (was_err) {
         crm_err("Aborting startup");
         exit(100);
     }
 
     cib_conn = local_conn;
 
     crm_info("Sending full refresh now that we're connected to the cib");
     g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL);
 
     return FALSE;
 }
 
 int
 main(int argc, char **argv)
 {
     int flag = 0;
     int argerr = 0;
     crm_cluster_t cluster;
     gboolean was_err = FALSE;
     qb_ipcs_connection_t *c = NULL;
     qb_ipcs_service_t *ipcs = NULL;
     
     crm_log_init(T_ATTRD, LOG_NOTICE, TRUE, FALSE, argc, argv, FALSE);
     mainloop_add_signal(SIGTERM, attrd_shutdown);
 
     while ((flag = getopt(argc, argv, OPTARGS)) != EOF) {
         switch (flag) {
             case 'V':
                 crm_bump_log_level(argc, argv);
                 break;
             case 'h':          /* Help message */
                 usage(T_ATTRD, EX_OK);
                 break;
             default:
                 ++argerr;
                 break;
         }
     }
 
     if (optind > argc) {
         ++argerr;
     }
 
     if (argerr) {
         usage(T_ATTRD, EX_USAGE);
     }
 
     attr_hash = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_hash_entry);
 
     crm_info("Starting up");
 
     if (was_err == FALSE) {
 
 #if SUPPORT_COROSYNC
         if (is_openais_cluster()) {
             cluster.destroy = attrd_ais_destroy;
             cluster.cs_dispatch = attrd_ais_dispatch;
         }
 #endif
 
 #if SUPPORT_HEARTBEAT
         if (is_heartbeat_cluster()) {
+            cluster.hb_conn = NULL;
             cluster.hb_dispatch = attrd_ha_callback;
             cluster.destroy = attrd_ha_connection_destroy;
         }
 #endif
 
         if (FALSE == crm_cluster_connect(&cluster)) {
             crm_err("HA Signon failed");
             was_err = TRUE;
         }
 
         attrd_uname = cluster.uname;
         attrd_uuid = cluster.uuid;
 #if SUPPORT_HEARTBEAT
         attrd_cluster_conn = cluster.hb_conn;
 #endif
     }
 
     crm_info("Cluster connection active");
 
     if (was_err == FALSE) {
         ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, &ipc_callbacks);
         if (ipcs == NULL) {
             crm_err("Could not start IPC server");
             was_err = TRUE;
         }
     }
 
     crm_info("Accepting attribute updates");
 
     mainloop = g_main_new(FALSE);
 
     if (0 == g_timeout_add_full(G_PRIORITY_LOW + 1, 5000, cib_connect, NULL, NULL)) {
         crm_info("Adding timer failed");
         was_err = TRUE;
     }
 
     if (was_err) {
         crm_err("Aborting startup");
         return 100;
     }
 
     crm_notice("Starting mainloop...");
     g_main_run(mainloop);
     crm_notice("Exiting...");
 
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         attrd_cluster_conn->llc_ops->signoff(attrd_cluster_conn, TRUE);
         attrd_cluster_conn->llc_ops->delete(attrd_cluster_conn);
     }
 #endif
 
     c = qb_ipcs_connection_first_get(ipcs);
     while(c != NULL) {
         qb_ipcs_connection_t *last = c;
         c = qb_ipcs_connection_next_get(ipcs, last);
 
         /* There really shouldn't be anyone connected at this point */
         crm_notice("Disconnecting client %p, pid=%d...", last, crm_ipcs_client_pid(last));
         qb_ipcs_disconnect(last);
         qb_ipcs_connection_unref(last);
     }
 
     qb_ipcs_destroy(ipcs);
     
     if (cib_conn) {
         cib_conn->cmds->signoff(cib_conn);
         cib_delete(cib_conn);
     }
 
     g_hash_table_destroy(attr_hash);
     free(attrd_uuid);
     empty_uuid_cache();
 
     qb_log_fini();
     return 0;
 }
 
 struct attrd_callback_s {
     char *attr;
     char *value;
 };
 
 static void
 attrd_cib_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     attr_hash_entry_t *hash_entry = NULL;
     struct attrd_callback_s *data = user_data;
 
     if(call_id < 0) {
         crm_warn("Update %s=%s failed: %s", data->attr, data->value, pcmk_strerror(call_id));
         goto cleanup;
 
     } else if (data->value == NULL && rc == -ENXIO) {
         rc = pcmk_ok;
     }
 
     switch (rc) {
         case pcmk_ok:
             crm_debug("Update %d for %s=%s passed", call_id, data->attr, data->value);
             hash_entry = g_hash_table_lookup(attr_hash, data->attr);
 
             if (hash_entry) {
                 free(hash_entry->stored_value);
                 hash_entry->stored_value = NULL;
                 if (data->value != NULL) {
                     hash_entry->stored_value = strdup(data->value);
                 }
             }
             break;
         case -pcmk_err_diff_failed:  /* When an attr changes while the CIB is syncing */
         case -ETIME:       /* When an attr changes while there is a DC election */
         case -ENXIO:    /* When an attr changes while the CIB is syncing a
                                  *   newer config from a node that just came up
                                  */
             crm_warn("Update %d for %s=%s failed: %s",
                      call_id, data->attr, data->value, pcmk_strerror(rc));
             break;
         default:
             crm_err("Update %d for %s=%s failed: %s",
                     call_id, data->attr, data->value, pcmk_strerror(rc));
     }
   cleanup:
     free(data->value);
     free(data->attr);
     free(data);
 }
 
 void
 attrd_perform_update(attr_hash_entry_t * hash_entry)
 {
     int rc = pcmk_ok;
     struct attrd_callback_s *data = NULL;
     const char *user_name = NULL;
 
     if (hash_entry == NULL) {
         return;
 
     } else if (cib_conn == NULL) {
         crm_info("Delaying operation %s=%s: cib not connected", hash_entry->id,
                  crm_str(hash_entry->value));
         return;
 
     }
 #if ENABLE_ACL
     if (hash_entry->user) {
         user_name = hash_entry->user;
         crm_trace("Performing request from user '%s'", hash_entry->user);
     }
 #endif
 
     if (hash_entry->value == NULL) {
         /* delete the attr */
         rc = delete_attr_delegate(cib_conn, cib_none, hash_entry->section, attrd_uuid, NULL,
                                   hash_entry->set, hash_entry->uuid, hash_entry->id, NULL, FALSE,
                                   user_name);
 
         if (rc >= 0 && hash_entry->stored_value) {
             crm_notice("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s",
                        rc, attrd_uuid, hash_entry->id,
                        hash_entry->uuid ? hash_entry->uuid : "<n/a>", hash_entry->set,
                        hash_entry->section);
 
         } else if (rc < 0 && rc != -ENXIO) {
             crm_notice
                 ("Delete operation failed: node=%s, attr=%s, id=%s, set=%s, section=%s: %s (%d)",
                  attrd_uuid, hash_entry->id, hash_entry->uuid ? hash_entry->uuid : "<n/a>",
                  hash_entry->set, hash_entry->section, pcmk_strerror(rc), rc);
 
         } else {
             crm_trace("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s",
                         rc, attrd_uuid, hash_entry->id,
                         hash_entry->uuid ? hash_entry->uuid : "<n/a>", hash_entry->set,
                         hash_entry->section);
         }
 
     } else {
         /* send update */
         rc = update_attr_delegate(cib_conn, cib_none, hash_entry->section,
                                   attrd_uuid, NULL, hash_entry->set, hash_entry->uuid,
                                   hash_entry->id, hash_entry->value, FALSE, user_name);
         if (rc < 0) {
             crm_notice("Sent update %s=%s failed: %s", hash_entry->id, hash_entry->value, pcmk_strerror(rc));
         } if (safe_str_neq(hash_entry->value, hash_entry->stored_value) || rc < 0) {
             crm_notice("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value);
         } else {
             crm_trace("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value);
         }
     }
 
     data = calloc(1, sizeof(struct attrd_callback_s));
     data->attr = strdup(hash_entry->id);
     if (hash_entry->value != NULL) {
         data->value = strdup(hash_entry->value);
     }
     add_cib_op_callback(cib_conn, rc, FALSE, data, attrd_cib_callback);
 
     return;
 }
 
 void
 attrd_local_callback(xmlNode * msg)
 {
     static int plus_plus_len = 5;
     attr_hash_entry_t *hash_entry = NULL;
     const char *from = crm_element_value(msg, F_ORIG);
     const char *op = crm_element_value(msg, F_ATTRD_TASK);
     const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE);
     const char *value = crm_element_value(msg, F_ATTRD_VALUE);
     const char *host = crm_element_value(msg, F_ATTRD_HOST);
 
     if (safe_str_eq(op, "refresh")) {
         crm_notice("Sending full refresh (origin=%s)", from);
         g_hash_table_foreach(attr_hash, update_for_hash_entry, NULL);
         return;
     }
 
     if (host != NULL && safe_str_neq(host, attrd_uname)) {
         send_cluster_message(crm_get_peer(0, host), crm_msg_attrd, msg, FALSE);
         return;
     }
 
     crm_debug("%s message from %s: %s=%s", op, from, attr, crm_str(value));
     hash_entry = find_hash_entry(msg);
     if (hash_entry == NULL) {
         return;
     }
 
     if (hash_entry->uuid == NULL) {
         const char *key = crm_element_value(msg, F_ATTRD_KEY);
 
         if (key) {
             hash_entry->uuid = strdup(key);
         }
     }
 
     crm_debug("Supplied: %s, Current: %s, Stored: %s",
               value, hash_entry->value, hash_entry->stored_value);
 
     if (safe_str_eq(value, hash_entry->value)
         && safe_str_eq(value, hash_entry->stored_value)) {
         crm_trace("Ignoring non-change");
         return;
 
     } else if (value) {
         int offset = 1;
         int int_value = 0;
         int value_len = strlen(value);
 
         if (value_len < (plus_plus_len + 2)
             || value[plus_plus_len] != '+'
             || (value[plus_plus_len + 1] != '+' && value[plus_plus_len + 1] != '=')) {
             goto set_unexpanded;
         }
 
         int_value = char2score(hash_entry->value);
         if (value[plus_plus_len + 1] != '+') {
             const char *offset_s = value + (plus_plus_len + 2);
 
             offset = char2score(offset_s);
         }
         int_value += offset;
 
         if (int_value > INFINITY) {
             int_value = INFINITY;
         }
 
         crm_info("Expanded %s=%s to %d", attr, value, int_value);
         crm_xml_add_int(msg, F_ATTRD_VALUE, int_value);
         value = crm_element_value(msg, F_ATTRD_VALUE);
     }
 
   set_unexpanded:
     if (safe_str_eq(value, hash_entry->value) && hash_entry->timer_id) {
         /* We're already waiting to set this value */
         return;
     }
 
     free(hash_entry->value);
     hash_entry->value = NULL;
     if (value != NULL) {
         hash_entry->value = strdup(value);
         crm_debug("New value of %s is %s", attr, value);
     }
 
     stop_attrd_timer(hash_entry);
 
     if (hash_entry->timeout > 0) {
         hash_entry->timer_id = g_timeout_add(hash_entry->timeout, attrd_timer_callback, hash_entry);
     } else {
         attrd_trigger_update(hash_entry);
     }
 
     return;
 }
 
 gboolean
 attrd_timer_callback(void *user_data)
 {
     stop_attrd_timer(user_data);
     attrd_trigger_update(user_data);
     return TRUE;                /* Always return true, removed cleanly by stop_attrd_timer() */
 }
 
 gboolean
 attrd_trigger_update(attr_hash_entry_t * hash_entry)
 {
     xmlNode *msg = NULL;
 
     /* send HA message to everyone */
     crm_notice("Sending flush op to all hosts for: %s (%s)",
                hash_entry->id, crm_str(hash_entry->value));
     log_hash_entry(LOG_DEBUG_2, hash_entry, "Sending flush op to all hosts for:");
 
     msg = create_xml_node(NULL, __FUNCTION__);
     crm_xml_add(msg, F_TYPE, T_ATTRD);
     crm_xml_add(msg, F_ORIG, attrd_uname);
     crm_xml_add(msg, F_ATTRD_TASK, "flush");
     crm_xml_add(msg, F_ATTRD_ATTRIBUTE, hash_entry->id);
     crm_xml_add(msg, F_ATTRD_SET, hash_entry->set);
     crm_xml_add(msg, F_ATTRD_SECTION, hash_entry->section);
     crm_xml_add(msg, F_ATTRD_DAMPEN, hash_entry->dampen);
     crm_xml_add(msg, F_ATTRD_VALUE, hash_entry->value);
 #if ENABLE_ACL
     if (hash_entry->user) {
         crm_xml_add(msg, F_ATTRD_USER, hash_entry->user);
     }
 #endif
 
     if (hash_entry->timeout <= 0) {
         crm_xml_add(msg, F_ATTRD_IGNORE_LOCALLY, hash_entry->value);
         attrd_perform_update(hash_entry);
     }
 
     send_cluster_message(NULL, crm_msg_attrd, msg, FALSE);
     free_xml(msg);
 
     return TRUE;
 }