diff --git a/crmd/lrm_state.c b/crmd/lrm_state.c
index 3db5a21f52..ef2c101992 100644
--- a/crmd/lrm_state.c
+++ b/crmd/lrm_state.c
@@ -1,704 +1,704 @@
 /* 
  * Copyright (C) 2012 David Vossel <dvossel@redhat.com>
  * 
  * 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 <crm/crm.h>
 #include <crm/msg_xml.h>
 
 #include <crmd.h>
 #include <crmd_fsa.h>
 #include <crmd_messages.h>
 #include <crmd_callbacks.h>
 #include <crmd_lrm.h>
 
 GHashTable *lrm_state_table = NULL;
 GHashTable *proxy_table = NULL;
 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
 
 typedef struct remote_proxy_s {
     char *node_name;
     char *session_id;
 
     gboolean is_local;
 
     crm_ipc_t *ipc;
     mainloop_io_t *source;
 
 } remote_proxy_t;
 
 static void
 history_cache_destroy(gpointer data)
 {
     rsc_history_t *entry = data;
 
     if (entry->stop_params) {
         g_hash_table_destroy(entry->stop_params);
     }
 
     free(entry->rsc.type);
     free(entry->rsc.class);
     free(entry->rsc.provider);
 
     lrmd_free_event(entry->failed);
     lrmd_free_event(entry->last);
     free(entry->id);
     free(entry);
 }
 static void
 free_rsc_info(gpointer value)
 {
     lrmd_rsc_info_t *rsc_info = value;
 
     lrmd_free_rsc_info(rsc_info);
 }
 
 static void
 free_deletion_op(gpointer value)
 {
     struct pending_deletion_op_s *op = value;
 
     free(op->rsc);
     delete_ha_msg_input(op->input);
     free(op);
 }
 
 static void
 free_recurring_op(gpointer value)
 {
     struct recurring_op_s *op = (struct recurring_op_s *)value;
 
     free(op->rsc_id);
     free(op->op_type);
     free(op->op_key);
     free(op);
 }
 
 lrm_state_t *
 lrm_state_create(const char *node_name)
 {
     lrm_state_t *state = NULL;
 
     if (!node_name) {
         crm_err("No node name given for lrm state object");
         return NULL;
     }
 
     state = calloc(1, sizeof(lrm_state_t));
     if (!state) {
         return NULL;
     }
 
     state->node_name = strdup(node_name);
 
     state->rsc_info_cache = g_hash_table_new_full(crm_str_hash,
                                                 g_str_equal, NULL, free_rsc_info);
 
     state->deletion_ops = g_hash_table_new_full(crm_str_hash,
                                                 g_str_equal, g_hash_destroy_str, free_deletion_op);
 
     state->pending_ops = g_hash_table_new_full(crm_str_hash,
                                                g_str_equal, g_hash_destroy_str, free_recurring_op);
 
     state->resource_history = g_hash_table_new_full(crm_str_hash,
                                                     g_str_equal, NULL, history_cache_destroy);
 
     g_hash_table_insert(lrm_state_table, (char *)state->node_name, state);
     return state;
 
 }
 
 void
 lrm_state_destroy(const char *node_name)
 {
     g_hash_table_remove(lrm_state_table, node_name);
 }
 
 static gboolean
 remote_proxy_remove_by_node(gpointer key, gpointer value, gpointer user_data)
 {
     remote_proxy_t *proxy = value;
     const char *node_name = user_data;
 
     if (safe_str_eq(node_name, proxy->node_name)) {
         return TRUE;
     }
 
     return FALSE;
 }
 
 static void
 internal_lrm_state_destroy(gpointer data)
 {
     lrm_state_t *lrm_state = data;
 
     if (!lrm_state) {
         return;
     }
 
     crm_trace("Destroying proxy table with %d members", g_hash_table_size(proxy_table));
     g_hash_table_foreach_remove(proxy_table, remote_proxy_remove_by_node, (char *) lrm_state->node_name);
     remote_ra_cleanup(lrm_state);
     lrmd_api_delete(lrm_state->conn);
 
     if (lrm_state->rsc_info_cache) {
         crm_trace("Destroying rsc info cache with %d members", g_hash_table_size(lrm_state->rsc_info_cache));
         g_hash_table_destroy(lrm_state->rsc_info_cache);
     }
     if (lrm_state->resource_history) {
         crm_trace("Destroying history op cache with %d members", g_hash_table_size(lrm_state->resource_history));
         g_hash_table_destroy(lrm_state->resource_history);
     }
     if (lrm_state->deletion_ops) {
         crm_trace("Destroying deletion op cache with %d members", g_hash_table_size(lrm_state->deletion_ops));
         g_hash_table_destroy(lrm_state->deletion_ops);
     }
     if (lrm_state->pending_ops) {
         crm_trace("Destroying pending op cache with %d members", g_hash_table_size(lrm_state->pending_ops));
         g_hash_table_destroy(lrm_state->pending_ops);
     }
 
     free((char *)lrm_state->node_name);
     free(lrm_state);
 }
 
 void
 lrm_state_reset_tables(lrm_state_t * lrm_state)
 {
     if (lrm_state->resource_history) {
         crm_trace("Re-setting history op cache with %d members",
                   g_hash_table_size(lrm_state->resource_history));
         g_hash_table_remove_all(lrm_state->resource_history);
     }
     if (lrm_state->deletion_ops) {
         crm_trace("Re-setting deletion op cache with %d members",
                   g_hash_table_size(lrm_state->deletion_ops));
         g_hash_table_remove_all(lrm_state->deletion_ops);
     }
     if (lrm_state->pending_ops) {
         crm_trace("Re-setting pending op cache with %d members",
                   g_hash_table_size(lrm_state->pending_ops));
         g_hash_table_remove_all(lrm_state->pending_ops);
     }
     if (lrm_state->rsc_info_cache) {
         crm_trace("Re-setting rsc info cache with %d members",
                   g_hash_table_size(lrm_state->rsc_info_cache));
         g_hash_table_remove_all(lrm_state->rsc_info_cache);
     }
 }
 
 static void
 remote_proxy_free(gpointer data)
 {
     remote_proxy_t *proxy = data;
     crm_debug("Signing out of the IPC Service");
 
     if (proxy->source != NULL) {
         mainloop_del_ipc_client(proxy->source);
     }
 
     free(proxy->node_name);
     free(proxy->session_id);
 }
 
 gboolean
 lrm_state_init_local(void)
 {
     if (lrm_state_table) {
         return TRUE;
     }
 
     lrm_state_table =
         g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, internal_lrm_state_destroy);
     if (!lrm_state_table) {
         return FALSE;
     }
 
     proxy_table =
         g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, remote_proxy_free);
     if (!proxy_table) {
          g_hash_table_destroy(lrm_state_table);
         return FALSE;
     }
 
     return TRUE;
 }
 
 void
 lrm_state_destroy_all(void)
 {
     if (lrm_state_table) {
         crm_trace("Destroying state table with %d members", g_hash_table_size(lrm_state_table));
         g_hash_table_destroy(lrm_state_table); lrm_state_table = NULL;
     }
     if(proxy_table) {
         crm_trace("Destroying proxy table with %d members", g_hash_table_size(proxy_table));
         g_hash_table_destroy(proxy_table); proxy_table = NULL;
     }
 }
 
 lrm_state_t *
 lrm_state_find(const char *node_name)
 {
     if (!node_name) {
         return NULL;
     }
     return g_hash_table_lookup(lrm_state_table, node_name);
 }
 
 lrm_state_t *
 lrm_state_find_or_create(const char *node_name)
 {
     lrm_state_t *lrm_state;
 
     lrm_state = g_hash_table_lookup(lrm_state_table, node_name);
     if (!lrm_state) {
         lrm_state = lrm_state_create(node_name);
     }
 
     return lrm_state;
 }
 
 GList *
 lrm_state_get_list(void)
 {
     return g_hash_table_get_values(lrm_state_table);
 }
 
 void
 lrm_state_disconnect(lrm_state_t * lrm_state)
 {
     if (!lrm_state->conn) {
         return;
     }
     ((lrmd_t *) lrm_state->conn)->cmds->disconnect(lrm_state->conn);
     lrmd_api_delete(lrm_state->conn);
     lrm_state->conn = NULL;
 }
 
 int
 lrm_state_is_connected(lrm_state_t * lrm_state)
 {
     if (!lrm_state->conn) {
         return FALSE;
     }
     return ((lrmd_t *) lrm_state->conn)->cmds->is_connected(lrm_state->conn);
 }
 
 int
 lrm_state_poke_connection(lrm_state_t * lrm_state)
 {
 
     if (!lrm_state->conn) {
         return -1;
     }
     return ((lrmd_t *) lrm_state->conn)->cmds->poke_connection(lrm_state->conn);
 }
 
 int
 lrm_state_ipc_connect(lrm_state_t * lrm_state)
 {
     int ret;
 
     if (!lrm_state->conn) {
         lrm_state->conn = lrmd_api_new();
         ((lrmd_t *) lrm_state->conn)->cmds->set_callback(lrm_state->conn, lrm_op_callback);
     }
 
     ret = ((lrmd_t *) lrm_state->conn)->cmds->connect(lrm_state->conn, CRM_SYSTEM_CRMD, NULL);
 
     if (ret != pcmk_ok) {
         lrm_state->num_lrm_register_fails++;
     } else {
         lrm_state->num_lrm_register_fails = 0;
     }
 
     return ret;
 }
 
 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, "destroy");
     crm_xml_add(msg, F_LRMD_IPC_SESSION, session_id);
     lrmd_internal_proxy_send(lrmd, msg);
     free_xml(msg);
 }
 
 static void
 remote_proxy_relay_event(lrmd_t *lrmd, const char *session_id, 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, "event");
     crm_xml_add(event, F_LRMD_IPC_SESSION, session_id);
     add_message_xml(event, F_LRMD_IPC_MSG, msg);
     lrmd_internal_proxy_send(lrmd, event);
     free_xml(event);
 }
 
 static void
 remote_proxy_relay_response(lrmd_t *lrmd, const char *session_id, 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, "response");
     crm_xml_add(response, F_LRMD_IPC_SESSION, 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(lrmd, response);
     free_xml(response);
 }
 
 static int
 remote_proxy_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
 {
     xmlNode *xml = NULL;
     remote_proxy_t *proxy = userdata;
     lrm_state_t *lrm_state = lrm_state_find(proxy->node_name);
 
     if (lrm_state == NULL) {
         return 0;
     }
 
     xml = string2xml(buffer);
     if (xml == NULL) {
         crm_warn("Received a NULL msg from IPC service.");
         return 1;
     }
 
     remote_proxy_relay_event(lrm_state->conn, proxy->session_id, xml);
     free_xml(xml);
     return 1;
 }
 
 static void
 remote_proxy_disconnected(void *userdata)
 {
     remote_proxy_t *proxy = userdata;
     lrm_state_t *lrm_state = lrm_state_find(proxy->node_name);
 
     crm_trace("destroying %p", userdata);
 
     proxy->source = NULL;
     proxy->ipc = NULL;
 
     if (lrm_state && lrm_state->conn) {
         remote_proxy_notify_destroy(lrm_state->conn, proxy->session_id);
     }
     g_hash_table_remove(proxy_table, proxy->session_id);
 }
 
 static remote_proxy_t *
 remote_proxy_new(const char *node_name, const char *session_id, const char *channel)
 {
     static struct ipc_client_callbacks proxy_callbacks = {
         .dispatch = remote_proxy_dispatch_internal,
         .destroy = remote_proxy_disconnected
     };
     remote_proxy_t *proxy = calloc(1, sizeof(remote_proxy_t));
 
     proxy->node_name = strdup(node_name);
     proxy->session_id = strdup(session_id);
 
     if (safe_str_eq(channel, CRM_SYSTEM_CRMD)) {
         proxy->is_local = TRUE;
     } else {
-        proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, &proxy_callbacks);
+        proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, proxy, &proxy_callbacks);
         proxy->ipc = mainloop_get_ipc_client(proxy->source);
 
         if (proxy->source == NULL) {
             remote_proxy_free(proxy);
             return NULL;
         }
     }
 
     g_hash_table_insert(proxy_table, proxy->session_id, proxy);
 
     return proxy;
 }
 
 gboolean
 crmd_is_proxy_session(const char *session)
 {
     return g_hash_table_lookup(proxy_table, session) ? TRUE : FALSE;
 }
 
 void
 crmd_proxy_send(const char *session, xmlNode *msg)
 {
     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
     lrm_state_t *lrm_state = NULL;
 
     if (!proxy) {
         return;
     }
     lrm_state = lrm_state_find(proxy->node_name);
     if (lrm_state) {
         remote_proxy_relay_event(lrm_state->conn, session, msg);
     }
 }
 
 static void
 crmd_proxy_dispatch(const char *user,
                     const char *session,
                     xmlNode *msg)
 {
 
 #if ENABLE_ACL
     determine_request_user(user, msg, F_CRM_USER);
 #endif
     crm_log_xml_trace(msg, "CRMd-PROXY[inbound]");
 
     crm_xml_add(msg, F_CRM_SYS_FROM, session);
     if (crmd_authorize_message(msg, NULL, session)) {
         route_message(C_IPC_MESSAGE, msg);
     }
 
     trigger_fsa(fsa_source);
 }
 
 static void
 remote_proxy_cb(lrmd_t *lrmd, void *userdata, xmlNode *msg)
 {
     lrm_state_t *lrm_state = userdata;
     xmlNode *op_reply = NULL;
     const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
     const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
     const char *user = crm_element_value(msg, F_LRMD_IPC_USER);
     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, "new")) {
         const char *channel = crm_element_value(msg, F_LRMD_IPC_IPC_SERVER);
 
         CRM_CHECK(channel != NULL, return);
 
         if (remote_proxy_new(lrm_state->node_name, session, channel) == NULL) {
             remote_proxy_notify_destroy(lrmd, session);
         }
         crm_info("new remote proxy client established, session id %s", session);
     } else if (safe_str_eq(op, "destroy")) {
         g_hash_table_remove(proxy_table, session);
 
     } else if (safe_str_eq(op, "request")) {
         int flags = 0;
         xmlNode *request = get_message_xml(msg, F_LRMD_IPC_MSG);
         remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
 
         CRM_CHECK(request != NULL, return);
 
         if (proxy == NULL) {
             /* proxy connection no longer exists */
             remote_proxy_notify_destroy(lrmd, session);
             return;
         } else if ((proxy->is_local == FALSE) && (crm_ipc_connected(proxy->ipc) == FALSE)) {
             g_hash_table_remove(proxy_table, session);
             return;
         }
         crm_element_value_int(msg, F_LRMD_IPC_MSG_FLAGS, &flags);
 
         if (proxy->is_local) {
             /* this is for the crmd, which we are, so don't try
              * and connect/send to ourselves over ipc. instead
              * do it directly. */
             if (flags & crm_ipc_client_response) {
                 op_reply = create_xml_node(NULL, "ack");
                 crm_xml_add(op_reply, "function", __FUNCTION__);
                 crm_xml_add_int(op_reply, "line", __LINE__);
             }
             crmd_proxy_dispatch(user, session, request);
         } else {
             /* TODO make this async. */
             crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
         }
     }
 
     if (op_reply) {
         remote_proxy_relay_response(lrmd, session, op_reply, msg_id);
         free_xml(op_reply);
     }
 }
 
 int
 lrm_state_remote_connect_async(lrm_state_t * lrm_state, const char *server, int port,
                                int timeout_ms)
 {
     int ret;
 
     if (!lrm_state->conn) {
         lrm_state->conn = lrmd_remote_api_new(lrm_state->node_name, server, port);
         if (!lrm_state->conn) {
             return -1;
         }
         ((lrmd_t *) lrm_state->conn)->cmds->set_callback(lrm_state->conn, remote_lrm_op_callback);
         lrmd_internal_set_proxy_callback(lrm_state->conn, lrm_state, remote_proxy_cb);
     }
 
     crm_trace("initiating remote connection to %s at %d with timeout %d", server, port, timeout_ms);
     ret =
         ((lrmd_t *) lrm_state->conn)->cmds->connect_async(lrm_state->conn, lrm_state->node_name,
                                                           timeout_ms);
 
     if (ret != pcmk_ok) {
         lrm_state->num_lrm_register_fails++;
     } else {
         lrm_state->num_lrm_register_fails = 0;
     }
 
     return ret;
 }
 
 int
 lrm_state_get_metadata(lrm_state_t * lrm_state,
                        const char *class,
                        const char *provider,
                        const char *agent, char **output, enum lrmd_call_options options)
 {
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
 
     /* Optimize this... only retrieve metadata from local lrmd connection. Perhaps consider
      * caching result. */
     return ((lrmd_t *) lrm_state->conn)->cmds->get_metadata(lrm_state->conn, class, provider, agent,
                                                             output, options);
 }
 
 int
 lrm_state_cancel(lrm_state_t * lrm_state, const char *rsc_id, const char *action, int interval)
 {
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
 
     /* Optimize this, cancel requires a synced request/response to the server.
      * Figure out a way to make this async. */
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         return remote_ra_cancel(lrm_state, rsc_id, action, interval);
     }
     return ((lrmd_t *) lrm_state->conn)->cmds->cancel(lrm_state->conn, rsc_id, action, interval);
 }
 
 lrmd_rsc_info_t *
 lrm_state_get_rsc_info(lrm_state_t * lrm_state, const char *rsc_id, enum lrmd_call_options options)
 {
     lrmd_rsc_info_t *rsc = NULL;
 
     if (!lrm_state->conn) {
         return NULL;
     }
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         return remote_ra_get_rsc_info(lrm_state, rsc_id);
     }
 
     rsc = g_hash_table_lookup(lrm_state->rsc_info_cache, rsc_id);
     if (rsc == NULL) {
         /* only contact the lrmd if we don't already have a cached rsc info */
         rsc = ((lrmd_t *) lrm_state->conn)->cmds->get_rsc_info(lrm_state->conn, rsc_id, options);
         if (rsc == NULL) {
 		    return NULL;
         }
         /* cache the result */
         g_hash_table_insert(lrm_state->rsc_info_cache, rsc->id, rsc);
     }
 
     return lrmd_copy_rsc_info(rsc);
 
 }
 
 int
 lrm_state_exec(lrm_state_t * lrm_state, const char *rsc_id, const char *action, const char *userdata, int interval,     /* ms */
                int timeout,     /* ms */
                int start_delay, /* ms */
                lrmd_key_value_t * params)
 {
 
     if (!lrm_state->conn) {
         lrmd_key_value_freeall(params);
         return -ENOTCONN;
     }
 
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         return remote_ra_exec(lrm_state,
                               rsc_id, action, userdata, interval, timeout, start_delay, params);
     }
 
     return ((lrmd_t *) lrm_state->conn)->cmds->exec(lrm_state->conn,
                                                     rsc_id,
                                                     action,
                                                     userdata,
                                                     interval,
                                                     timeout,
                                                     start_delay,
                                                     lrmd_opt_notify_changes_only, params);
 }
 
 int
 lrm_state_register_rsc(lrm_state_t * lrm_state,
                        const char *rsc_id,
                        const char *class,
                        const char *provider, const char *agent, enum lrmd_call_options options)
 {
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
 
     /* optimize this... this function is a synced round trip from client to daemon.
      * The crmd/lrm.c code path should be re-factored to allow the register of resources
      * to be performed async. The lrmd client api needs to make an async version
      * of register available. */
     if (is_remote_lrmd_ra(agent, provider, NULL)) {
         return lrm_state_find_or_create(rsc_id) ? pcmk_ok : -1;
     }
 
     return ((lrmd_t *) lrm_state->conn)->cmds->register_rsc(lrm_state->conn, rsc_id, class,
                                                             provider, agent, options);
 }
 
 int
 lrm_state_unregister_rsc(lrm_state_t * lrm_state,
                          const char *rsc_id, enum lrmd_call_options options)
 {
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
 
     /* optimize this... this function is a synced round trip from client to daemon.
      * The crmd/lrm.c code path that uses this function should always treat it as an
      * async operation. The lrmd client api needs to make an async version unreg available. */
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         lrm_state_destroy(rsc_id);
         return pcmk_ok;
     }
 
     g_hash_table_remove(lrm_state->rsc_info_cache, rsc_id);
 
     return ((lrmd_t *) lrm_state->conn)->cmds->unregister_rsc(lrm_state->conn, rsc_id, options);
 }
diff --git a/crmd/pengine.c b/crmd/pengine.c
index 2f3eba85b3..0e3caafa5b 100644
--- a/crmd/pengine.c
+++ b/crmd/pengine.c
@@ -1,298 +1,297 @@
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <crm/crm.h>
 #include <crmd_fsa.h>
 
 #include <sys/types.h>
 #include <sys/wait.h>
 
 #include <unistd.h>             /* for access */
 
 #include <sys/types.h>          /* for calls to open */
 #include <sys/stat.h>           /* for calls to open */
 #include <fcntl.h>              /* for calls to open */
 #include <pwd.h>                /* for getpwuid */
 #include <grp.h>                /* for initgroups */
 
 #include <sys/time.h>           /* for getrlimit */
 #include <sys/resource.h>       /* for getrlimit */
 
 #include <errno.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/cluster.h>
 #include <crmd_messages.h>
 #include <crmd_callbacks.h>
 
 #include <crm/cib.h>
 #include <crmd.h>
 
 struct crm_subsystem_s *pe_subsystem = NULL;
 void do_pe_invoke_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data);
 
 static void
 save_cib_contents(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     char *id = user_data;
 
     register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
     CRM_CHECK(id != NULL, return);
 
     if (rc == pcmk_ok) {
         int len = 15;
         char *filename = NULL;
 
         len += strlen(id);
         len += strlen(PE_STATE_DIR);
 
         filename = calloc(1, len);
         CRM_CHECK(filename != NULL, return);
 
         sprintf(filename, PE_STATE_DIR "/pe-core-%s.bz2", id);
         if (write_xml_file(output, filename, TRUE) < 0) {
             crm_err("Could not save CIB contents after PE crash to %s", filename);
         } else {
             crm_notice("Saved CIB contents after PE crash to %s", filename);
         }
 
         free(filename);
     }
 
     free(id);
 }
 
 static void
 pe_ipc_destroy(gpointer user_data)
 {
     clear_bit(fsa_input_register, pe_subsystem->flag_connected);
     if (is_set(fsa_input_register, pe_subsystem->flag_required)) {
         int rc = pcmk_ok;
         char *uuid_str = crm_generate_uuid();
 
         crm_crit("Connection to the Policy Engine failed (pid=%d, uuid=%s)",
                  pe_subsystem->pid, uuid_str);
 
         /*
          *The PE died...
          *
          * Save the current CIB so that we have a chance of
          * figuring out what killed it.
          *
          * Delay raising the I_ERROR until the query below completes or
          * 5s is up, whichever comes first.
          *
          */
         rc = fsa_cib_conn->cmds->query(fsa_cib_conn, NULL, NULL, cib_scope_local);
         fsa_register_cib_callback(rc, FALSE, uuid_str, save_cib_contents);
 
     } else {
         crm_info("Connection to the Policy Engine released");
     }
 
     pe_subsystem->pid = -1;
     pe_subsystem->source = NULL;
     pe_subsystem->client = NULL;
 
     mainloop_set_trigger(fsa_source);
     return;
 }
 
 static int
 pe_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
 {
     xmlNode *msg = string2xml(buffer);
 
     if (msg) {
         route_message(C_IPC_MESSAGE, msg);
     }
 
     free_xml(msg);
     return 0;
 }
 
 /*	 A_PE_START, A_PE_STOP, A_TE_RESTART	*/
 void
 do_pe_control(long long action,
               enum crmd_fsa_cause cause,
               enum crmd_fsa_state cur_state,
               enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 {
     struct crm_subsystem_s *this_subsys = pe_subsystem;
 
     long long stop_actions = A_PE_STOP;
     long long start_actions = A_PE_START;
 
     static struct ipc_client_callbacks pe_callbacks = {
         .dispatch = pe_ipc_dispatch,
         .destroy = pe_ipc_destroy
     };
 
     if (action & stop_actions) {
         clear_bit(fsa_input_register, pe_subsystem->flag_required);
 
         mainloop_del_ipc_client(pe_subsystem->source);
         pe_subsystem->source = NULL;
 
         clear_bit(fsa_input_register, pe_subsystem->flag_connected);
     }
 
     if ((action & start_actions) && (is_set(fsa_input_register, R_PE_CONNECTED) == FALSE)) {
         if (cur_state != S_STOPPING) {
             set_bit(fsa_input_register, pe_subsystem->flag_required);
 
             pe_subsystem->source =
-                mainloop_add_ipc_client(CRM_SYSTEM_PENGINE, G_PRIORITY_DEFAULT,
-                                        5 * 1024 * 1024 /* 5Mb */ , NULL, &pe_callbacks);
+                mainloop_add_ipc_client(CRM_SYSTEM_PENGINE, G_PRIORITY_DEFAULT, NULL, &pe_callbacks);
 
             if (pe_subsystem->source == NULL) {
                 crm_warn("Setup of client connection failed, not adding channel to mainloop");
                 register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
                 return;
             }
 
             /* if (is_openais_cluster()) { */
             /*     pe_subsystem->pid = pe_subsystem->ipc->farside_pid; */
             /* } */
 
             set_bit(fsa_input_register, pe_subsystem->flag_connected);
 
         } else {
             crm_info("Ignoring request to start %s while shutting down", this_subsys->name);
         }
     }
 }
 
 int fsa_pe_query = 0;
 char *fsa_pe_ref = NULL;
 
 /*	 A_PE_INVOKE	*/
 void
 do_pe_invoke(long long action,
              enum crmd_fsa_cause cause,
              enum crmd_fsa_state cur_state,
              enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 {
     if (AM_I_DC == FALSE) {
         crm_err("Not DC: No need to invoke the PE (anymore): %s", fsa_action2string(action));
         return;
     }
 
     if (is_set(fsa_input_register, R_PE_CONNECTED) == FALSE) {
         if (is_set(fsa_input_register, R_SHUTDOWN)) {
             crm_err("Cannot shut down gracefully without the PE");
             register_fsa_input_before(C_FSA_INTERNAL, I_TERMINATE, NULL);
 
         } else {
             crm_info("Waiting for the PE to connect");
             crmd_fsa_stall(FALSE);
             register_fsa_action(A_PE_START);
         }
         return;
     }
 
     if (cur_state != S_POLICY_ENGINE) {
         crm_notice("No need to invoke the PE in state %s", fsa_state2string(cur_state));
         return;
     }
     if (is_set(fsa_input_register, R_HAVE_CIB) == FALSE) {
         crm_err("Attempted to invoke the PE without a consistent copy of the CIB!");
 
         /* start the join from scratch */
         register_fsa_input_before(C_FSA_INTERNAL, I_ELECTION, NULL);
         return;
     }
 
     fsa_pe_query = fsa_cib_conn->cmds->query(fsa_cib_conn, NULL, NULL, cib_scope_local);
 
     crm_debug("Query %d: Requesting the current CIB: %s", fsa_pe_query,
               fsa_state2string(fsa_state));
 
     /* Make sure any queued calculations are discarded */
     free(fsa_pe_ref);
     fsa_pe_ref = NULL;
 
     fsa_register_cib_callback(fsa_pe_query, FALSE, NULL, do_pe_invoke_callback);
 }
 
 void
 do_pe_invoke_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     int sent;
     xmlNode *cmd = NULL;
 
     if (rc != pcmk_ok) {
         crm_err("Cant retrieve the CIB: %s (call %d)", pcmk_strerror(rc), call_id);
         register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
         return;
 
     } else if (call_id != fsa_pe_query) {
         crm_trace("Skipping superceeded CIB query: %d (current=%d)", call_id, fsa_pe_query);
         return;
 
     } else if (AM_I_DC == FALSE || is_set(fsa_input_register, R_PE_CONNECTED) == FALSE) {
         crm_debug("No need to invoke the PE anymore");
         return;
 
     } else if (fsa_state != S_POLICY_ENGINE) {
         crm_debug("Discarding PE request in state: %s", fsa_state2string(fsa_state));
         return;
 
     } else if (last_peer_update != 0) {
         crm_debug("Re-asking for the CIB: peer update %d still pending", last_peer_update);
 
         sleep(1);
         register_fsa_action(A_PE_INVOKE);
         return;
 
     } else if (fsa_state != S_POLICY_ENGINE) {
         crm_err("Invoking PE in state: %s", fsa_state2string(fsa_state));
         return;
     }
 
     CRM_LOG_ASSERT(output != NULL);
 
     /* refresh our remote-node cache when the pengine is invoked */
     crm_remote_peer_cache_refresh(output);
 
     crm_xml_add(output, XML_ATTR_DC_UUID, fsa_our_uuid);
     crm_xml_add_int(output, XML_ATTR_HAVE_QUORUM, fsa_has_quorum);
 
     if (ever_had_quorum && crm_have_quorum == FALSE) {
         crm_xml_add_int(output, XML_ATTR_QUORUM_PANIC, 1);
     }
 
     cmd = create_request(CRM_OP_PECALC, output, NULL, CRM_SYSTEM_PENGINE, CRM_SYSTEM_DC, NULL);
 
     free(fsa_pe_ref);
     fsa_pe_ref = crm_element_value_copy(cmd, XML_ATTR_REFERENCE);
 
     sent = crm_ipc_send(mainloop_get_ipc_client(pe_subsystem->source), cmd, 0, 0, NULL);
     if (sent <= 0) {
         crm_err("Could not contact the pengine: %d", sent);
         register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
     }
 
     crm_debug("Invoking the PE: query=%d, ref=%s, seq=%llu, quorate=%d",
               fsa_pe_query, fsa_pe_ref, crm_peer_seq, fsa_has_quorum);
     free_xml(cmd);
 }
diff --git a/include/crm/common/mainloop.h b/include/crm/common/mainloop.h
index 7a60a1d30a..ec68364087 100644
--- a/include/crm/common/mainloop.h
+++ b/include/crm/common/mainloop.h
@@ -1,113 +1,113 @@
 /*
  * 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
  */
 #ifndef CRM_COMMON_MAINLOOP__H
 #  define CRM_COMMON_MAINLOOP__H
 
 /**
  * \file
  * \brief Wrappers for and extensions to glib mainloop
  * \ingroup core
  */
 
 #  include <glib.h>
 
 typedef struct trigger_s crm_trigger_t;
 typedef struct mainloop_io_s mainloop_io_t;
 typedef struct mainloop_child_s mainloop_child_t;
 typedef struct mainloop_timer_s mainloop_timer_t;
 
 void mainloop_cleanup(void);
 
 crm_trigger_t *mainloop_add_trigger(int priority, int (*dispatch) (gpointer user_data),
                                     gpointer userdata);
 
 void mainloop_set_trigger(crm_trigger_t * source);
 
 void mainloop_trigger_complete(crm_trigger_t * trig);
 
 gboolean mainloop_destroy_trigger(crm_trigger_t * source);
 
 gboolean crm_signal(int sig, void (*dispatch) (int sig));
 
 gboolean mainloop_add_signal(int sig, void (*dispatch) (int sig));
 
 gboolean mainloop_destroy_signal(int sig);
 
 bool mainloop_timer_running(mainloop_timer_t *t);
 
 void mainloop_timer_start(mainloop_timer_t *t);
 
 void mainloop_timer_stop(mainloop_timer_t *t);
 
 guint mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms);
 
 mainloop_timer_t *mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata);
 
 void mainloop_timer_del(mainloop_timer_t *t);
 
 
 #  include <crm/common/ipc.h>
 #  include <qb/qbipcs.h>
 
 struct ipc_client_callbacks {
     int (*dispatch) (const char *buffer, ssize_t length, gpointer userdata);
     void (*destroy) (gpointer);
 };
 
 qb_ipcs_service_t *mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
                                            struct qb_ipcs_service_handlers *callbacks);
 
 void mainloop_del_ipc_server(qb_ipcs_service_t * server);
 
-mainloop_io_t *mainloop_add_ipc_client(const char *name, int priority, size_t max_size,
+mainloop_io_t *mainloop_add_ipc_client(const char *name, int priority,
                                        void *userdata, struct ipc_client_callbacks *callbacks);
 
 void mainloop_del_ipc_client(mainloop_io_t * client);
 
 crm_ipc_t *mainloop_get_ipc_client(mainloop_io_t * client);
 
 struct mainloop_fd_callbacks {
     int (*dispatch) (gpointer userdata);
     void (*destroy) (gpointer userdata);
 };
 
 mainloop_io_t *mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
                                struct mainloop_fd_callbacks *callbacks);
 
 void mainloop_del_fd(mainloop_io_t * client);
 
 /*
  * Create a new tracked process
  * To track a process group, use -pid
  */
 void mainloop_child_add(pid_t pid,
                         int timeout,
                         const char *desc,
                         void *userdata,
                         void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode));
 
 void *mainloop_child_userdata(mainloop_child_t * child);
 int mainloop_child_timeout(mainloop_child_t * child);
 const char *mainloop_child_name(mainloop_child_t * child);
 
 pid_t mainloop_child_pid(mainloop_child_t * child);
 void mainloop_clear_child_userdata(mainloop_child_t * child);
 
 #  define G_PRIORITY_MEDIUM (G_PRIORITY_HIGH/2)
 
 #endif
diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c
index f03d050605..7a4c1ae3ab 100644
--- a/lib/cib/cib_native.c
+++ b/lib/cib/cib_native.c
@@ -1,512 +1,512 @@
 /*
  * Copyright (c) 2004 International Business Machines
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 #include <crm_internal.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
 
 #include <glib.h>
 
 #include <crm/crm.h>
 #include <crm/cib/internal.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/mainloop.h>
 
 typedef struct cib_native_opaque_s {
     char *token;
     crm_ipc_t *ipc;
     void (*dnotify_fn) (gpointer user_data);
     mainloop_io_t *source;
 
 } cib_native_opaque_t;
 
 int cib_native_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
                           xmlNode * data, xmlNode ** output_data, int call_options);
 
 int cib_native_perform_op_delegate(cib_t * cib, const char *op, const char *host,
                                    const char *section, xmlNode * data, xmlNode ** output_data,
                                    int call_options, const char *user_name);
 
 int cib_native_free(cib_t * cib);
 int cib_native_signoff(cib_t * cib);
 int cib_native_signon(cib_t * cib, const char *name, enum cib_conn_type type);
 int cib_native_signon_raw(cib_t * cib, const char *name, enum cib_conn_type type, int *event_fd);
 
 bool cib_native_dispatch(cib_t * cib);
 
 int cib_native_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data));
 
 cib_t *
 cib_native_new(void)
 {
     cib_native_opaque_t *native = NULL;
     cib_t *cib = cib_new_variant();
 
     native = calloc(1, sizeof(cib_native_opaque_t));
 
     cib->variant = cib_native;
     cib->variant_opaque = native;
 
     native->ipc = NULL;
     native->source = NULL;
     native->dnotify_fn = NULL;
 
     /* assign variant specific ops */
     cib->delegate_fn = cib_native_perform_op_delegate;
     cib->cmds->signon = cib_native_signon;
     cib->cmds->signon_raw = cib_native_signon_raw;
     cib->cmds->signoff = cib_native_signoff;
     cib->cmds->free = cib_native_free;
 
     cib->cmds->register_notification = cib_native_register_notification;
     cib->cmds->set_connection_dnotify = cib_native_set_connection_dnotify;
 
     return cib;
 }
 
 int
 cib_native_signon(cib_t * cib, const char *name, enum cib_conn_type type)
 {
     return cib_native_signon_raw(cib, name, type, NULL);
 }
 
 static int
 cib_native_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
 {
     const char *type = NULL;
     xmlNode *msg = NULL;
 
     cib_t *cib = userdata;
 
     crm_trace("dispatching %p", userdata);
 
     if (cib == NULL) {
         crm_err("No CIB!");
         return 0;
     }
 
     msg = string2xml(buffer);
 
     if (msg == NULL) {
         crm_warn("Received a NULL msg from CIB service.");
         return 0;
     }
 
     /* do callbacks */
     type = crm_element_value(msg, F_TYPE);
     crm_trace("Activating %s callbacks...", type);
     crm_log_xml_explicit(msg, "cib-reply");
 
     if (safe_str_eq(type, T_CIB)) {
         cib_native_callback(cib, msg, 0, 0);
 
     } else if (safe_str_eq(type, T_CIB_NOTIFY)) {
         g_list_foreach(cib->notify_list, cib_native_notify, msg);
 
     } else {
         crm_err("Unknown message type: %s", type);
     }
 
     free_xml(msg);
     return 0;
 }
 
 bool
 cib_native_dispatch(cib_t * cib)
 {
     gboolean stay_connected = TRUE;
     cib_native_opaque_t *native;
 
     if (cib == NULL) {
         crm_err("No CIB!");
         return FALSE;
     }
 
     crm_trace("dispatching %p", cib);
     native = cib->variant_opaque;
     while (crm_ipc_ready(native->ipc)) {
 
         if (crm_ipc_read(native->ipc) > 0) {
             const char *msg = crm_ipc_buffer(native->ipc);
 
             cib_native_dispatch_internal(msg, strlen(msg), cib);
         }
 
         if (crm_ipc_connected(native->ipc) == FALSE) {
             crm_err("Connection closed");
             stay_connected = FALSE;
         }
     }
 
     return stay_connected;
 }
 
 static void
 cib_native_destroy(void *userdata)
 {
     cib_t *cib = userdata;
     cib_native_opaque_t *native = cib->variant_opaque;
 
     crm_trace("destroying %p", userdata);
     cib->state = cib_disconnected;
     native->source = NULL;
     native->ipc = NULL;
 
     if (native->dnotify_fn) {
         native->dnotify_fn(userdata);
     }
 }
 
 int
 cib_native_signon_raw(cib_t * cib, const char *name, enum cib_conn_type type, int *async_fd)
 {
     int rc = pcmk_ok;
     const char *channel = NULL;
     cib_native_opaque_t *native = cib->variant_opaque;
 
     static struct ipc_client_callbacks cib_callbacks = {
         .dispatch = cib_native_dispatch_internal,
         .destroy = cib_native_destroy
     };
 
     cib->call_timeout = MAX_IPC_DELAY;
 
     if (type == cib_command) {
         cib->state = cib_connected_command;
         channel = cib_channel_rw;
 
     } else if (type == cib_command_nonblocking) {
         cib->state = cib_connected_command;
         channel = cib_channel_shm;
 
     } else if (type == cib_query) {
         cib->state = cib_connected_query;
         channel = cib_channel_ro;
 
     } else {
         return -ENOTCONN;
     }
 
     crm_trace("Connecting %s channel", channel);
 
     if (async_fd != NULL) {
         native->ipc = crm_ipc_new(channel, 0);
 
         if (native->ipc && crm_ipc_connect(native->ipc)) {
             *async_fd = crm_ipc_get_fd(native->ipc);
 
         } else if (native->ipc) {
             rc = -ENOTCONN;
         }
 
     } else {
         native->source =
-            mainloop_add_ipc_client(channel, G_PRIORITY_HIGH, 512 * 1024 /* 512k */ , cib,
+            mainloop_add_ipc_client(channel, G_PRIORITY_HIGH, cib,
                                     &cib_callbacks);
         native->ipc = mainloop_get_ipc_client(native->source);
     }
 
     if (rc != pcmk_ok || native->ipc == NULL || crm_ipc_connected(native->ipc) == FALSE) {
         crm_debug("Connection unsuccessful (%d %p)", rc, native->ipc);
         rc = -ENOTCONN;
     }
 
     if (rc == pcmk_ok) {
         xmlNode *reply = NULL;
         xmlNode *hello = create_xml_node(NULL, "cib_command");
 
         crm_xml_add(hello, F_TYPE, T_CIB);
         crm_xml_add(hello, F_CIB_OPERATION, CRM_OP_REGISTER);
         crm_xml_add(hello, F_CIB_CLIENTNAME, name);
         crm_xml_add_int(hello, F_CIB_CALLOPTS, cib_sync_call);
 
         if (crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply) > 0) {
             const char *msg_type = crm_element_value(reply, F_CIB_OPERATION);
 
             rc = pcmk_ok;
             crm_log_xml_trace(reply, "reg-reply");
 
             if (safe_str_neq(msg_type, CRM_OP_REGISTER)) {
                 crm_err("Invalid registration message: %s", msg_type);
                 rc = -EPROTO;
 
             } else {
                 native->token = crm_element_value_copy(reply, F_CIB_CLIENTID);
                 if (native->token == NULL) {
                     rc = -EPROTO;
                 }
             }
             free_xml(reply);
 
         } else {
             rc = -ECOMM;
         }
 
         free_xml(hello);
     }
 
     if (rc == pcmk_ok) {
         crm_debug("Connection to CIB successful");
         return pcmk_ok;
     }
 
     crm_debug("Connection to CIB failed: %s", pcmk_strerror(rc));
     cib_native_signoff(cib);
     return rc;
 }
 
 int
 cib_native_signoff(cib_t * cib)
 {
     cib_native_opaque_t *native = cib->variant_opaque;
 
     crm_debug("Signing out of the CIB Service");
 
     if (native->source != NULL) {
         /* Attached to mainloop */
         mainloop_del_ipc_client(native->source);
         native->source = NULL;
         native->ipc = NULL;
 
     } else if (native->ipc) {
         /* Not attached to mainloop */
         crm_ipc_t *ipc = native->ipc;
 
         native->ipc = NULL;
         crm_ipc_close(ipc);
         crm_ipc_destroy(ipc);
     }
 
     cib->state = cib_disconnected;
     cib->type = cib_none;
 
     return pcmk_ok;
 }
 
 int
 cib_native_free(cib_t * cib)
 {
     int rc = pcmk_ok;
 
     if (cib->state != cib_disconnected) {
         rc = cib_native_signoff(cib);
     }
 
     if (cib->state == cib_disconnected) {
         cib_native_opaque_t *native = cib->variant_opaque;
 
         free(native->token);
         free(cib->variant_opaque);
         free(cib->cmds);
         free(cib);
     }
 
     return rc;
 }
 
 int
 cib_native_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
                       xmlNode * data, xmlNode ** output_data, int call_options)
 {
     return cib_native_perform_op_delegate(cib, op, host, section,
                                           data, output_data, call_options, NULL);
 }
 
 int
 cib_native_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
                                xmlNode * data, xmlNode ** output_data, int call_options,
                                const char *user_name)
 {
     int rc = pcmk_ok;
     int reply_id = 0;
     enum crm_ipc_flags ipc_flags = crm_ipc_client_none;
 
     xmlNode *op_msg = NULL;
     xmlNode *op_reply = NULL;
 
     cib_native_opaque_t *native = cib->variant_opaque;
 
     if (cib->state == cib_disconnected) {
         return -ENOTCONN;
     }
 
     if (output_data != NULL) {
         *output_data = NULL;
     }
 
     if (op == NULL) {
         crm_err("No operation specified");
         return -EINVAL;
     }
 
     if (call_options & cib_sync_call) {
         ipc_flags |= crm_ipc_client_response;
     }
 
     cib->call_id++;
     /* prevent call_id from being negative (or zero) and conflicting
      *    with the cib_errors enum
      * use 2 because we use it as (cib->call_id - 1) below
      */
     if (cib->call_id < 1) {
         cib->call_id = 1;
     }
 
     CRM_CHECK(native->token != NULL,;
         );
     op_msg =
         cib_create_op(cib->call_id, native->token, op, host, section, data, call_options,
                       user_name);
     if (op_msg == NULL) {
         return -EPROTO;
     }
 
     crm_trace("Sending %s message to CIB service (timeout=%ds)", op, cib->call_timeout);
     rc = crm_ipc_send(native->ipc, op_msg, ipc_flags, cib->call_timeout * 1000, &op_reply);
     free_xml(op_msg);
 
     if (rc < 0) {
         crm_err("Couldn't perform %s operation (timeout=%ds): %s (%d)", op,
                 cib->call_timeout, pcmk_strerror(rc), rc);
         rc = -ECOMM;
         goto done;
     }
 
     crm_log_xml_trace(op_reply, "Reply");
 
     if (!(call_options & cib_sync_call)) {
         crm_trace("Async call, returning %d", cib->call_id);
         CRM_CHECK(cib->call_id != 0, return -ENOMSG);
         free_xml(op_reply);
         return cib->call_id;
     }
 
     rc = pcmk_ok;
     crm_element_value_int(op_reply, F_CIB_CALLID, &reply_id);
     if (reply_id == cib->call_id) {
         xmlNode *tmp = get_message_xml(op_reply, F_CIB_CALLDATA);
 
         crm_trace("Syncronous reply %d received", reply_id);
         if (crm_element_value_int(op_reply, F_CIB_RC, &rc) != 0) {
             rc = -EPROTO;
         }
 
         if (output_data == NULL || (call_options & cib_discard_reply)) {
             crm_trace("Discarding reply");
 
         } else if (tmp != NULL) {
             *output_data = copy_xml(tmp);
         }
 
     } else if (reply_id <= 0) {
         crm_err("Received bad reply: No id set");
         crm_log_xml_err(op_reply, "Bad reply");
         rc = -ENOMSG;
         goto done;
 
     } else {
         crm_err("Received bad reply: %d (wanted %d)", reply_id, cib->call_id);
         crm_log_xml_err(op_reply, "Old reply");
         rc = -ENOMSG;
         goto done;
     }
 
     if (op_reply == NULL && cib->state == cib_disconnected) {
         rc = -ENOTCONN;
 
     } else if (rc == pcmk_ok && op_reply == NULL) {
         rc = -ETIME;
     }
 
     switch (rc) {
         case pcmk_ok:
         case -EPERM:
             break;
 
             /* This is an internal value that clients do not and should not care about */
         case -pcmk_err_diff_resync:
             rc = pcmk_ok;
             break;
 
             /* These indicate internal problems */
         case -EPROTO:
         case -ENOMSG:
             crm_err("Call failed: %s", pcmk_strerror(rc));
             if (op_reply) {
                 crm_log_xml_err(op_reply, "Invalid reply");
             }
             break;
 
         default:
             if (safe_str_neq(op, CIB_OP_QUERY)) {
                 crm_warn("Call failed: %s", pcmk_strerror(rc));
             }
     }
 
   done:
     if (crm_ipc_connected(native->ipc) == FALSE) {
         crm_err("CIB disconnected");
         cib->state = cib_disconnected;
     }
 
     free_xml(op_reply);
     return rc;
 }
 
 int
 cib_native_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
 {
     cib_native_opaque_t *native = NULL;
 
     if (cib == NULL) {
         crm_err("No CIB!");
         return FALSE;
     }
 
     native = cib->variant_opaque;
     native->dnotify_fn = dnotify;
 
     return pcmk_ok;
 }
 
 int
 cib_native_register_notification(cib_t * cib, const char *callback, int enabled)
 {
     int rc = pcmk_ok;
     xmlNode *notify_msg = create_xml_node(NULL, "cib-callback");
     cib_native_opaque_t *native = cib->variant_opaque;
 
     if (cib->state != cib_disconnected) {
         crm_xml_add(notify_msg, F_CIB_OPERATION, T_CIB_NOTIFY);
         crm_xml_add(notify_msg, F_CIB_NOTIFY_TYPE, callback);
         crm_xml_add_int(notify_msg, F_CIB_NOTIFY_ACTIVATE, enabled);
         rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response,
                           1000 * cib->call_timeout, NULL);
         if (rc <= 0) {
             crm_trace("Notification not registered: %d", rc);
             rc = -ECOMM;
         }
     }
 
     free_xml(notify_msg);
     return rc;
 }
diff --git a/lib/cluster/legacy.c b/lib/cluster/legacy.c
index f3daee808d..792d8123b4 100644
--- a/lib/cluster/legacy.c
+++ b/lib/cluster/legacy.c
@@ -1,946 +1,946 @@
 /*
  * 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 <crm/cluster/internal.h>
 #include <bzlib.h>
 #include <crm/common/ipc.h>
 #include <crm/cluster.h>
 #include <crm/common/mainloop.h>
 #include <sys/utsname.h>
 #include <sys/socket.h>
 #include <netdb.h>
 
 #if SUPPORT_COROSYNC
 #  include <corosync/confdb.h>
 #  include <corosync/corodefs.h>
 #  include <corosync/cpg.h>
 #  include <corosync/cfg.h>
 #endif
 
 #if HAVE_CMAP
 #  include <corosync/cmap.h>
 #endif
 
 #if SUPPORT_CMAN
 #  include <libcman.h>
 cman_handle_t pcmk_cman_handle = NULL;
 #endif
 
 int ais_membership_timer = 0;
 gboolean ais_membership_force = FALSE;
 int plugin_dispatch(gpointer user_data);
 
 int ais_fd_sync = -1;
 int ais_fd_async = -1;          /* never send messages via this channel */
 void *ais_ipc_ctx = NULL;
 
 hdb_handle_t ais_ipc_handle = 0;
 
 static gboolean
 plugin_get_details(uint32_t * id, char **uname)
 {
     struct iovec iov;
     int retries = 0;
     int rc = CS_OK;
     cs_ipc_header_response_t header;
     struct crm_ais_nodeid_resp_s answer;
 
     static uint32_t local_id = 0;
     static char *local_uname = NULL;
 
     if(local_id) {
         if(id) *id = local_id;
         if(uname) *uname = strdup(local_uname);
         return TRUE;
     }
 
     header.error = CS_OK;
     header.id = crm_class_nodeid;
     header.size = sizeof(cs_ipc_header_response_t);
 
     iov.iov_base = &header;
     iov.iov_len = header.size;
 
   retry:
     errno = 0;
     rc = coroipcc_msg_send_reply_receive(ais_ipc_handle, &iov, 1, &answer, sizeof(answer));
     if (rc == CS_OK) {
         CRM_CHECK(answer.header.size == sizeof(struct crm_ais_nodeid_resp_s),
                   crm_err("Odd message: id=%d, size=%d, error=%d",
                           answer.header.id, answer.header.size, answer.header.error));
         CRM_CHECK(answer.header.id == crm_class_nodeid,
                   crm_err("Bad response id: %d", answer.header.id));
     }
 
     if ((rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) && retries < 20) {
         retries++;
         crm_info("Peer overloaded: Re-sending message (Attempt %d of 20)", retries);
         sleep(retries);         /* Proportional back off */
         goto retry;
     }
 
     if (rc != CS_OK) {
         crm_err("Sending nodeid request: FAILED (rc=%d): %s", rc, ais_error2text(rc));
         return FALSE;
 
     } else if (answer.header.error != CS_OK) {
         crm_err("Bad response from peer: (rc=%d): %s", rc, ais_error2text(rc));
         return FALSE;
     }
 
     crm_info("Server details: id=%u uname=%s cname=%s", answer.id, answer.uname, answer.cname);
 
     local_id = answer.id;
     local_uname = strdup(answer.uname);
 
     if(id) *id = local_id;
     if(uname) *uname = strdup(local_uname);
     return TRUE;
 }
 
 bool
 send_plugin_text(int class, struct iovec *iov)
 {
     int rc = CS_OK;
     int retries = 0;
     int buf_len = sizeof(cs_ipc_header_response_t);
     char *buf = malloc(buf_len);
     AIS_Message *ais_msg = (AIS_Message*)iov[0].iov_base;
     cs_ipc_header_response_t *header = (cs_ipc_header_response_t *) buf;
 
     CRM_ASSERT(buf != NULL);
     /* There are only 6 handlers registered to crm_lib_service in plugin.c */
     CRM_CHECK(class < 6, crm_err("Invalid message class: %d", class);
               return FALSE);
 
     do {
         if (rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {
             retries++;
             crm_info("Peer overloaded or membership in flux:"
                      " Re-sending message (Attempt %d of 20)", retries);
             sleep(retries);     /* Proportional back off */
         }
 
         errno = 0;
         rc = coroipcc_msg_send_reply_receive(ais_ipc_handle, iov, 1, buf, buf_len);
 
     } while ((rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) && retries < 20);
 
     if (rc == CS_OK) {
         CRM_CHECK(header->size == sizeof(cs_ipc_header_response_t),
                   crm_err("Odd message: id=%d, size=%d, class=%d, error=%d",
                           header->id, header->size, class, header->error));
 
         CRM_ASSERT(buf_len >= header->size);
         CRM_CHECK(header->id == CRM_MESSAGE_IPC_ACK,
                   crm_err("Bad response id (%d) for request (%d)", header->id,
                           ais_msg->header.id));
         CRM_CHECK(header->error == CS_OK, rc = header->error);
 
     } else {
         crm_perror(LOG_ERR, "Sending plugin message %d FAILED: %s (%d)",
                    ais_msg->id, ais_error2text(rc), rc);
     }
 
     free(iov[0].iov_base);
     free(iov);
     free(buf);
 
     return (rc == CS_OK);
 }
 
 void
 terminate_cs_connection(crm_cluster_t *cluster)
 {
     crm_notice("Disconnecting from Corosync");
 
     if (is_classic_ais_cluster()) {
         if (ais_ipc_handle) {
             crm_trace("Disconnecting plugin");
             coroipcc_service_disconnect(ais_ipc_handle);
             ais_ipc_handle = 0;
         } else {
             crm_info("No plugin connection");
         }
     }
     cluster_disconnect_cpg(cluster);
 
 #  if SUPPORT_CMAN
     if (is_cman_cluster()) {
         if (pcmk_cman_handle) {
             crm_info("Disconnecting cman");
             if (cman_stop_notification(pcmk_cman_handle) >= 0) {
                 crm_info("Destroying cman");
                 cman_finish(pcmk_cman_handle);
             }
 
         } else {
             crm_info("No cman connection");
         }
     }
 #  endif
     ais_fd_async = -1;
     ais_fd_sync = -1;
 }
 
 void
 plugin_handle_membership(AIS_Message *msg)
 {
     if (msg->header.id == crm_class_members || msg->header.id == crm_class_quorum) {
         xmlNode *member = NULL;
         const char *value = NULL;
         gboolean quorate = FALSE;
         xmlNode *xml = string2xml(msg->data);
 
         if (xml == NULL) {
             crm_err("Invalid membership update: %s", msg->data);
             return;
         }
 
         value = crm_element_value(xml, "quorate");
         CRM_CHECK(value != NULL, crm_log_xml_err(xml, "No quorum value:"); return);
         if (crm_is_true(value)) {
             quorate = TRUE;
         }
 
         value = crm_element_value(xml, "id");
         CRM_CHECK(value != NULL, crm_log_xml_err(xml, "No membership id"); return);
         crm_peer_seq = crm_int_helper(value, NULL);
 
         if (quorate != crm_have_quorum) {
             crm_notice("Membership %s: quorum %s", value, quorate ? "acquired" : "lost");
             crm_have_quorum = quorate;
 
         } else {
             crm_info("Membership %s: quorum %s", value, quorate ? "retained" : "still lost");
         }
 
         for (member = __xml_first_child(xml); member != NULL; member = __xml_next(member)) {
             const char *id_s = crm_element_value(member, "id");
             const char *addr = crm_element_value(member, "addr");
             const char *uname = crm_element_value(member, "uname");
             const char *state = crm_element_value(member, "state");
             const char *born_s = crm_element_value(member, "born");
             const char *seen_s = crm_element_value(member, "seen");
             const char *votes_s = crm_element_value(member, "votes");
             const char *procs_s = crm_element_value(member, "processes");
 
             int votes = crm_int_helper(votes_s, NULL);
             unsigned int id = crm_int_helper(id_s, NULL);
             unsigned int procs = crm_int_helper(procs_s, NULL);
 
             /* TODO: These values will contain garbage if version < 0.7.1 */
             uint64_t born = crm_int_helper(born_s, NULL);
             uint64_t seen = crm_int_helper(seen_s, NULL);
 
             crm_update_peer(__FUNCTION__, id, born, seen, votes, procs, uname, uname, addr, state);
         }
         free_xml(xml);
     }
 }
 
 static void
 plugin_default_deliver_message(cpg_handle_t handle,
                                const struct cpg_name *groupName,
                                uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 {
     uint32_t kind = 0;
     const char *from = NULL;
     char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
 
     free(data);
 }
 
 int
 plugin_dispatch(gpointer user_data)
 {
     int rc = CS_OK;
     crm_cluster_t *cluster = (crm_cluster_t *) user_data;
 
     do {
         char *buffer = NULL;
 
         rc = coroipcc_dispatch_get(ais_ipc_handle, (void **)&buffer, 0);
         if (rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {
             return 0;
         }
         if (rc != CS_OK) {
             crm_perror(LOG_ERR, "Receiving message body failed: (%d) %s", rc, ais_error2text(rc));
             return -1;
         }
         if (buffer == NULL) {
             /* NULL is a legal "no message afterall" value */
             return 0;
         }
         /*
         cpg_deliver_fn_t(cpg_handle_t handle, const struct cpg_name *group_name,
                          uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len);
         */
         if (cluster && cluster->cpg.cpg_deliver_fn) {
             cluster->cpg.cpg_deliver_fn(0, NULL, 0, 0, buffer, 0);
 
         } else {
             plugin_default_deliver_message(0, NULL, 0, 0, buffer, 0);
         }
 
         coroipcc_dispatch_put(ais_ipc_handle);
 
     } while (ais_ipc_handle);
 
     return 0;
 }
 
 static void
 plugin_destroy(gpointer user_data)
 {
     crm_err("AIS connection terminated");
     ais_fd_sync = -1;
     crm_exit(ENOTCONN);
 }
 
 #  if SUPPORT_CMAN
 
 static int
 pcmk_cman_dispatch(gpointer user_data)
 {
     int rc = cman_dispatch(pcmk_cman_handle, CMAN_DISPATCH_ALL);
 
     if (rc < 0) {
         crm_err("Connection to cman failed: %d", rc);
         pcmk_cman_handle = 0;
         return FALSE;
     }
     return TRUE;
 }
 
 #    define MAX_NODES 256
 
 static void
 cman_event_callback(cman_handle_t handle, void *privdata, int reason, int arg)
 {
     int rc = 0, lpc = 0, node_count = 0;
 
     cman_cluster_t cluster;
     static cman_node_t cman_nodes[MAX_NODES];
 
     gboolean(*dispatch) (unsigned long long, gboolean) = privdata;
 
     switch (reason) {
         case CMAN_REASON_STATECHANGE:
 
             memset(&cluster, 0, sizeof(cluster));
             rc = cman_get_cluster(pcmk_cman_handle, &cluster);
             if (rc < 0) {
                 crm_err("Couldn't query cman cluster details: %d %d", rc, errno);
                 return;
             }
 
             crm_peer_seq = cluster.ci_generation;
             if (arg != crm_have_quorum) {
                 crm_notice("Membership %llu: quorum %s", crm_peer_seq, arg ? "acquired" : "lost");
                 crm_have_quorum = arg;
 
             } else {
                 crm_info("Membership %llu: quorum %s", crm_peer_seq,
                          arg ? "retained" : "still lost");
             }
 
             rc = cman_get_nodes(pcmk_cman_handle, MAX_NODES, &node_count, cman_nodes);
             if (rc < 0) {
                 crm_err("Couldn't query cman node list: %d %d", rc, errno);
                 return;
             }
 
             for (lpc = 0; lpc < node_count; lpc++) {
                 crm_node_t *peer = NULL;
 
                 if (cman_nodes[lpc].cn_nodeid == 0) {
                     /* Never allow node ID 0 to be considered a member #315711 */
                     /* Skip entirely, its a qdisk */
                     continue;
                 }
 
                 peer = crm_get_peer(cman_nodes[lpc].cn_nodeid, cman_nodes[lpc].cn_name);
                 if(cman_nodes[lpc].cn_member) {
                     crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_MEMBER, crm_peer_seq);
 
                 } else if(peer->state) {
                     crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_LOST, 0);
 
                 } else {
                     crm_info("State of node %s[%u] is still unknown", peer->uname, peer->id);
                 }
             }
 
             if (dispatch) {
                 dispatch(crm_peer_seq, crm_have_quorum);
             }
             break;
 
         case CMAN_REASON_TRY_SHUTDOWN:
             /* Always reply with a negative - pacemaker needs to be stopped first */
             crm_notice("CMAN wants to shut down: %s", arg ? "forced" : "optional");
             cman_replyto_shutdown(pcmk_cman_handle, 0);
             break;
 
         case CMAN_REASON_CONFIG_UPDATE:
             /* Ignore */
             break;
     }
 }
 #  endif
 
 gboolean
 init_cman_connection(gboolean(*dispatch) (unsigned long long, gboolean), void (*destroy) (gpointer))
 {
 #  if SUPPORT_CMAN
     int rc = -1, fd = -1;
     cman_cluster_t cluster;
 
     struct mainloop_fd_callbacks cman_fd_callbacks = {
         .dispatch = pcmk_cman_dispatch,
         .destroy = destroy,
     };
 
     crm_info("Configuring Pacemaker to obtain quorum from cman");
 
     memset(&cluster, 0, sizeof(cluster));
 
     pcmk_cman_handle = cman_init(dispatch);
     if (pcmk_cman_handle == NULL || cman_is_active(pcmk_cman_handle) == FALSE) {
         crm_err("Couldn't connect to cman");
         goto cman_bail;
     }
 
     rc = cman_start_notification(pcmk_cman_handle, cman_event_callback);
     if (rc < 0) {
         crm_err("Couldn't register for cman notifications: %d %d", rc, errno);
         goto cman_bail;
     }
 
     /* Get the current membership state */
     cman_event_callback(pcmk_cman_handle, dispatch, CMAN_REASON_STATECHANGE,
                         cman_is_quorate(pcmk_cman_handle));
 
     fd = cman_get_fd(pcmk_cman_handle);
 
     mainloop_add_fd("cman", G_PRIORITY_MEDIUM, fd, dispatch, &cman_fd_callbacks);
 
   cman_bail:
     if (rc < 0) {
         cman_finish(pcmk_cman_handle);
         return FALSE;
     }
 #  else
     crm_err("cman qorum is not supported in this build");
     crm_exit(DAEMON_RESPAWN_STOP);
 #  endif
     return TRUE;
 }
 
 #  ifdef SUPPORT_COROSYNC
 
 gboolean
 cluster_connect_quorum(gboolean(*dispatch) (unsigned long long, gboolean),
                        void (*destroy) (gpointer))
 {
     crm_err("The Corosync quorum API is not supported in this build");
     crm_exit(DAEMON_RESPAWN_STOP);
     return TRUE;
 }
 
 static gboolean
 init_cs_connection_classic(crm_cluster_t * cluster)
 {
     int rc;
     int pid = 0;
     char *pid_s = NULL;
     const char *name = NULL;
     crm_node_t *peer = NULL;
     enum crm_proc_flag proc = 0;
 
     struct mainloop_fd_callbacks ais_fd_callbacks = {
         .dispatch = plugin_dispatch,
         .destroy = cluster->destroy,
     };
 
     crm_info("Creating connection to our Corosync plugin");
     rc = coroipcc_service_connect(COROSYNC_SOCKET_NAME, PCMK_SERVICE_ID,
                                   AIS_IPC_MESSAGE_SIZE, AIS_IPC_MESSAGE_SIZE, AIS_IPC_MESSAGE_SIZE,
                                   &ais_ipc_handle);
     if (ais_ipc_handle) {
         coroipcc_fd_get(ais_ipc_handle, &ais_fd_async);
     } else {
         crm_info("Connection to our Corosync plugin (%d) failed: %s (%d)",
                  PCMK_SERVICE_ID, strerror(errno), errno);
         return FALSE;
     }
     if (ais_fd_async <= 0 && rc == CS_OK) {
         crm_err("No context created, but connection reported 'ok'");
         rc = CS_ERR_LIBRARY;
     }
     if (rc != CS_OK) {
         crm_info("Connection to our Corosync plugin (%d) failed: %s (%d)", PCMK_SERVICE_ID,
                  ais_error2text(rc), rc);
     }
 
     if (rc != CS_OK) {
         return FALSE;
     }
 
     if (ais_fd_callbacks.destroy == NULL) {
         ais_fd_callbacks.destroy = plugin_destroy;
     }
 
     mainloop_add_fd("corosync-plugin", G_PRIORITY_MEDIUM, ais_fd_async, cluster, &ais_fd_callbacks);
     crm_info("AIS connection established");
 
     pid = getpid();
     pid_s = crm_itoa(pid);
     send_cluster_text(crm_class_cluster, pid_s, TRUE, NULL, crm_msg_ais);
     free(pid_s);
 
     cluster->nodeid = get_local_nodeid(0);
 
     name = get_local_node_name();
     plugin_get_details(NULL, &(cluster->uname));
     if (safe_str_neq(name, cluster->uname)) {
         crm_crit("Node name mismatch!  Corosync supplied %s but our lookup returned %s",
                  cluster->uname, name);
         crm_notice
             ("Node name mismatches usually occur when assigned automatically by DHCP servers");
         crm_exit(ENOTUNIQ);
     }
 
     proc = text2proc(crm_system_name);
     peer = crm_get_peer(cluster->nodeid, cluster->uname);
     crm_update_peer_proc(__FUNCTION__, peer, proc|crm_proc_plugin, ONLINESTATUS);
 
     return TRUE;
 }
 
 static int
 pcmk_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
 {
     xmlNode *msg = string2xml(buffer);
 
     if (msg && is_classic_ais_cluster()) {
         xmlNode *node = NULL;
 
         for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
             int id = 0;
             int children = 0;
             const char *uname = crm_element_value(node, "uname");
 
             crm_element_value_int(node, "id", &id);
             crm_element_value_int(node, "processes", &children);
             if (id == 0) {
                 crm_log_xml_err(msg, "Bad Update");
             } else {
                 crm_node_t *peer = crm_get_peer(id, uname);
 
                 crm_update_peer_proc(__FUNCTION__, peer, children, NULL);
             }
         }
     }
 
     free_xml(msg);
     return 0;
 }
 
 static void
 pcmk_mcp_destroy(gpointer user_data)
 {
     void (*callback) (gpointer data) = user_data;
 
     if (callback) {
         callback(NULL);
     }
 }
 
 gboolean
 init_cs_connection(crm_cluster_t * cluster)
 {
     int retries = 0;
 
     static struct ipc_client_callbacks mcp_callbacks = {
         .dispatch = pcmk_mcp_dispatch,
         .destroy = pcmk_mcp_destroy
     };
 
     while (retries < 5) {
         int rc = init_cs_connection_once(cluster);
 
         retries++;
         switch (rc) {
             case CS_OK:
                 if (getenv("HA_mcp") && get_cluster_type() != pcmk_cluster_cman) {
                     xmlNode *poke = create_xml_node(NULL, "poke");
                     mainloop_io_t *ipc =
-                        mainloop_add_ipc_client(CRM_SYSTEM_MCP, G_PRIORITY_MEDIUM, 0,
+                        mainloop_add_ipc_client(CRM_SYSTEM_MCP, G_PRIORITY_MEDIUM,
                                                 cluster->destroy, &mcp_callbacks);
 
                     crm_ipc_send(mainloop_get_ipc_client(ipc), poke, 0, 0, NULL);
                     free_xml(poke);
                 }
                 return TRUE;
                 break;
             case CS_ERR_TRY_AGAIN:
             case CS_ERR_QUEUE_FULL:
                 sleep(retries);
                 break;
             default:
                 return FALSE;
         }
     }
 
     crm_err("Retry count exceeded: %d", retries);
     return FALSE;
 }
 
 char *
 classic_node_name(uint32_t nodeid)
 {
     return NULL;                /* Always use the uname() default for localhost.  No way to look up peers */
 }
 
 char *
 cman_node_name(uint32_t nodeid)
 {
     char *name = NULL;
 
 #  if SUPPORT_CMAN
     cman_node_t us;
     cman_handle_t cman;
 
     cman = cman_init(NULL);
     if (cman != NULL && cman_is_active(cman)) {
         us.cn_name[0] = 0;
         cman_get_node(cman, nodeid, &us);
         name = strdup(us.cn_name);
         crm_info("Using CMAN node name %s for %u", name, nodeid);
     }
 
     cman_finish(cman);
 #  endif
 
     if (name == NULL) {
         crm_debug("Unable to get node name for nodeid %u", nodeid);
     }
     return name;
 }
 
 extern int set_cluster_type(enum cluster_type_e type);
 
 gboolean
 init_cs_connection_once(crm_cluster_t * cluster)
 {
     crm_node_t *peer = NULL;
     enum cluster_type_e stack = get_cluster_type();
 
     crm_peer_init();
 
     /* Here we just initialize comms */
     switch (stack) {
         case pcmk_cluster_classic_ais:
             if (init_cs_connection_classic(cluster) == FALSE) {
                 return FALSE;
             }
             break;
         case pcmk_cluster_cman:
             if (cluster_connect_cpg(cluster) == FALSE) {
                 return FALSE;
             }
             cluster->uname = cman_node_name(0 /* CMAN_NODEID_US */ );
             break;
         case pcmk_cluster_heartbeat:
             crm_info("Could not find an active corosync based cluster");
             return FALSE;
             break;
         default:
             crm_err("Invalid cluster type: %s (%d)", name_for_cluster_type(stack), stack);
             return FALSE;
             break;
     }
 
     crm_info("Connection to '%s': established", name_for_cluster_type(stack));
 
     cluster->nodeid = get_local_nodeid(0);
     if(cluster->nodeid == 0) {
         crm_err("Could not establish local nodeid");
         return FALSE;
     }
 
     cluster->uname = get_node_name(0);
     if(cluster->uname == NULL) {
         crm_err("Could not establish local node name");
         return FALSE;
     }
 
     /* Ensure the local node always exists */
     peer = crm_get_peer(cluster->nodeid, cluster->uname);
     cluster->uuid = get_corosync_uuid(peer);
 
     return TRUE;
 }
 
 gboolean
 check_message_sanity(const AIS_Message * msg, const char *data)
 {
     gboolean sane = TRUE;
     int dest = msg->host.type;
     int tmp_size = msg->header.size - sizeof(AIS_Message);
 
     if (sane && msg->header.size == 0) {
         crm_warn("Message with no size");
         sane = FALSE;
     }
 
     if (sane && msg->header.error != CS_OK) {
         crm_warn("Message header contains an error: %d", msg->header.error);
         sane = FALSE;
     }
 
     if (sane && ais_data_len(msg) != tmp_size) {
         crm_warn("Message payload size is incorrect: expected %d, got %d", ais_data_len(msg),
                  tmp_size);
         sane = TRUE;
     }
 
     if (sane && ais_data_len(msg) == 0) {
         crm_warn("Message with no payload");
         sane = FALSE;
     }
 
     if (sane && data && msg->is_compressed == FALSE) {
         int str_size = strlen(data) + 1;
 
         if (ais_data_len(msg) != str_size) {
             int lpc = 0;
 
             crm_warn("Message payload is corrupted: expected %d bytes, got %d",
                      ais_data_len(msg), str_size);
             sane = FALSE;
             for (lpc = (str_size - 10); lpc < msg->size; lpc++) {
                 if (lpc < 0) {
                     lpc = 0;
                 }
                 crm_debug("bad_data[%d]: %d / '%c'", lpc, data[lpc], data[lpc]);
             }
         }
     }
 
     if (sane == FALSE) {
         crm_err("Invalid message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
                 msg->id, ais_dest(&(msg->host)), msg_type2text(dest),
                 ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
                 msg->sender.pid, msg->is_compressed, ais_data_len(msg), msg->header.size);
 
     } else {
         crm_trace
             ("Verified message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
              msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)),
              msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed,
              ais_data_len(msg), msg->header.size);
     }
 
     return sane;
 }
 #endif
 
 static int
 get_config_opt(confdb_handle_t config,
                hdb_handle_t object_handle, const char *key, char **value, const char *fallback)
 {
     size_t len = 0;
     char *env_key = NULL;
     const char *env_value = NULL;
     char buffer[256];
 
     if (*value) {
         free(*value);
         *value = NULL;
     }
 
     if (object_handle > 0) {
         if (CS_OK == confdb_key_get(config, object_handle, key, strlen(key), &buffer, &len)) {
             *value = strdup(buffer);
         }
     }
 
     if (*value) {
         crm_info("Found '%s' for option: %s", *value, key);
         return 0;
     }
 
     env_key = crm_concat("HA", key, '_');
     env_value = getenv(env_key);
     free(env_key);
 
     if (*value) {
         crm_info("Found '%s' in ENV for option: %s", *value, key);
         *value = strdup(env_value);
         return 0;
     }
 
     if (fallback) {
         crm_info("Defaulting to '%s' for option: %s", fallback, key);
         *value = strdup(fallback);
 
     } else {
         crm_info("No default for option: %s", key);
     }
 
     return -1;
 }
 
 static confdb_handle_t
 config_find_init(confdb_handle_t config)
 {
     cs_error_t rc = CS_OK;
     confdb_handle_t local_handle = OBJECT_PARENT_HANDLE;
 
     rc = confdb_object_find_start(config, local_handle);
     if (rc == CS_OK) {
         return local_handle;
     } else {
         crm_err("Couldn't create search context: %d", rc);
     }
     return 0;
 }
 
 static hdb_handle_t
 config_find_next(confdb_handle_t config, const char *name, confdb_handle_t top_handle)
 {
     cs_error_t rc = CS_OK;
     hdb_handle_t local_handle = 0;
 
     if (top_handle == 0) {
         crm_err("Couldn't search for %s: no valid context", name);
         return 0;
     }
 
     crm_trace("Searching for %s in " HDB_X_FORMAT, name, top_handle);
     rc = confdb_object_find(config, top_handle, name, strlen(name), &local_handle);
     if (rc != CS_OK) {
         crm_info("No additional configuration supplied for: %s", name);
         local_handle = 0;
     } else {
         crm_info("Processing additional %s options...", name);
     }
     return local_handle;
 }
 
 enum cluster_type_e
 find_corosync_variant(void)
 {
     confdb_handle_t config;
     enum cluster_type_e found = pcmk_cluster_unknown;
 
     int rc;
     char *value = NULL;
     confdb_handle_t top_handle = 0;
     hdb_handle_t local_handle = 0;
     static confdb_callbacks_t callbacks = { };
 
     rc = confdb_initialize(&config, &callbacks);
     if (rc != CS_OK) {
         crm_debug("Could not initialize Cluster Configuration Database API instance error %d", rc);
         return found;
     }
 
     top_handle = config_find_init(config);
     local_handle = config_find_next(config, "service", top_handle);
     while (local_handle) {
         get_config_opt(config, local_handle, "name", &value, NULL);
         if (safe_str_eq("pacemaker", value)) {
             found = pcmk_cluster_classic_ais;
 
             get_config_opt(config, local_handle, "ver", &value, "0");
             crm_trace("Found Pacemaker plugin version: %s", value);
             break;
         }
 
         local_handle = config_find_next(config, "service", top_handle);
     }
 
     if (found == pcmk_cluster_unknown) {
         top_handle = config_find_init(config);
         local_handle = config_find_next(config, "quorum", top_handle);
         get_config_opt(config, local_handle, "provider", &value, NULL);
 
         if (safe_str_eq("quorum_cman", value)) {
             crm_trace("Found CMAN quorum provider");
             found = pcmk_cluster_cman;
         }
     }
     free(value);
 
     confdb_finalize(config);
     if (found == pcmk_cluster_unknown) {
         crm_err
             ("Corosync is running, but Pacemaker could not find the CMAN or Pacemaker plugin loaded");
         found = pcmk_cluster_invalid;
     }
     return found;
 }
 
 gboolean
 crm_is_corosync_peer_active(const crm_node_t * node)
 {
     enum crm_proc_flag proc = crm_proc_none;
 
     if (node == NULL) {
         crm_trace("NULL");
         return FALSE;
 
     } else if (safe_str_neq(node->state, CRM_NODE_MEMBER)) {
         crm_trace("%s: state=%s", node->uname, node->state);
         return FALSE;
 
     } else if (is_cman_cluster() && (node->processes & crm_proc_cpg)) {
         /* If we can still talk to our peer process on that node,
          * then its also part of the corosync membership
          */
         crm_trace("%s: processes=%.8x", node->uname, node->processes);
         return TRUE;
 
     } else if (is_classic_ais_cluster()) {
         if (node->processes < crm_proc_none) {
             crm_debug("%s: unknown process list, assuming active for now", node->uname);
             return TRUE;
 
         } else if (is_set(node->processes, crm_proc_none)) {
             crm_debug("%s: all processes are inactive", node->uname);
             return FALSE;
 
         } else if (is_not_set(node->processes, crm_proc_plugin)) {
             crm_trace("%s: processes=%.8x", node->uname, node->processes);
             return FALSE;
         }
     }
 
     proc = text2proc(crm_system_name);
     if (proc > crm_proc_none && (node->processes & proc) == 0) {
         crm_trace("%s: proc %.8x not in %.8x", node->uname, proc, node->processes);
         return FALSE;
     }
 
     return TRUE;
 }
diff --git a/lib/common/mainloop.c b/lib/common/mainloop.c
index 18a67e67b2..497913b311 100644
--- a/lib/common/mainloop.c
+++ b/lib/common/mainloop.c
@@ -1,1105 +1,1105 @@
 /*
  * 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>
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <stdlib.h>
 #include <signal.h>
 #include <errno.h>
 
 #include <sys/wait.h>
 
 #include <crm/crm.h>
 #include <crm/common/xml.h>
 #include <crm/common/mainloop.h>
 #include <crm/common/ipcs.h>
 
 struct mainloop_child_s {
     pid_t pid;
     char *desc;
     unsigned timerid;
     unsigned watchid;
     gboolean timeout;
     void *privatedata;
 
     /* Called when a process dies */
     void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode);
 };
 
 struct trigger_s {
     GSource source;
     gboolean running;
     gboolean trigger;
     void *user_data;
     guint id;
 
 };
 
 static gboolean
 crm_trigger_prepare(GSource * source, gint * timeout)
 {
     crm_trigger_t *trig = (crm_trigger_t *) source;
 
     /* cluster-glue's FD and IPC related sources make use of
      * g_source_add_poll() but do not set a timeout in their prepare
      * functions
      *
      * This means mainloop's poll() will block until an event for one
      * of these sources occurs - any /other/ type of source, such as
      * this one or g_idle_*, that doesn't use g_source_add_poll() is
      * S-O-L and wont be processed until there is something fd-based
      * happens.
      *
      * Luckily the timeout we can set here affects all sources and
      * puts an upper limit on how long poll() can take.
      *
      * So unconditionally set a small-ish timeout, not too small that
      * we're in constant motion, which will act as an upper bound on
      * how long the signal handling might be delayed for.
      */
     *timeout = 500;             /* Timeout in ms */
 
     return trig->trigger;
 }
 
 static gboolean
 crm_trigger_check(GSource * source)
 {
     crm_trigger_t *trig = (crm_trigger_t *) source;
 
     return trig->trigger;
 }
 
 static gboolean
 crm_trigger_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
 {
     int rc = TRUE;
     crm_trigger_t *trig = (crm_trigger_t *) source;
 
     if (trig->running) {
         /* Wait until the existing job is complete before starting the next one */
         return TRUE;
     }
     trig->trigger = FALSE;
 
     if (callback) {
         rc = callback(trig->user_data);
         if (rc < 0) {
             crm_trace("Trigger handler %p not yet complete", trig);
             trig->running = TRUE;
             rc = TRUE;
         }
     }
     return rc;
 }
 
 static void
 crm_trigger_finalize(GSource * source)
 {
     crm_trace("Trigger %p destroyed", source);
 }
 
 #if 0
 struct _GSourceCopy
 {
   gpointer callback_data;
   GSourceCallbackFuncs *callback_funcs;
 
   const GSourceFuncs *source_funcs;
   guint ref_count;
 
   GMainContext *context;
 
   gint priority;
   guint flags;
   guint source_id;
 
   GSList *poll_fds;
   
   GSource *prev;
   GSource *next;
 
   char    *name;
 
   void *priv;
 };
 
 static int
 g_source_refcount(GSource * source)
 {
     /* Duplicating the contents of private header files is a necessary evil */
     if (source) {
         struct _GSourceCopy *evil = (struct _GSourceCopy*)source;
         return evil->ref_count;
     }
     return 0;
 }
 #else
 static int g_source_refcount(GSource * source)
 {
     return 0;
 }
 #endif
 
 static GSourceFuncs crm_trigger_funcs = {
     crm_trigger_prepare,
     crm_trigger_check,
     crm_trigger_dispatch,
     crm_trigger_finalize,
 };
 
 static crm_trigger_t *
 mainloop_setup_trigger(GSource * source, int priority, int (*dispatch) (gpointer user_data),
                        gpointer userdata)
 {
     crm_trigger_t *trigger = NULL;
 
     trigger = (crm_trigger_t *) source;
 
     trigger->id = 0;
     trigger->trigger = FALSE;
     trigger->user_data = userdata;
 
     if (dispatch) {
         g_source_set_callback(source, dispatch, trigger, NULL);
     }
 
     g_source_set_priority(source, priority);
     g_source_set_can_recurse(source, FALSE);
 
     crm_trace("Setup %p with ref-count=%u", source, g_source_refcount(source));
     trigger->id = g_source_attach(source, NULL);
     crm_trace("Attached %p with ref-count=%u", source, g_source_refcount(source));
 
     return trigger;
 }
 
 void
 mainloop_trigger_complete(crm_trigger_t * trig)
 {
     crm_trace("Trigger handler %p complete", trig);
     trig->running = FALSE;
 }
 
 /* If dispatch returns:
  *  -1: Job running but not complete
  *   0: Remove the trigger from mainloop
  *   1: Leave the trigger in mainloop
  */
 crm_trigger_t *
 mainloop_add_trigger(int priority, int (*dispatch) (gpointer user_data), gpointer userdata)
 {
     GSource *source = NULL;
 
     CRM_ASSERT(sizeof(crm_trigger_t) > sizeof(GSource));
     source = g_source_new(&crm_trigger_funcs, sizeof(crm_trigger_t));
     CRM_ASSERT(source != NULL);
 
     return mainloop_setup_trigger(source, priority, dispatch, userdata);
 }
 
 void
 mainloop_set_trigger(crm_trigger_t * source)
 {
     if(source) {
         source->trigger = TRUE;
     }
 }
 
 gboolean
 mainloop_destroy_trigger(crm_trigger_t * source)
 {
     GSource *gs = NULL;
 
     if(source == NULL) {
         return TRUE;
     }
 
     gs = (GSource *)source;
 
     if(g_source_refcount(gs) > 2) {
         crm_info("Trigger %p is still referenced %u times", gs, g_source_refcount(gs));
     }
 
     g_source_destroy(gs); /* Remove from mainloop, ref_count-- */
     g_source_unref(gs); /* The caller no longer carries a reference to source
                          *
                          * At this point the source should be free'd,
                          * unless we're currently processing said
                          * source, in which case mainloop holds an
                          * additional reference and it will be free'd
                          * once our processing completes
                          */
     return TRUE;
 }
 
 typedef struct signal_s {
     crm_trigger_t trigger;      /* must be first */
     void (*handler) (int sig);
     int signal;
 
 } crm_signal_t;
 
 static crm_signal_t *crm_signals[NSIG];
 
 static gboolean
 crm_signal_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
 {
     crm_signal_t *sig = (crm_signal_t *) source;
 
     if(sig->signal != SIGCHLD) {
         crm_info("Invoking handler for signal %d: %s", sig->signal, strsignal(sig->signal));
     }
 
     sig->trigger.trigger = FALSE;
     if (sig->handler) {
         sig->handler(sig->signal);
     }
     return TRUE;
 }
 
 static void
 mainloop_signal_handler(int sig)
 {
     if (sig > 0 && sig < NSIG && crm_signals[sig] != NULL) {
         mainloop_set_trigger((crm_trigger_t *) crm_signals[sig]);
     }
 }
 
 static GSourceFuncs crm_signal_funcs = {
     crm_trigger_prepare,
     crm_trigger_check,
     crm_signal_dispatch,
     crm_trigger_finalize,
 };
 
 gboolean
 crm_signal(int sig, void (*dispatch) (int sig))
 {
     sigset_t mask;
     struct sigaction sa;
     struct sigaction old;
 
     if (sigemptyset(&mask) < 0) {
         crm_perror(LOG_ERR, "Call to sigemptyset failed");
         return FALSE;
     }
 
     memset(&sa, 0, sizeof(struct sigaction));
     sa.sa_handler = dispatch;
     sa.sa_flags = SA_RESTART;
     sa.sa_mask = mask;
 
     if (sigaction(sig, &sa, &old) < 0) {
         crm_perror(LOG_ERR, "Could not install signal handler for signal %d", sig);
         return FALSE;
     }
 
     return TRUE;
 }
 
 gboolean
 mainloop_add_signal(int sig, void (*dispatch) (int sig))
 {
     GSource *source = NULL;
     int priority = G_PRIORITY_HIGH - 1;
 
     if (sig == SIGTERM) {
         /* TERM is higher priority than other signals,
          *   signals are higher priority than other ipc.
          * Yes, minus: smaller is "higher"
          */
         priority--;
     }
 
     if (sig >= NSIG || sig < 0) {
         crm_err("Signal %d is out of range", sig);
         return FALSE;
 
     } else if (crm_signals[sig] != NULL && crm_signals[sig]->handler == dispatch) {
         crm_trace("Signal handler for %d is already installed", sig);
         return TRUE;
 
     } else if (crm_signals[sig] != NULL) {
         crm_err("Different signal handler for %d is already installed", sig);
         return FALSE;
     }
 
     CRM_ASSERT(sizeof(crm_signal_t) > sizeof(GSource));
     source = g_source_new(&crm_signal_funcs, sizeof(crm_signal_t));
 
     crm_signals[sig] = (crm_signal_t *) mainloop_setup_trigger(source, priority, NULL, NULL);
     CRM_ASSERT(crm_signals[sig] != NULL);
 
     crm_signals[sig]->handler = dispatch;
     crm_signals[sig]->signal = sig;
 
     if (crm_signal(sig, mainloop_signal_handler) == FALSE) {
         crm_signal_t *tmp = crm_signals[sig];
 
         crm_signals[sig] = NULL;
 
         mainloop_destroy_trigger((crm_trigger_t *) tmp);
         return FALSE;
     }
 #if 0
     /* If we want signals to interrupt mainloop's poll(), instead of waiting for
      * the timeout, then we should call siginterrupt() below
      *
      * For now, just enforce a low timeout
      */
     if (siginterrupt(sig, 1) < 0) {
         crm_perror(LOG_INFO, "Could not enable system call interruptions for signal %d", sig);
     }
 #endif
 
     return TRUE;
 }
 
 gboolean
 mainloop_destroy_signal(int sig)
 {
     crm_signal_t *tmp = NULL;
 
     if (sig >= NSIG || sig < 0) {
         crm_err("Signal %d is out of range", sig);
         return FALSE;
 
     } else if (crm_signal(sig, NULL) == FALSE) {
         crm_perror(LOG_ERR, "Could not uninstall signal handler for signal %d", sig);
         return FALSE;
 
     } else if (crm_signals[sig] == NULL) {
         return TRUE;
     }
 
     crm_trace("Destroying signal %d", sig);
     tmp = crm_signals[sig];
     crm_signals[sig] = NULL;
     mainloop_destroy_trigger((crm_trigger_t *) tmp);
     return TRUE;
 }
 
 static qb_array_t *gio_map = NULL;
 
 void
 mainloop_cleanup(void) 
 {
     if(gio_map) {
         qb_array_free(gio_map);
     }
 }
 
 /*
  * libqb...
  */
 struct gio_to_qb_poll {
     int32_t is_used;
     guint source;
     int32_t events;
     void *data;
     qb_ipcs_dispatch_fn_t fn;
     enum qb_loop_priority p;
 };
 
 static gboolean
 gio_read_socket(GIOChannel * gio, GIOCondition condition, gpointer data)
 {
     struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
     gint fd = g_io_channel_unix_get_fd(gio);
 
     crm_trace("%p.%d %d", data, fd, condition);
 
     if (condition & G_IO_NVAL) {
         crm_trace("Marking failed adaptor %p unused", adaptor);
         adaptor->is_used = QB_FALSE;
     }
 
     return (adaptor->fn(fd, condition, adaptor->data) == 0);
 }
 
 static void
 gio_poll_destroy(gpointer data)
 {
     struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
 
     adaptor->is_used = QB_FALSE;
     adaptor->source = 0;
 }
 
 static int32_t
 gio_poll_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
                       void *data, qb_ipcs_dispatch_fn_t fn)
 {
     struct gio_to_qb_poll *adaptor;
     GIOChannel *channel;
     int32_t res = 0;
 
     res = qb_array_index(gio_map, fd, (void **)&adaptor);
     if (res < 0) {
         crm_err("Array lookup failed for fd=%d: %d", fd, res);
         return res;
     }
 
     crm_trace("Adding fd=%d to mainloop as adapater %p", fd, adaptor);
     if (adaptor->is_used) {
         crm_err("Adapter for descriptor %d is still in-use", fd);
         return -EEXIST;
     }
 
     /* channel is created with ref_count = 1 */
     channel = g_io_channel_unix_new(fd);
     if (!channel) {
         crm_err("No memory left to add fd=%d", fd);
         return -ENOMEM;
     }
 
     /* Because unlike the poll() API, glib doesn't tell us about HUPs by default */
     evts |= (G_IO_HUP | G_IO_NVAL | G_IO_ERR);
 
     adaptor->fn = fn;
     adaptor->events = evts;
     adaptor->data = data;
     adaptor->p = p;
     adaptor->is_used = QB_TRUE;
     adaptor->source =
         g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, evts, gio_read_socket, adaptor,
                             gio_poll_destroy);
 
     /* Now that mainloop now holds a reference to channel,
      * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
      *
      * This means that channel will be free'd by:
      * g_main_context_dispatch()
      *  -> g_source_destroy_internal()
      *      -> g_source_callback_unref()
      * shortly after gio_poll_destroy() completes
      */
     g_io_channel_unref(channel);
 
     crm_trace("Added to mainloop with gsource id=%d", adaptor->source);
     if (adaptor->source > 0) {
         return 0;
     }
 
     return -EINVAL;
 }
 
 static int32_t
 gio_poll_dispatch_mod(enum qb_loop_priority p, int32_t fd, int32_t evts,
                       void *data, qb_ipcs_dispatch_fn_t fn)
 {
     return 0;
 }
 
 static int32_t
 gio_poll_dispatch_del(int32_t fd)
 {
     struct gio_to_qb_poll *adaptor;
 
     crm_trace("Looking for fd=%d", fd);
     if (qb_array_index(gio_map, fd, (void **)&adaptor) == 0) {
         crm_trace("Marking adaptor %p unused", adaptor);
         if (adaptor->source) {
             g_source_remove(adaptor->source);
             adaptor->source = 0;
         }
         adaptor->is_used = QB_FALSE;
     }
     return 0;
 }
 
 struct qb_ipcs_poll_handlers gio_poll_funcs = {
     .job_add = NULL,
     .dispatch_add = gio_poll_dispatch_add,
     .dispatch_mod = gio_poll_dispatch_mod,
     .dispatch_del = gio_poll_dispatch_del,
 };
 
 static enum qb_ipc_type
 pick_ipc_type(enum qb_ipc_type requested)
 {
     const char *env = getenv("PCMK_ipc_type");
 
     if (env && strcmp("shared-mem", env) == 0) {
         return QB_IPC_SHM;
     } else if (env && strcmp("socket", env) == 0) {
         return QB_IPC_SOCKET;
     } else if (env && strcmp("posix", env) == 0) {
         return QB_IPC_POSIX_MQ;
     } else if (env && strcmp("sysv", env) == 0) {
         return QB_IPC_SYSV_MQ;
     } else if (requested == QB_IPC_NATIVE) {
         /* We prefer shared memory because the server never blocks on
          * send.  If part of a message fits into the socket, libqb
          * needs to block until the remainder can be sent also.
          * Otherwise the client will wait forever for the remaining
          * bytes.
          */
         return QB_IPC_SHM;
     }
     return requested;
 }
 
 qb_ipcs_service_t *
 mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
                         struct qb_ipcs_service_handlers * callbacks)
 {
     int rc = 0;
     qb_ipcs_service_t *server = NULL;
 
     if (gio_map == NULL) {
         gio_map = qb_array_create_2(64, sizeof(struct gio_to_qb_poll), 1);
     }
 
     crm_client_init();
     server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks);
     qb_ipcs_poll_handlers_set(server, &gio_poll_funcs);
 
     rc = qb_ipcs_run(server);
     if (rc < 0) {
         crm_err("Could not start %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
         return NULL;
     }
 
     return server;
 }
 
 void
 mainloop_del_ipc_server(qb_ipcs_service_t * server)
 {
     if (server) {
         qb_ipcs_destroy(server);
     }
 }
 
 struct mainloop_io_s {
     char *name;
     void *userdata;
 
     int fd;
     guint source;
     crm_ipc_t *ipc;
     GIOChannel *channel;
 
     int (*dispatch_fn_ipc) (const char *buffer, ssize_t length, gpointer userdata);
     int (*dispatch_fn_io) (gpointer userdata);
     void (*destroy_fn) (gpointer userdata);
 
 };
 
 static gboolean
 mainloop_gio_callback(GIOChannel * gio, GIOCondition condition, gpointer data)
 {
     gboolean keep = TRUE;
     mainloop_io_t *client = data;
 
     CRM_ASSERT(client->fd == g_io_channel_unix_get_fd(gio));
 
     if (condition & G_IO_IN) {
         if (client->ipc) {
             long rc = 0;
             int max = 10;
 
             do {
                 rc = crm_ipc_read(client->ipc);
                 if (rc <= 0) {
                     crm_trace("Message acquisition from %s[%p] failed: %s (%ld)",
                               client->name, client, pcmk_strerror(rc), rc);
 
                 } else if (client->dispatch_fn_ipc) {
                     const char *buffer = crm_ipc_buffer(client->ipc);
 
                     crm_trace("New message from %s[%p] = %d", client->name, client, rc, condition);
                     if (client->dispatch_fn_ipc(buffer, rc, client->userdata) < 0) {
                         crm_trace("Connection to %s no longer required", client->name);
                         keep = FALSE;
                     }
                 }
 
             } while (keep && rc > 0 && --max > 0);
 
         } else {
             crm_trace("New message from %s[%p] %u", client->name, client, condition);
             if (client->dispatch_fn_io) {
                 if (client->dispatch_fn_io(client->userdata) < 0) {
                     crm_trace("Connection to %s no longer required", client->name);
                     keep = FALSE;
                 }
             }
         }
     }
 
     if (client->ipc && crm_ipc_connected(client->ipc) == FALSE) {
         crm_err("Connection to %s[%p] closed (I/O condition=%d)", client->name, client, condition);
         keep = FALSE;
 
     } else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) {
         crm_trace("The connection %s[%p] has been closed (I/O condition=%d)",
                   client->name, client, condition);
         keep = FALSE;
 
     } else if ((condition & G_IO_IN) == 0) {
         /*
            #define      GLIB_SYSDEF_POLLIN     =1
            #define      GLIB_SYSDEF_POLLPRI    =2
            #define      GLIB_SYSDEF_POLLOUT    =4
            #define      GLIB_SYSDEF_POLLERR    =8
            #define      GLIB_SYSDEF_POLLHUP    =16
            #define      GLIB_SYSDEF_POLLNVAL   =32
 
            typedef enum
            {
            G_IO_IN      GLIB_SYSDEF_POLLIN,
            G_IO_OUT     GLIB_SYSDEF_POLLOUT,
            G_IO_PRI     GLIB_SYSDEF_POLLPRI,
            G_IO_ERR     GLIB_SYSDEF_POLLERR,
            G_IO_HUP     GLIB_SYSDEF_POLLHUP,
            G_IO_NVAL    GLIB_SYSDEF_POLLNVAL
            } GIOCondition;
 
            A bitwise combination representing a condition to watch for on an event source.
 
            G_IO_IN      There is data to read.
            G_IO_OUT     Data can be written (without blocking).
            G_IO_PRI     There is urgent data to read.
            G_IO_ERR     Error condition.
            G_IO_HUP     Hung up (the connection has been broken, usually for pipes and sockets).
            G_IO_NVAL    Invalid request. The file descriptor is not open.
          */
         crm_err("Strange condition: %d", condition);
     }
 
     /* keep == FALSE results in mainloop_gio_destroy() being called
      * just before the source is removed from mainloop
      */
     return keep;
 }
 
 static void
 mainloop_gio_destroy(gpointer c)
 {
     mainloop_io_t *client = c;
     char *c_name = strdup(client->name);
 
     /* client->source is valid but about to be destroyed (ref_count == 0) in gmain.c
      * client->channel will still have ref_count > 0... should be == 1
      */
     crm_trace("Destroying client %s[%p]", c_name, c);
 
     if (client->ipc) {
         crm_ipc_close(client->ipc);
     }
 
     if (client->destroy_fn) {
         void (*destroy_fn) (gpointer userdata) = client->destroy_fn;
 
         client->destroy_fn = NULL;
         destroy_fn(client->userdata);
     }
 
     if (client->ipc) {
         crm_ipc_t *ipc = client->ipc;
 
         client->ipc = NULL;
         crm_ipc_destroy(ipc);
     }
 
     crm_trace("Destroyed client %s[%p]", c_name, c);
 
     free(client->name); client->name = NULL;
     free(client);
 
     free(c_name);
 }
 
 mainloop_io_t *
-mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata,
+mainloop_add_ipc_client(const char *name, int priority, void *userdata,
                         struct ipc_client_callbacks *callbacks)
 {
     mainloop_io_t *client = NULL;
-    crm_ipc_t *conn = crm_ipc_new(name, max_size);
+    crm_ipc_t *conn = crm_ipc_new(name, 0);
 
     if (conn && crm_ipc_connect(conn)) {
         int32_t fd = crm_ipc_get_fd(conn);
 
         client = mainloop_add_fd(name, priority, fd, userdata, NULL);
         client->ipc = conn;
         client->destroy_fn = callbacks->destroy;
         client->dispatch_fn_ipc = callbacks->dispatch;
     }
 
     if (conn && client == NULL) {
         crm_trace("Connection to %s failed", name);
         crm_ipc_close(conn);
         crm_ipc_destroy(conn);
     }
 
     return client;
 }
 
 void
 mainloop_del_ipc_client(mainloop_io_t * client)
 {
     mainloop_del_fd(client);
 }
 
 crm_ipc_t *
 mainloop_get_ipc_client(mainloop_io_t * client)
 {
     if (client) {
         return client->ipc;
     }
     return NULL;
 }
 
 mainloop_io_t *
 mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
                 struct mainloop_fd_callbacks * callbacks)
 {
     mainloop_io_t *client = NULL;
 
     if (fd > 0) {
         client = calloc(1, sizeof(mainloop_io_t));
         client->name = strdup(name);
         client->userdata = userdata;
 
         if (callbacks) {
             client->destroy_fn = callbacks->destroy;
             client->dispatch_fn_io = callbacks->dispatch;
         }
 
         client->fd = fd;
         client->channel = g_io_channel_unix_new(fd);
         client->source =
             g_io_add_watch_full(client->channel, priority,
                                 (G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR), mainloop_gio_callback,
                                 client, mainloop_gio_destroy);
 
         /* Now that mainloop now holds a reference to channel,
          * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
          *
          * This means that channel will be free'd by:
          * g_main_context_dispatch() or g_source_remove()
          *  -> g_source_destroy_internal()
          *      -> g_source_callback_unref()
          * shortly after mainloop_gio_destroy() completes
          */
         g_io_channel_unref(client->channel);
         crm_trace("Added connection %d for %s[%p].%d", client->source, client->name, client, fd);
     }
 
     return client;
 }
 
 void
 mainloop_del_fd(mainloop_io_t * client)
 {
     if (client != NULL) {
         crm_trace("Removing client %s[%p]", client->name, client);
         if (client->source) {
             /* Results in mainloop_gio_destroy() being called just
              * before the source is removed from mainloop
              */
             g_source_remove(client->source);
         }
     }
 }
 
 pid_t
 mainloop_child_pid(mainloop_child_t * child)
 {
     return child->pid;
 }
 
 const char *
 mainloop_child_name(mainloop_child_t * child)
 {
     return child->desc;
 }
 
 int
 mainloop_child_timeout(mainloop_child_t * child)
 {
     return child->timeout;
 }
 
 void *
 mainloop_child_userdata(mainloop_child_t * child)
 {
     return child->privatedata;
 }
 
 void
 mainloop_clear_child_userdata(mainloop_child_t * child)
 {
     child->privatedata = NULL;
 }
 
 static gboolean
 child_timeout_callback(gpointer p)
 {
     mainloop_child_t *child = p;
 
     child->timerid = 0;
     if (child->timeout) {
         crm_crit("%s process (PID %d) will not die!", child->desc, (int)child->pid);
         return FALSE;
     }
 
     child->timeout = TRUE;
     crm_warn("%s process (PID %d) timed out", child->desc, (int)child->pid);
 
     if (kill(child->pid, SIGKILL) < 0) {
         if (errno == ESRCH) {
             /* Nothing left to do */
             return FALSE;
         }
         crm_perror(LOG_ERR, "kill(%d, KILL) failed", child->pid);
     }
 
     child->timerid = g_timeout_add(5000, child_timeout_callback, child);
     return FALSE;
 }
 
 static GListPtr child_list = NULL;
 
 static void
 child_death_dispatch(int signal)
 {
     GListPtr iter = child_list;
 
     while(iter) {
         int rc = 0;
         int core = 0;
         int signo = 0;
         int status = 0;
         int exitcode = 0;
 
         GListPtr saved = NULL;
         mainloop_child_t *child = iter->data;
 
         rc = waitpid(child->pid, &status, WNOHANG);
         if(rc == 0) {
             iter = iter->next;
             continue;
 
         } else if(rc != child->pid) {
             signo = signal;
             exitcode = 1;
             status = 1;
             crm_perror(LOG_ERR, "Call to waitpid(%d) failed", child->pid);
 
         } else {
             crm_trace("Managed process %d exited: %p", child->pid, child);
 
             if (WIFEXITED(status)) {
                 exitcode = WEXITSTATUS(status);
                 crm_trace("Managed process %d (%s) exited with rc=%d", child->pid, child->desc, exitcode);
 
             } else if (WIFSIGNALED(status)) {
                 signo = WTERMSIG(status);
                 crm_trace("Managed process %d (%s) exited with signal=%d", child->pid, child->desc, signo);
             }
 #ifdef WCOREDUMP
             if (WCOREDUMP(status)) {
                 core = 1;
                 crm_err("Managed process %d (%s) dumped core", child->pid, child->desc);
             }
 #endif
         }
 
         if (child->callback) {
             child->callback(child, child->pid, core, signo, exitcode);
         }
 
         crm_trace("Removing process entry %p for %d", child, child->pid);
 
         saved = iter;
         iter = iter->next;
 
         child_list = g_list_remove_link(child_list, saved);
         g_list_free(saved);
 
         if (child->timerid != 0) {
             crm_trace("Removing timer %d", child->timerid);
             g_source_remove(child->timerid);
             child->timerid = 0;
         }
         free(child->desc);
         free(child);
     }
 }
 
 /* Create/Log a new tracked process
  * To track a process group, use -pid
  */
 void
 mainloop_child_add(pid_t pid, int timeout, const char *desc, void *privatedata,
                    void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
 {
     static bool need_init = TRUE;
     mainloop_child_t *child = g_new(mainloop_child_t, 1);
 
     child->pid = pid;
     child->timerid = 0;
     child->timeout = FALSE;
     child->privatedata = privatedata;
     child->callback = callback;
 
     if(desc) {
         child->desc = strdup(desc);
     }
 
     if (timeout) {
         child->timerid = g_timeout_add(timeout, child_timeout_callback, child);
     }
 
     child_list = g_list_append(child_list, child);
 
     if(need_init) {
         need_init = FALSE;
 
         /* Do NOT use g_child_watch_add() and friends, they rely on pthreads */
         mainloop_add_signal(SIGCHLD, child_death_dispatch);
 
         /* In case they terminated before the signal handler was installed */
         child_death_dispatch(SIGCHLD);
     }
 }
 
 
 struct mainloop_timer_s {
         guint id;
         guint period_ms;
         bool repeat;
         char *name;
         GSourceFunc cb;
         void *userdata;
 };
 
 struct mainloop_timer_s mainloop;
 
 static gboolean mainloop_timer_cb(gpointer user_data)
 {
     int id = 0;
     bool repeat = FALSE;
     struct mainloop_timer_s *t = user_data;
 
     CRM_ASSERT(t != NULL);
 
     id = t->id;
     t->id = 0; /* Ensure its unset during callbacks so that
                 * mainloop_timer_running() works as expected
                 */
 
     if(t->cb) {
         crm_trace("Invoking callbacks for timer %s", t->name);
         repeat = t->repeat;
         if(t->cb(t->userdata) == FALSE) {
             crm_trace("Timer %s complete", t->name);
             repeat = FALSE;
         }
     }
 
     if(repeat) {
         /* Restore if repeating */
         t->id = id;
     }
 
     return repeat;
 }
 
 bool mainloop_timer_running(mainloop_timer_t *t)
 {
     if(t && t->id != 0) {
         return TRUE;
     }
     return FALSE;
 }
 
 void mainloop_timer_start(mainloop_timer_t *t)
 {
     mainloop_timer_stop(t);
     if(t && t->period_ms > 0) {
         crm_trace("Starting timer %s", t->name);
         t->id = g_timeout_add(t->period_ms, mainloop_timer_cb, t);
     }
 }
 
 void mainloop_timer_stop(mainloop_timer_t *t)
 {
     if(t && t->id != 0) {
         crm_trace("Stopping timer %s", t->name);
         g_source_remove(t->id);
         t->id = 0;
     }
 }
 
 guint mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms)
 {
     guint last = 0;
 
     if(t) {
         last = t->period_ms;
         t->period_ms = period_ms;
     }
 
     if(t && t->id != 0 && last != t->period_ms) {
         mainloop_timer_start(t);
     }
     return last;
 }
 
 
 mainloop_timer_t *
 mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata)
 {
     mainloop_timer_t *t = calloc(1, sizeof(mainloop_timer_t));
 
     if(t) {
         if(name) {
             t->name = g_strdup_printf("%s-%u-%d", name, period_ms, repeat);
         } else {
             t->name = g_strdup_printf("%p-%u-%d", t, period_ms, repeat);
         }
         t->id = 0;
         t->period_ms = period_ms;
         t->repeat = repeat;
         t->cb = cb;
         t->userdata = userdata;
         crm_trace("Created timer %s", t->name);
     }
     return t;
 }
 
 void
 mainloop_timer_del(mainloop_timer_t *t)
 {
     if(t) {
         crm_trace("Destroying timer %s", t->name);
         mainloop_timer_stop(t);
         free(t->name);
         free(t);
     }
 }
 
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
index 385fa1c98f..231adbafff 100644
--- a/lib/fencing/st_client.c
+++ b/lib/fencing/st_client.c
@@ -1,2468 +1,2468 @@
 /*
  * 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 <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
 #include <ctype.h>
 
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
 #include <glib.h>
 #include <dirent.h>
 #include <libgen.h>             /* Add it for compiling on OSX */
 
 #include <crm/crm.h>
 #include <crm/stonith-ng.h>
 #include <crm/fencing/internal.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 
 #ifdef HAVE_STONITH_STONITH_H
 #  include <stonith/stonith.h>
 #  define LHA_STONITH_LIBRARY "libstonith.so.1"
 static void *lha_agents_lib = NULL;
 #endif
 
 #include <crm/common/mainloop.h>
 
 CRM_TRACE_INIT_DATA(stonith);
 
 struct stonith_action_s {
     /*! user defined data */
     char *agent;
     char *action;
     char *victim;
     char *args;
     int timeout;
     int async;
     void *userdata;
     void (*done_cb) (GPid pid, gint status, const char *output, gpointer user_data);
 
     /*! internal async track data */
     int fd_stdout;
     int last_timeout_signo;
 
     /*! internal timing information */
     time_t initial_start_time;
     int tries;
     int remaining_timeout;
     guint timer_sigterm;
     guint timer_sigkill;
     int max_retries;
 
     /* device output data */
     GPid pid;
     int rc;
     char *output;
 };
 
 typedef struct stonith_private_s {
     char *token;
     crm_ipc_t *ipc;
     mainloop_io_t *source;
     GHashTable *stonith_op_callback_table;
     GList *notify_list;
 
     void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
 
 } stonith_private_t;
 
 typedef struct stonith_notify_client_s {
     const char *event;
     const char *obj_id;         /* implement one day */
     const char *obj_type;       /* implement one day */
     void (*notify) (stonith_t * st, stonith_event_t * e);
 
 } stonith_notify_client_t;
 
 typedef struct stonith_callback_client_s {
     void (*callback) (stonith_t * st, stonith_callback_data_t * data);
     const char *id;
     void *user_data;
     gboolean only_success;
     gboolean allow_timeout_updates;
     struct timer_rec_s *timer;
 
 } stonith_callback_client_t;
 
 struct notify_blob_s {
     stonith_t *stonith;
     xmlNode *xml;
 };
 
 struct timer_rec_s {
     int call_id;
     int timeout;
     guint ref;
     stonith_t *stonith;
 };
 
 typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
                              xmlNode *, xmlNode *, xmlNode **, xmlNode **);
 
 static const char META_TEMPLATE[] =
     "<?xml version=\"1.0\"?>\n"
     "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
     "<resource-agent name=\"%s\">\n"
     "  <version>1.0</version>\n"
     "  <longdesc lang=\"en\">\n"
     "%s\n"
     "  </longdesc>\n"
     "  <shortdesc lang=\"en\">%s</shortdesc>\n"
     "%s\n"
     "  <actions>\n"
     "    <action name=\"start\"   timeout=\"20\" />\n"
     "    <action name=\"stop\"    timeout=\"15\" />\n"
     "    <action name=\"status\"  timeout=\"20\" />\n"
     "    <action name=\"monitor\" timeout=\"20\" interval=\"3600\"/>\n"
     "    <action name=\"meta-data\"  timeout=\"15\" />\n"
     "  </actions>\n"
     "  <special tag=\"heartbeat\">\n"
     "    <version>2.0</version>\n" "  </special>\n" "</resource-agent>\n";
 
 bool stonith_dispatch(stonith_t * st);
 int stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata);
 void stonith_perform_callback(stonith_t * stonith, xmlNode * msg, int call_id, int rc);
 xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
                            int call_options);
 int stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data,
                          xmlNode ** output_data, int call_options, int timeout);
 
 static void stonith_connection_destroy(gpointer user_data);
 static void stonith_send_notification(gpointer data, gpointer user_data);
 static int internal_stonith_action_execute(stonith_action_t * action);
 
 static void
 stonith_connection_destroy(gpointer user_data)
 {
     stonith_t *stonith = user_data;
     stonith_private_t *native = NULL;
     struct notify_blob_s blob;
 
     crm_trace("Sending destroyed notification");
     blob.stonith = stonith;
     blob.xml = create_xml_node(NULL, "notify");
 
     native = stonith->private;
     native->ipc = NULL;
     native->source = NULL;
 
     stonith->state = stonith_disconnected;
     crm_xml_add(blob.xml, F_TYPE, T_STONITH_NOTIFY);
     crm_xml_add(blob.xml, F_SUBTYPE, T_STONITH_NOTIFY_DISCONNECT);
 
     g_list_foreach(native->notify_list, stonith_send_notification, &blob);
     free_xml(blob.xml);
 }
 
 xmlNode *
 create_device_registration_xml(const char *id, const char *namespace, const char *agent,
                                stonith_key_value_t * params)
 {
     xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
     xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
 
 #if HAVE_STONITH_STONITH_H
     namespace = get_stonith_provider(agent, namespace);
     if (safe_str_eq(namespace, "heartbeat")) {
         hash2field((gpointer) "plugin", (gpointer) agent, args);
         agent = "fence_legacy";
     }
 #endif
 
     crm_xml_add(data, XML_ATTR_ID, id);
     crm_xml_add(data, "origin", __FUNCTION__);
     crm_xml_add(data, "agent", agent);
     crm_xml_add(data, "namespace", namespace);
 
     for (; params; params = params->next) {
         hash2field((gpointer) params->key, (gpointer) params->value, args);
     }
 
     return data;
 }
 
 static int
 stonith_api_register_device(stonith_t * st, int call_options,
                             const char *id, const char *namespace, const char *agent,
                             stonith_key_value_t * params)
 {
     int rc = 0;
     xmlNode *data = NULL;
 
     data = create_device_registration_xml(id, namespace, agent, params);
 
     rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
     free_xml(data);
 
     return rc;
 }
 
 static int
 stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
 {
     int rc = 0;
     xmlNode *data = NULL;
 
     data = create_xml_node(NULL, F_STONITH_DEVICE);
     crm_xml_add(data, "origin", __FUNCTION__);
     crm_xml_add(data, XML_ATTR_ID, name);
     rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
     free_xml(data);
 
     return rc;
 }
 
 static int
 stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
 {
     int rc = 0;
     xmlNode *data = NULL;
 
     data = create_xml_node(NULL, F_STONITH_LEVEL);
     crm_xml_add(data, "origin", __FUNCTION__);
     crm_xml_add(data, F_STONITH_TARGET, node);
     crm_xml_add_int(data, XML_ATTR_ID, level);
     rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
     free_xml(data);
 
     return rc;
 }
 
 xmlNode *
 create_level_registration_xml(const char *node, int level, stonith_key_value_t * device_list)
 {
     xmlNode *data = create_xml_node(NULL, F_STONITH_LEVEL);
 
     crm_xml_add_int(data, XML_ATTR_ID, level);
     crm_xml_add(data, F_STONITH_TARGET, node);
     crm_xml_add(data, "origin", __FUNCTION__);
 
     for (; device_list; device_list = device_list->next) {
         xmlNode *dev = create_xml_node(data, F_STONITH_DEVICE);
 
         crm_xml_add(dev, XML_ATTR_ID, device_list->value);
     }
 
     return data;
 }
 
 static int
 stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
                            stonith_key_value_t * device_list)
 {
     int rc = 0;
     xmlNode *data = create_level_registration_xml(node, level, device_list);
 
     rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
     free_xml(data);
 
     return rc;
 }
 
 static void
 append_arg(gpointer key, gpointer value, gpointer user_data)
 {
     int len = 3;                /* =, \n, \0 */
     int last = 0;
     char **args = user_data;
 
     CRM_CHECK(key != NULL, return);
     CRM_CHECK(value != NULL, return);
 
     if (strstr(key, "pcmk_")) {
         return;
     } else if (strstr(key, CRM_META)) {
         return;
     } else if (safe_str_eq(key, "crm_feature_set")) {
         return;
     }
 
     len += strlen(key);
     len += strlen(value);
     if (*args != NULL) {
         last = strlen(*args);
     }
 
     *args = realloc(*args, last + len);
     crm_trace("Appending: %s=%s", (char *)key, (char *)value);
     sprintf((*args) + last, "%s=%s\n", (char *)key, (char *)value);
 }
 
 static void
 append_const_arg(const char *key, const char *value, char **arg_list)
 {
     char *glib_sucks_key = strdup(key);
     char *glib_sucks_value = strdup(value);
 
     append_arg(glib_sucks_key, glib_sucks_value, arg_list);
 
     free(glib_sucks_value);
     free(glib_sucks_key);
 }
 
 static void
 append_host_specific_args(const char *victim, const char *map, GHashTable * params, char **arg_list)
 {
     char *name = NULL;
     int last = 0, lpc = 0, max = 0;
 
     if (map == NULL) {
         /* The best default there is for now... */
         crm_debug("Using default arg map: port=uname");
         append_const_arg("port", victim, arg_list);
         return;
     }
 
     max = strlen(map);
     crm_debug("Processing arg map: %s", map);
     for (; lpc < max + 1; lpc++) {
         if (isalpha(map[lpc])) {
             /* keep going */
 
         } else if (map[lpc] == '=' || map[lpc] == ':') {
             free(name);
             name = calloc(1, 1 + lpc - last);
             memcpy(name, map + last, lpc - last);
             crm_debug("Got name: %s", name);
             last = lpc + 1;
 
         } else if (map[lpc] == 0 || map[lpc] == ',' || isspace(map[lpc])) {
             char *param = NULL;
             const char *value = NULL;
 
             param = calloc(1, 1 + lpc - last);
             memcpy(param, map + last, lpc - last);
             last = lpc + 1;
 
             crm_debug("Got key: %s", param);
             if (name == NULL) {
                 crm_err("Misparsed '%s', found '%s' without a name", map, param);
                 free(param);
                 continue;
             }
 
             if (safe_str_eq(param, "uname")) {
                 value = victim;
             } else {
                 char *key = crm_meta_name(param);
 
                 value = g_hash_table_lookup(params, key);
                 free(key);
             }
 
             if (value) {
                 crm_debug("Setting '%s'='%s' (%s) for %s", name, value, param, victim);
                 append_const_arg(name, value, arg_list);
 
             } else {
                 crm_err("No node attribute '%s' for '%s'", name, victim);
             }
 
             free(name);
             name = NULL;
             free(param);
             if (map[lpc] == 0) {
                 break;
             }
 
         } else if (isspace(map[lpc])) {
             last = lpc;
         }
     }
     free(name);
 }
 
 static char *
 make_args(const char *action, const char *victim, uint32_t victim_nodeid, GHashTable * device_args,
           GHashTable * port_map)
 {
     char buffer[512];
     char *arg_list = NULL;
     const char *value = NULL;
     const char *_action = action;
 
     CRM_CHECK(action != NULL, return NULL);
 
     buffer[511] = 0;
     snprintf(buffer, 511, "pcmk_%s_action", action);
     if (device_args) {
         value = g_hash_table_lookup(device_args, buffer);
     }
 
     if (value == NULL && device_args) {
         /* Legacy support for early 1.1 releases - Remove for 1.4 */
         snprintf(buffer, 511, "pcmk_%s_cmd", action);
         value = g_hash_table_lookup(device_args, buffer);
     }
 
     if (value == NULL && device_args && safe_str_eq(action, "off")) {
         /* Legacy support for late 1.1 releases - Remove for 1.4 */
         value = g_hash_table_lookup(device_args, "pcmk_poweroff_action");
     }
 
     if (value) {
         crm_info("Substituting action '%s' for requested operation '%s'", value, action);
         action = value;
     }
 
     append_const_arg(STONITH_ATTR_ACTION_OP, action, &arg_list);
     if (victim && device_args) {
         const char *alias = victim;
         const char *param = g_hash_table_lookup(device_args, STONITH_ATTR_HOSTARG);
 
         if (port_map && g_hash_table_lookup(port_map, victim)) {
             alias = g_hash_table_lookup(port_map, victim);
         }
 
         /* Always supply the node's name too:
          *    https://fedorahosted.org/cluster/wiki/FenceAgentAPI
          */
         append_const_arg("nodename", victim, &arg_list);
         if (victim_nodeid) {
             char nodeid_str[33] = { 0, };
             if (snprintf(nodeid_str, 33, "%u", (unsigned int)victim_nodeid)) {
                 crm_info("For stonith action (%s) for victim %s, adding nodeid (%d) to parameters",
                          action, victim, nodeid_str);
                 append_const_arg("nodeid", nodeid_str, &arg_list);
             }
         }
 
         /* Check if we need to supply the victim in any other form */
         if (param == NULL) {
             const char *map = g_hash_table_lookup(device_args, STONITH_ATTR_ARGMAP);
 
             if (map == NULL) {
                 param = "port";
                 value = g_hash_table_lookup(device_args, param);
 
             } else {
                 /* Legacy handling */
                 append_host_specific_args(alias, map, device_args, &arg_list);
                 value = map;    /* Nothing more to do */
             }
 
         } else if (safe_str_eq(param, "none")) {
             value = param;      /* Nothing more to do */
 
         } else {
             value = g_hash_table_lookup(device_args, param);
         }
 
         /* Don't overwrite explictly set values for $param */
         if (value == NULL || safe_str_eq(value, "dynamic")) {
             crm_debug("Performing %s action for node '%s' as '%s=%s'", action, victim, param,
                       alias);
             append_const_arg(param, alias, &arg_list);
         }
     }
 
     if (device_args) {
         g_hash_table_foreach(device_args, append_arg, &arg_list);
     }
 
     if(device_args && g_hash_table_lookup(device_args, STONITH_ATTR_ACTION_OP)) {
         if(safe_str_eq(_action,"list")
            || safe_str_eq(_action,"status")
            || safe_str_eq(_action,"monitor")
            || safe_str_eq(_action,"metadata")) {
             /* Force use of the calculated command for support ops
              * We don't want list or monitor ops initiating fencing, regardless of what the admin configured
              */
             append_const_arg(STONITH_ATTR_ACTION_OP, action, &arg_list);
         }
     }
 
     return arg_list;
 }
 
 static gboolean
 st_child_term(gpointer data)
 {
     int rc = 0;
     stonith_action_t *track = data;
 
     crm_info("Child %d timed out, sending SIGTERM", track->pid);
     track->timer_sigterm = 0;
     track->last_timeout_signo = SIGTERM;
     rc = kill(-track->pid, SIGTERM);
     if (rc < 0) {
         crm_perror(LOG_ERR, "Couldn't send SIGTERM to %d", track->pid);
     }
     return FALSE;
 }
 
 static gboolean
 st_child_kill(gpointer data)
 {
     int rc = 0;
     stonith_action_t *track = data;
 
     crm_info("Child %d timed out, sending SIGKILL", track->pid);
     track->timer_sigkill = 0;
     track->last_timeout_signo = SIGKILL;
     rc = kill(-track->pid, SIGKILL);
     if (rc < 0) {
         crm_perror(LOG_ERR, "Couldn't send SIGKILL to %d", track->pid);
     }
     return FALSE;
 }
 
 static void
 stonith_action_clear_tracking_data(stonith_action_t * action)
 {
     if (action->timer_sigterm > 0) {
         g_source_remove(action->timer_sigterm);
         action->timer_sigterm = 0;
     }
     if (action->timer_sigkill > 0) {
         g_source_remove(action->timer_sigkill);
         action->timer_sigkill = 0;
     }
     if (action->fd_stdout) {
         close(action->fd_stdout);
         action->fd_stdout = 0;
     }
     free(action->output);
     action->output = NULL;
     action->rc = 0;
     action->pid = 0;
     action->last_timeout_signo = 0;
 }
 
 static void
 stonith_action_destroy(stonith_action_t * action)
 {
     stonith_action_clear_tracking_data(action);
     free(action->agent);
     free(action->args);
     free(action->action);
     free(action->victim);
     free(action);
 }
 
 #define FAILURE_MAX_RETRIES 2
 stonith_action_t *
 stonith_action_create(const char *agent,
                       const char *_action,
                       const char *victim,
                       uint32_t victim_nodeid,
                       int timeout, GHashTable * device_args, GHashTable * port_map)
 {
     stonith_action_t *action;
 
     action = calloc(1, sizeof(stonith_action_t));
     crm_info("Initiating action %s for agent %s (target=%s)", _action, agent, victim);
     action->args = make_args(_action, victim, victim_nodeid, device_args, port_map);
     action->agent = strdup(agent);
     action->action = strdup(_action);
     if (victim) {
         action->victim = strdup(victim);
     }
     action->timeout = action->remaining_timeout = timeout;
     action->max_retries = FAILURE_MAX_RETRIES;
 
     if (device_args) {
         char buffer[512];
         const char *value = NULL;
 
         snprintf(buffer, 511, "pcmk_%s_retries", _action);
         value = g_hash_table_lookup(device_args, buffer);
 
         if (value) {
             action->max_retries = atoi(value);
         }
     }
 
     return action;
 }
 
 #define READ_MAX 500
 static char *
 read_output(int fd)
 {
     char buffer[READ_MAX];
     char *output = NULL;
     int len = 0;
     int more = 0;
 
     if (!fd) {
         return NULL;
     }
 
     do {
         errno = 0;
         memset(&buffer, 0, READ_MAX);
         more = read(fd, buffer, READ_MAX - 1);
 
         if (more > 0) {
             buffer[more] = 0; /* Make sure its nul-terminated for logging
                               * 'more' is always less than our buffer size
                               */
             crm_trace("Got %d more bytes: %.200s...", more, buffer);
             output = realloc(output, len + more + 1);
             snprintf(output + len, more + 1, "%s", buffer);
             len += more;
         }
 
     } while (more == (READ_MAX - 1) || (more < 0 && errno == EINTR));
 
     return output;
 }
 
 static gboolean
 update_remaining_timeout(stonith_action_t * action)
 {
     int diff = time(NULL) - action->initial_start_time;
 
     if (action->tries >= action->max_retries) {
         crm_info("Attempted to execute agent %s (%s) the maximum number of times (%d) allowed",
                  action->agent, action->action, action->max_retries);
         action->remaining_timeout = 0;
     } else if ((action->rc != -ETIME) && diff < (action->timeout * 0.7)) {
         /* only set remaining timeout period if there is 30%
          * or greater of the original timeout period left */
         action->remaining_timeout = action->timeout - diff;
     } else {
         action->remaining_timeout = 0;
     }
     return action->remaining_timeout ? TRUE : FALSE;
 }
 
 static void
 stonith_action_async_done(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
 {
     stonith_action_t *action = mainloop_child_userdata(p);
 
     if (action->timer_sigterm > 0) {
         g_source_remove(action->timer_sigterm);
     }
     if (action->timer_sigkill > 0) {
         g_source_remove(action->timer_sigkill);
     }
 
     if (action->last_timeout_signo) {
         action->rc = -ETIME;
         crm_notice("Child process %d performing action '%s' timed out with signal %d",
                    pid, action->action, action->last_timeout_signo);
 
     } else if (signo) {
         action->rc = -ECONNABORTED;
         crm_notice("Child process %d performing action '%s' timed out with signal %d",
                    pid, action->action, signo);
 
     } else {
         action->rc = exitcode;
         crm_debug("Child process %d performing action '%s' exited with rc %d",
                   pid, action->action, exitcode);
     }
 
     action->output = read_output(action->fd_stdout);
 
     if (action->rc != pcmk_ok && update_remaining_timeout(action)) {
         int rc = internal_stonith_action_execute(action);
         if (rc == pcmk_ok) {
             return;
         }
     }
 
     if (action->done_cb) {
         action->done_cb(pid, action->rc, action->output, action->userdata);
     }
 
     stonith_action_destroy(action);
 }
 
 static int
 internal_stonith_action_execute(stonith_action_t * action)
 {
     int pid, status, len, rc = -EPROTO;
     int ret;
     int total = 0;
     int p_read_fd, p_write_fd;  /* parent read/write file descriptors */
     int c_read_fd, c_write_fd;  /* child read/write file descriptors */
     int fd1[2];
     int fd2[2];
     int is_retry = 0;
 
     /* clear any previous tracking data */
     stonith_action_clear_tracking_data(action);
 
     if (!action->tries) {
         action->initial_start_time = time(NULL);
     }
     action->tries++;
 
     if (action->tries > 1) {
         crm_info("Attempt %d to execute %s (%s). remaining timeout is %d",
                  action->tries, action->agent, action->action, action->remaining_timeout);
         is_retry = 1;
     }
 
     c_read_fd = c_write_fd = p_read_fd = p_write_fd = -1;
 
     if (action->args == NULL || action->agent == NULL)
         goto fail;
     len = strlen(action->args);
 
     if (pipe(fd1))
         goto fail;
     p_read_fd = fd1[0];
     c_write_fd = fd1[1];
 
     if (pipe(fd2))
         goto fail;
     c_read_fd = fd2[0];
     p_write_fd = fd2[1];
 
     crm_debug("forking");
     pid = fork();
     if (pid < 0) {
         rc = -ECHILD;
         goto fail;
     }
 
     if (!pid) {
         /* child */
         setpgid(0, 0);
 
         close(1);
         /* coverity[leaked_handle] False positive */
         if (dup(c_write_fd) < 0)
             goto fail;
         close(2);
         /* coverity[leaked_handle] False positive */
         if (dup(c_write_fd) < 0)
             goto fail;
         close(0);
         /* coverity[leaked_handle] False positive */
         if (dup(c_read_fd) < 0)
             goto fail;
 
         /* keep c_write_fd open so parent can report all errors. */
         close(c_read_fd);
         close(p_read_fd);
         close(p_write_fd);
 
         /* keep retries from executing out of control */
         if (is_retry) {
             sleep(1);
         }
         execlp(action->agent, action->agent, NULL);
         exit(EXIT_FAILURE);
     }
 
     /* parent */
     action->pid = pid;
     ret = fcntl(p_read_fd, F_SETFL, fcntl(p_read_fd, F_GETFL, 0) | O_NONBLOCK);
     if (ret < 0) {
         crm_perror(LOG_NOTICE, "Could not change the output of %s to be non-blocking",
                    action->agent);
     }
 
     do {
         crm_debug("sending args");
         ret = write(p_write_fd, action->args + total, len - total);
         if (ret > 0) {
             total += ret;
         }
 
     } while (errno == EINTR && total < len);
 
     if (total != len) {
         crm_perror(LOG_ERR, "Sent %d not %d bytes", total, len);
         if (ret >= 0) {
             rc = -ECOMM;
         }
         goto fail;
     }
 
     close(p_write_fd); p_write_fd = -1;
 
     /* async */
     if (action->async) {
         action->fd_stdout = p_read_fd;
         mainloop_child_add(pid, 0/* Move the timeout here? */, action->action, action, stonith_action_async_done);
         crm_trace("Op: %s on %s, pid: %d, timeout: %ds", action->action, action->agent, pid,
                   action->remaining_timeout);
         action->last_timeout_signo = 0;
         if (action->remaining_timeout) {
             action->timer_sigterm =
                 g_timeout_add(1000 * action->remaining_timeout, st_child_term, action);
             action->timer_sigkill =
                 g_timeout_add(1000 * (action->remaining_timeout + 5), st_child_kill, action);
         } else {
             crm_err("No timeout set for stonith operation %s with device %s",
                     action->action, action->agent);
         }
 
         close(c_write_fd);
         close(c_read_fd);
         return 0;
 
     } else {
         /* sync */
         int timeout = action->remaining_timeout + 1;
         pid_t p = 0;
 
         while (action->remaining_timeout < 0 || timeout > 0) {
             p = waitpid(pid, &status, WNOHANG);
             if (p > 0) {
                 break;
             }
             sleep(1);
             timeout--;
         }
 
         if (timeout == 0) {
             int killrc = kill(-pid, SIGKILL);
 
             if (killrc && errno != ESRCH) {
                 crm_err("kill(%d, KILL) failed: %s (%d)", pid, pcmk_strerror(errno), errno);
             }
             /*
              * From sigprocmask(2):
              * It is not possible to block SIGKILL or SIGSTOP.  Attempts to do so are silently ignored.
              *
              * This makes it safe to skip WNOHANG here
              */
             p = waitpid(pid, &status, 0);
         }
 
         if (p <= 0) {
             crm_perror(LOG_ERR, "waitpid(%d)", pid);
 
         } else if (p != pid) {
             crm_err("Waited for %d, got %d", pid, p);
         }
 
         action->output = read_output(p_read_fd);
 
         action->rc = -ECONNABORTED;
         rc = action->rc;
         if (timeout == 0) {
             action->rc = -ETIME;
         } else if (WIFEXITED(status)) {
             crm_debug("result = %d", WEXITSTATUS(status));
             action->rc = -WEXITSTATUS(status);
             rc = 0;
 
         } else if (WIFSIGNALED(status)) {
             crm_err("call %s for %s exited due to signal %d", action->action, action->agent,
                     WTERMSIG(status));
 
         } else {
             crm_err("call %s for %s exited abnormally. stopped=%d, continued=%d",
                     action->action, action->agent, WIFSTOPPED(status), WIFCONTINUED(status));
         }
     }
 
   fail:
 
     if (p_read_fd >= 0) {
         close(p_read_fd);
     }
     if (p_write_fd >= 0) {
         close(p_write_fd);
     }
 
     if (c_read_fd >= 0) {
         close(c_read_fd);
     }
     if (c_write_fd >= 0) {
         close(c_write_fd);
     }
 
     return rc;
 }
 
 GPid
 stonith_action_execute_async(stonith_action_t * action,
                              void *userdata,
                              void (*done) (GPid pid, int rc, const char *output,
                                            gpointer user_data))
 {
     int rc = 0;
 
     if (!action) {
         return -1;
     }
 
     action->userdata = userdata;
     action->done_cb = done;
     action->async = 1;
 
     rc = internal_stonith_action_execute(action);
 
     return rc < 0 ? rc : action->pid;
 }
 
 int
 stonith_action_execute(stonith_action_t * action, int *agent_result, char **output)
 {
     int rc = 0;
 
     if (!action) {
         return -1;
     }
 
     do {
         rc = internal_stonith_action_execute(action);
         if (rc == pcmk_ok) {
             /* success! */
             break;
         }
         /* keep retrying while we have time left */
     } while (update_remaining_timeout(action));
 
     if (rc) {
         /* error */
         return rc;
     }
 
     if (agent_result) {
         *agent_result = action->rc;
     }
     if (output) {
         *output = action->output;
         action->output = NULL;  /* handed it off, do not free */
     }
 
     stonith_action_destroy(action);
     return rc;
 }
 
 static int
 stonith_api_device_list(stonith_t * stonith, int call_options, const char *namespace,
                         stonith_key_value_t ** devices, int timeout)
 {
     int count = 0;
 
     if (devices == NULL) {
         crm_err("Parameter error: stonith_api_device_list");
         return -EFAULT;
     }
 
     /* Include Heartbeat agents */
     if (namespace == NULL || safe_str_eq("heartbeat", namespace)) {
 #if HAVE_STONITH_STONITH_H
         static gboolean need_init = TRUE;
 
         char **entry = NULL;
         char **type_list = NULL;
         static char **(*type_list_fn) (void) = NULL;
         static void (*type_free_fn) (char **) = NULL;
 
         if (need_init) {
             need_init = FALSE;
             type_list_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_types", FALSE);
             type_free_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_free_hostlist",
                                       FALSE);
         }
 
         if (type_list_fn) {
             type_list = (*type_list_fn) ();
         }
 
         for (entry = type_list; entry != NULL && *entry; ++entry) {
             crm_trace("Added: %s", *entry);
             *devices = stonith_key_value_add(*devices, NULL, *entry);
             count++;
         }
         if (type_list && type_free_fn) {
             (*type_free_fn) (type_list);
         }
 #else
         if (namespace != NULL) {
             return -EINVAL;     /* Heartbeat agents not supported */
         }
 #endif
     }
 
     /* Include Red Hat agents, basically: ls -1 @sbin_dir@/fence_* */
     if (namespace == NULL || safe_str_eq("redhat", namespace)) {
         struct dirent **namelist;
         int file_num = scandir(RH_STONITH_DIR, &namelist, 0, alphasort);
 
         if (file_num > 0) {
             struct stat prop;
             char buffer[FILENAME_MAX + 1];
 
             while (file_num--) {
                 if ('.' == namelist[file_num]->d_name[0]) {
                     free(namelist[file_num]);
                     continue;
 
                 } else if (0 != strncmp(RH_STONITH_PREFIX,
                                         namelist[file_num]->d_name, strlen(RH_STONITH_PREFIX))) {
                     free(namelist[file_num]);
                     continue;
                 }
 
                 snprintf(buffer, FILENAME_MAX, "%s/%s", RH_STONITH_DIR, namelist[file_num]->d_name);
                 if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
                     *devices = stonith_key_value_add(*devices, NULL, namelist[file_num]->d_name);
                     count++;
                 }
 
                 free(namelist[file_num]);
             }
             free(namelist);
         }
     }
 
     return count;
 }
 
 #if HAVE_STONITH_STONITH_H
 static inline char *
 strdup_null(const char *val)
 {
     if (val) {
         return strdup(val);
     }
     return NULL;
 }
 
 static void
 stonith_plugin(int priority, const char *fmt, ...)
 G_GNUC_PRINTF(2, 3);
 
 static void
 stonith_plugin(int priority, const char *fmt, ...)
 {
     va_list args;
     char *str;
     int err = errno;
 
     va_start(args, fmt);
     str = g_strdup_vprintf(fmt, args);
     va_end(args);
     do_crm_log_alias(priority, __FILE__, __func__, __LINE__, "%s", str);
     g_free(str);
     errno = err;
 }
 #endif
 
 static int
 stonith_api_device_metadata(stonith_t * stonith, int call_options, const char *agent,
                             const char *namespace, char **output, int timeout)
 {
     int rc = 0;
     char *buffer = NULL;
     const char *provider = get_stonith_provider(agent, namespace);
 
     crm_trace("looking up %s/%s metadata", agent, provider);
 
     /* By having this in a library, we can access it from stonith_admin
      *  when neither lrmd or stonith-ng are running
      * Important for the crm shell's validations...
      */
 
     if (safe_str_eq(provider, "redhat")) {
         stonith_action_t *action = stonith_action_create(agent, "metadata", NULL, 0, 5, NULL, NULL);
         int exec_rc = stonith_action_execute(action, &rc, &buffer);
 
         if (exec_rc < 0 || rc != 0 || buffer == NULL) {
             crm_debug("Query failed: %d %d: %s", exec_rc, rc, crm_str(buffer));
             free(buffer);       /* Just in case */
             return -EINVAL;
 
         } else {
 
             xmlNode *xml = string2xml(buffer);
             xmlNode *actions = NULL;
             xmlXPathObject *xpathObj = NULL;
 
             xpathObj = xpath_search(xml, "//actions");
             if (numXpathResults(xpathObj) > 0) {
                 actions = getXpathResult(xpathObj, 0);
             }
 
             freeXpathObject(xpathObj);
 
             /* Now fudge the metadata so that the start/stop actions appear */
             xpathObj = xpath_search(xml, "//action[@name='stop']");
             if (numXpathResults(xpathObj) <= 0) {
                 xmlNode *tmp = NULL;
 
                 tmp = create_xml_node(actions, "action");
                 crm_xml_add(tmp, "name", "stop");
                 crm_xml_add(tmp, "timeout", "20s");
 
                 tmp = create_xml_node(actions, "action");
                 crm_xml_add(tmp, "name", "start");
                 crm_xml_add(tmp, "timeout", "20s");
             }
 
             freeXpathObject(xpathObj);
 
             /* Now fudge the metadata so that the port isn't required in the configuration */
             xpathObj = xpath_search(xml, "//parameter[@name='port']");
             if (numXpathResults(xpathObj) > 0) {
                 /* We'll fill this in */
                 xmlNode *tmp = getXpathResult(xpathObj, 0);
 
                 crm_xml_add(tmp, "required", "0");
             }
 
             freeXpathObject(xpathObj);
             free(buffer);
             buffer = dump_xml_formatted(xml);
             free_xml(xml);
             if (!buffer) {
                 return -EINVAL;
             }
         }
 
     } else {
 #if !HAVE_STONITH_STONITH_H
         return -EINVAL;         /* Heartbeat agents not supported */
 #else
         int bufferlen = 0;
         static const char *no_parameter_info = "<!-- no value -->";
 
         Stonith *stonith_obj = NULL;
 
         static gboolean need_init = TRUE;
         static Stonith *(*st_new_fn) (const char *) = NULL;
         static const char *(*st_info_fn) (Stonith *, int) = NULL;
         static void (*st_del_fn) (Stonith *) = NULL;
         static void (*st_log_fn) (Stonith *, PILLogFun) = NULL;
 
         if (need_init) {
             need_init = FALSE;
             st_new_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_new", FALSE);
             st_del_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_delete",
                                       FALSE);
             st_log_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_set_log",
                                       FALSE);
             st_info_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_get_info",
                                       FALSE);
         }
 
         if (lha_agents_lib && st_new_fn && st_del_fn && st_info_fn && st_log_fn) {
             char *xml_meta_longdesc = NULL;
             char *xml_meta_shortdesc = NULL;
 
             char *meta_param = NULL;
             char *meta_longdesc = NULL;
             char *meta_shortdesc = NULL;
 
             stonith_obj = (*st_new_fn) (agent);
             if (stonith_obj) {
                 (*st_log_fn) (stonith_obj, (PILLogFun) & stonith_plugin);
                 meta_longdesc = strdup_null((*st_info_fn) (stonith_obj, ST_DEVICEDESCR));
                 if (meta_longdesc == NULL) {
                     crm_warn("no long description in %s's metadata.", agent);
                     meta_longdesc = strdup(no_parameter_info);
                 }
 
                 meta_shortdesc = strdup_null((*st_info_fn) (stonith_obj, ST_DEVICEID));
                 if (meta_shortdesc == NULL) {
                     crm_warn("no short description in %s's metadata.", agent);
                     meta_shortdesc = strdup(no_parameter_info);
                 }
 
                 meta_param = strdup_null((*st_info_fn) (stonith_obj, ST_CONF_XML));
                 if (meta_param == NULL) {
                     crm_warn("no list of parameters in %s's metadata.", agent);
                     meta_param = strdup(no_parameter_info);
                 }
                 (*st_del_fn) (stonith_obj);
             } else {
                 return -EINVAL; /* Heartbeat agents not supported */
             }
 
             xml_meta_longdesc =
                 (char *)xmlEncodeEntitiesReentrant(NULL, (const unsigned char *)meta_longdesc);
             xml_meta_shortdesc =
                 (char *)xmlEncodeEntitiesReentrant(NULL, (const unsigned char *)meta_shortdesc);
 
             bufferlen = strlen(META_TEMPLATE) + strlen(agent)
                 + strlen(xml_meta_longdesc) + strlen(xml_meta_shortdesc)
                 + strlen(meta_param) + 1;
 
             buffer = calloc(1, bufferlen);
             snprintf(buffer, bufferlen - 1, META_TEMPLATE,
                      agent, xml_meta_longdesc, xml_meta_shortdesc, meta_param);
 
             xmlFree(xml_meta_longdesc);
             xmlFree(xml_meta_shortdesc);
 
             free(meta_shortdesc);
             free(meta_longdesc);
             free(meta_param);
         }
 #endif
     }
 
     if (output) {
         *output = buffer;
 
     } else {
         free(buffer);
     }
 
     return rc;
 }
 
 static int
 stonith_api_query(stonith_t * stonith, int call_options, const char *target,
                   stonith_key_value_t ** devices, int timeout)
 {
     int rc = 0, lpc = 0, max = 0;
 
     xmlNode *data = NULL;
     xmlNode *output = NULL;
     xmlXPathObjectPtr xpathObj = NULL;
 
     CRM_CHECK(devices != NULL, return -EINVAL);
 
     data = create_xml_node(NULL, F_STONITH_DEVICE);
     crm_xml_add(data, "origin", __FUNCTION__);
     crm_xml_add(data, F_STONITH_TARGET, target);
     crm_xml_add(data, F_STONITH_ACTION, "off");
     rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
 
     if (rc < 0) {
         return rc;
     }
 
     xpathObj = xpath_search(output, "//@agent");
     if (xpathObj) {
         max = numXpathResults(xpathObj);
 
         for (lpc = 0; lpc < max; lpc++) {
             xmlNode *match = getXpathResult(xpathObj, lpc);
 
             CRM_CHECK(match != NULL, continue);
 
             crm_info("%s[%d] = %s", "//@agent", lpc, xmlGetNodePath(match));
             *devices = stonith_key_value_add(*devices, NULL, crm_element_value(match, XML_ATTR_ID));
         }
 
         freeXpathObject(xpathObj);
     }
 
     free_xml(output);
     free_xml(data);
     return max;
 }
 
 static int
 stonith_api_call(stonith_t * stonith,
                  int call_options,
                  const char *id,
                  const char *action, const char *victim, int timeout, xmlNode ** output)
 {
     int rc = 0;
     xmlNode *data = NULL;
 
     data = create_xml_node(NULL, F_STONITH_DEVICE);
     crm_xml_add(data, "origin", __FUNCTION__);
     crm_xml_add(data, F_STONITH_DEVICE, id);
     crm_xml_add(data, F_STONITH_ACTION, action);
     crm_xml_add(data, F_STONITH_TARGET, victim);
 
     rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output, call_options, timeout);
     free_xml(data);
 
     return rc;
 }
 
 static int
 stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
                  int timeout)
 {
     int rc;
     xmlNode *output = NULL;
 
     rc = stonith_api_call(stonith, call_options, id, "list", NULL, timeout, &output);
 
     if (output && list_info) {
         const char *list_str;
 
         list_str = crm_element_value(output, "st_output");
 
         if (list_str) {
             *list_info = strdup(list_str);
         }
     }
 
     if (output) {
         free_xml(output);
     }
 
     return rc;
 }
 
 static int
 stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
 {
     return stonith_api_call(stonith, call_options, id, "monitor", NULL, timeout, NULL);
 }
 
 static int
 stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
                    int timeout)
 {
     return stonith_api_call(stonith, call_options, id, "status", port, timeout, NULL);
 }
 
 static int
 stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
                   int timeout, int tolerance)
 {
     int rc = 0;
     xmlNode *data = NULL;
 
     data = create_xml_node(NULL, __FUNCTION__);
     crm_xml_add(data, F_STONITH_TARGET, node);
     crm_xml_add(data, F_STONITH_ACTION, action);
     crm_xml_add_int(data, F_STONITH_TIMEOUT, timeout);
     crm_xml_add_int(data, F_STONITH_TOLERANCE, tolerance);
 
     rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
     free_xml(data);
 
     return rc;
 }
 
 static int
 stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
 {
     return stonith_api_fence(stonith, call_options | st_opt_manual_ack, target, "off", 0, 0);
 }
 
 static int
 stonith_api_history(stonith_t * stonith, int call_options, const char *node,
                     stonith_history_t ** history, int timeout)
 {
     int rc = 0;
     xmlNode *data = NULL;
     xmlNode *output = NULL;
     stonith_history_t *last = NULL;
 
     *history = NULL;
 
     if (node) {
         data = create_xml_node(NULL, __FUNCTION__);
         crm_xml_add(data, F_STONITH_TARGET, node);
     }
 
     rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
                               call_options | st_opt_sync_call, timeout);
     free_xml(data);
 
     if (rc == 0) {
         xmlNode *op = NULL;
         xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output, LOG_ERR);
 
         for (op = __xml_first_child(reply); op != NULL; op = __xml_next(op)) {
             stonith_history_t *kvp;
 
             kvp = calloc(1, sizeof(stonith_history_t));
             kvp->target = crm_element_value_copy(op, F_STONITH_TARGET);
             kvp->action = crm_element_value_copy(op, F_STONITH_ACTION);
             kvp->origin = crm_element_value_copy(op, F_STONITH_ORIGIN);
             kvp->delegate = crm_element_value_copy(op, F_STONITH_DELEGATE);
             kvp->client = crm_element_value_copy(op, F_STONITH_CLIENTNAME);
             crm_element_value_int(op, F_STONITH_DATE, &kvp->completed);
             crm_element_value_int(op, F_STONITH_STATE, &kvp->state);
 
             if (last) {
                 last->next = kvp;
             } else {
                 *history = kvp;
             }
             last = kvp;
         }
     }
     return rc;
 }
 
 gboolean
 is_redhat_agent(const char *agent)
 {
     int rc = 0;
     struct stat prop;
     char buffer[FILENAME_MAX + 1];
 
     snprintf(buffer, FILENAME_MAX, "%s/%s", RH_STONITH_DIR, agent);
     rc = stat(buffer, &prop);
     if (rc >= 0 && S_ISREG(prop.st_mode)) {
         return TRUE;
     }
     return FALSE;
 }
 
 const char *
 get_stonith_provider(const char *agent, const char *provider)
 {
     /* This function sucks */
     if (is_redhat_agent(agent)) {
         return "redhat";
 
 #if HAVE_STONITH_STONITH_H
     } else {
         Stonith *stonith_obj = NULL;
 
         static gboolean need_init = TRUE;
         static Stonith *(*st_new_fn) (const char *) = NULL;
         static void (*st_del_fn) (Stonith *) = NULL;
 
         if (need_init) {
             need_init = FALSE;
             st_new_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_new", FALSE);
             st_del_fn =
                 find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY, "stonith_delete",
                                       FALSE);
         }
 
         if (lha_agents_lib && st_new_fn && st_del_fn) {
             stonith_obj = (*st_new_fn) (agent);
             if (stonith_obj) {
                 (*st_del_fn) (stonith_obj);
                 return "heartbeat";
             }
         }
 #endif
     }
 
     crm_err("No such device: %s", agent);
     return NULL;
 }
 
 static gint
 stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
 {
     int rc = 0;
     const stonith_notify_client_t *a_client = a;
     const stonith_notify_client_t *b_client = b;
 
     CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
     rc = strcmp(a_client->event, b_client->event);
     if (rc == 0) {
         if (a_client->notify == NULL || b_client->notify == NULL) {
             return 0;
 
         } else if (a_client->notify == b_client->notify) {
             return 0;
 
         } else if (((long)a_client->notify) < ((long)b_client->notify)) {
             crm_err("callbacks for %s are not equal: %p vs. %p",
                     a_client->event, a_client->notify, b_client->notify);
             return -1;
         }
         crm_err("callbacks for %s are not equal: %p vs. %p",
                 a_client->event, a_client->notify, b_client->notify);
         return 1;
     }
     return rc;
 }
 
 xmlNode *
 stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
 {
     xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
 
     CRM_CHECK(op_msg != NULL, return NULL);
     CRM_CHECK(token != NULL, return NULL);
 
     crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
 
     crm_xml_add(op_msg, F_TYPE, T_STONITH_NG);
     crm_xml_add(op_msg, F_STONITH_CALLBACK_TOKEN, token);
     crm_xml_add(op_msg, F_STONITH_OPERATION, op);
     crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
     crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
     crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
 
     if (data != NULL) {
         add_message_xml(op_msg, F_STONITH_CALLDATA, data);
     }
 
     return op_msg;
 }
 
 static void
 stonith_destroy_op_callback(gpointer data)
 {
     stonith_callback_client_t *blob = data;
 
     if (blob->timer && blob->timer->ref > 0) {
         g_source_remove(blob->timer->ref);
     }
     free(blob->timer);
     free(blob);
 }
 
 static int
 stonith_api_signoff(stonith_t * stonith)
 {
     stonith_private_t *native = stonith->private;
 
     crm_debug("Signing out of the STONITH Service");
 
     if (native->source != NULL) {
         /* Attached to mainloop */
         mainloop_del_ipc_client(native->source);
         native->source = NULL;
         native->ipc = NULL;
 
     } else if (native->ipc) {
         /* Not attached to mainloop */
         crm_ipc_t *ipc = native->ipc;
 
         native->ipc = NULL;
         crm_ipc_close(ipc);
         crm_ipc_destroy(ipc);
     }
 
     free(native->token); native->token = NULL;
     stonith->state = stonith_disconnected;
     return pcmk_ok;
 }
 
 static int
 stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
 {
     int rc = pcmk_ok;
     stonith_private_t *native = stonith->private;
 
     static struct ipc_client_callbacks st_callbacks = {
         .dispatch = stonith_dispatch_internal,
         .destroy = stonith_connection_destroy
     };
 
     crm_trace("Connecting command channel");
 
     stonith->state = stonith_connected_command;
     if (stonith_fd) {
         /* No mainloop */
         native->ipc = crm_ipc_new("stonith-ng", 0);
 
         if (native->ipc && crm_ipc_connect(native->ipc)) {
             *stonith_fd = crm_ipc_get_fd(native->ipc);
 
         } else if (native->ipc) {
             rc = -ENOTCONN;
         }
 
     } else {
         /* With mainloop */
         native->source =
-            mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
+            mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, stonith, &st_callbacks);
         native->ipc = mainloop_get_ipc_client(native->source);
     }
 
     if (native->ipc == NULL) {
         crm_debug("Could not connect to the Stonith API");
         rc = -ENOTCONN;
     }
 
     if (rc == pcmk_ok) {
         xmlNode *reply = NULL;
         xmlNode *hello = create_xml_node(NULL, "stonith_command");
 
         crm_xml_add(hello, F_TYPE, T_STONITH_NG);
         crm_xml_add(hello, F_STONITH_OPERATION, CRM_OP_REGISTER);
         crm_xml_add(hello, F_STONITH_CLIENTNAME, name);
         rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
 
         if (rc < 0) {
             crm_perror(LOG_DEBUG, "Couldn't complete registration with the fencing API: %d", rc);
             rc = -ECOMM;
 
         } else if (reply == NULL) {
             crm_err("Did not receive registration reply");
             rc = -EPROTO;
 
         } else {
             const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
             const char *tmp_ticket = crm_element_value(reply, F_STONITH_CLIENTID);
 
             if (safe_str_neq(msg_type, CRM_OP_REGISTER)) {
                 crm_err("Invalid registration message: %s", msg_type);
                 crm_log_xml_err(reply, "Bad reply");
                 rc = -EPROTO;
 
             } else if (tmp_ticket == NULL) {
                 crm_err("No registration token provided");
                 crm_log_xml_err(reply, "Bad reply");
                 rc = -EPROTO;
 
             } else {
                 crm_trace("Obtained registration token: %s", tmp_ticket);
                 native->token = strdup(tmp_ticket);
                 rc = pcmk_ok;
             }
         }
 
         free_xml(reply);
         free_xml(hello);
     }
 
     if (rc == pcmk_ok) {
 #if HAVE_MSGFROMIPC_TIMEOUT
         stonith->call_timeout = MAX_IPC_DELAY;
 #endif
         crm_debug("Connection to STONITH successful");
         return pcmk_ok;
     }
 
     crm_debug("Connection to STONITH failed: %s", pcmk_strerror(rc));
     stonith->cmds->disconnect(stonith);
     return rc;
 }
 
 static int
 stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
 {
     xmlNode *notify_msg = create_xml_node(NULL, __FUNCTION__);
     stonith_private_t *native = stonith->private;
 
     if (stonith->state != stonith_disconnected) {
         int rc;
 
         crm_xml_add(notify_msg, F_STONITH_OPERATION, T_STONITH_NOTIFY);
         if (enabled) {
             crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
         } else {
             crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
         }
         rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
         if (rc < 0) {
             crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
             rc = -ECOMM;
         }
     }
 
     free_xml(notify_msg);
     return pcmk_ok;
 }
 
 static int
 stonith_api_add_notification(stonith_t * stonith, const char *event,
                              void (*callback) (stonith_t * stonith, stonith_event_t * e))
 {
     GList *list_item = NULL;
     stonith_notify_client_t *new_client = NULL;
     stonith_private_t *private = NULL;
 
     private = stonith->private;
     crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
 
     new_client = calloc(1, sizeof(stonith_notify_client_t));
     new_client->event = event;
     new_client->notify = callback;
 
     list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
 
     if (list_item != NULL) {
         crm_warn("Callback already present");
         free(new_client);
         return -ENOTUNIQ;
 
     } else {
         private->notify_list = g_list_append(private->notify_list, new_client);
 
         stonith_set_notification(stonith, event, 1);
 
         crm_trace("Callback added (%d)", g_list_length(private->notify_list));
     }
     return pcmk_ok;
 }
 
 static int
 stonith_api_del_notification(stonith_t * stonith, const char *event)
 {
     GList *list_item = NULL;
     stonith_notify_client_t *new_client = NULL;
     stonith_private_t *private = NULL;
 
     crm_debug("Removing callback for %s events", event);
 
     private = stonith->private;
     new_client = calloc(1, sizeof(stonith_notify_client_t));
     new_client->event = event;
     new_client->notify = NULL;
 
     list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
 
     stonith_set_notification(stonith, event, 0);
 
     if (list_item != NULL) {
         stonith_notify_client_t *list_client = list_item->data;
 
         private->notify_list = g_list_remove(private->notify_list, list_client);
         free(list_client);
 
         crm_trace("Removed callback");
 
     } else {
         crm_trace("Callback not present");
     }
     free(new_client);
     return pcmk_ok;
 }
 
 static gboolean
 stonith_async_timeout_handler(gpointer data)
 {
     struct timer_rec_s *timer = data;
 
     crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
     stonith_perform_callback(timer->stonith, NULL, timer->call_id, -ETIME);
 
     /* Always return TRUE, never remove the handler
      * We do that in stonith_del_callback()
      */
     return TRUE;
 }
 
 static void
 set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
                      int timeout)
 {
     struct timer_rec_s *async_timer = callback->timer;
 
     if (timeout <= 0) {
         return;
     }
 
     if (!async_timer) {
         async_timer = calloc(1, sizeof(struct timer_rec_s));
         callback->timer = async_timer;
     }
 
     async_timer->stonith = stonith;
     async_timer->call_id = call_id;
     /* Allow a fair bit of grace to allow the server to tell us of a timeout
      * This is only a fallback
      */
     async_timer->timeout = (timeout + 60) * 1000;
     if (async_timer->ref) {
         g_source_remove(async_timer->ref);
     }
     async_timer->ref =
         g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
 }
 
 static void
 update_callback_timeout(int call_id, int timeout, stonith_t * st)
 {
     stonith_callback_client_t *callback = NULL;
     stonith_private_t *private = st->private;
 
     callback = g_hash_table_lookup(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
     if (!callback || !callback->allow_timeout_updates) {
         return;
     }
 
     set_callback_timeout(callback, st, call_id, timeout);
 }
 
 static void
 invoke_callback(stonith_t * st, int call_id, int rc, void *userdata,
                 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
 {
     stonith_callback_data_t data = { 0, };
 
     data.call_id = call_id;
     data.rc = rc;
     data.userdata = userdata;
 
     callback(st, &data);
 }
 
 static int
 stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
                          void *user_data, const char *callback_name,
                          void (*callback) (stonith_t * st, stonith_callback_data_t * data))
 {
     stonith_callback_client_t *blob = NULL;
     stonith_private_t *private = NULL;
 
     CRM_CHECK(stonith != NULL, return -EINVAL);
     CRM_CHECK(stonith->private != NULL, return -EINVAL);
     private = stonith->private;
 
     if (call_id == 0) {
         private->op_callback = callback;
 
     } else if (call_id < 0) {
         if (!(options & st_opt_report_only_success)) {
             crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
             invoke_callback(stonith, call_id, call_id, user_data, callback);
         } else {
             crm_warn("STONITH call failed: %s", pcmk_strerror(call_id));
         }
         return FALSE;
     }
 
     blob = calloc(1, sizeof(stonith_callback_client_t));
     blob->id = callback_name;
     blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
     blob->user_data = user_data;
     blob->callback = callback;
     blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
 
     if (timeout > 0) {
         set_callback_timeout(blob, stonith, call_id, timeout);
     }
 
     g_hash_table_insert(private->stonith_op_callback_table, GINT_TO_POINTER(call_id), blob);
     crm_trace("Added callback to %s for call %d", callback_name, call_id);
 
     return TRUE;
 }
 
 static int
 stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
 {
     stonith_private_t *private = stonith->private;
 
     if (all_callbacks) {
         private->op_callback = NULL;
         g_hash_table_destroy(private->stonith_op_callback_table);
         private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
                                                                    NULL,
                                                                    stonith_destroy_op_callback);
 
     } else if (call_id == 0) {
         private->op_callback = NULL;
 
     } else {
         g_hash_table_remove(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
     }
     return pcmk_ok;
 }
 
 static void
 stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
 {
     int call = GPOINTER_TO_INT(key);
     stonith_callback_client_t *blob = value;
 
     crm_debug("Call %d (%s): pending", call, crm_str(blob->id));
 }
 
 void
 stonith_dump_pending_callbacks(stonith_t * stonith)
 {
     stonith_private_t *private = stonith->private;
 
     if (private->stonith_op_callback_table == NULL) {
         return;
     }
     return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
 }
 
 void
 stonith_perform_callback(stonith_t * stonith, xmlNode * msg, int call_id, int rc)
 {
     stonith_private_t *private = NULL;
     stonith_callback_client_t *blob = NULL;
     stonith_callback_client_t local_blob;
 
     CRM_CHECK(stonith != NULL, return);
     CRM_CHECK(stonith->private != NULL, return);
 
     private = stonith->private;
 
     local_blob.id = NULL;
     local_blob.callback = NULL;
     local_blob.user_data = NULL;
     local_blob.only_success = FALSE;
 
     if (msg != NULL) {
         crm_element_value_int(msg, F_STONITH_RC, &rc);
         crm_element_value_int(msg, F_STONITH_CALLID, &call_id);
     }
 
     CRM_CHECK(call_id > 0, crm_log_xml_err(msg, "Bad result"));
 
     blob = g_hash_table_lookup(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
 
     if (blob != NULL) {
         local_blob = *blob;
         blob = NULL;
 
         stonith_api_del_callback(stonith, call_id, FALSE);
 
     } else {
         crm_trace("No callback found for call %d", call_id);
         local_blob.callback = NULL;
     }
 
     if (local_blob.callback != NULL && (rc == pcmk_ok || local_blob.only_success == FALSE)) {
         crm_trace("Invoking callback %s for call %d", crm_str(local_blob.id), call_id);
         invoke_callback(stonith, call_id, rc, local_blob.user_data, local_blob.callback);
 
     } else if (private->op_callback == NULL && rc != pcmk_ok) {
         crm_warn("STONITH command failed: %s", pcmk_strerror(rc));
         crm_log_xml_debug(msg, "Failed STONITH Update");
     }
 
     if (private->op_callback != NULL) {
         crm_trace("Invoking global callback for call %d", call_id);
         invoke_callback(stonith, call_id, rc, NULL, private->op_callback);
     }
     crm_trace("OP callback activated.");
 }
 
 /*
  <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
    <st_calldata >
      <stonith_command t="stonith-ng" st_async_id="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_op="st_device_register" st_callid="2" st_callopt="4096" st_timeout="0" st_clientid="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_clientname="stonith-test" >
        <st_calldata >
          <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
            <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
          </st_device_id>
        </st_calldata>
      </stonith_command>
    </st_calldata>
  </notify>
 
  <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
    <st_calldata >
      <st_notify_fence st_rc="0" st_target="some-host" st_op="st_fence" st_delegate="test-id" st_origin="61dd7759-e229-4be7-b1f8-ef49dd14d9f0" />
    </st_calldata>
  </notify>
 */
 static stonith_event_t *
 xml_to_event(xmlNode * msg)
 {
     stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
     const char *ntype = crm_element_value(msg, F_SUBTYPE);
     char *data_addr = g_strdup_printf("//%s", ntype);
     xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
 
     crm_log_xml_trace(msg, "stonith_notify");
 
     crm_element_value_int(msg, F_STONITH_RC, &(event->result));
 
     if (safe_str_eq(ntype, T_STONITH_NOTIFY_FENCE)) {
         event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
 
         if (data) {
             event->origin = crm_element_value_copy(data, F_STONITH_ORIGIN);
             event->action = crm_element_value_copy(data, F_STONITH_ACTION);
             event->target = crm_element_value_copy(data, F_STONITH_TARGET);
             event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
             event->id = crm_element_value_copy(data, F_STONITH_REMOTE_OP_ID);
             event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
         } else {
             crm_err("No data for %s event", ntype);
             crm_log_xml_notice(msg, "BadEvent");
         }
     }
 
     g_free(data_addr);
     return event;
 }
 
 static void
 event_free(stonith_event_t * event)
 {
     free(event->id);
     free(event->type);
     free(event->message);
     free(event->operation);
     free(event->origin);
     free(event->action);
     free(event->target);
     free(event->executioner);
     free(event->device);
     free(event->client_origin);
     free(event);
 }
 
 static void
 stonith_send_notification(gpointer data, gpointer user_data)
 {
     struct notify_blob_s *blob = user_data;
     stonith_notify_client_t *entry = data;
     stonith_event_t *st_event = NULL;
     const char *event = NULL;
 
     if (blob->xml == NULL) {
         crm_warn("Skipping callback - NULL message");
         return;
     }
 
     event = crm_element_value(blob->xml, F_SUBTYPE);
 
     if (entry == NULL) {
         crm_warn("Skipping callback - NULL callback client");
         return;
 
     } else if (entry->notify == NULL) {
         crm_warn("Skipping callback - NULL callback");
         return;
 
     } else if (safe_str_neq(entry->event, event)) {
         crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
         return;
     }
 
     st_event = xml_to_event(blob->xml);
 
     crm_trace("Invoking callback for %p/%s event...", entry, event);
     entry->notify(blob->stonith, st_event);
     crm_trace("Callback invoked...");
 
     event_free(st_event);
 }
 
 int
 stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
                      int call_options, int timeout)
 {
     int rc = 0;
     int reply_id = -1;
     enum crm_ipc_flags ipc_flags = crm_ipc_client_none;
 
     xmlNode *op_msg = NULL;
     xmlNode *op_reply = NULL;
 
     stonith_private_t *native = stonith->private;
 
     if (stonith->state == stonith_disconnected) {
         return -ENOTCONN;
     }
 
     if (output_data != NULL) {
         *output_data = NULL;
     }
 
     if (op == NULL) {
         crm_err("No operation specified");
         return -EINVAL;
     }
 
     if (call_options & st_opt_sync_call) {
         ipc_flags |= crm_ipc_client_response;
     }
 
     stonith->call_id++;
     /* prevent call_id from being negative (or zero) and conflicting
      *    with the stonith_errors enum
      * use 2 because we use it as (stonith->call_id - 1) below
      */
     if (stonith->call_id < 1) {
         stonith->call_id = 1;
     }
 
     CRM_CHECK(native->token != NULL,;
         );
     op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
     if (op_msg == NULL) {
         return -EINVAL;
     }
 
     crm_xml_add_int(op_msg, F_STONITH_TIMEOUT, timeout);
     crm_trace("Sending %s message to STONITH service, Timeout: %ds", op, timeout);
 
     rc = crm_ipc_send(native->ipc, op_msg, ipc_flags, 1000 * (timeout + 60), &op_reply);
     free_xml(op_msg);
 
     if (rc < 0) {
         crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
         rc = -ECOMM;
         goto done;
     }
 
     crm_log_xml_trace(op_reply, "Reply");
 
     if (!(call_options & st_opt_sync_call)) {
         crm_trace("Async call %d, returning", stonith->call_id);
         CRM_CHECK(stonith->call_id != 0, return -EPROTO);
         free_xml(op_reply);
 
         return stonith->call_id;
     }
 
     rc = pcmk_ok;
     crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
 
     if (reply_id == stonith->call_id) {
         crm_trace("Syncronous reply %d received", reply_id);
 
         if (crm_element_value_int(op_reply, F_STONITH_RC, &rc) != 0) {
             rc = -ENOMSG;
         }
 
         if ((call_options & st_opt_discard_reply) || output_data == NULL) {
             crm_trace("Discarding reply");
 
         } else {
             *output_data = op_reply;
             op_reply = NULL;    /* Prevent subsequent free */
         }
 
     } else if (reply_id <= 0) {
         crm_err("Received bad reply: No id set");
         crm_log_xml_err(op_reply, "Bad reply");
         free_xml(op_reply);
         rc = -ENOMSG;
 
     } else {
         crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
         crm_log_xml_err(op_reply, "Old reply");
         free_xml(op_reply);
         rc = -ENOMSG;
     }
 
   done:
     if (crm_ipc_connected(native->ipc) == FALSE) {
         crm_err("STONITH disconnected");
         stonith->state = stonith_disconnected;
     }
 
     free_xml(op_reply);
     return rc;
 }
 
 /* Not used with mainloop */
 bool
 stonith_dispatch(stonith_t * st)
 {
     gboolean stay_connected = TRUE;
     stonith_private_t *private = NULL;
 
     CRM_ASSERT(st != NULL);
     private = st->private;
 
     while (crm_ipc_ready(private->ipc)) {
 
         if (crm_ipc_read(private->ipc) > 0) {
             const char *msg = crm_ipc_buffer(private->ipc);
 
             stonith_dispatch_internal(msg, strlen(msg), st);
         }
 
         if (crm_ipc_connected(private->ipc) == FALSE) {
             crm_err("Connection closed");
             stay_connected = FALSE;
         }
     }
 
     return stay_connected;
 }
 
 int
 stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
 {
     const char *type = NULL;
     struct notify_blob_s blob;
 
     stonith_t *st = userdata;
     stonith_private_t *private = NULL;
 
     CRM_ASSERT(st != NULL);
     private = st->private;
 
     blob.stonith = st;
     blob.xml = string2xml(buffer);
     if (blob.xml == NULL) {
         crm_warn("Received a NULL msg from STONITH service: %s.", buffer);
         return 0;
     }
 
     /* do callbacks */
     type = crm_element_value(blob.xml, F_TYPE);
     crm_trace("Activating %s callbacks...", type);
 
     if (safe_str_eq(type, T_STONITH_NG)) {
         stonith_perform_callback(st, blob.xml, 0, 0);
 
     } else if (safe_str_eq(type, T_STONITH_NOTIFY)) {
         g_list_foreach(private->notify_list, stonith_send_notification, &blob);
     } else if (safe_str_eq(type, T_STONITH_TIMEOUT_VALUE)) {
         int call_id = 0;
         int timeout = 0;
 
         crm_element_value_int(blob.xml, F_STONITH_TIMEOUT, &timeout);
         crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
 
         update_callback_timeout(call_id, timeout, st);
     } else {
         crm_err("Unknown message type: %s", type);
         crm_log_xml_warn(blob.xml, "BadReply");
     }
 
     free_xml(blob.xml);
     return 1;
 }
 
 static int
 stonith_api_free(stonith_t * stonith)
 {
     int rc = pcmk_ok;
 
     crm_trace("Destroying %p", stonith);
 
     if (stonith->state != stonith_disconnected) {
         crm_trace("Disconnecting %p first", stonith);
         rc = stonith->cmds->disconnect(stonith);
     }
 
     if (stonith->state == stonith_disconnected) {
         stonith_private_t *private = stonith->private;
 
         crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
         g_hash_table_destroy(private->stonith_op_callback_table);
 
         crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
         g_list_free_full(private->notify_list, free);
 
         free(stonith->private);
         free(stonith->cmds);
         free(stonith);
 
     } else {
         crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
     }
 
     return rc;
 }
 
 void
 stonith_api_delete(stonith_t * stonith)
 {
     crm_trace("Destroying %p", stonith);
     if(stonith) {
         stonith->cmds->free(stonith);
     }
 }
 
 stonith_t *
 stonith_api_new(void)
 {
     stonith_t *new_stonith = NULL;
     stonith_private_t *private = NULL;
 
     new_stonith = calloc(1, sizeof(stonith_t));
     private = calloc(1, sizeof(stonith_private_t));
     new_stonith->private = private;
 
     private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
                                                                NULL, stonith_destroy_op_callback);
     private->notify_list = NULL;
 
     new_stonith->call_id = 1;
     new_stonith->state = stonith_disconnected;
 
     new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
 
 /* *INDENT-OFF* */
     new_stonith->cmds->free       = stonith_api_free;
     new_stonith->cmds->connect    = stonith_api_signon;
     new_stonith->cmds->disconnect = stonith_api_signoff;
 
     new_stonith->cmds->list       = stonith_api_list;
     new_stonith->cmds->monitor    = stonith_api_monitor;
     new_stonith->cmds->status     = stonith_api_status;
     new_stonith->cmds->fence      = stonith_api_fence;
     new_stonith->cmds->confirm    = stonith_api_confirm;
     new_stonith->cmds->history    = stonith_api_history;
 
     new_stonith->cmds->list_agents  = stonith_api_device_list;
     new_stonith->cmds->metadata     = stonith_api_device_metadata;
 
     new_stonith->cmds->query           = stonith_api_query;
     new_stonith->cmds->remove_device   = stonith_api_remove_device;
     new_stonith->cmds->register_device = stonith_api_register_device;
 
     new_stonith->cmds->remove_level    = stonith_api_remove_level;
     new_stonith->cmds->register_level  = stonith_api_register_level;
 
     new_stonith->cmds->remove_callback       = stonith_api_del_callback;
     new_stonith->cmds->register_callback     = stonith_api_add_callback;
     new_stonith->cmds->remove_notification   = stonith_api_del_notification;
     new_stonith->cmds->register_notification = stonith_api_add_notification;
 /* *INDENT-ON* */
 
     return new_stonith;
 }
 
 stonith_key_value_t *
 stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
 {
     stonith_key_value_t *p, *end;
 
     p = calloc(1, sizeof(stonith_key_value_t));
     if (key) {
         p->key = strdup(key);
     }
     if (value) {
         p->value = strdup(value);
     }
 
     end = head;
     while (end && end->next) {
         end = end->next;
     }
 
     if (end) {
         end->next = p;
     } else {
         head = p;
     }
 
     return head;
 }
 
 void
 stonith_key_value_freeall(stonith_key_value_t * head, int keys, int values)
 {
     stonith_key_value_t *p;
 
     while (head) {
         p = head->next;
         if (keys) {
             free(head->key);
         }
         if (values) {
             free(head->value);
         }
         free(head);
         head = p;
     }
 }
 
 int
 stonith_api_kick(int nodeid, const char *uname, int timeout, bool off)
 {
     char *name = NULL;
     const char *action = "reboot";
 
     int rc = -EPROTO;
     stonith_t *st = NULL;
     enum stonith_call_options opts = st_opt_sync_call | st_opt_allow_suicide;
 
     st = stonith_api_new();
     if (st) {
         rc = st->cmds->connect(st, "stonith-api", NULL);
     }
 
     if (uname != NULL) {
         name = strdup(uname);
 
     } else if (nodeid > 0) {
         opts |= st_opt_cs_nodeid;
         name = crm_itoa(nodeid);
     }
 
     if (off) {
         action = "off";
     }
 
     if (rc == pcmk_ok) {
         rc = st->cmds->fence(st, opts, name, action, timeout, 0);
     }
 
     if (st) {
         st->cmds->disconnect(st);
         stonith_api_delete(st);
     }
 
     free(name);
     return rc;
 }
 
 time_t
 stonith_api_time(int nodeid, const char *uname, bool in_progress)
 {
     int rc = 0;
     char *name = NULL;
 
     time_t when = 0;
     time_t progress = 0;
     stonith_t *st = NULL;
     stonith_history_t *history, *hp = NULL;
     enum stonith_call_options opts = st_opt_sync_call;
 
     st = stonith_api_new();
     if (st) {
         rc = st->cmds->connect(st, "stonith-api", NULL);
     }
 
     if (uname != NULL) {
         name = strdup(uname);
 
     } else if (nodeid > 0) {
         opts |= st_opt_cs_nodeid;
         name = crm_itoa(nodeid);
     }
 
     if (st && rc == pcmk_ok) {
         st->cmds->history(st, st_opt_sync_call | st_opt_cs_nodeid, name, &history, 120);
 
         for (hp = history; hp; hp = hp->next) {
             if (in_progress) {
                 if (hp->state != st_done && hp->state != st_failed) {
                     progress = time(NULL);
                 }
 
             } else if (hp->state == st_done) {
                 when = hp->completed;
             }
         }
     }
 
     if (progress) {
         when = progress;
     }
 
     if (st) {
         st->cmds->disconnect(st);
         stonith_api_delete(st);
     }
 
     free(name);
     return when;
 }
 
 #if HAVE_STONITH_STONITH_H
 #  include <pils/plugin.h>
 
 const char *i_hate_pils(int rc);
 
 const char *
 i_hate_pils(int rc)
 {
     return PIL_strerror(rc);
 }
 #endif
diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c
index 48d9b84138..7b11f87ed4 100644
--- a/lib/lrmd/lrmd_client.c
+++ b/lib/lrmd/lrmd_client.c
@@ -1,2035 +1,2035 @@
 /*
  * Copyright (c) 2012 David Vossel <dvossel@redhat.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
 #include <crm_internal.h>
 
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
 #include <ctype.h>
 
 #include <sys/types.h>
 #include <sys/wait.h>
 
 #include <glib.h>
 #include <dirent.h>
 
 #include <crm/crm.h>
 #include <crm/lrmd.h>
 #include <crm/services.h>
 #include <crm/common/mainloop.h>
 #include <crm/common/ipcs.h>
 #include <crm/msg_xml.h>
 
 #include <crm/stonith-ng.h>
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 #  undef KEYFILE
 #  include <gnutls/gnutls.h>
 #endif
 
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 
 CRM_TRACE_INIT_DATA(lrmd);
 
 static int lrmd_api_disconnect(lrmd_t * lrmd);
 static int lrmd_api_is_connected(lrmd_t * lrmd);
 
 /* IPC proxy functions */
 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
 static void lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg);
 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 #  define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000    /* 5 seconds */
 gnutls_psk_client_credentials_t psk_cred_s;
 int lrmd_tls_set_key(gnutls_datum_t * key);
 static void lrmd_tls_disconnect(lrmd_t * lrmd);
 static int global_remote_msg_id = 0;
 int lrmd_tls_send_msg(crm_remote_t * session, xmlNode * msg, uint32_t id, const char *msg_type);
 static void lrmd_tls_connection_destroy(gpointer userdata);
 #endif
 
 typedef struct lrmd_private_s {
     enum client_type type;
     char *token;
     mainloop_io_t *source;
 
     /* IPC parameters */
     crm_ipc_t *ipc;
 
     crm_remote_t *remote;
 
     /* Extra TLS parameters */
     char *remote_nodename;
 #ifdef HAVE_GNUTLS_GNUTLS_H
     char *server;
     int port;
     gnutls_psk_client_credentials_t psk_cred_c;
 
     int sock;
     /* since tls requires a round trip across the network for a
      * request/reply, there are times where we just want to be able
      * to send a request from the client and not wait around (or even care
      * about) what the reply is. */
     int expected_late_replies;
     GList *pending_notify;
     crm_trigger_t *process_notify;
 #endif
 
     lrmd_event_callback callback;
 
     /* Internal IPC proxy msg passing for remote guests */
     void (*proxy_callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg);
     void *proxy_callback_userdata;
 } lrmd_private_t;
 
 static lrmd_list_t *
 lrmd_list_add(lrmd_list_t * head, const char *value)
 {
     lrmd_list_t *p, *end;
 
     p = calloc(1, sizeof(lrmd_list_t));
     p->val = strdup(value);
 
     end = head;
     while (end && end->next) {
         end = end->next;
     }
 
     if (end) {
         end->next = p;
     } else {
         head = p;
     }
 
     return head;
 }
 
 void
 lrmd_list_freeall(lrmd_list_t * head)
 {
     lrmd_list_t *p;
 
     while (head) {
         char *val = (char *)head->val;
 
         p = head->next;
         free(val);
         free(head);
         head = p;
     }
 }
 
 lrmd_key_value_t *
 lrmd_key_value_add(lrmd_key_value_t * head, const char *key, const char *value)
 {
     lrmd_key_value_t *p, *end;
 
     p = calloc(1, sizeof(lrmd_key_value_t));
     p->key = strdup(key);
     p->value = strdup(value);
 
     end = head;
     while (end && end->next) {
         end = end->next;
     }
 
     if (end) {
         end->next = p;
     } else {
         head = p;
     }
 
     return head;
 }
 
 void
 lrmd_key_value_freeall(lrmd_key_value_t * head)
 {
     lrmd_key_value_t *p;
 
     while (head) {
         p = head->next;
         free(head->key);
         free(head->value);
         free(head);
         head = p;
     }
 }
 
 static void
 dup_attr(gpointer key, gpointer value, gpointer user_data)
 {
     g_hash_table_replace(user_data, strdup(key), strdup(value));
 }
 
 lrmd_event_data_t *
 lrmd_copy_event(lrmd_event_data_t * event)
 {
     lrmd_event_data_t *copy = NULL;
 
     copy = calloc(1, sizeof(lrmd_event_data_t));
 
     /* This will get all the int values.
      * we just have to be careful not to leave any
      * dangling pointers to strings. */
     memcpy(copy, event, sizeof(lrmd_event_data_t));
 
     copy->rsc_id = event->rsc_id ? strdup(event->rsc_id) : NULL;
     copy->op_type = event->op_type ? strdup(event->op_type) : NULL;
     copy->user_data = event->user_data ? strdup(event->user_data) : NULL;
     copy->output = event->output ? strdup(event->output) : NULL;
     copy->remote_nodename = event->remote_nodename ? strdup(event->remote_nodename) : NULL;
 
     if (event->params) {
         copy->params = g_hash_table_new_full(crm_str_hash,
                                              g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
 
         if (copy->params != NULL) {
             g_hash_table_foreach(event->params, dup_attr, copy->params);
         }
     }
 
     return copy;
 }
 
 void
 lrmd_free_event(lrmd_event_data_t * event)
 {
     if (!event) {
         return;
     }
 
     /* free gives me grief if i try to cast */
     free((char *)event->rsc_id);
     free((char *)event->op_type);
     free((char *)event->user_data);
     free((char *)event->output);
     free((char *)event->remote_nodename);
     if (event->params) {
         g_hash_table_destroy(event->params);
     }
     free(event);
 }
 
 static int
 lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg)
 {
     const char *type;
     const char *proxy_session = crm_element_value(msg, F_LRMD_IPC_SESSION);
     lrmd_private_t *native = lrmd->private;
     lrmd_event_data_t event = { 0, };
 
     if (proxy_session != NULL) {
         /* this is proxy business */
         lrmd_internal_proxy_dispatch(lrmd, msg);
         return 1;
     } else if (!native->callback) {
         /* no callback set */
         crm_trace("notify event received but client has not set callback");
         return 1;
     }
 
     event.remote_nodename = native->remote_nodename;
     type = crm_element_value(msg, F_LRMD_OPERATION);
     crm_element_value_int(msg, F_LRMD_CALLID, &event.call_id);
     event.rsc_id = crm_element_value(msg, F_LRMD_RSC_ID);
 
     if (crm_str_eq(type, LRMD_OP_RSC_REG, TRUE)) {
         event.type = lrmd_event_register;
     } else if (crm_str_eq(type, LRMD_OP_RSC_UNREG, TRUE)) {
         event.type = lrmd_event_unregister;
     } else if (crm_str_eq(type, LRMD_OP_RSC_EXEC, TRUE)) {
         crm_element_value_int(msg, F_LRMD_TIMEOUT, &event.timeout);
         crm_element_value_int(msg, F_LRMD_RSC_INTERVAL, &event.interval);
         crm_element_value_int(msg, F_LRMD_RSC_START_DELAY, &event.start_delay);
         crm_element_value_int(msg, F_LRMD_EXEC_RC, (int *)&event.rc);
         crm_element_value_int(msg, F_LRMD_OP_STATUS, &event.op_status);
         crm_element_value_int(msg, F_LRMD_RSC_DELETED, &event.rsc_deleted);
 
         crm_element_value_int(msg, F_LRMD_RSC_RUN_TIME, (int *)&event.t_run);
         crm_element_value_int(msg, F_LRMD_RSC_RCCHANGE_TIME, (int *)&event.t_rcchange);
         crm_element_value_int(msg, F_LRMD_RSC_EXEC_TIME, (int *)&event.exec_time);
         crm_element_value_int(msg, F_LRMD_RSC_QUEUE_TIME, (int *)&event.queue_time);
 
         event.op_type = crm_element_value(msg, F_LRMD_RSC_ACTION);
         event.user_data = crm_element_value(msg, F_LRMD_RSC_USERDATA_STR);
         event.output = crm_element_value(msg, F_LRMD_RSC_OUTPUT);
         event.type = lrmd_event_exec_complete;
 
         event.params = xml2list(msg);
     } else if (crm_str_eq(type, LRMD_OP_POKE, TRUE)) {
         event.type = lrmd_event_poke;
     } else {
         return 1;
     }
 
     crm_trace("op %s notify event received", type);
     native->callback(&event);
 
     if (event.params) {
         g_hash_table_destroy(event.params);
     }
     return 1;
 }
 
 static int
 lrmd_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
 {
     lrmd_t *lrmd = userdata;
     lrmd_private_t *native = lrmd->private;
     xmlNode *msg;
     int rc;
 
     if (!native->callback) {
         /* no callback set */
         return 1;
     }
 
     msg = string2xml(buffer);
     rc = lrmd_dispatch_internal(lrmd, msg);
     free_xml(msg);
     return rc;
 }
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 static void
 lrmd_free_xml(gpointer userdata)
 {
     free_xml((xmlNode *) userdata);
 }
 
 static int
 lrmd_tls_connected(lrmd_t * lrmd)
 {
     lrmd_private_t *native = lrmd->private;
 
     if (native->remote->tls_session) {
         return TRUE;
     }
 
     return FALSE;
 }
 
 static int
 lrmd_tls_dispatch(gpointer userdata)
 {
     lrmd_t *lrmd = userdata;
     lrmd_private_t *native = lrmd->private;
     xmlNode *xml = NULL;
     int rc = 0;
     int disconnected = 0;
 
     if (lrmd_tls_connected(lrmd) == FALSE) {
         crm_trace("tls dispatch triggered after disconnect");
         return 0;
     }
 
     crm_trace("tls_dispatch triggered");
 
     /* First check if there are any pending notifies to process that came
      * while we were waiting for replies earlier. */
     if (native->pending_notify) {
         GList *iter = NULL;
 
         crm_trace("Processing pending notifies");
         for (iter = native->pending_notify; iter; iter = iter->next) {
             lrmd_dispatch_internal(lrmd, iter->data);
         }
         g_list_free_full(native->pending_notify, lrmd_free_xml);
         native->pending_notify = NULL;
     }
 
     /* Next read the current buffer and see if there are any messages to handle. */
     rc = crm_remote_ready(native->remote, 0);
     if (rc == 0) {
         /* nothing to read, see if any full messages are already in buffer. */
         xml = crm_remote_parse_buffer(native->remote);
     } else if (rc < 0) {
         disconnected = 1;
     } else {
         crm_remote_recv(native->remote, -1, &disconnected);
         xml = crm_remote_parse_buffer(native->remote);
     }
     while (xml) {
         const char *msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
         if (safe_str_eq(msg_type, "notify")) {
             lrmd_dispatch_internal(lrmd, xml);
         } else if (safe_str_eq(msg_type, "reply")) {
             if (native->expected_late_replies > 0) {
                 native->expected_late_replies--;
             } else {
                 int reply_id = 0;
                 crm_element_value_int(xml, F_LRMD_CALLID, &reply_id);
                 /* if this happens, we want to know about it */
                 crm_err("Got outdated reply %d", reply_id);
             }
         }
         free_xml(xml);
         xml = crm_remote_parse_buffer(native->remote);
     }
 
     if (disconnected) {
         crm_info("Server disconnected while reading remote server msg.");
         lrmd_tls_disconnect(lrmd);
         return 0;
     }
     return 1;
 }
 #endif
 
 /* Not used with mainloop */
 int
 lrmd_poll(lrmd_t * lrmd, int timeout)
 {
     lrmd_private_t *native = lrmd->private;
 
     switch (native->type) {
         case CRM_CLIENT_IPC:
             return crm_ipc_ready(native->ipc);
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             if (native->pending_notify) {
                 return 1;
             } else if (native->remote->buffer
                        && strstr(native->remote->buffer, REMOTE_MSG_TERMINATOR)) {
                 return 1;
             }
 
             return crm_remote_ready(native->remote, 0);
 #endif
         default:
             crm_err("Unsupported connection type: %d", native->type);
     }
 
     return 0;
 }
 
 /* Not used with mainloop */
 bool
 lrmd_dispatch(lrmd_t * lrmd)
 {
     lrmd_private_t *private = NULL;
 
     CRM_ASSERT(lrmd != NULL);
 
     private = lrmd->private;
     switch (private->type) {
         case CRM_CLIENT_IPC:
             while (crm_ipc_ready(private->ipc)) {
                 if (crm_ipc_read(private->ipc) > 0) {
                     const char *msg = crm_ipc_buffer(private->ipc);
 
                     lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
                 }
             }
             break;
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             lrmd_tls_dispatch(lrmd);
             break;
 #endif
         default:
             crm_err("Unsupported connection type: %d", private->type);
     }
 
     if (lrmd_api_is_connected(lrmd) == FALSE) {
         crm_err("Connection closed");
         return FALSE;
     }
 
     return TRUE;
 }
 
 static xmlNode *
 lrmd_create_op(const char *token, const char *op, xmlNode * data, enum lrmd_call_options options)
 {
     xmlNode *op_msg = create_xml_node(NULL, "lrmd_command");
 
     CRM_CHECK(op_msg != NULL, return NULL);
     CRM_CHECK(token != NULL, return NULL);
 
     crm_xml_add(op_msg, F_XML_TAGNAME, "lrmd_command");
 
     crm_xml_add(op_msg, F_TYPE, T_LRMD);
     crm_xml_add(op_msg, F_LRMD_CALLBACK_TOKEN, token);
     crm_xml_add(op_msg, F_LRMD_OPERATION, op);
     crm_trace("Sending call options: %.8lx, %d", (long)options, options);
     crm_xml_add_int(op_msg, F_LRMD_CALLOPTS, options);
 
     if (data != NULL) {
         add_message_xml(op_msg, F_LRMD_CALLDATA, data);
     }
 
     return op_msg;
 }
 
 static void
 lrmd_ipc_connection_destroy(gpointer userdata)
 {
     lrmd_t *lrmd = userdata;
     lrmd_private_t *native = lrmd->private;
 
     crm_info("IPC connection destroyed");
 
     /* Prevent these from being cleaned up in lrmd_api_disconnect() */
     native->ipc = NULL;
     native->source = NULL;
 
     if (native->callback) {
         lrmd_event_data_t event = { 0, };
         event.type = lrmd_event_disconnect;
         event.remote_nodename = native->remote_nodename;
         native->callback(&event);
     }
 }
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 static void
 lrmd_tls_connection_destroy(gpointer userdata)
 {
     lrmd_t *lrmd = userdata;
     lrmd_private_t *native = lrmd->private;
 
     crm_info("TLS connection destroyed");
 
     if (native->remote->tls_session) {
         gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
         gnutls_deinit(*native->remote->tls_session);
         gnutls_free(native->remote->tls_session);
     }
     if (native->psk_cred_c) {
         gnutls_psk_free_client_credentials(native->psk_cred_c);
     }
     if (native->sock) {
         close(native->sock);
     }
     if (native->process_notify) {
         mainloop_destroy_trigger(native->process_notify);
         native->process_notify = NULL;
     }
     if (native->pending_notify) {
         g_list_free_full(native->pending_notify, lrmd_free_xml);
         native->pending_notify = NULL;
     }
 
     free(native->remote->buffer);
     native->remote->buffer = NULL;
     native->source = 0;
     native->sock = 0;
     native->psk_cred_c = NULL;
     native->remote->tls_session = NULL;
     native->sock = 0;
 
     if (native->callback) {
         lrmd_event_data_t event = { 0, };
         event.remote_nodename = native->remote_nodename;
         event.type = lrmd_event_disconnect;
         native->callback(&event);
     }
     return;
 }
 
 int
 lrmd_tls_send_msg(crm_remote_t * session, xmlNode * msg, uint32_t id, const char *msg_type)
 {
     int rc = -1;
 
     crm_xml_add_int(msg, F_LRMD_REMOTE_MSG_ID, id);
     crm_xml_add(msg, F_LRMD_REMOTE_MSG_TYPE, msg_type);
 
     rc = crm_remote_send(session, msg);
 
     if (rc < 0) {
         crm_err("Failed to send remote lrmd tls msg, rc = %d", rc);
         return rc;
     }
 
     return rc;
 }
 
 static xmlNode *
 lrmd_tls_recv_reply(lrmd_t * lrmd, int total_timeout, int expected_reply_id, int *disconnected)
 {
     lrmd_private_t *native = lrmd->private;
     xmlNode *xml = NULL;
     time_t start = time(NULL);
     const char *msg_type = NULL;
     int reply_id = 0;
     int remaining_timeout = 0;
 
     /* A timeout of 0 here makes no sense.  We have to wait a period of time
      * for the response to come back.  If -1 or 0, default to 10 seconds. */
     if (total_timeout <= 0) {
         total_timeout = 10000;
     }
 
     while (!xml) {
 
         xml = crm_remote_parse_buffer(native->remote);
         if (!xml) {
             /* read some more off the tls buffer if we still have time left. */
             if (remaining_timeout) {
                 remaining_timeout = remaining_timeout - ((time(NULL) - start) * 1000);
             } else {
                 remaining_timeout = total_timeout;
             }
             if (remaining_timeout <= 0) {
                 return NULL;
             }
 
             crm_remote_recv(native->remote, remaining_timeout, disconnected);
             xml = crm_remote_parse_buffer(native->remote);
             if (!xml || *disconnected) {
                 return NULL;
             }
         }
 
         CRM_ASSERT(xml != NULL);
 
         crm_element_value_int(xml, F_LRMD_REMOTE_MSG_ID, &reply_id);
         msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
 
         if (!msg_type) {
             crm_err("Empty msg type received while waiting for reply");
             free_xml(xml);
             xml = NULL;
         } else if (safe_str_eq(msg_type, "notify")) {
             /* got a notify while waiting for reply, trigger the notify to be processed later */
             crm_info("queueing notify");
             native->pending_notify = g_list_append(native->pending_notify, xml);
             if (native->process_notify) {
                 crm_info("notify trigger set.");
                 mainloop_set_trigger(native->process_notify);
             }
             xml = NULL;
         } else if (safe_str_neq(msg_type, "reply")) {
             /* msg isn't a reply, make some noise */
             crm_err("Expected a reply, got %s", msg_type);
             free_xml(xml);
             xml = NULL;
         } else if (reply_id != expected_reply_id) {
             if (native->expected_late_replies > 0) {
                 native->expected_late_replies--;
             } else {
                 crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
             }
             free_xml(xml);
             xml = NULL;
         }
     }
 
     if (native->remote->buffer && native->process_notify) {
         mainloop_set_trigger(native->process_notify);
     }
 
     return xml;
 }
 
 static int
 lrmd_tls_send(lrmd_t * lrmd, xmlNode * msg)
 {
     int rc = 0;
     lrmd_private_t *native = lrmd->private;
 
     global_remote_msg_id++;
     if (global_remote_msg_id <= 0) {
         global_remote_msg_id = 1;
     }
 
     rc = lrmd_tls_send_msg(native->remote, msg, global_remote_msg_id, "request");
     if (rc <= 0) {
         crm_err("Remote lrmd send failed, disconnecting");
         lrmd_tls_disconnect(lrmd);
         return -ENOTCONN;
     }
     return pcmk_ok;
 }
 
 static int
 lrmd_tls_send_recv(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
 {
     int rc = 0;
     int disconnected = 0;
     xmlNode *xml = NULL;
 
     if (lrmd_tls_connected(lrmd) == FALSE) {
         return -1;
     }
 
     rc = lrmd_tls_send(lrmd, msg);
     if (rc < 0) {
         return rc;
     }
 
     xml = lrmd_tls_recv_reply(lrmd, timeout, global_remote_msg_id, &disconnected);
 
     if (disconnected) {
         crm_err("Remote lrmd server disconnected while waiting for reply with id %d. ",
                 global_remote_msg_id);
         lrmd_tls_disconnect(lrmd);
         rc = -ENOTCONN;
     } else if (!xml) {
         crm_err("Remote lrmd never received reply for request id %d. timeout: %dms ",
                 global_remote_msg_id, timeout);
         rc = -ECOMM;
     }
 
     if (reply) {
         *reply = xml;
     } else {
         free_xml(xml);
     }
 
     return rc;
 }
 #endif
 
 static int
 lrmd_send_xml(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
 {
     int rc = -1;
     lrmd_private_t *native = lrmd->private;
 
     switch (native->type) {
         case CRM_CLIENT_IPC:
             rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_response, timeout, reply);
             break;
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
             break;
 #endif
         default:
             crm_err("Unsupported connection type: %d", native->type);
     }
 
     return rc;
 }
 
 static int
 lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg)
 {
     int rc = -1;
     lrmd_private_t *native = lrmd->private;
 
     switch (native->type) {
         case CRM_CLIENT_IPC:
             rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_none, 0, NULL);
             break;
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             rc = lrmd_tls_send(lrmd, msg);
             if (rc == pcmk_ok) {
                 /* we don't want to wait around for the reply, but
                  * since the request/reply protocol needs to behave the same
                  * as libqb, a reply will eventually come later anyway. */
                 native->expected_late_replies++;
             }
             break;
 #endif
         default:
             crm_err("Unsupported connection type: %d", native->type);
     }
 
     return rc;
 }
 
 static int
 lrmd_api_is_connected(lrmd_t * lrmd)
 {
     lrmd_private_t *native = lrmd->private;
 
     switch (native->type) {
         case CRM_CLIENT_IPC:
             return crm_ipc_connected(native->ipc);
             break;
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             return lrmd_tls_connected(lrmd);
             break;
 #endif
         default:
             crm_err("Unsupported connection type: %d", native->type);
     }
 
     return 0;
 }
 
 static int
 lrmd_send_command(lrmd_t * lrmd, const char *op, xmlNode * data, xmlNode ** output_data, int timeout,   /* ms. defaults to 1000 if set to 0 */
                   enum lrmd_call_options options, gboolean expect_reply)
 {                               /* TODO we need to reduce usage of this boolean */
     int rc = pcmk_ok;
     int reply_id = -1;
     lrmd_private_t *native = lrmd->private;
     xmlNode *op_msg = NULL;
     xmlNode *op_reply = NULL;
 
     if (!lrmd_api_is_connected(lrmd)) {
         return -ENOTCONN;
     }
 
     if (op == NULL) {
         crm_err("No operation specified");
         return -EINVAL;
     }
 
     CRM_CHECK(native->token != NULL,;
         );
     crm_trace("sending %s op to lrmd", op);
 
     op_msg = lrmd_create_op(native->token, op, data, options);
 
     if (op_msg == NULL) {
         return -EINVAL;
     }
 
     crm_xml_add_int(op_msg, F_LRMD_TIMEOUT, timeout);
 
     if (expect_reply) {
         rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
     } else {
         rc = lrmd_send_xml_no_reply(lrmd, op_msg);
         goto done;
     }
 
     if (rc < 0) {
         crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
         rc = -ECOMM;
         goto done;
     }
 
     rc = pcmk_ok;
     crm_element_value_int(op_reply, F_LRMD_CALLID, &reply_id);
     crm_trace("%s op reply received", op);
     if (crm_element_value_int(op_reply, F_LRMD_RC, &rc) != 0) {
         rc = -ENOMSG;
         goto done;
     }
 
     crm_log_xml_trace(op_reply, "Reply");
 
     if (output_data) {
         *output_data = op_reply;
         op_reply = NULL;        /* Prevent subsequent free */
     }
 
   done:
     if (lrmd_api_is_connected(lrmd) == FALSE) {
         crm_err("LRMD disconnected");
     }
 
     free_xml(op_msg);
     free_xml(op_reply);
     return rc;
 }
 
 static int
 lrmd_api_poke_connection(lrmd_t * lrmd)
 {
     int rc;
     xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
 
     crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
     rc = lrmd_send_command(lrmd, LRMD_OP_POKE, data, NULL, 0, 0, FALSE);
     free_xml(data);
 
     return rc;
 }
 
 static int
 lrmd_handshake(lrmd_t * lrmd, const char *name)
 {
     int rc = pcmk_ok;
     lrmd_private_t *native = lrmd->private;
     xmlNode *reply = NULL;
     xmlNode *hello = create_xml_node(NULL, "lrmd_command");
 
     crm_xml_add(hello, F_TYPE, T_LRMD);
     crm_xml_add(hello, F_LRMD_OPERATION, CRM_OP_REGISTER);
     crm_xml_add(hello, F_LRMD_CLIENTNAME, name);
     crm_xml_add(hello, F_LRMD_PROTOCOL_VERSION, LRMD_PROTOCOL_VERSION);
 
     /* advertise that we are a proxy provider */
     if (native->proxy_callback) {
         crm_xml_add(hello, F_LRMD_IS_IPC_PROVIDER, "true");
     }
 
     rc = lrmd_send_xml(lrmd, hello, -1, &reply);
 
     if (rc < 0) {
         crm_perror(LOG_DEBUG, "Couldn't complete registration with the lrmd API: %d", rc);
         rc = -ECOMM;
     } else if (reply == NULL) {
         crm_err("Did not receive registration reply");
         rc = -EPROTO;
     } else {
         const char *msg_type = crm_element_value(reply, F_LRMD_OPERATION);
         const char *tmp_ticket = crm_element_value(reply, F_LRMD_CLIENTID);
 
         crm_element_value_int(reply, F_LRMD_RC, &rc);
 
         if (rc == -EPROTO) {
             crm_err("LRMD protocol mismatch client version %s, server version %s",
                 LRMD_PROTOCOL_VERSION, crm_element_value(reply, F_LRMD_PROTOCOL_VERSION));
             crm_log_xml_err(reply, "Protocol Error");
 
         } else if (safe_str_neq(msg_type, CRM_OP_REGISTER)) {
             crm_err("Invalid registration message: %s", msg_type);
             crm_log_xml_err(reply, "Bad reply");
             rc = -EPROTO;
         } else if (tmp_ticket == NULL) {
             crm_err("No registration token provided");
             crm_log_xml_err(reply, "Bad reply");
             rc = -EPROTO;
         } else {
             crm_trace("Obtained registration token: %s", tmp_ticket);
             native->token = strdup(tmp_ticket);
             rc = pcmk_ok;
         }
     }
 
     free_xml(reply);
     free_xml(hello);
 
     if (rc != pcmk_ok) {
         lrmd_api_disconnect(lrmd);
     }
     return rc;
 }
 
 static int
 lrmd_ipc_connect(lrmd_t * lrmd, int *fd)
 {
     int rc = pcmk_ok;
     lrmd_private_t *native = lrmd->private;
 
     static struct ipc_client_callbacks lrmd_callbacks = {
         .dispatch = lrmd_ipc_dispatch,
         .destroy = lrmd_ipc_connection_destroy
     };
 
     crm_info("Connecting to lrmd");
 
     if (fd) {
         /* No mainloop */
         native->ipc = crm_ipc_new("lrmd", 0);
         if (native->ipc && crm_ipc_connect(native->ipc)) {
             *fd = crm_ipc_get_fd(native->ipc);
         } else if (native->ipc) {
             rc = -ENOTCONN;
         }
     } else {
-        native->source = mainloop_add_ipc_client("lrmd", G_PRIORITY_HIGH, 0, lrmd, &lrmd_callbacks);
+        native->source = mainloop_add_ipc_client("lrmd", G_PRIORITY_HIGH, lrmd, &lrmd_callbacks);
         native->ipc = mainloop_get_ipc_client(native->source);
     }
 
     if (native->ipc == NULL) {
         crm_debug("Could not connect to the LRMD API");
         rc = -ENOTCONN;
     }
 
     return rc;
 }
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 static int
 set_key(gnutls_datum_t * key, const char *location)
 {
     FILE *stream;
     int read_len = 256;
     int cur_len = 0;
     int buf_len = read_len;
     static char *key_cache = NULL;
     static size_t key_cache_len = 0;
     static time_t key_cache_updated;
 
     if (location == NULL) {
         return -1;
     }
 
     if (key_cache) {
         time_t now = time(NULL);
 
         if ((now - key_cache_updated) < 60) {
             key->data = gnutls_malloc(key_cache_len + 1);
             key->size = key_cache_len;
             memcpy(key->data, key_cache, key_cache_len);
 
             crm_debug("using cached LRMD key");
             return 0;
         } else {
             key_cache_len = 0;
             key_cache_updated = 0;
             free(key_cache);
             key_cache = NULL;
             crm_debug("clearing lrmd key cache");
         }
     }
 
     stream = fopen(location, "r");
     if (!stream) {
         return -1;
     }
 
     key->data = gnutls_malloc(read_len);
     while (!feof(stream)) {
         int next;
 
         if (cur_len == buf_len) {
             buf_len = cur_len + read_len;
             key->data = gnutls_realloc(key->data, buf_len);
         }
         next = fgetc(stream);
         if (next == EOF && feof(stream)) {
             break;
         }
 
         key->data[cur_len] = next;
         cur_len++;
     }
     fclose(stream);
 
     key->size = cur_len;
     if (!cur_len) {
         gnutls_free(key->data);
         key->data = 0;
         return -1;
     }
 
     if (!key_cache) {
         key_cache = calloc(1, key->size + 1);
         memcpy(key_cache, key->data, key->size);
 
         key_cache_len = key->size;
         key_cache_updated = time(NULL);
     }
 
     return 0;
 }
 
 int
 lrmd_tls_set_key(gnutls_datum_t * key)
 {
     int rc = 0;
     const char *specific_location = getenv("PCMK_authkey_location");
 
     if (set_key(key, specific_location) == 0) {
         crm_debug("Using custom authkey location %s", specific_location);
         return 0;
     }
 
     if (set_key(key, DEFAULT_REMOTE_KEY_LOCATION)) {
         rc = set_key(key, ALT_REMOTE_KEY_LOCATION);
     }
     if (rc) {
         crm_err("No lrmd remote key found");
         return -1;
     }
 
     return rc;
 }
 
 static void
 lrmd_gnutls_global_init(void)
 {
     static int gnutls_init = 0;
 
     if (!gnutls_init) {
         gnutls_global_init();
     }
     gnutls_init = 1;
 }
 #endif
 
 static void
 report_async_connection_result(lrmd_t * lrmd, int rc)
 {
     lrmd_private_t *native = lrmd->private;
 
     if (native->callback) {
         lrmd_event_data_t event = { 0, };
         event.type = lrmd_event_connect;
         event.remote_nodename = native->remote_nodename;
         event.connection_rc = rc;
         native->callback(&event);
     }
 }
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 static void
 lrmd_tcp_connect_cb(void *userdata, int sock)
 {
     lrmd_t *lrmd = userdata;
     lrmd_private_t *native = lrmd->private;
     char name[256] = { 0, };
     static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
         .dispatch = lrmd_tls_dispatch,
         .destroy = lrmd_tls_connection_destroy,
     };
     int rc = sock;
     gnutls_datum_t psk_key = { NULL, 0 };
 
     if (rc < 0) {
         lrmd_tls_connection_destroy(lrmd);
         crm_info("remote lrmd connect to %s at port %d failed", native->server, native->port);
         report_async_connection_result(lrmd, rc);
         return;
     }
 
     /* TODO continue with tls stuff now that tcp connect passed. make this async as well soon
      * to avoid all blocking code in the client. */
     native->sock = sock;
 
     if (lrmd_tls_set_key(&psk_key) != 0) {
         lrmd_tls_connection_destroy(lrmd);
         return;
     }
 
     gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
     gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
     gnutls_free(psk_key.data);
 
     native->remote->tls_session = create_psk_tls_session(sock, GNUTLS_CLIENT, native->psk_cred_c);
 
     if (crm_initiate_client_tls_handshake(native->remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT) != 0) {
         crm_warn("Client tls handshake failed for server %s:%d. Disconnecting", native->server,
                  native->port);
         gnutls_deinit(*native->remote->tls_session);
         gnutls_free(native->remote->tls_session);
         native->remote->tls_session = NULL;
         lrmd_tls_connection_destroy(lrmd);
         report_async_connection_result(lrmd, -1);
         return;
     }
 
     crm_info("Remote lrmd client TLS connection established with server %s:%d", native->server,
              native->port);
 
     snprintf(name, 128, "remote-lrmd-%s:%d", native->server, native->port);
 
     native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
     native->source =
         mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
 
     rc = lrmd_handshake(lrmd, name);
     report_async_connection_result(lrmd, rc);
 
     return;
 }
 
 static int
 lrmd_tls_connect_async(lrmd_t * lrmd, int timeout /*ms */ )
 {
     int rc = 0;
     lrmd_private_t *native = lrmd->private;
 
     lrmd_gnutls_global_init();
 
     rc = crm_remote_tcp_connect_async(native->server, native->port, timeout, lrmd,
                                       lrmd_tcp_connect_cb);
 
     return rc;
 }
 
 static int
 lrmd_tls_connect(lrmd_t * lrmd, int *fd)
 {
     static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
         .dispatch = lrmd_tls_dispatch,
         .destroy = lrmd_tls_connection_destroy,
     };
 
     lrmd_private_t *native = lrmd->private;
     int sock;
     gnutls_datum_t psk_key = { NULL, 0 };
 
     lrmd_gnutls_global_init();
 
     sock = crm_remote_tcp_connect(native->server, native->port);
     if (sock < 0) {
         crm_warn("Could not establish remote lrmd connection to %s", native->server);
         lrmd_tls_connection_destroy(lrmd);
         return -ENOTCONN;
     }
 
     native->sock = sock;
 
     if (lrmd_tls_set_key(&psk_key) != 0) {
         lrmd_tls_connection_destroy(lrmd);
         return -1;
     }
 
     gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
     gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
     gnutls_free(psk_key.data);
 
     native->remote->tls_session = create_psk_tls_session(sock, GNUTLS_CLIENT, native->psk_cred_c);
 
     if (crm_initiate_client_tls_handshake(native->remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT) != 0) {
         crm_err("Session creation for %s:%d failed", native->server, native->port);
         gnutls_deinit(*native->remote->tls_session);
         gnutls_free(native->remote->tls_session);
         native->remote->tls_session = NULL;
         lrmd_tls_connection_destroy(lrmd);
         return -1;
     }
 
     crm_info("Remote lrmd client TLS connection established with server %s:%d", native->server,
              native->port);
 
     if (fd) {
         *fd = sock;
     } else {
         char name[256] = { 0, };
         snprintf(name, 128, "remote-lrmd-%s:%d", native->server, native->port);
 
         native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
         native->source =
             mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
     }
     return pcmk_ok;
 }
 #endif
 
 static int
 lrmd_api_connect(lrmd_t * lrmd, const char *name, int *fd)
 {
     int rc = -ENOTCONN;
     lrmd_private_t *native = lrmd->private;
 
     switch (native->type) {
         case CRM_CLIENT_IPC:
             rc = lrmd_ipc_connect(lrmd, fd);
             break;
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             rc = lrmd_tls_connect(lrmd, fd);
             break;
 #endif
         default:
             crm_err("Unsupported connection type: %d", native->type);
     }
 
     if (rc == pcmk_ok) {
         rc = lrmd_handshake(lrmd, name);
     }
 
     return rc;
 }
 
 static int
 lrmd_api_connect_async(lrmd_t * lrmd, const char *name, int timeout)
 {
     int rc = 0;
     lrmd_private_t *native = lrmd->private;
 
     if (!native->callback) {
         crm_err("Async connect not possible, no lrmd client callback set.");
         return -1;
     }
 
     switch (native->type) {
         case CRM_CLIENT_IPC:
             /* fake async connection with ipc.  it should be fast
              * enough that we gain very little from async */
             rc = lrmd_api_connect(lrmd, name, NULL);
             if (!rc) {
                 report_async_connection_result(lrmd, rc);
             }
             break;
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             rc = lrmd_tls_connect_async(lrmd, timeout);
             if (rc) {
                 /* connection failed, report rc now */
                 report_async_connection_result(lrmd, rc);
             }
             break;
 #endif
         default:
             crm_err("Unsupported connection type: %d", native->type);
     }
 
     return rc;
 }
 
 static void
 lrmd_ipc_disconnect(lrmd_t * lrmd)
 {
     lrmd_private_t *native = lrmd->private;
 
     if (native->source != NULL) {
         /* Attached to mainloop */
         mainloop_del_ipc_client(native->source);
         native->source = NULL;
         native->ipc = NULL;
 
     } else if (native->ipc) {
         /* Not attached to mainloop */
         crm_ipc_t *ipc = native->ipc;
 
         native->ipc = NULL;
         crm_ipc_close(ipc);
         crm_ipc_destroy(ipc);
     }
 }
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
 static void
 lrmd_tls_disconnect(lrmd_t * lrmd)
 {
     lrmd_private_t *native = lrmd->private;
 
     if (native->remote->tls_session) {
         gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
         gnutls_deinit(*native->remote->tls_session);
         gnutls_free(native->remote->tls_session);
         native->remote->tls_session = 0;
     }
 
     if (native->source != NULL) {
         /* Attached to mainloop */
         mainloop_del_ipc_client(native->source);
         native->source = NULL;
 
     } else if (native->sock) {
         close(native->sock);
     }
 
     if (native->pending_notify) {
         g_list_free_full(native->pending_notify, lrmd_free_xml);
         native->pending_notify = NULL;
     }
 }
 #endif
 
 static int
 lrmd_api_disconnect(lrmd_t * lrmd)
 {
     lrmd_private_t *native = lrmd->private;
 
     crm_info("Disconnecting from lrmd service");
     switch (native->type) {
         case CRM_CLIENT_IPC:
             lrmd_ipc_disconnect(lrmd);
             break;
 #ifdef HAVE_GNUTLS_GNUTLS_H
         case CRM_CLIENT_TLS:
             lrmd_tls_disconnect(lrmd);
             break;
 #endif
         default:
             crm_err("Unsupported connection type: %d", native->type);
     }
 
     free(native->token);
     native->token = NULL;
     return 0;
 }
 
 static int
 lrmd_api_register_rsc(lrmd_t * lrmd,
                       const char *rsc_id,
                       const char *class,
                       const char *provider, const char *type, enum lrmd_call_options options)
 {
     int rc = pcmk_ok;
     xmlNode *data = NULL;
 
     if (!class || !type || !rsc_id) {
         return -EINVAL;
     }
     if (safe_str_eq(class, "ocf") && !provider) {
         return -EINVAL;
     }
 
     data = create_xml_node(NULL, F_LRMD_RSC);
 
     crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
     crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
     crm_xml_add(data, F_LRMD_CLASS, class);
     crm_xml_add(data, F_LRMD_PROVIDER, provider);
     crm_xml_add(data, F_LRMD_TYPE, type);
     rc = lrmd_send_command(lrmd, LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
     free_xml(data);
 
     return rc;
 }
 
 static int
 lrmd_api_unregister_rsc(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
 {
     int rc = pcmk_ok;
     xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
 
     crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
     crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
     rc = lrmd_send_command(lrmd, LRMD_OP_RSC_UNREG, data, NULL, 0, options, TRUE);
     free_xml(data);
 
     return rc;
 }
 
 lrmd_rsc_info_t *
 lrmd_copy_rsc_info(lrmd_rsc_info_t * rsc_info)
 {
     lrmd_rsc_info_t *copy = NULL;
 
     copy = calloc(1, sizeof(lrmd_rsc_info_t));
 
     copy->id = strdup(rsc_info->id);
     copy->type = strdup(rsc_info->type);
     copy->class = strdup(rsc_info->class);
     if (rsc_info->provider) {
         copy->provider = strdup(rsc_info->provider);
     }
 
     return copy;
 }
 
 void
 lrmd_free_rsc_info(lrmd_rsc_info_t * rsc_info)
 {
     if (!rsc_info) {
         return;
     }
     free(rsc_info->id);
     free(rsc_info->type);
     free(rsc_info->class);
     free(rsc_info->provider);
     free(rsc_info);
 }
 
 static lrmd_rsc_info_t *
 lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
 {
     lrmd_rsc_info_t *rsc_info = NULL;
     xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
     xmlNode *output = NULL;
     const char *class = NULL;
     const char *provider = NULL;
     const char *type = NULL;
 
     crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
     crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
     lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 30000, options, TRUE);
     free_xml(data);
 
     if (!output) {
         return NULL;
     }
 
     class = crm_element_value(output, F_LRMD_CLASS);
     provider = crm_element_value(output, F_LRMD_PROVIDER);
     type = crm_element_value(output, F_LRMD_TYPE);
 
     if (!class || !type) {
         free_xml(output);
         return NULL;
     } else if (safe_str_eq(class, "ocf") && !provider) {
         free_xml(output);
         return NULL;
     }
 
     rsc_info = calloc(1, sizeof(lrmd_rsc_info_t));
     rsc_info->id = strdup(rsc_id);
     rsc_info->class = strdup(class);
     if (provider) {
         rsc_info->provider = strdup(provider);
     }
     rsc_info->type = strdup(type);
 
     free_xml(output);
     return rsc_info;
 }
 
 static void
 lrmd_api_set_callback(lrmd_t * lrmd, lrmd_event_callback callback)
 {
     lrmd_private_t *native = lrmd->private;
 
     native->callback = callback;
 }
 
 void
 lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
 {
     lrmd_private_t *native = lrmd->private;
 
     native->proxy_callback = callback;
     native->proxy_callback_userdata = userdata;
 }
 
 void
 lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg)
 {
     lrmd_private_t *native = lrmd->private;
 
     if (native->proxy_callback) {
         crm_log_xml_trace(msg, "PROXY_INBOUND");
         native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
     }
 }
 
 int
 lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg)
 {
     if (lrmd == NULL) {
         return -ENOTCONN;
     }
     crm_xml_add(msg, F_LRMD_OPERATION, CRM_OP_IPC_FWD);
 
     crm_log_xml_trace(msg, "PROXY_OUTBOUND");
     return lrmd_send_xml_no_reply(lrmd, msg);
 }
 
 static int
 stonith_get_metadata(const char *provider, const char *type, char **output)
 {
     int rc = pcmk_ok;
     stonith_t *stonith_api = stonith_api_new();
 
     if(stonith_api) {
         stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type, provider, output, 0);
         stonith_api->cmds->free(stonith_api);
     }
     if (*output == NULL) {
         rc = -EIO;
     }
     return rc;
 }
 
 #define lsb_metadata_template  \
     "<?xml version='1.0'?>\n"                                           \
     "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n"                 \
     "<resource-agent name='%s' version='0.1'>\n"                        \
     "  <version>1.0</version>\n"                                        \
     "  <longdesc lang='en'>\n"                                          \
     "    %s\n"                                                          \
     "  </longdesc>\n"                                                   \
     "  <shortdesc lang='en'>%s</shortdesc>\n"                           \
     "  <parameters>\n"                                                  \
     "  </parameters>\n"                                                 \
     "  <actions>\n"                                                     \
     "    <action name='meta-data'    timeout='5' />\n"                  \
     "    <action name='start'        timeout='15' />\n"                 \
     "    <action name='stop'         timeout='15' />\n"                 \
     "    <action name='status'       timeout='15' />\n"                 \
     "    <action name='restart'      timeout='15' />\n"                 \
     "    <action name='force-reload' timeout='15' />\n"                 \
     "    <action name='monitor'      timeout='15' interval='15' />\n"   \
     "  </actions>\n"                                                    \
     "  <special tag='LSB'>\n"                                           \
     "    <Provides>%s</Provides>\n"                                     \
     "    <Required-Start>%s</Required-Start>\n"                         \
     "    <Required-Stop>%s</Required-Stop>\n"                           \
     "    <Should-Start>%s</Should-Start>\n"                             \
     "    <Should-Stop>%s</Should-Stop>\n"                               \
     "    <Default-Start>%s</Default-Start>\n"                           \
     "    <Default-Stop>%s</Default-Stop>\n"                             \
     "  </special>\n"                                                    \
     "</resource-agent>\n"
 
 #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO"
 #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO"
 #define PROVIDES    "# Provides:"
 #define REQ_START   "# Required-Start:"
 #define REQ_STOP    "# Required-Stop:"
 #define SHLD_START  "# Should-Start:"
 #define SHLD_STOP   "# Should-Stop:"
 #define DFLT_START  "# Default-Start:"
 #define DFLT_STOP   "# Default-Stop:"
 #define SHORT_DSCR  "# Short-Description:"
 #define DESCRIPTION "# Description:"
 
 #define lsb_meta_helper_free_value(m)   \
     if ((m) != NULL) {                  \
         xmlFree(m);                     \
         (m) = NULL;                     \
     }
 
 #define lsb_meta_helper_get_value(buffer, ptr, keyword)                 \
     if (!ptr && !strncasecmp(buffer, keyword, strlen(keyword))) {       \
         (ptr) = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer+strlen(keyword)); \
         continue;                                                       \
     }
 
 static int
 lsb_get_metadata(const char *type, char **output)
 {
     char ra_pathname[PATH_MAX] = { 0, };
     FILE *fp;
     GString *meta_data = NULL;
     char buffer[1024];
     char *provides = NULL;
     char *req_start = NULL;
     char *req_stop = NULL;
     char *shld_start = NULL;
     char *shld_stop = NULL;
     char *dflt_start = NULL;
     char *dflt_stop = NULL;
     char *s_dscrpt = NULL;
     char *xml_l_dscrpt = NULL;
     GString *l_dscrpt = NULL;
 
     if(type[0] == '/') {
         snprintf(ra_pathname, sizeof(ra_pathname), "%s", type);
     } else {
         snprintf(ra_pathname, sizeof(ra_pathname), "%s/%s", LSB_ROOT_DIR, type);
     }
 
     crm_trace("Looking into %s", ra_pathname);
     if (!(fp = fopen(ra_pathname, "r"))) {
         return -errno;
     }
 
     /* Enter into the lsb-compliant comment block */
     while (fgets(buffer, sizeof(buffer), fp)) {
         /* Now suppose each of the following eight arguments contain only one line */
         lsb_meta_helper_get_value(buffer, provides, PROVIDES)
             lsb_meta_helper_get_value(buffer, req_start, REQ_START)
             lsb_meta_helper_get_value(buffer, req_stop, REQ_STOP)
             lsb_meta_helper_get_value(buffer, shld_start, SHLD_START)
             lsb_meta_helper_get_value(buffer, shld_stop, SHLD_STOP)
             lsb_meta_helper_get_value(buffer, dflt_start, DFLT_START)
             lsb_meta_helper_get_value(buffer, dflt_stop, DFLT_STOP)
             lsb_meta_helper_get_value(buffer, s_dscrpt, SHORT_DSCR)
 
             /* Long description may cross multiple lines */
             if ((l_dscrpt == NULL) && (0 == strncasecmp(buffer, DESCRIPTION, strlen(DESCRIPTION)))) {
             l_dscrpt = g_string_new(buffer + strlen(DESCRIPTION));
             /* Between # and keyword, more than one space, or a tab character,
              * indicates the continuation line.     Extracted from LSB init script standard */
             while (fgets(buffer, sizeof(buffer), fp)) {
                 if (!strncmp(buffer, "#  ", 3) || !strncmp(buffer, "#\t", 2)) {
                     buffer[0] = ' ';
                     l_dscrpt = g_string_append(l_dscrpt, buffer);
                 } else {
                     fputs(buffer, fp);
                     break;      /* Long description ends */
                 }
             }
             continue;
         }
         if (l_dscrpt) {
             xml_l_dscrpt = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST(l_dscrpt->str));
         }
         if (!strncasecmp(buffer, LSB_INITSCRIPT_INFOEND_TAG, strlen(LSB_INITSCRIPT_INFOEND_TAG))) {
             /* Get to the out border of LSB comment block */
             break;
         }
         if (buffer[0] != '#') {
             break;              /* Out of comment block in the beginning */
         }
     }
     fclose(fp);
 
     meta_data = g_string_new("");
     g_string_sprintf(meta_data, lsb_metadata_template, type,
                      (xml_l_dscrpt == NULL) ? type : xml_l_dscrpt,
                      (s_dscrpt == NULL) ? type : s_dscrpt, (provides == NULL) ? "" : provides,
                      (req_start == NULL) ? "" : req_start, (req_stop == NULL) ? "" : req_stop,
                      (shld_start == NULL) ? "" : shld_start, (shld_stop == NULL) ? "" : shld_stop,
                      (dflt_start == NULL) ? "" : dflt_start, (dflt_stop == NULL) ? "" : dflt_stop);
 
     lsb_meta_helper_free_value(xml_l_dscrpt);
     lsb_meta_helper_free_value(s_dscrpt);
     lsb_meta_helper_free_value(provides);
     lsb_meta_helper_free_value(req_start);
     lsb_meta_helper_free_value(req_stop);
     lsb_meta_helper_free_value(shld_start);
     lsb_meta_helper_free_value(shld_stop);
     lsb_meta_helper_free_value(dflt_start);
     lsb_meta_helper_free_value(dflt_stop);
 
     if (l_dscrpt) {
         g_string_free(l_dscrpt, TRUE);
     }
 
     *output = strdup(meta_data->str);
     g_string_free(meta_data, TRUE);
 
     crm_trace("Created fake metadata: %d", strlen(*output));
     return pcmk_ok;
 }
 
 #if SUPPORT_NAGIOS
 static int
 nagios_get_metadata(const char *type, char **output)
 {
     int rc = pcmk_ok;
     FILE *file_strm = NULL;
     int start = 0, length = 0, read_len = 0;
     char *metadata_file = NULL;
     int len = 36;
 
     len += strlen(NAGIOS_METADATA_DIR);
     len += strlen(type);
     metadata_file = calloc(1, len);
     CRM_CHECK(metadata_file != NULL, return -ENOMEM);
 
     sprintf(metadata_file, "%s/%s.xml", NAGIOS_METADATA_DIR, type);
     file_strm = fopen(metadata_file, "r");
     if (file_strm == NULL) {
         crm_err("Metadata file %s does not exist", metadata_file);
         free(metadata_file);
         return -EIO;
     }
 
     /* see how big the file is */
     start = ftell(file_strm);
     fseek(file_strm, 0L, SEEK_END);
     length = ftell(file_strm);
     fseek(file_strm, 0L, start);
 
     CRM_ASSERT(length >= 0);
     CRM_ASSERT(start == ftell(file_strm));
 
     if (length <= 0) {
         crm_info("%s was not valid", metadata_file);
         free(*output);
         *output = NULL;
         rc = -EIO;
 
     } else {
         crm_trace("Reading %d bytes from file", length);
         *output = calloc(1, (length + 1));
         read_len = fread(*output, 1, length, file_strm);
         if (read_len != length) {
             crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len);
             free(*output);
             *output = NULL;
             rc = -EIO;
         }
     }
 
     fclose(file_strm);
     free(metadata_file);
     return rc;
 }
 #endif
 
 static int
 generic_get_metadata(const char *standard, const char *provider, const char *type, char **output)
 {
     svc_action_t *action = resources_action_create(type,
                                                    standard,
                                                    provider,
                                                    type,
                                                    "meta-data",
                                                    0,
                                                    30000,
                                                    NULL);
 
     if (!(services_action_sync(action))) {
         crm_err("Failed to retrieve meta-data for %s:%s:%s", standard, provider, type);
         services_action_free(action);
         return -EIO;
     }
 
     if (!action->stdout_data) {
         crm_err("Failed to retrieve meta-data for %s:%s:%s", standard, provider, type);
         services_action_free(action);
         return -EIO;
     }
 
     *output = strdup(action->stdout_data);
     services_action_free(action);
 
     return pcmk_ok;
 }
 
 static int
 lrmd_api_get_metadata(lrmd_t * lrmd,
                       const char *class,
                       const char *provider,
                       const char *type, char **output, enum lrmd_call_options options)
 {
     if (!class || !type) {
         return -EINVAL;
     }
 
     if (safe_str_eq(class, "stonith")) {
         return stonith_get_metadata(provider, type, output);
     } else if (safe_str_eq(class, "lsb")) {
         return lsb_get_metadata(type, output);
 #if SUPPORT_NAGIOS
     } else if (safe_str_eq(class, "nagios")) {
         return nagios_get_metadata(type, output);
 #endif
     }
     return generic_get_metadata(class, provider, type, output);
 }
 
 static int
 lrmd_api_exec(lrmd_t * lrmd, const char *rsc_id, const char *action, const char *userdata, int interval,        /* ms */
               int timeout,      /* ms */
               int start_delay,  /* ms */
               enum lrmd_call_options options, lrmd_key_value_t * params)
 {
     int rc = pcmk_ok;
     xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
     xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
     lrmd_key_value_t *tmp = NULL;
 
     crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
     crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
     crm_xml_add(data, F_LRMD_RSC_ACTION, action);
     crm_xml_add(data, F_LRMD_RSC_USERDATA_STR, userdata);
     crm_xml_add_int(data, F_LRMD_RSC_INTERVAL, interval);
     crm_xml_add_int(data, F_LRMD_TIMEOUT, timeout);
     crm_xml_add_int(data, F_LRMD_RSC_START_DELAY, start_delay);
 
     for (tmp = params; tmp; tmp = tmp->next) {
         hash2field((gpointer) tmp->key, (gpointer) tmp->value, args);
     }
 
     rc = lrmd_send_command(lrmd, LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
     free_xml(data);
 
     lrmd_key_value_freeall(params);
     return rc;
 }
 
 static int
 lrmd_api_cancel(lrmd_t * lrmd, const char *rsc_id, const char *action, int interval)
 {
     int rc = pcmk_ok;
     xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
 
     crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
     crm_xml_add(data, F_LRMD_RSC_ACTION, action);
     crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
     crm_xml_add_int(data, F_LRMD_RSC_INTERVAL, interval);
     rc = lrmd_send_command(lrmd, LRMD_OP_RSC_CANCEL, data, NULL, 0, 0, TRUE);
     free_xml(data);
     return rc;
 }
 
 static int
 list_stonith_agents(lrmd_list_t ** resources)
 {
     int rc = 0;
     stonith_t *stonith_api = stonith_api_new();
     stonith_key_value_t *stonith_resources = NULL;
     stonith_key_value_t *dIter = NULL;
 
     if(stonith_api) {
         stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL, &stonith_resources, 0);
         stonith_api->cmds->free(stonith_api);
     }
 
     for (dIter = stonith_resources; dIter; dIter = dIter->next) {
         rc++;
         if (resources) {
             *resources = lrmd_list_add(*resources, dIter->value);
         }
     }
 
     stonith_key_value_freeall(stonith_resources, 1, 0);
     return rc;
 }
 
 static int
 lrmd_api_list_agents(lrmd_t * lrmd, lrmd_list_t ** resources, const char *class,
                      const char *provider)
 {
     int rc = 0;
 
     if (safe_str_eq(class, "stonith")) {
         rc += list_stonith_agents(resources);
 
     } else {
         GListPtr gIter = NULL;
         GList *agents = resources_list_agents(class, provider);
 
         for (gIter = agents; gIter != NULL; gIter = gIter->next) {
             *resources = lrmd_list_add(*resources, (const char *)gIter->data);
             rc++;
         }
         g_list_free_full(agents, free);
 
         if (!class) {
             rc += list_stonith_agents(resources);
         }
     }
 
     if (rc == 0) {
         crm_notice("No agents found for class %s", class);
         rc = -EPROTONOSUPPORT;
     }
     return rc;
 }
 
 static int
 does_provider_have_agent(const char *agent, const char *provider, const char *class)
 {
     int found = 0;
     GList *agents = NULL;
     GListPtr gIter2 = NULL;
 
     agents = resources_list_agents(class, provider);
     for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
         if (safe_str_eq(agent, gIter2->data)) {
             found = 1;
         }
     }
     g_list_free_full(agents, free);
 
     return found;
 }
 
 static int
 lrmd_api_list_ocf_providers(lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers)
 {
     int rc = pcmk_ok;
     char *provider = NULL;
     GList *ocf_providers = NULL;
     GListPtr gIter = NULL;
 
     ocf_providers = resources_list_providers("ocf");
 
     for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
         provider = gIter->data;
         if (!agent || does_provider_have_agent(agent, provider, "ocf")) {
             *providers = lrmd_list_add(*providers, (const char *)gIter->data);
             rc++;
         }
     }
 
     g_list_free_full(ocf_providers, free);
     return rc;
 }
 
 static int
 lrmd_api_list_standards(lrmd_t * lrmd, lrmd_list_t ** supported)
 {
     int rc = 0;
     GList *standards = NULL;
     GListPtr gIter = NULL;
 
     standards = resources_list_standards();
 
     for (gIter = standards; gIter != NULL; gIter = gIter->next) {
         *supported = lrmd_list_add(*supported, (const char *)gIter->data);
         rc++;
     }
 
     if (list_stonith_agents(NULL) > 0) {
         *supported = lrmd_list_add(*supported, "stonith");
         rc++;
     }
 
     g_list_free_full(standards, free);
     return rc;
 }
 
 lrmd_t *
 lrmd_api_new(void)
 {
     lrmd_t *new_lrmd = NULL;
     lrmd_private_t *pvt = NULL;
 
     new_lrmd = calloc(1, sizeof(lrmd_t));
     pvt = calloc(1, sizeof(lrmd_private_t));
     pvt->remote = calloc(1, sizeof(crm_remote_t));
     new_lrmd->cmds = calloc(1, sizeof(lrmd_api_operations_t));
 
     pvt->type = CRM_CLIENT_IPC;
     new_lrmd->private = pvt;
 
     new_lrmd->cmds->connect = lrmd_api_connect;
     new_lrmd->cmds->connect_async = lrmd_api_connect_async;
     new_lrmd->cmds->is_connected = lrmd_api_is_connected;
     new_lrmd->cmds->poke_connection = lrmd_api_poke_connection;
     new_lrmd->cmds->disconnect = lrmd_api_disconnect;
     new_lrmd->cmds->register_rsc = lrmd_api_register_rsc;
     new_lrmd->cmds->unregister_rsc = lrmd_api_unregister_rsc;
     new_lrmd->cmds->get_rsc_info = lrmd_api_get_rsc_info;
     new_lrmd->cmds->set_callback = lrmd_api_set_callback;
     new_lrmd->cmds->get_metadata = lrmd_api_get_metadata;
     new_lrmd->cmds->exec = lrmd_api_exec;
     new_lrmd->cmds->cancel = lrmd_api_cancel;
     new_lrmd->cmds->list_agents = lrmd_api_list_agents;
     new_lrmd->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
     new_lrmd->cmds->list_standards = lrmd_api_list_standards;
 
     return new_lrmd;
 }
 
 lrmd_t *
 lrmd_remote_api_new(const char *nodename, const char *server, int port)
 {
 #ifdef HAVE_GNUTLS_GNUTLS_H
     lrmd_t *new_lrmd = lrmd_api_new();
     lrmd_private_t *native = new_lrmd->private;
 
     if (!nodename && !server) {
         lrmd_api_delete(new_lrmd);
         return NULL;
     }
 
     native->type = CRM_CLIENT_TLS;
     native->remote_nodename = nodename ? strdup(nodename) : strdup(server);
     native->server = server ? strdup(server) : strdup(nodename);
     native->port = port;
     if (native->port == 0) {
         const char *remote_port_str = getenv("PCMK_remote_port");
         native->port = remote_port_str ? atoi(remote_port_str) : DEFAULT_REMOTE_PORT;
     }
 
     return new_lrmd;
 #else
     crm_err("GNUTLS is not enabled for this build, remote LRMD client can not be created");
     return NULL;
 #endif
 
 }
 
 void
 lrmd_api_delete(lrmd_t * lrmd)
 {
     if (!lrmd) {
         return;
     }
     lrmd->cmds->disconnect(lrmd);       /* no-op if already disconnected */
     free(lrmd->cmds);
     if (lrmd->private) {
         lrmd_private_t *native = lrmd->private;
 
 #ifdef HAVE_GNUTLS_GNUTLS_H
         free(native->server);
 #endif
         free(native->remote_nodename);
         free(native->remote);
     }
 
     free(lrmd->private);
     free(lrmd);
 }
diff --git a/tools/crm_node.c b/tools/crm_node.c
index 56cb55415e..6e653aee1b 100644
--- a/tools/crm_node.c
+++ b/tools/crm_node.c
@@ -1,903 +1,903 @@
 /* 
  * 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 <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 
 #include <libgen.h>             /* for basename() */
 
 #include <crm/crm.h>
 #include <crm/cluster/internal.h>
 #include <crm/common/mainloop.h>
 #include <crm/msg_xml.h>
 #include <crm/cib.h>
 
 int command = 0;
 int ccm_fd = 0;
 gboolean do_quiet = FALSE;
 
 char *target_uuid = NULL;
 char *target_uname = NULL;
 const char *standby_value = NULL;
 const char *standby_scope = NULL;
 
 /* *INDENT-OFF* */
 static struct crm_option long_options[] = {
     /* Top-level Options */
     {"help",       0, 0, '?', "\tThis text"},
     {"version",    0, 0, '$', "\tVersion information"  },
     {"verbose",    0, 0, 'V', "\tIncrease debug output"},
     {"quiet",      0, 0, 'Q', "\tEssential output only"},
 
     {"-spacer-",   1, 0, '-', "\nStack:"},
 #if SUPPORT_CMAN
     {"cman",       0, 0, 'c', "\tOnly try connecting to a cman-based cluster"},
 #endif
 #if SUPPORT_COROSYNC
     {"openais",    0, 0, 'A', "\tOnly try connecting to an OpenAIS-based cluster"},
 #endif
 #ifdef SUPPORT_HEARTBEAT
     {"heartbeat",  0, 0, 'H', "Only try connecting to a Heartbeat-based cluster"},
 #endif
     
     {"-spacer-",      1, 0, '-', "\nCommands:"},
     {"name",	      0, 0, 'n', "\tDisplay the name used by the cluster for this node"},
     {"name-for-id",   1, 0, 'N', "\tDisplay the name used by the cluster for the node with the specified id"},
     {"epoch",	      0, 0, 'e', "\tDisplay the epoch during which this node joined the cluster"},
     {"quorum",        0, 0, 'q', "\tDisplay a 1 if our partition has quorum, 0 if not"},
     {"list",          0, 0, 'l', "\tDisplay all known members (past and present) of this cluster (Not available for heartbeat clusters)"},
     {"partition",     0, 0, 'p', "Display the members of this partition"},
     {"cluster-id",    0, 0, 'i', "Display this node's cluster id"},
     {"remove",        1, 0, 'R', "(Advanced) Remove the (stopped) node with the specified name from Pacemaker's configuration and caches"},
     {"-spacer-",      1, 0, '-', "In the case of Heartbeat, CMAN and Corosync 2.0, requires that the node has already been removed from the underlying cluster"},
 
     {"-spacer-", 1, 0, '-', "\nAdditional Options:"},
     {"force",	 0, 0, 'f'},
 
     {0, 0, 0, 0}
 };
 /* *INDENT-ON* */
 
 static int
 cib_remove_node(uint32_t id, const char *name)
 {
     int rc;
     cib_t *cib = NULL;
     xmlNode *node = NULL;
     xmlNode *node_state = NULL;
 
     crm_trace("Removing %s from the CIB", name);
 
     node = create_xml_node(NULL, XML_CIB_TAG_NODE);
     node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
 
     crm_xml_add(node, XML_ATTR_UNAME, name);
     crm_xml_add(node_state, XML_ATTR_UNAME, name);
 
     cib = cib_new();
     cib->cmds->signon(cib, crm_system_name, cib_command);
 
     rc = cib->cmds->delete(cib, XML_CIB_TAG_NODES, node, cib_sync_call);
     if (rc != pcmk_ok) {
         printf("Could not remove %s from " XML_CIB_TAG_NODES ": %s", name, pcmk_strerror(rc));
     }
     rc = cib->cmds->delete(cib, XML_CIB_TAG_STATUS, node_state, cib_sync_call);
     if (rc != pcmk_ok) {
         printf("Could not remove %s from " XML_CIB_TAG_STATUS ": %s", name, pcmk_strerror(rc));
     }
 
     cib->cmds->signoff(cib);
     cib_delete(cib);
     return rc;
 }
 
 int tools_remove_node_cache(const char *node, const char *target);
 
 int tools_remove_node_cache(const char *node, const char *target)
 {
     int n = 0;
     int rc = -1;
     char *name = NULL;
     char *admin_uuid = NULL;
     crm_ipc_t *conn = crm_ipc_new(target, 0);
     xmlNode *cmd = NULL;
     xmlNode *hello = NULL;
     char *endptr = NULL;
 
     if (!conn) {
         return -ENOTCONN;
     }
 
     if (!crm_ipc_connect(conn)) {
         crm_ipc_destroy(conn);
         return -ENOTCONN;
     }
 
     if(safe_str_eq(target, CRM_SYSTEM_CRMD)) {
         admin_uuid = calloc(1, 11);
         snprintf(admin_uuid, 10, "%d", getpid());
         admin_uuid[10] = '\0';
 
         hello = create_hello_message(admin_uuid, "crm_node", "0", "1");
         rc = crm_ipc_send(conn, hello, 0, 0, NULL);
 
         free_xml(hello);
         free(admin_uuid);
         if (rc < 0) {
             return rc;
         }
     }
 
     errno = 0;
     n = strtol(node, &endptr, 10);
     if (errno != 0 || endptr == node || *endptr != '\0') {
         /* Argument was not a nodeid */
         n = 0;
         name = strdup(node);
     } else {
         name = get_node_name(n);
     }
 
     crm_trace("Removing %s aka. %s from the membership cache", name, node);
 
     cmd = create_request(CRM_OP_RM_NODE_CACHE,
                          NULL, NULL, CRM_SYSTEM_CRMD, "crm_node", admin_uuid);
 
     if (n) {
         crm_xml_add_int(cmd, XML_ATTR_ID, n);
     }
     crm_xml_add(cmd, XML_ATTR_UNAME, name);
 
     rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
     if (rc > 0) {
         rc = cib_remove_node(n, name);
     }
 
     if (conn) {
         crm_ipc_close(conn);
         crm_ipc_destroy(conn);
     }
     free_xml(cmd);
     return rc > 0 ? 0 : rc;
 }
 
 #if SUPPORT_HEARTBEAT
 #  include <ocf/oc_event.h>
 #  include <ocf/oc_membership.h>
 #  include <clplumbing/cl_uuid.h>
 
 #  define UUID_LEN 16
 
 oc_ev_t *ccm_token = NULL;
 static void *ccm_library = NULL;
 void oc_ev_special(const oc_ev_t *, oc_ev_class_t, int);
 
 static gboolean
 read_local_hb_uuid(void)
 {
     cl_uuid_t uuid;
     char *buffer = NULL;
     long start = 0, read_len = 0;
 
     FILE *input = fopen(UUID_FILE, "r");
 
     if (input == NULL) {
         crm_info("Could not open UUID file %s\n", UUID_FILE);
         return FALSE;
     }
 
     /* see how big the file is */
     start = ftell(input);
     fseek(input, 0L, SEEK_END);
     if (UUID_LEN != ftell(input)) {
         fprintf(stderr, "%s must contain exactly %d bytes\n", UUID_FILE, UUID_LEN);
         abort();
     }
 
     fseek(input, 0L, start);
     if (start != ftell(input)) {
         fprintf(stderr, "fseek not behaving: %ld vs. %ld\n", start, ftell(input));
         crm_exit(pcmk_err_generic);
     }
 
     buffer = malloc(50);
     read_len = fread(uuid.uuid, 1, UUID_LEN, input);
     fclose(input);
 
     if (read_len != UUID_LEN) {
         fprintf(stderr, "Expected and read bytes differ: %d vs. %ld\n", UUID_LEN, read_len);
         crm_exit(pcmk_err_generic);
 
     } else if (buffer != NULL) {
         cl_uuid_unparse(&uuid, buffer);
         fprintf(stdout, "%s\n", buffer);
         return TRUE;
 
     } else {
         fprintf(stderr, "No buffer to unparse\n");
         crm_exit(ENODATA);
     }
 
     free(buffer);
     return FALSE;
 }
 
 static void
 ccm_age_callback(oc_ed_t event, void *cookie, size_t size, const void *data)
 {
     int lpc;
     int node_list_size;
     const oc_ev_membership_t *oc = (const oc_ev_membership_t *)data;
 
     int (*ccm_api_callback_done) (void *cookie) =
         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_callback_done", 1);
 
     node_list_size = oc->m_n_member;
     if (command == 'q') {
         crm_debug("Processing \"%s\" event.",
                   event == OC_EV_MS_NEW_MEMBERSHIP ? "NEW MEMBERSHIP" :
                   event == OC_EV_MS_NOT_PRIMARY ? "NOT PRIMARY" :
                   event == OC_EV_MS_PRIMARY_RESTORED ? "PRIMARY RESTORED" :
                   event == OC_EV_MS_EVICTED ? "EVICTED" : "NO QUORUM MEMBERSHIP");
         if (ccm_have_quorum(event)) {
             fprintf(stdout, "1\n");
         } else {
             fprintf(stdout, "0\n");
         }
 
     } else if (command == 'e') {
         crm_debug("Searching %d members for our birth", oc->m_n_member);
     }
     for (lpc = 0; lpc < node_list_size; lpc++) {
         if (command == 'p') {
             fprintf(stdout, "%s ", oc->m_array[oc->m_memb_idx + lpc].node_uname);
 
         } else if (command == 'e') {
             int (*ccm_api_is_my_nodeid) (const oc_ev_t * token, const oc_node_t * node) =
                 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_is_my_nodeid", 1);
             if ((*ccm_api_is_my_nodeid) (ccm_token, &(oc->m_array[lpc]))) {
                 crm_debug("MATCH: nodeid=%d, uname=%s, born=%d",
                           oc->m_array[oc->m_memb_idx + lpc].node_id,
                           oc->m_array[oc->m_memb_idx + lpc].node_uname,
                           oc->m_array[oc->m_memb_idx + lpc].node_born_on);
                 fprintf(stdout, "%d\n", oc->m_array[oc->m_memb_idx + lpc].node_born_on);
             }
         }
     }
 
     (*ccm_api_callback_done) (cookie);
 
     if (command == 'p') {
         fprintf(stdout, "\n");
     }
     fflush(stdout);
     crm_exit(pcmk_ok);
 }
 
 static gboolean
 ccm_age_connect(int *ccm_fd)
 {
     gboolean did_fail = FALSE;
     int ret = 0;
 
     int (*ccm_api_register) (oc_ev_t ** token) =
         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_register", 1);
 
     int (*ccm_api_set_callback) (const oc_ev_t * token,
                                  oc_ev_class_t class,
                                  oc_ev_callback_t * fn,
                                  oc_ev_callback_t ** prev_fn) =
         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_set_callback", 1);
 
     void (*ccm_api_special) (const oc_ev_t *, oc_ev_class_t, int) =
         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_special", 1);
     int (*ccm_api_activate) (const oc_ev_t * token, int *fd) =
         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_activate", 1);
 
     crm_debug("Registering with CCM");
     ret = (*ccm_api_register) (&ccm_token);
     if (ret != 0) {
         crm_info("CCM registration failed: %d", ret);
         did_fail = TRUE;
     }
 
     if (did_fail == FALSE) {
         crm_debug("Setting up CCM callbacks");
         ret = (*ccm_api_set_callback) (ccm_token, OC_EV_MEMB_CLASS, ccm_age_callback, NULL);
         if (ret != 0) {
             crm_warn("CCM callback not set: %d", ret);
             did_fail = TRUE;
         }
     }
     if (did_fail == FALSE) {
         (*ccm_api_special) (ccm_token, OC_EV_MEMB_CLASS, 0 /*don't care */ );
 
         crm_debug("Activating CCM token");
         ret = (*ccm_api_activate) (ccm_token, ccm_fd);
         if (ret != 0) {
             crm_warn("CCM Activation failed: %d", ret);
             did_fail = TRUE;
         }
     }
 
     return !did_fail;
 }
 
 static gboolean
 try_heartbeat(int command, enum cluster_type_e stack)
 {
     crm_debug("Attempting to process %c command", command);
 
     if (command == 'i') {
         if (read_local_hb_uuid()) {
             crm_exit(pcmk_ok);
         }
 
     } else if (command == 'R') {
         if (tools_remove_node_cache(target_uname, CRM_SYSTEM_CRMD)) {
             crm_err("Failed to connect to "CRM_SYSTEM_CRMD" to remove node '%s'", target_uname);
             crm_exit(pcmk_err_generic);
         }
         crm_exit(pcmk_ok);
 
     } else if (ccm_age_connect(&ccm_fd)) {
         int rc = 0;
         fd_set rset;
         int (*ccm_api_handle_event) (const oc_ev_t * token) =
             find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_handle_event", 1);
 
         while (1) {
 
             sleep(1);
             FD_ZERO(&rset);
             FD_SET(ccm_fd, &rset);
 
             errno = 0;
             rc = select(ccm_fd + 1, &rset, NULL, NULL, NULL);
 
             if (rc > 0 && (*ccm_api_handle_event) (ccm_token) != 0) {
                 crm_err("oc_ev_handle_event failed");
                 return FALSE;
 
             } else if (rc < 0 && errno != EINTR) {
                 crm_perror(LOG_ERR, "select failed: %d", rc);
                 return FALSE;
             }
         }
     }
     return FALSE;
 }
 #endif
 
 #if SUPPORT_CMAN
 #  include <libcman.h>
 #  define MAX_NODES 256
 static gboolean
 try_cman(int command, enum cluster_type_e stack)
 {
 
     int rc = -1, lpc = 0, node_count = 0;
     cman_node_t node;
     cman_cluster_t cluster;
     cman_handle_t cman_handle = NULL;
     cman_node_t cman_nodes[MAX_NODES];
 
     memset(&cluster, 0, sizeof(cluster));
 
     cman_handle = cman_init(NULL);
     if (cman_handle == NULL || cman_is_active(cman_handle) == FALSE) {
         crm_info("Couldn't connect to cman");
         return FALSE;
     }
 
     switch (command) {
         case 'R':
             if (tools_remove_node_cache(target_uname, CRM_SYSTEM_CRMD)) {
                 crm_err("Failed to connect to "CRM_SYSTEM_CRMD" to remove node '%s'", target_uname);
             }
             break;
 
         case 'e':
             /* Age makes no sense (yet?) in a cman cluster */
             fprintf(stdout, "1\n");
             break;
 
         case 'q':
             fprintf(stdout, "%d\n", cman_is_quorate(cman_handle));
             break;
 
         case 'l':
         case 'p':
             rc = cman_get_nodes(cman_handle, MAX_NODES, &node_count, cman_nodes);
             if (rc != 0) {
                 fprintf(stderr, "Couldn't query cman node list: %d %d", rc, errno);
                 goto cman_bail;
             }
 
             for (lpc = 0; lpc < node_count; lpc++) {
                 if (command == 'l') {
                     printf("%s ", cman_nodes[lpc].cn_name);
 
                 } else if (cman_nodes[lpc].cn_nodeid != 0 && cman_nodes[lpc].cn_member) {
                     /* Never allow node ID 0 to be considered a member #315711 */
                     printf("%s ", cman_nodes[lpc].cn_name);
                 }
             }
             printf("\n");
             break;
 
         case 'i':
             rc = cman_get_node(cman_handle, CMAN_NODEID_US, &node);
             if (rc != 0) {
                 fprintf(stderr, "Couldn't query cman node id: %d %d", rc, errno);
                 goto cman_bail;
             }
             fprintf(stdout, "%u\n", node.cn_nodeid);
             break;
 
         default:
             fprintf(stderr, "Unknown option '%c'\n", command);
             crm_help('?', EX_USAGE);
     }
     cman_finish(cman_handle);
     crm_exit(pcmk_ok);
 
   cman_bail:
     cman_finish(cman_handle);
     return crm_exit(EINVAL);
 }
 #endif
 
 #if HAVE_CONFDB
 static void
 ais_membership_destroy(gpointer user_data)
 {
     crm_err("AIS connection terminated");
     ais_fd_sync = -1;
     crm_exit(ENOTCONN);
 }
 
 static gint
 member_sort(gconstpointer a, gconstpointer b)
 {
     const crm_node_t *node_a = a;
     const crm_node_t *node_b = b;
 
     return strcmp(node_a->uname, node_b->uname);
 }
 
 static void
 crm_add_member(gpointer key, gpointer value, gpointer user_data)
 {
     GList **list = user_data;
     crm_node_t *node = value;
 
     if (node->uname != NULL) {
         *list = g_list_insert_sorted(*list, node, member_sort);
     }
 }
 
 static void
 ais_membership_dispatch(cpg_handle_t handle,
                           const struct cpg_name *groupName,
                           uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 {
     uint32_t kind = 0;
     const char *from = NULL;
     char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
 
     switch (kind) {
         case crm_class_members:
         case crm_class_notify:
         case crm_class_quorum:
             break;
         default:
             free(data);
             return;
 
             break;
     }
 
     if (command == 'q') {
         if (crm_have_quorum) {
             fprintf(stdout, "1\n");
         } else {
             fprintf(stdout, "0\n");
         }
 
     } else if (command == 'l') {
         GList *nodes = NULL;
         GListPtr lpc = NULL;
 
         g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes);
         for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
             crm_node_t *node = (crm_node_t *) lpc->data;
 
             fprintf(stdout, "%u %s %s\n", node->id, node->uname, node->state);
         }
         fprintf(stdout, "\n");
 
     } else if (command == 'p') {
         GList *nodes = NULL;
         GListPtr lpc = NULL;
 
         g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes);
         for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
             crm_node_t *node = (crm_node_t *) lpc->data;
 
             if (node->uname && safe_str_eq(node->state, CRM_NODE_MEMBER)) {
                 fprintf(stdout, "%s ", node->uname);
             }
         }
         fprintf(stdout, "\n");
     }
 
     free(data);
     crm_exit(pcmk_ok);
 
     return;
 }
 #endif
 
 #ifdef SUPPORT_CS_QUORUM
 #  include <corosync/quorum.h>
 #  include <corosync/cpg.h>
 
 static gint
 compare_node_uname(gconstpointer a, gconstpointer b)
 {
     const crm_node_t *a_node = a;
     const crm_node_t *b_node = b;
     return strcmp(a_node->uname?a_node->uname:"", b_node->uname?b_node->uname:"");
 }
 
 static int
 node_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
 {
     xmlNode *msg = string2xml(buffer);
 
     if (msg) {
         xmlNode *node = NULL;
         GListPtr nodes = NULL;
         GListPtr iter = NULL;
 
         crm_log_xml_trace(msg, "message");
 
         for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
             crm_node_t *peer = calloc(1, sizeof(crm_node_t));
 
             nodes = g_list_insert_sorted(nodes, peer, compare_node_uname);
             peer->uname = (char*)crm_element_value_copy(node, "uname");
             peer->state = (char*)crm_element_value_copy(node, "state");
             crm_element_value_int(node, "id", (int*)&peer->id);
         }
 
         for(iter = nodes; iter; iter = iter->next) {
             crm_node_t *peer = iter->data;
             if (command == 'l') {
                 fprintf(stdout, "%u %s\n", peer->id, peer->uname);
 
             } else if (command == 'p') {
                 if(safe_str_eq(peer->state, CRM_NODE_MEMBER)) {
                     fprintf(stdout, "%s ", peer->uname);
                 }
             }
         }
 
         g_list_free_full(nodes, free);
         free_xml(msg);
 
         if (command == 'p') {
             fprintf(stdout, "\n");
         }
 
         crm_exit(pcmk_ok);
     }
 
     return 0;
 }
 
 static void
 node_mcp_destroy(gpointer user_data)
 {
     crm_exit(ENOTCONN);
 }
 
 static gboolean
 try_corosync(int command, enum cluster_type_e stack)
 {
     int rc = 0;
     int quorate = 0;
     uint32_t quorum_type = 0;
     unsigned int nodeid = 0;
     cpg_handle_t c_handle = 0;
     quorum_handle_t q_handle = 0;
 
     mainloop_io_t *ipc = NULL;
     GMainLoop *amainloop = NULL;
 
     struct ipc_client_callbacks node_callbacks = {
         .dispatch = node_mcp_dispatch,
         .destroy = node_mcp_destroy
     };
 
     switch (command) {
         case 'R':
             if (tools_remove_node_cache(target_uname, CRM_SYSTEM_CRMD)) {
                 crm_err("Failed to connect to "CRM_SYSTEM_CRMD" to remove node '%s'", target_uname);
                 crm_exit(pcmk_err_generic);
             }
             if (tools_remove_node_cache(target_uname, CRM_SYSTEM_MCP)) {
                 crm_err("Failed to connect to "CRM_SYSTEM_MCP" to remove node '%s'", target_uname);
                 crm_exit(pcmk_err_generic);
             }
             crm_exit(pcmk_ok);
             break;
 
         case 'e':
             /* Age makes no sense (yet) in an AIS cluster */
             fprintf(stdout, "1\n");
             crm_exit(pcmk_ok);
 
         case 'q':
             /* Go direct to the Quorum API */
             rc = quorum_initialize(&q_handle, NULL, &quorum_type);
             if (rc != CS_OK) {
                 crm_err("Could not connect to the Quorum API: %d\n", rc);
                 return FALSE;
             }
 
             rc = quorum_getquorate(q_handle, &quorate);
             if (rc != CS_OK) {
                 crm_err("Could not obtain the current Quorum API state: %d\n", rc);
                 return FALSE;
             }
 
             if (quorate) {
                 fprintf(stdout, "1\n");
             } else {
                 fprintf(stdout, "0\n");
             }
             quorum_finalize(q_handle);
             crm_exit(pcmk_ok);
 
         case 'i':
             /* Go direct to the CPG API */
             rc = cpg_initialize(&c_handle, NULL);
             if (rc != CS_OK) {
                 crm_err("Could not connect to the Cluster Process Group API: %d\n", rc);
                 return FALSE;
             }
 
             rc = cpg_local_get(c_handle, &nodeid);
             if (rc != CS_OK) {
                 crm_err("Could not get local node id from the CPG API");
                 return FALSE;
             }
 
             fprintf(stdout, "%u\n", nodeid);
             cpg_finalize(c_handle);
             crm_exit(pcmk_ok);
 
         case 'l':
         case 'p':
             /* Go to pacemakerd */
             amainloop = g_main_new(FALSE);
             ipc =
-                mainloop_add_ipc_client(CRM_SYSTEM_MCP, G_PRIORITY_DEFAULT, 0, NULL,
+                mainloop_add_ipc_client(CRM_SYSTEM_MCP, G_PRIORITY_DEFAULT, NULL,
                                         &node_callbacks);
             if (ipc != NULL) {
                 /* Sending anything will get us a list of nodes */
                 xmlNode *poke = create_xml_node(NULL, "poke");
 
                 crm_ipc_send(mainloop_get_ipc_client(ipc), poke, 0, 0, NULL);
                 free_xml(poke);
                 g_main_run(amainloop);
             }
             break;
     }
     return FALSE;
 }
 #endif
 
 #if HAVE_CONFDB
 static gboolean
 try_openais(int command, enum cluster_type_e stack)
 {
     static crm_cluster_t cluster;
 
     cluster.destroy = ais_membership_destroy;
     cluster.cpg.cpg_deliver_fn = ais_membership_dispatch;
     cluster.cpg.cpg_confchg_fn = NULL;
 
     if (init_cs_connection_once(&cluster)) {
 
         GMainLoop *amainloop = NULL;
 
         switch (command) {
             case 'R':
                 send_cluster_text(crm_class_rmpeer, target_uname, TRUE, NULL, crm_msg_ais);
                 cib_remove_node(0, target_uname);
                 crm_exit(pcmk_ok);
 
             case 'e':
                 /* Age makes no sense (yet) in an AIS cluster */
                 fprintf(stdout, "1\n");
                 crm_exit(pcmk_ok);
 
             case 'q':
                 send_cluster_text(crm_class_quorum, NULL, TRUE, NULL, crm_msg_ais);
                 break;
 
             case 'l':
             case 'p':
                 crm_info("Requesting the list of configured nodes");
                 send_cluster_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais);
                 break;
 
             case 'i':
                 printf("%u\n", cluster.nodeid);
                 crm_exit(pcmk_ok);
 
             default:
                 fprintf(stderr, "Unknown option '%c'\n", command);
                 crm_help('?', EX_USAGE);
         }
         amainloop = g_main_new(FALSE);
         g_main_run(amainloop);
     }
     return FALSE;
 }
 #endif
 
 int set_cluster_type(enum cluster_type_e type);
 
 int
 main(int argc, char **argv)
 {
     int flag = 0;
     int argerr = 0;
     uint32_t nodeid = 0;
     gboolean force_flag = FALSE;
     gboolean dangerous_cmd = FALSE;
     enum cluster_type_e try_stack = pcmk_cluster_unknown;
 
     int option_index = 0;
 
     crm_peer_init();
     crm_log_cli_init("crm_node");
     crm_set_options(NULL, "command [options]", long_options,
                     "Tool for displaying low-level node information");
 
     while (flag >= 0) {
         flag = crm_get_option(argc, argv, &option_index);
         switch (flag) {
             case -1:
                 break;
             case 'V':
                 crm_bump_log_level(argc, argv);
                 break;
             case '$':
             case '?':
                 crm_help(flag, EX_OK);
                 break;
             case 'Q':
                 do_quiet = TRUE;
                 break;
             case 'H':
                 set_cluster_type(pcmk_cluster_heartbeat);
                 break;
             case 'A':
                 set_cluster_type(pcmk_cluster_classic_ais);
                 break;
             case 'C':
                 set_cluster_type(pcmk_cluster_corosync);
                 break;
             case 'c':
                 set_cluster_type(pcmk_cluster_cman);
                 break;
             case 'f':
                 force_flag = TRUE;
                 break;
             case 'R':
                 dangerous_cmd = TRUE;
                 command = flag;
                 target_uname = optarg;
                 break;
             case 'N':
                 command = flag;
                 nodeid = crm_parse_int(optarg, NULL);
                 break;
             case 'p':
             case 'e':
             case 'q':
             case 'i':
             case 'l':
             case 'n':
                 command = flag;
                 break;
             default:
                 ++argerr;
                 break;
         }
     }
 
     if (optind > argc) {
         ++argerr;
     }
 
     if (argerr) {
         crm_help('?', EX_USAGE);
     }
 
     if (command == 'n') {
         fprintf(stdout, "%s\n", get_local_node_name());
         crm_exit(pcmk_ok);
 
     } else if (command == 'N') {
         fprintf(stdout, "%s\n", get_node_name(nodeid));
         crm_exit(pcmk_ok);
     }
 
     if (dangerous_cmd && force_flag == FALSE) {
         fprintf(stderr, "The supplied command is considered dangerous."
                 "  To prevent accidental destruction of the cluster,"
                 " the --force flag is required in order to proceed.\n");
         fflush(stderr);
         crm_exit(EINVAL);
     }
 
     try_stack = get_cluster_type();
     crm_debug("Attempting to process -%c command for cluster type: %s", command,
               name_for_cluster_type(try_stack));
 
 #if SUPPORT_CMAN
     if (try_stack == pcmk_cluster_cman) {
         try_cman(command, try_stack);
     }
 #endif
 
 #ifdef SUPPORT_CS_QUORUM
     if (try_stack == pcmk_cluster_corosync) {
         try_corosync(command, try_stack);
     }
 #endif
 
 #if HAVE_CONFDB
     /* Only an option if we're using the plugins */
     if (try_stack == pcmk_cluster_classic_ais) {
         try_openais(command, try_stack);
     }
 #endif
 
 #if SUPPORT_HEARTBEAT
     if (try_stack == pcmk_cluster_heartbeat) {
         try_heartbeat(command, try_stack);
     }
 #endif
 
     return (1);
 }
diff --git a/tools/crm_resource.c b/tools/crm_resource.c
index 2d348591e3..35408896bd 100644
--- a/tools/crm_resource.c
+++ b/tools/crm_resource.c
@@ -1,2189 +1,2189 @@
 
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 
 #include <crm/crm.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
 
 #include <crm/msg_xml.h>
 #include <crm/services.h>
 #include <crm/common/xml.h>
 #include <crm/common/mainloop.h>
 
 #include <crm/cib.h>
 #include <crm/attrd.h>
 #include <crm/pengine/rules.h>
 #include <crm/pengine/status.h>
 #include <crm/pengine/internal.h>
 
 bool scope_master = FALSE;
 gboolean do_force = FALSE;
 gboolean BE_QUIET = FALSE;
 const char *attr_set_type = XML_TAG_ATTR_SETS;
 char *host_id = NULL;
 const char *rsc_id = NULL;
 const char *host_uname = NULL;
 const char *prop_name = NULL;
 const char *prop_value = NULL;
 const char *rsc_type = NULL;
 const char *prop_id = NULL;
 const char *prop_set = NULL;
 char *move_lifetime = NULL;
 char rsc_cmd = 'L';
 const char *rsc_long_cmd = NULL;
 char *our_pid = NULL;
 crm_ipc_t *crmd_channel = NULL;
 char *xml_file = NULL;
 int cib_options = cib_sync_call;
 int crmd_replies_needed = 0;
 GMainLoop *mainloop = NULL;
 
 extern void cleanup_alloc_calculations(pe_working_set_t * data_set);
 
 #define CMD_ERR(fmt, args...) do {		\
 	crm_warn(fmt, ##args);			\
 	fprintf(stderr, fmt, ##args);		\
     } while(0)
 
 #define message_timeout_ms 60*1000
 
 static gboolean
 resource_ipc_timeout(gpointer data)
 {
     fprintf(stderr, "No messages received in %d seconds.. aborting\n",
             (int)message_timeout_ms / 1000);
     crm_err("No messages received in %d seconds", (int)message_timeout_ms / 1000);
     return crm_exit(-1);
 }
 
 static void
 resource_ipc_connection_destroy(gpointer user_data)
 {
     crm_info("Connection to CRMd was terminated");
     crm_exit(1);
 }
 
 static void
 start_mainloop(void)
 {
     mainloop = g_main_new(FALSE);
     fprintf(stderr, "Waiting for %d replies from the CRMd", crmd_replies_needed);
     crm_debug("Waiting for %d replies from the CRMd", crmd_replies_needed);
 
     g_timeout_add(message_timeout_ms, resource_ipc_timeout, NULL);
     g_main_run(mainloop);
 }
 
 static int
 resource_ipc_callback(const char *buffer, ssize_t length, gpointer userdata)
 {
     xmlNode *msg = string2xml(buffer);
 
     fprintf(stderr, ".");
     crm_log_xml_trace(msg, "[inbound]");
 
     crmd_replies_needed--;
     if (crmd_replies_needed == 0) {
         fprintf(stderr, " OK\n");
         crm_debug("Got all the replies we expected");
         return crm_exit(pcmk_ok);
     }
 
     free_xml(msg);
     return 0;
 }
 
 struct ipc_client_callbacks crm_callbacks = {
     .dispatch = resource_ipc_callback,
     .destroy = resource_ipc_connection_destroy,
 };
 
 static int
 do_find_resource(const char *rsc, resource_t * the_rsc, pe_working_set_t * data_set)
 {
     int found = 0;
     GListPtr lpc = NULL;
 
     if (the_rsc == NULL) {
         the_rsc = pe_find_resource(data_set->resources, rsc);
     }
 
     if (the_rsc == NULL) {
         return -ENXIO;
     }
 
     if (the_rsc->variant >= pe_clone) {
         GListPtr gIter = the_rsc->children;
 
         for (; gIter != NULL; gIter = gIter->next) {
             found += do_find_resource(rsc, gIter->data, data_set);
         }
         return found;
     }
 
     for (lpc = the_rsc->running_on; lpc != NULL; lpc = lpc->next) {
         node_t *node = (node_t *) lpc->data;
 
         crm_trace("resource %s is running on: %s", rsc, node->details->uname);
         if (BE_QUIET) {
             fprintf(stdout, "%s\n", node->details->uname);
         } else {
             const char *state = "";
 
             if (the_rsc->variant == pe_native && the_rsc->role == RSC_ROLE_MASTER) {
                 state = "Master";
             }
             fprintf(stdout, "resource %s is running on: %s %s\n", rsc, node->details->uname, state);
         }
 
         found++;
     }
 
     if (BE_QUIET == FALSE && found == 0) {
         fprintf(stderr, "resource %s is NOT running\n", rsc);
     }
 
     return 0;
 }
 
 #define cons_string(x) x?x:"NA"
 static void
 print_cts_constraints(pe_working_set_t * data_set)
 {
     xmlNode *xml_obj = NULL;
     xmlNode *lifetime = NULL;
     xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
 
     for (xml_obj = __xml_first_child(cib_constraints); xml_obj != NULL;
          xml_obj = __xml_next(xml_obj)) {
         const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
 
         if (id == NULL) {
             continue;
         }
 
         lifetime = first_named_child(xml_obj, "lifetime");
 
         if (test_ruleset(lifetime, NULL, data_set->now) == FALSE) {
             continue;
         }
 
         if (safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) {
             printf("Constraint %s %s %s %s %s %s %s\n",
                    crm_element_name(xml_obj),
                    cons_string(crm_element_value(xml_obj, XML_ATTR_ID)),
                    cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE)),
                    cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET)),
                    cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_SCORE)),
                    cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE)),
                    cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE)));
 
         } else if (safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) {
             /* unpack_location(xml_obj, data_set); */
         }
     }
 }
 
 static void
 print_cts_rsc(resource_t * rsc)
 {
     GListPtr lpc = NULL;
     const char *host = NULL;
     gboolean needs_quorum = TRUE;
     const char *rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
     const char *rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
     const char *rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 
     if (safe_str_eq(rclass, "stonith")) {
         xmlNode *op = NULL;
 
         needs_quorum = FALSE;
 
         for (op = __xml_first_child(rsc->ops_xml); op != NULL; op = __xml_next(op)) {
             if (crm_str_eq((const char *)op->name, "op", TRUE)) {
                 const char *name = crm_element_value(op, "name");
 
                 if (safe_str_neq(name, CRMD_ACTION_START)) {
                     const char *value = crm_element_value(op, "requires");
 
                     if (safe_str_eq(value, "nothing")) {
                         needs_quorum = FALSE;
                     }
                     break;
                 }
             }
         }
     }
 
     if (rsc->running_on != NULL && g_list_length(rsc->running_on) == 1) {
         node_t *tmp = rsc->running_on->data;
 
         host = tmp->details->uname;
     }
 
     printf("Resource: %s %s %s %s %s %s %s %s %d %lld 0x%.16llx\n",
            crm_element_name(rsc->xml), rsc->id,
            rsc->clone_name ? rsc->clone_name : rsc->id, rsc->parent ? rsc->parent->id : "NA",
            rprov ? rprov : "NA", rclass, rtype, host ? host : "NA", needs_quorum, rsc->flags,
            rsc->flags);
 
     for (lpc = rsc->children; lpc != NULL; lpc = lpc->next) {
         resource_t *child = (resource_t *) lpc->data;
 
         print_cts_rsc(child);
     }
 }
 
 static void
 print_raw_rsc(resource_t * rsc)
 {
     GListPtr lpc = NULL;
     GListPtr children = rsc->children;
 
     if (children == NULL) {
         printf("%s\n", rsc->id);
     }
 
     for (lpc = children; lpc != NULL; lpc = lpc->next) {
         resource_t *child = (resource_t *) lpc->data;
 
         print_raw_rsc(child);
     }
 }
 
 static int
 do_find_resource_list(pe_working_set_t * data_set, gboolean raw)
 {
     int found = 0;
 
     GListPtr lpc = NULL;
 
     for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
         resource_t *rsc = (resource_t *) lpc->data;
 
         if (is_set(rsc->flags, pe_rsc_orphan)
             && rsc->fns->active(rsc, TRUE) == FALSE) {
             continue;
         }
         rsc->fns->print(rsc, NULL, pe_print_printf | pe_print_rsconly, stdout);
         found++;
     }
 
     if (found == 0) {
         printf("NO resources configured\n");
         return -ENXIO;
     }
 
     return 0;
 }
 
 static resource_t *
 find_rsc_or_clone(const char *rsc, pe_working_set_t * data_set)
 {
     resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
 
     if (the_rsc == NULL) {
         char *as_clone = crm_concat(rsc, "0", ':');
 
         the_rsc = pe_find_resource(data_set->resources, as_clone);
         free(as_clone);
     }
     return the_rsc;
 }
 
 static int
 dump_resource(const char *rsc, pe_working_set_t * data_set, gboolean expanded)
 {
     char *rsc_xml = NULL;
     resource_t *the_rsc = find_rsc_or_clone(rsc, data_set);
 
     if (the_rsc == NULL) {
         return -ENXIO;
     }
     the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout);
 
     if (expanded) {
         rsc_xml = dump_xml_formatted(the_rsc->xml);
     } else {
         if (the_rsc->orig_xml) {
             rsc_xml = dump_xml_formatted(the_rsc->orig_xml);
         } else {
             rsc_xml = dump_xml_formatted(the_rsc->xml);
         }
     }
 
     fprintf(stdout, "%sxml:\n%s\n", expanded ? "" : "raw ", rsc_xml);
 
     free(rsc_xml);
 
     return 0;
 }
 
 static int
 dump_resource_attr(const char *rsc, const char *attr, pe_working_set_t * data_set)
 {
     int rc = -ENXIO;
     node_t *current = NULL;
     GHashTable *params = NULL;
     resource_t *the_rsc = find_rsc_or_clone(rsc, data_set);
     const char *value = NULL;
 
     if (the_rsc == NULL) {
         return -ENXIO;
     }
 
     if (g_list_length(the_rsc->running_on) == 1) {
         current = the_rsc->running_on->data;
 
     } else if (g_list_length(the_rsc->running_on) > 1) {
         CMD_ERR("%s is active on more than one node,"
                 " returning the default value for %s\n", the_rsc->id, crm_str(value));
     }
 
     params = g_hash_table_new_full(crm_str_hash, g_str_equal,
                                    g_hash_destroy_str, g_hash_destroy_str);
 
     if (safe_str_eq(attr_set_type, XML_TAG_ATTR_SETS)) {
         get_rsc_attributes(params, the_rsc, current, data_set);
     } else if (safe_str_eq(attr_set_type, XML_TAG_META_SETS)) {
         get_meta_attributes(params, the_rsc, current, data_set);
     } else {
         unpack_instance_attributes(data_set->input, the_rsc->xml, XML_TAG_UTILIZATION, NULL,
                                    params, NULL, FALSE, data_set->now);
     }
 
     crm_debug("Looking up %s in %s", attr, the_rsc->id);
     value = g_hash_table_lookup(params, attr);
     if (value != NULL) {
         fprintf(stdout, "%s\n", value);
         rc = 0;
     }
 
     g_hash_table_destroy(params);
     return rc;
 }
 
 static int
 find_resource_attr(cib_t * the_cib, const char *attr, const char *rsc, const char *set_type,
                    const char *set_name, const char *attr_id, const char *attr_name, char **value)
 {
     int offset = 0;
     static int xpath_max = 1024;
     int rc = pcmk_ok;
     xmlNode *xml_search = NULL;
 
     char *xpath_string = NULL;
 
     CRM_ASSERT(value != NULL);
     *value = NULL;
 
     xpath_string = calloc(1, xpath_max);
     offset +=
         snprintf(xpath_string + offset, xpath_max - offset, "%s", get_object_path("resources"));
 
     offset += snprintf(xpath_string + offset, xpath_max - offset, "//*[@id=\"%s\"]", rsc);
 
     if (set_type) {
         offset += snprintf(xpath_string + offset, xpath_max - offset, "/%s", set_type);
         if (set_name) {
             offset += snprintf(xpath_string + offset, xpath_max - offset, "[@id=\"%s\"]", set_name);
         }
     }
 
     offset += snprintf(xpath_string + offset, xpath_max - offset, "//nvpair[");
     if (attr_id) {
         offset += snprintf(xpath_string + offset, xpath_max - offset, "@id=\"%s\"", attr_id);
     }
 
     if (attr_name) {
         if (attr_id) {
             offset += snprintf(xpath_string + offset, xpath_max - offset, " and ");
         }
         offset += snprintf(xpath_string + offset, xpath_max - offset, "@name=\"%s\"", attr_name);
     }
     offset += snprintf(xpath_string + offset, xpath_max - offset, "]");
 
     rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
                               cib_sync_call | cib_scope_local | cib_xpath);
 
     if (rc != pcmk_ok) {
         goto bail;
     }
 
     crm_log_xml_debug(xml_search, "Match");
     if (xml_has_children(xml_search)) {
         xmlNode *child = NULL;
 
         rc = -EINVAL;
         printf("Multiple attributes match name=%s\n", attr_name);
 
         for (child = __xml_first_child(xml_search); child != NULL; child = __xml_next(child)) {
             printf("  Value: %s \t(id=%s)\n",
                    crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child));
         }
 
     } else {
         const char *tmp = crm_element_value(xml_search, attr);
 
         if (tmp) {
             *value = strdup(tmp);
         }
     }
 
   bail:
     free(xpath_string);
     free_xml(xml_search);
     return rc;
 }
 
 #include "../pengine/pengine.h"
 
 
 static int
 set_resource_attr(const char *rsc_id, const char *attr_set, const char *attr_id,
                   const char *attr_name, const char *attr_value, bool recursive,
                   cib_t * cib, pe_working_set_t * data_set)
 {
     int rc = pcmk_ok;
     static bool need_init = TRUE;
 
     char *local_attr_id = NULL;
     char *local_attr_set = NULL;
 
     xmlNode *xml_top = NULL;
     xmlNode *xml_obj = NULL;
 
     gboolean use_attributes_tag = FALSE;
     resource_t *rsc = find_rsc_or_clone(rsc_id, data_set);
 
     if (rsc == NULL) {
         return -ENXIO;
     }
 
     if (safe_str_eq(attr_set_type, XML_TAG_ATTR_SETS)) {
         rc = find_resource_attr(cib, XML_ATTR_ID, rsc_id, XML_TAG_META_SETS, attr_set, attr_id,
                                 attr_name, &local_attr_id);
         if (rc == pcmk_ok) {
             printf("WARNING: There is already a meta attribute called %s (id=%s)\n", attr_name,
                    local_attr_id);
         }
     }
     rc = find_resource_attr(cib, XML_ATTR_ID, rsc_id, attr_set_type, attr_set, attr_id, attr_name,
                             &local_attr_id);
 
     if (rc == pcmk_ok) {
         crm_debug("Found a match for name=%s: id=%s", attr_name, local_attr_id);
         attr_id = local_attr_id;
 
     } else if (rc != -ENXIO) {
         free(local_attr_id);
         return rc;
 
     } else {
         const char *value = NULL;
         xmlNode *cib_top = NULL;
         const char *tag = crm_element_name(rsc->xml);
 
         rc = cib->cmds->query(cib, "/cib", &cib_top,
                               cib_sync_call | cib_scope_local | cib_xpath | cib_no_children);
         value = crm_element_value(cib_top, "ignore_dtd");
         if (value != NULL) {
             use_attributes_tag = TRUE;
 
         } else {
             value = crm_element_value(cib_top, XML_ATTR_VALIDATION);
             if (value && strstr(value, "-0.6")) {
                 use_attributes_tag = TRUE;
             }
         }
         free_xml(cib_top);
 
         if (attr_set == NULL) {
             local_attr_set = crm_concat(rsc_id, attr_set_type, '-');
             attr_set = local_attr_set;
         }
         if (attr_id == NULL) {
             local_attr_id = crm_concat(attr_set, attr_name, '-');
             attr_id = local_attr_id;
         }
 
         if (use_attributes_tag && safe_str_eq(tag, XML_CIB_TAG_MASTER)) {
             tag = "master_slave";       /* use the old name */
         }
 
         xml_top = create_xml_node(NULL, tag);
         crm_xml_add(xml_top, XML_ATTR_ID, rsc_id);
 
         xml_obj = create_xml_node(xml_top, attr_set_type);
         crm_xml_add(xml_obj, XML_ATTR_ID, attr_set);
 
         if (use_attributes_tag) {
             xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS);
         }
     }
 
     xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
     if (xml_top == NULL) {
         xml_top = xml_obj;
     }
 
     crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
     crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
     crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value);
 
     crm_log_xml_debug(xml_top, "Update");
 
     rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, cib_options);
     free_xml(xml_top);
     free(local_attr_id);
     free(local_attr_set);
 
     if(recursive && safe_str_eq(attr_set_type, XML_TAG_META_SETS)) {
         GListPtr lpc = NULL;
 
         if(need_init) {
             xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
 
             need_init = FALSE;
             unpack_constraints(cib_constraints, data_set);
 
             for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
                 resource_t *r = (resource_t *) lpc->data;
 
                 clear_bit(r->flags, pe_rsc_allocating);
             }
         }
 
         crm_debug("Looking for dependancies %p", rsc->rsc_cons_lhs);
         set_bit(rsc->flags, pe_rsc_allocating);
         for (lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
             rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data;
             resource_t *peer = cons->rsc_lh;
 
             crm_debug("Checking %s %d", cons->id, cons->score);
             if (cons->score > 0 && is_not_set(peer->flags, pe_rsc_allocating)) {
                 /* Don't get into colocation loops */
                 crm_debug("Setting %s=%s for dependant resource %s", attr_name, attr_value, peer->id);
                 set_resource_attr(peer->id, NULL, NULL, attr_name, attr_value, recursive, cib, data_set);
             }
         }
     }
 
     return rc;
 }
 
 static int
 delete_resource_attr(const char *rsc_id, const char *attr_set, const char *attr_id,
                      const char *attr_name, cib_t * cib, pe_working_set_t * data_set)
 {
     xmlNode *xml_obj = NULL;
 
     int rc = pcmk_ok;
     char *local_attr_id = NULL;
     resource_t *rsc = find_rsc_or_clone(rsc_id, data_set);
 
     if (rsc == NULL) {
         return -ENXIO;
     }
 
     rc = find_resource_attr(cib, XML_ATTR_ID, rsc_id, attr_set_type, attr_set, attr_id, attr_name,
                             &local_attr_id);
 
     if (rc == -ENXIO) {
         return pcmk_ok;
 
     } else if (rc != pcmk_ok) {
         return rc;
     }
 
     if (attr_id == NULL) {
         attr_id = local_attr_id;
     }
 
     xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR);
     crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
     crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
 
     crm_log_xml_debug(xml_obj, "Delete");
 
     rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, cib_options);
 
     if (rc == pcmk_ok) {
         printf("Deleted %s option: id=%s%s%s%s%s\n", rsc_id, local_attr_id,
                attr_set ? " set=" : "", attr_set ? attr_set : "",
                attr_name ? " name=" : "", attr_name ? attr_name : "");
     }
 
     free_xml(xml_obj);
     free(local_attr_id);
     return rc;
 }
 
 static int
 dump_resource_prop(const char *rsc, const char *attr, pe_working_set_t * data_set)
 {
     const char *value = NULL;
     resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
 
     if (the_rsc == NULL) {
         return -ENXIO;
     }
 
     value = crm_element_value(the_rsc->xml, attr);
 
     if (value != NULL) {
         fprintf(stdout, "%s\n", value);
         return 0;
     }
     return -ENXIO;
 }
 
 static int
 send_lrm_rsc_op(crm_ipc_t * crmd_channel, const char *op,
                 const char *host_uname, const char *rsc_id,
                 gboolean only_failed, pe_working_set_t * data_set)
 {
     char *key = NULL;
     int rc = -ECOMM;
     xmlNode *cmd = NULL;
     xmlNode *xml_rsc = NULL;
     const char *value = NULL;
     const char *router_node = host_uname;
     xmlNode *params = NULL;
     xmlNode *msg_data = NULL;
     resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
 
     if (rsc == NULL) {
         CMD_ERR("Resource %s not found\n", rsc_id);
         return -ENXIO;
 
     } else if (rsc->variant != pe_native) {
         CMD_ERR("We can only process primitive resources, not %s\n", rsc_id);
         return -EINVAL;
 
     } else if (host_uname == NULL) {
         CMD_ERR("Please supply a hostname with -H\n");
         return -EINVAL;
     } else {
         node_t *node = pe_find_node(data_set->nodes, host_uname);
 
         if (node && is_remote_node(node)) {
             if (node->details->remote_rsc->running_on) {
                 node = node->details->remote_rsc->running_on->data;
                 router_node = node->details->uname;
             } else {
                 CMD_ERR("No lrmd connection detected to remote node %s", host_uname);
                 return -ENXIO;
             }
         }
     }
 
     key = generate_transition_key(0, getpid(), 0, "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
 
     msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
     crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
     free(key);
 
     crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, host_uname);
     if (safe_str_neq(router_node, host_uname)) {
         crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
     }
 
     xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
     if (rsc->clone_name) {
         crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->clone_name);
         crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc->id);
 
     } else {
         crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->id);
     }
 
     value = crm_element_value(rsc->xml, XML_ATTR_TYPE);
     crm_xml_add(xml_rsc, XML_ATTR_TYPE, value);
     if (value == NULL) {
         CMD_ERR("%s has no type!  Aborting...\n", rsc_id);
         return -ENXIO;
     }
 
     value = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
     crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, value);
     if (value == NULL) {
         CMD_ERR("%s has no class!  Aborting...\n", rsc_id);
         return -ENXIO;
     }
 
     value = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
     crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, value);
 
     params = create_xml_node(msg_data, XML_TAG_ATTRS);
     crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 
     key = crm_meta_name(XML_LRM_ATTR_INTERVAL);
     crm_xml_add(params, key, "60000");  /* 1 minute */
     free(key);
 
     cmd = create_request(op, msg_data, router_node, CRM_SYSTEM_CRMD, crm_system_name, our_pid);
 
 /* 	crm_log_xml_warn(cmd, "send_lrm_rsc_op"); */
     free_xml(msg_data);
 
     if (crm_ipc_send(crmd_channel, cmd, 0, 0, NULL) > 0) {
         crmd_replies_needed++;
         rc = 0;
 
     } else {
         CMD_ERR("Could not send %s op to the crmd", op);
         rc = -ENOTCONN;
     }
 
     free_xml(cmd);
     return rc;
 }
 
 static int
 delete_lrm_rsc(cib_t *cib_conn, crm_ipc_t * crmd_channel, const char *host_uname,
                resource_t * rsc, pe_working_set_t * data_set)
 {
     int rc = pcmk_ok;
 
     if (rsc == NULL) {
         return -ENXIO;
 
     } else if (rsc->children) {
         GListPtr lpc = NULL;
 
         for (lpc = rsc->children; lpc != NULL; lpc = lpc->next) {
             resource_t *child = (resource_t *) lpc->data;
 
             delete_lrm_rsc(cib_conn, crmd_channel, host_uname, child, data_set);
         }
         return pcmk_ok;
 
     } else if (host_uname == NULL) {
         GListPtr lpc = NULL;
 
         for (lpc = data_set->nodes; lpc != NULL; lpc = lpc->next) {
             node_t *node = (node_t *) lpc->data;
 
             if (node->details->online) {
                 delete_lrm_rsc(cib_conn, crmd_channel, node->details->uname, rsc, data_set);
             }
         }
 
         return pcmk_ok;
     }
 
     printf("Cleaning up %s on %s\n", rsc->id, host_uname);
     rc = send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_DELETE, host_uname, rsc->id, TRUE, data_set);
     if (rc == pcmk_ok) {
         char *attr_name = NULL;
         const char *id = rsc->id;
         node_t *node = pe_find_node(data_set->nodes, host_uname);
 
         if (rsc->clone_name) {
             id = rsc->clone_name;
         }
 
         attr_name = crm_concat("fail-count", id, '-');
         rc = attrd_update_delegate(NULL, 'D', host_uname, attr_name, NULL, XML_CIB_TAG_STATUS, NULL,
                               NULL, NULL, node ? is_remote_node(node) : FALSE);
         free(attr_name);
     }
     return rc;
 }
 
 static int
 fail_lrm_rsc(crm_ipc_t * crmd_channel, const char *host_uname,
              const char *rsc_id, pe_working_set_t * data_set)
 {
     crm_warn("Failing: %s", rsc_id);
     return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_FAIL, host_uname, rsc_id, FALSE, data_set);
 }
 
 static char *
 parse_cli_lifetime(const char *input)
 {
     char *later_s = NULL;
     crm_time_t *now = NULL;
     crm_time_t *later = NULL;
     crm_time_t *duration = NULL;
 
     if (input == NULL) {
         return NULL;
     }
 
     duration = crm_time_parse_duration(move_lifetime);
     if (duration == NULL) {
         CMD_ERR("Invalid duration specified: %s\n", move_lifetime);
         CMD_ERR("Please refer to"
                 " http://en.wikipedia.org/wiki/ISO_8601#Duration"
                 " for examples of valid durations\n");
         return NULL;
     }
 
     now = crm_time_new(NULL);
     later = crm_time_add(now, duration);
     crm_time_log(LOG_INFO, "now     ", now,
                  crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
     crm_time_log(LOG_INFO, "later   ", later,
                  crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
     crm_time_log(LOG_INFO, "duration", duration, crm_time_log_date | crm_time_log_timeofday);
     later_s = crm_time_as_string(later, crm_time_log_date | crm_time_log_timeofday);
     printf("Migration will take effect until: %s\n", later_s);
 
     crm_time_free(duration);
     crm_time_free(later);
     crm_time_free(now);
     return later_s;
 }
 
 static int
 ban_resource(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * cib_conn)
 {
     char *later_s = NULL;
     int rc = pcmk_ok;
     char *id = NULL;
     xmlNode *fragment = NULL;
     xmlNode *location = NULL;
 
     if(host == NULL) {
         GListPtr n = allnodes;
         for(; n && rc == pcmk_ok; n = n->next) {
             node_t *target = n->data;
 
             rc = ban_resource(rsc_id, target->details->uname, NULL, cib_conn);
         }
         return rc;
     }
 
     later_s = parse_cli_lifetime(move_lifetime);
     if(move_lifetime && later_s == NULL) {
         return -EINVAL;
     }
 
     fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
 
     id = g_strdup_printf("cli-ban-%s-on-%s", rsc_id, host);
     location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
     crm_xml_add(location, XML_ATTR_ID, id);
     free(id);
 
     if (BE_QUIET == FALSE) {
         CMD_ERR("WARNING: Creating rsc_location constraint '%s'"
                 " with a score of -INFINITY for resource %s"
                 " on %s.\n", ID(location), rsc_id, host);
         CMD_ERR("\tThis will prevent %s from %s"
                 " on %s until the constraint is removed using"
                 " the 'crm_resource --clear' command or manually"
                 " with cibadmin\n", rsc_id, scope_master?"being promoted":"running", host);
         CMD_ERR("\tThis will be the case even if %s is"
                 " the last node in the cluster\n", host);
         CMD_ERR("\tThis message can be disabled with --quiet\n");
     }
 
     crm_xml_add(location, XML_COLOC_ATTR_SOURCE, rsc_id);
     if(scope_master) {
         crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_MASTER_S);
     }
 
     if (later_s == NULL) {
         /* Short form */
         crm_xml_add(location, XML_CIB_TAG_NODE, host);
         crm_xml_add(location, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S);
 
     } else {
         xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
         xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
 
         id = g_strdup_printf("cli-ban-%s-on-%s-rule", rsc_id, host);
         crm_xml_add(rule, XML_ATTR_ID, id);
         free(id);
 
         crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S);
         crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
 
         id = g_strdup_printf("cli-ban-%s-on-%s-expr", rsc_id, host);
         crm_xml_add(expr, XML_ATTR_ID, id);
         free(id);
 
         crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname");
         crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
         crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
         crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
 
         expr = create_xml_node(rule, "date_expression");
         id = g_strdup_printf("cli-ban-%s-on-%s-lifetime", rsc_id, host);
         crm_xml_add(expr, XML_ATTR_ID, id);
         free(id);
 
         crm_xml_add(expr, "operation", "lt");
         crm_xml_add(expr, "end", later_s);
     }
 
     crm_log_xml_notice(fragment, "Modify");
     rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
 
     free_xml(fragment);
     free(later_s);
     return rc;
 }
 
 static int
 prefer_resource(const char *rsc_id, const char *host, cib_t * cib_conn)
 {
     char *later_s = parse_cli_lifetime(move_lifetime);
     int rc = pcmk_ok;
     char *id = NULL;
     xmlNode *location = NULL;
     xmlNode *fragment = NULL;
 
     if(move_lifetime && later_s == NULL) {
         return -EINVAL;
     }
 
     fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
 
     id = g_strdup_printf("cli-prefer-%s", rsc_id);
     location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
     crm_xml_add(location, XML_ATTR_ID, id);
     free(id);
 
     crm_xml_add(location, XML_COLOC_ATTR_SOURCE, rsc_id);
 
     if (later_s == NULL) {
         /* Short form */
         crm_xml_add(location, XML_CIB_TAG_NODE, host);
         crm_xml_add(location, XML_RULE_ATTR_SCORE, INFINITY_S);
 
     } else {
         xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
         xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
 
         id = crm_concat("cli-prefer-rule", rsc_id, '-');
         crm_xml_add(rule, XML_ATTR_ID, id);
         free(id);
 
         crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S);
         crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
 
         id = crm_concat("cli-prefer-expr", rsc_id, '-');
         crm_xml_add(expr, XML_ATTR_ID, id);
         free(id);
 
         crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname");
         crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
         crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
         crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
 
         expr = create_xml_node(rule, "date_expression");
         id = crm_concat("cli-prefer-lifetime-end", rsc_id, '-');
         crm_xml_add(expr, XML_ATTR_ID, id);
         free(id);
 
         crm_xml_add(expr, "operation", "lt");
         crm_xml_add(expr, "end", later_s);
     }
 
     crm_log_xml_info(fragment, "Modify");
     rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
 
     free_xml(fragment);
     free(later_s);
     return rc;
 }
 
 static int
 clear_resource(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * cib_conn)
 {
     char *id = NULL;
     int rc = pcmk_ok;
     xmlNode *fragment = NULL;
     xmlNode *location = NULL;
 
     fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
 
     if(host) {
         id = g_strdup_printf("cli-ban-%s-on-%s", rsc_id, host);
         location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
         crm_xml_add(location, XML_ATTR_ID, id);
         free(id);
 
     } else {
         GListPtr n = allnodes;
         for(; n; n = n->next) {
             node_t *target = n->data;
 
             id = g_strdup_printf("cli-ban-%s-on-%s", rsc_id, target->details->uname);
             location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
             crm_xml_add(location, XML_ATTR_ID, id);
             free(id);
         }
     }
 
     id = g_strdup_printf("cli-prefer-%s", rsc_id);
     location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
     crm_xml_add(location, XML_ATTR_ID, id);
     if(host && do_force == FALSE) {
         crm_xml_add(location, XML_CIB_TAG_NODE, host);
     }
     free(id);
 
     crm_log_xml_info(fragment, "Delete");
     rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
     if (rc == -ENXIO) {
         rc = pcmk_ok;
 
     } else if (rc != pcmk_ok) {
         goto bail;
     }
 
   bail:
     free_xml(fragment);
     return rc;
 }
 
 static int
 list_resource_operations(const char *rsc_id, const char *host_uname, gboolean active,
                          pe_working_set_t * data_set)
 {
     resource_t *rsc = NULL;
     int opts = pe_print_printf | pe_print_rsconly | pe_print_suppres_nl;
     GListPtr ops = find_operations(rsc_id, host_uname, active, data_set);
     GListPtr lpc = NULL;
 
     for (lpc = ops; lpc != NULL; lpc = lpc->next) {
         xmlNode *xml_op = (xmlNode *) lpc->data;
 
         const char *op_rsc = crm_element_value(xml_op, "resource");
         const char *last = crm_element_value(xml_op, XML_RSC_OP_LAST_CHANGE);
         const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS);
         const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
         int status = crm_parse_int(status_s, "0");
 
         rsc = pe_find_resource(data_set->resources, op_rsc);
         if(rsc) {
             rsc->fns->print(rsc, "", opts, stdout);
         } else {
             fprintf(stdout, "Unknown resource %s", op_rsc);
         }
 
         fprintf(stdout, ": %s (node=%s, call=%s, rc=%s",
                 op_key ? op_key : ID(xml_op),
                 crm_element_value(xml_op, XML_ATTR_UNAME),
                 crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
                 crm_element_value(xml_op, XML_LRM_ATTR_RC));
         if (last) {
             time_t run_at = crm_parse_int(last, "0");
 
             fprintf(stdout, ", last-rc-change=%s, exec=%sms\n",
                     ctime(&run_at), crm_element_value(xml_op, XML_RSC_OP_T_EXEC));
         }
         fprintf(stdout, "): %s\n", services_lrm_status_str(status));
     }
     return pcmk_ok;
 }
 
 static void
 show_location(resource_t * rsc, const char *prefix)
 {
     GListPtr lpc = NULL;
     GListPtr list = rsc->rsc_location;
     int offset = 0;
 
     if (prefix) {
         offset = strlen(prefix) - 2;
     }
 
     for (lpc = list; lpc != NULL; lpc = lpc->next) {
         rsc_to_node_t *cons = (rsc_to_node_t *) lpc->data;
 
         GListPtr lpc2 = NULL;
 
         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
             node_t *node = (node_t *) lpc2->data;
             char *score = score2char(node->weight);
 
             fprintf(stdout, "%s: Node %-*s (score=%s, id=%s)\n",
                     prefix ? prefix : "  ", 71 - offset, node->details->uname, score, cons->id);
             free(score);
         }
     }
 }
 
 static void
 show_colocation(resource_t * rsc, gboolean dependants, gboolean recursive, int offset)
 {
     char *prefix = NULL;
     GListPtr lpc = NULL;
     GListPtr list = rsc->rsc_cons;
 
     prefix = calloc(1, (offset * 4) + 1);
     memset(prefix, ' ', offset * 4);
 
     if (dependants) {
         list = rsc->rsc_cons_lhs;
     }
 
     if (is_set(rsc->flags, pe_rsc_allocating)) {
         /* Break colocation loops */
         printf("loop %s\n", rsc->id);
         free(prefix);
         return;
     }
 
     set_bit(rsc->flags, pe_rsc_allocating);
     for (lpc = list; lpc != NULL; lpc = lpc->next) {
         rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data;
 
         char *score = NULL;
         resource_t *peer = cons->rsc_rh;
 
         if (dependants) {
             peer = cons->rsc_lh;
         }
 
         if (is_set(peer->flags, pe_rsc_allocating)) {
             if (dependants == FALSE) {
                 fprintf(stdout, "%s%-*s (id=%s - loop)\n", prefix, 80 - (4 * offset), peer->id,
                         cons->id);
             }
             continue;
         }
 
         if (dependants && recursive) {
             show_colocation(peer, dependants, recursive, offset + 1);
         }
 
         score = score2char(cons->score);
         if (cons->role_rh > RSC_ROLE_STARTED) {
             fprintf(stdout, "%s%-*s (score=%s, %s role=%s, id=%s)\n", prefix, 80 - (4 * offset),
                     peer->id, score, dependants ? "needs" : "with", role2text(cons->role_rh),
                     cons->id);
         } else {
             fprintf(stdout, "%s%-*s (score=%s, id=%s)\n", prefix, 80 - (4 * offset),
                     peer->id, score, cons->id);
         }
         show_location(peer, prefix);
         free(score);
 
         if (!dependants && recursive) {
             show_colocation(peer, dependants, recursive, offset + 1);
         }
     }
     free(prefix);
 }
 
 static GHashTable *
 generate_resource_params(resource_t * rsc, pe_working_set_t * data_set)
 {
     GHashTable *params = NULL;
     GHashTable *meta = NULL;
     GHashTable *combined = NULL;
     GHashTableIter iter;
 
     if (!rsc) {
         crm_err("Resource does not exist in config");
         return NULL;
     }
 
     params =
         g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
     meta = g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
     combined =
         g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
 
     get_rsc_attributes(params, rsc, NULL /* TODO: Pass in local node */ , data_set);
     get_meta_attributes(meta, rsc, NULL /* TODO: Pass in local node */ , data_set);
 
     if (params) {
         char *key = NULL;
         char *value = NULL;
 
         g_hash_table_iter_init(&iter, params);
         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
             g_hash_table_insert(combined, strdup(key), strdup(value));
         }
         g_hash_table_destroy(params);
     }
 
     if (meta) {
         char *key = NULL;
         char *value = NULL;
 
         g_hash_table_iter_init(&iter, meta);
         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
             char *crm_name = crm_meta_name(key);
 
             g_hash_table_insert(combined, crm_name, strdup(value));
         }
         g_hash_table_destroy(meta);
     }
 
     return combined;
 }
 
 
 /* *INDENT-OFF* */
 static struct crm_option long_options[] = {
     /* Top-level Options */
     {"help",    0, 0, '?', "\t\tThis text"},
     {"version", 0, 0, '$', "\t\tVersion information"  },
     {"verbose", 0, 0, 'V', "\t\tIncrease debug output"},
     {"quiet",   0, 0, 'Q', "\t\tPrint only the value on stdout\n"},
 
     {"resource",   1, 0, 'r', "\tResource ID" },
 
     {"-spacer-",1, 0, '-', "\nQueries:"},
     {"list",       0, 0, 'L', "\t\tList all cluster resources"},
     {"list-raw",   0, 0, 'l', "\tList the IDs of all instantiated resources (no groups/clones/...)"},
     {"list-cts",   0, 0, 'c', NULL, 1},
     {"list-operations", 0, 0, 'O', "\tList active resource operations.  Optionally filtered by resource (-r) and/or node (-N)"},
     {"list-all-operations", 0, 0, 'o', "List all resource operations.  Optionally filtered by resource (-r) and/or node (-N)\n"},
 
     {"list-standards",        0, 0, 0, "\tList supported standards"},
     {"list-ocf-providers",    0, 0, 0, "List all available OCF providers"},
     {"list-agents",           1, 0, 0, "List all agents available for the named standard and/or provider."},
     {"list-ocf-alternatives", 1, 0, 0, "List all available providers for the named OCF agent\n"},
     {"show-metadata",         1, 0, 0, "Show the metadata for the named class:provider:agent"},
 
     {"query-xml",  0, 0, 'q', "\tQuery the definition of a resource (template expanded)"},
     {"query-xml-raw",  0, 0, 'w', "\tQuery the definition of a resource (raw xml)"},
     {"locate",     0, 0, 'W', "\t\tDisplay the current location(s) of a resource"},
     {"stack",      0, 0, 'A', "\t\tDisplay the prerequisites and dependents of a resource"},
     {"constraints",0, 0, 'a', "\tDisplay the (co)location constraints that apply to a resource"},
 
     {"-spacer-",	1, 0, '-', "\nCommands:"},
     {"cleanup",         0, 0, 'C', "\t\tDelete the resource history and re-check the current state. Optional: --resource"},
     {"set-parameter",   1, 0, 'p', "Set the named parameter for a resource. See also -m, --meta"},
     {"get-parameter",   1, 0, 'g', "Display the named parameter for a resource. See also -m, --meta"},
     {"delete-parameter",1, 0, 'd', "Delete the named parameter for a resource. See also -m, --meta"},
     {"get-property",    1, 0, 'G', "Display the 'class', 'type' or 'provider' of a resource", 1},
     {"set-property",    1, 0, 'S', "(Advanced) Set the class, type or provider of a resource", 1},
 
     {"-spacer-",	1, 0, '-', "\nResource location:"},
     {
         "move",    0, 0, 'M',
         "\t\tMove a resource from its current location to the named destination.\n  "
         "\t\t\t\tRequires: --host. Optional: --lifetime, --master\n\n"
         "\t\t\t\tNOTE: This may prevent the resource from running on the previous location node until the implicit constraints expire or are removed with --unban\n"
     },
     {
         "ban",    0, 0, 'B',
         "\t\tPrevent the named resource from running on the named --host.  \n"
         "\t\t\t\tRequires: --resource. Optional: --host, --lifetime, --master\n\n"
         "\t\t\t\tIf --host is not specified, it defaults to:\n"
         "\t\t\t\t * the curent location for primitives and groups, or\n\n"
         "\t\t\t\t * the curent location of the master for m/s resources with master-max=1\n\n"
         "\t\t\t\tAll other situations result in an error as there is no sane default.\n\n"
         "\t\t\t\tNOTE: This will prevent the resource from running on this node until the constraint expires or is removed with --clear\n"
     },
     {
         "clear", 0, 0, 'U', "\t\tRemove all constraints created by the --ban and/or --move commands.  \n"
         "\t\t\t\tRequires: --resource. Optional: --host, --master\n\n"
         "\t\t\t\tIf --host is not specified, all constraints created by --ban and --move will be removed for the named resource.\n"
     },
     {"lifetime",   1, 0, 'u', "\tLifespan of constraints created by the --ban and --move commands"},
     {
         "master",  0, 0,  0,
         "\t\tLimit the scope of the --ban, --move and --clear  commands to the Master role.\n"
         "\t\t\t\tFor --ban and --move, the previous master can still remain active in the Slave role."
     },
 
     {"-spacer-",   1, 0, '-', "\nAdvanced Commands:"},
     {"delete",     0, 0, 'D', "\t\t(Advanced) Delete a resource from the CIB"},
     {"fail",       0, 0, 'F', "\t\t(Advanced) Tell the cluster this resource has failed"},
     {"force-stop", 0, 0,  0,  "\t(Advanced) Bypass the cluster and stop a resource on the local node. Additional detail with -V"},
     {"force-start",0, 0,  0,  "\t(Advanced) Bypass the cluster and start a resource on the local node. Additional detail with -V"},
     {"force-check",0, 0,  0,  "\t(Advanced) Bypass the cluster and check the state of a resource on the local node. Additional detail with -V\n"},
 
     {"-spacer-",	1, 0, '-', "\nAdditional Options:"},
     {"node",		1, 0, 'N', "\tHost uname"},
     {"recursive",       0, 0,  0,  "\tFollow colocation chains when using --set-parameter"},
     {"resource-type",	1, 0, 't', "Resource type (primitive, clone, group, ...)"},
     {"parameter-value", 1, 0, 'v', "Value to use with -p, -g or -d"},
     {"meta",		0, 0, 'm', "\t\tModify a resource's configuration option rather than one which is passed to the resource agent script. For use with -p, -g, -d"},
     {"utilization",	0, 0, 'z', "\tModify a resource's utilization attribute. For use with -p, -g, -d"},
     {"set-name",        1, 0, 's', "\t(Advanced) ID of the instance_attributes object to change"},
     {"nvpair",          1, 0, 'i', "\t(Advanced) ID of the nvpair object to change/delete"},
     {"force",		0, 0, 'f', "\n" /* Is this actually true anymore?
 					   "\t\tForce the resource to move by creating a rule for the current location and a score of -INFINITY"
 					   "\n\t\tThis should be used if the resource's stickiness and constraint scores total more than INFINITY (Currently 100,000)"
 					   "\n\t\tNOTE: This will prevent the resource from running on this node until the constraint is removed with -U or the --lifetime duration expires\n"*/ },
 
     {"xml-file", 1, 0, 'x', NULL, 1},\
 
     /* legacy options */
     {"host-uname", 1, 0, 'H', NULL, 1},
     {"migrate",    0, 0, 'M', NULL, 1},
     {"un-migrate", 0, 0, 'U', NULL, 1},
     {"un-move",    0, 0, 'U', NULL, 1},
 
     {"refresh",    0, 0, 'R', NULL, 1},
     {"reprobe",    0, 0, 'P', NULL, 1},
 
     {"-spacer-",	1, 0, '-', "\nExamples:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', "List the configured resources:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --list", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "List the available OCF agents:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --list-agents ocf", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "List the available OCF agents from the linux-ha project:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --list-agents ocf:heartbeat", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Display the current location of 'myResource':", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --locate", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Move 'myResource' to another machine:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --move", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Move 'myResource' to a specific machine:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --move --node altNode", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Allow (but not force) 'myResource' to move back to its original location:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --un-move", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Tell the cluster that 'myResource' failed:", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --fail", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Stop a 'myResource' (and anything that depends on it):", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --set-parameter target-role --meta --parameter-value Stopped", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Tell the cluster not to manage 'myResource':", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', "The cluster will not attempt to start or stop the resource under any circumstances."},
     {"-spacer-",	1, 0, '-', "Useful when performing maintenance tasks on a resource.", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --set-parameter is-managed --meta --parameter-value false", pcmk_option_example},
     {"-spacer-",	1, 0, '-', "Erase the operation history of 'myResource' on 'aNode':", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', "The cluster will 'forget' the existing resource state (including any errors) and attempt to recover the resource."},
     {"-spacer-",	1, 0, '-', "Useful when a resource had failed permanently and has been repaired by an administrator.", pcmk_option_paragraph},
     {"-spacer-",	1, 0, '-', " crm_resource --resource myResource --cleanup --node aNode", pcmk_option_example},
 
     {0, 0, 0, 0}
 };
 /* *INDENT-ON* */
 
 int
 main(int argc, char **argv)
 {
     const char *longname = NULL;
     pe_working_set_t data_set;
     xmlNode *cib_xml_copy = NULL;
     cib_t *cib_conn = NULL;
     bool do_trace = FALSE;
     bool recursive = FALSE;
 
     int rc = pcmk_ok;
     int option_index = 0;
     int argerr = 0;
     int flag;
 
     crm_log_cli_init("crm_resource");
     crm_set_options(NULL, "(query|command) [options]", long_options,
                     "Perform tasks related to cluster resources.\nAllows resources to be queried (definition and location), modified, and moved around the cluster.\n");
 
     if (argc < 2) {
         crm_help('?', EX_USAGE);
     }
 
     while (1) {
         flag = crm_get_option_long(argc, argv, &option_index, &longname);
         if (flag == -1)
             break;
 
         switch (flag) {
             case 0:
                 if (safe_str_eq("master", longname)) {
                     scope_master = TRUE;
 
                 } else if(safe_str_eq(longname, "recursive")) {
                     recursive = TRUE;
 
                 } else if (safe_str_eq("force-stop", longname)
                     || safe_str_eq("force-start", longname)
                     || safe_str_eq("force-check", longname)) {
                     rsc_cmd = flag;
                     rsc_long_cmd = longname;
 
                 } else if (safe_str_eq("list-ocf-providers", longname)
                            || safe_str_eq("list-ocf-alternatives", longname)
                            || safe_str_eq("list-standards", longname)) {
                     const char *text = NULL;
                     lrmd_list_t *list = NULL;
                     lrmd_list_t *iter = NULL;
                     lrmd_t *lrmd_conn = lrmd_api_new();
 
                     if (safe_str_eq("list-ocf-providers", longname)
                         || safe_str_eq("list-ocf-alternatives", longname)) {
                         rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, optarg, &list);
                         text = "OCF providers";
 
                     } else if (safe_str_eq("list-standards", longname)) {
                         rc = lrmd_conn->cmds->list_standards(lrmd_conn, &list);
                         text = "standards";
                     }
 
                     if (rc > 0) {
                         rc = 0;
                         for (iter = list; iter != NULL; iter = iter->next) {
                             rc++;
                             printf("%s\n", iter->val);
                         }
                         lrmd_list_freeall(list);
 
                     } else if (optarg) {
                         fprintf(stderr, "No %s found for %s\n", text, optarg);
                     } else {
                         fprintf(stderr, "No %s found\n", text);
                     }
 
                     lrmd_api_delete(lrmd_conn);
                     return crm_exit(rc);
 
                 } else if (safe_str_eq("show-metadata", longname)) {
                     char standard[512];
                     char provider[512];
                     char type[512];
                     char *metadata = NULL;
                     lrmd_t *lrmd_conn = lrmd_api_new();
 
                     rc = sscanf(optarg, "%[^:]:%[^:]:%s", standard, provider, type);
                     if (rc == 3) {
                         rc = lrmd_conn->cmds->get_metadata(lrmd_conn, standard, provider, type,
                                                            &metadata, 0);
 
                     } else if (rc == 2) {
                         rc = lrmd_conn->cmds->get_metadata(lrmd_conn, standard, NULL, provider,
                                                            &metadata, 0);
 
                     } else if (rc < 2) {
                         fprintf(stderr,
                                 "Please specify standard:type or standard:provider:type, not %s\n",
                                 optarg);
                         rc = -EINVAL;
                     }
 
                     if (metadata) {
                         printf("%s\n", metadata);
                     } else {
                         fprintf(stderr, "Metadata query for %s failed: %d\n", optarg, rc);
                     }
                     lrmd_api_delete(lrmd_conn);
                     return crm_exit(rc);
 
                 } else if (safe_str_eq("list-agents", longname)) {
                     lrmd_list_t *list = NULL;
                     lrmd_list_t *iter = NULL;
                     char standard[512];
                     char provider[512];
                     lrmd_t *lrmd_conn = lrmd_api_new();
 
                     rc = sscanf(optarg, "%[^:]:%s", standard, provider);
                     if (rc == 1) {
                         rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, optarg, NULL);
                         provider[0] = '*';
                         provider[1] = 0;
 
                     } else if (rc == 2) {
                         rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, standard, provider);
                     }
 
                     if (rc > 0) {
                         rc = 0;
                         for (iter = list; iter != NULL; iter = iter->next) {
                             printf("%s\n", iter->val);
                             rc++;
                         }
                         lrmd_list_freeall(list);
                         rc = 0;
                     } else {
                         fprintf(stderr, "No agents found for standard=%s, provider=%s\n", standard,
                                 provider);
                         rc = -1;
                     }
                     lrmd_api_delete(lrmd_conn);
                     return crm_exit(rc);
 
                 } else {
                     crm_err("Unhandled long option: %s", longname);
                 }
                 break;
             case 'V':
                 do_trace = TRUE;
                 crm_bump_log_level(argc, argv);
                 break;
             case '$':
             case '?':
                 crm_help(flag, EX_OK);
                 break;
             case 'x':
                 xml_file = strdup(optarg);
                 break;
             case 'Q':
                 BE_QUIET = TRUE;
                 break;
             case 'm':
                 attr_set_type = XML_TAG_META_SETS;
                 break;
             case 'z':
                 attr_set_type = XML_TAG_UTILIZATION;
                 break;
             case 'u':
                 move_lifetime = strdup(optarg);
                 break;
             case 'f':
                 do_force = TRUE;
                 break;
             case 'i':
                 prop_id = optarg;
                 break;
             case 's':
                 prop_set = optarg;
                 break;
             case 'r':
                 rsc_id = optarg;
                 break;
             case 'v':
                 prop_value = optarg;
                 break;
             case 't':
                 rsc_type = optarg;
                 break;
             case 'C':
             case 'R':
             case 'P':
                 rsc_cmd = 'C';
                 break;
             case 'L':
             case 'c':
             case 'l':
             case 'q':
             case 'w':
             case 'D':
             case 'F':
             case 'W':
             case 'M':
             case 'U':
             case 'B':
             case 'O':
             case 'o':
             case 'A':
             case 'a':
                 rsc_cmd = flag;
                 break;
             case 'p':
             case 'g':
             case 'd':
             case 'S':
             case 'G':
                 prop_name = optarg;
                 rsc_cmd = flag;
                 break;
             case 'h':
             case 'H':
             case 'N':
                 crm_trace("Option %c => %s", flag, optarg);
                 host_uname = optarg;
                 break;
 
             default:
                 CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
                 ++argerr;
                 break;
         }
     }
 
     if (optind < argc && argv[optind] != NULL) {
         CMD_ERR("non-option ARGV-elements: ");
         while (optind < argc && argv[optind] != NULL) {
             CMD_ERR("%s ", argv[optind++]);
             ++argerr;
         }
         CMD_ERR("\n");
     }
 
     if (optind > argc) {
         ++argerr;
     }
 
     if (argerr) {
         crm_help('?', EX_USAGE);
     }
 
     our_pid = calloc(1, 11);
     if (our_pid != NULL) {
         snprintf(our_pid, 10, "%d", getpid());
         our_pid[10] = '\0';
     }
 
     if (do_force) {
         crm_debug("Forcing...");
         cib_options |= cib_quorum_override;
     }
 
     set_working_set_defaults(&data_set);
     if (rsc_cmd != 'P' || rsc_id) {
         resource_t *rsc = NULL;
 
         cib_conn = cib_new();
         rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
         if (rc != pcmk_ok) {
             CMD_ERR("Error signing on to the CIB service: %s\n", pcmk_strerror(rc));
             return crm_exit(rc);
         }
 
         if (xml_file != NULL) {
             cib_xml_copy = filename2xml(xml_file);
 
         } else {
             cib_xml_copy = get_cib_copy(cib_conn);
         }
 
         if (cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) {
             rc = -ENOKEY;
             goto bail;
         }
 
         data_set.input = cib_xml_copy;
         data_set.now = crm_time_new(NULL);
 
         cluster_status(&data_set);
         if (rsc_id) {
             rsc = find_rsc_or_clone(rsc_id, &data_set);
         }
         if (rsc == NULL && rsc_cmd != 'C') {
             rc = -ENXIO;
         }
     }
 
     if (rsc_cmd == 'R' || rsc_cmd == 'C' || rsc_cmd == 'F' || rsc_cmd == 'P') {
         xmlNode *xml = NULL;
         mainloop_io_t *source =
-            mainloop_add_ipc_client(CRM_SYSTEM_CRMD, G_PRIORITY_DEFAULT, 0, NULL, &crm_callbacks);
+            mainloop_add_ipc_client(CRM_SYSTEM_CRMD, G_PRIORITY_DEFAULT, NULL, &crm_callbacks);
         crmd_channel = mainloop_get_ipc_client(source);
 
         if (crmd_channel == NULL) {
             CMD_ERR("Error signing on to the CRMd service\n");
             rc = -ENOTCONN;
             goto bail;
         }
 
         xml = create_hello_message(our_pid, crm_system_name, "0", "1");
         crm_ipc_send(crmd_channel, xml, 0, 0, NULL);
         free_xml(xml);
     }
 
     if (rsc_cmd == 'L') {
         rc = pcmk_ok;
         do_find_resource_list(&data_set, FALSE);
 
     } else if (rsc_cmd == 'l') {
         int found = 0;
         GListPtr lpc = NULL;
 
         rc = pcmk_ok;
         for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
             resource_t *rsc = (resource_t *) lpc->data;
 
             found++;
             print_raw_rsc(rsc);
         }
 
         if (found == 0) {
             printf("NO resources configured\n");
             rc = -ENXIO;
             goto bail;
         }
 
     } else if (rsc_cmd == 0 && rsc_long_cmd) {
         svc_action_t *op = NULL;
         const char *rtype = NULL;
         const char *rprov = NULL;
         const char *rclass = NULL;
         const char *action = NULL;
         GHashTable *params = NULL;
         resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
 
         if (rsc == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
 
         if (safe_str_eq(rsc_long_cmd, "force-stop")) {
             action = "stop";
         } else if (safe_str_eq(rsc_long_cmd, "force-start")) {
             action = "start";
             if(rsc->variant >= pe_clone) {
                 rc = do_find_resource(rsc_id, NULL, &data_set);
                 if(rc > 0 && do_force == FALSE) {
                     CMD_ERR("It is not safe to start %s here: the cluster claims it is already active", rsc_id);
                     CMD_ERR("Try setting target-role=stopped first or specifying --force");
                     crm_exit(EPERM);
                 }
             }
 
         } else if (safe_str_eq(rsc_long_cmd, "force-check")) {
             action = "monitor";
         }
 
         rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
         rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
         rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
 
         if(safe_str_eq(rclass, "stonith")){
             CMD_ERR("Sorry, --%s doesn't support %s resources yet\n", rsc_long_cmd, rclass);
             crm_exit(EOPNOTSUPP);
         }
 
         params = generate_resource_params(rsc, &data_set);
         op = resources_action_create(rsc->id, rclass, rprov, rtype, action, 0, -1, params);
 
         if(do_trace) {
             setenv("OCF_TRACE_RA", "1", 1);
         }
 
         if(op == NULL) {
             /* Re-run but with stderr enabled so we can display a sane error message */
             crm_enable_stderr(TRUE);
             resources_action_create(rsc->id, rclass, rprov, rtype, action, 0, -1, params);
             return crm_exit(EINVAL);
 
         } else if (services_action_sync(op)) {
             int more, lpc, last;
             char *local_copy = NULL;
 
             if (op->status == PCMK_LRM_OP_DONE) {
                 printf("Operation %s for %s (%s:%s:%s) returned %d\n",
                        action, rsc->id, rclass, rprov ? rprov : "", rtype, op->rc);
             } else {
                 printf("Operation %s for %s (%s:%s:%s) failed: %d\n",
                        action, rsc->id, rclass, rprov ? rprov : "", rtype, op->status);
             }
 
             if (op->stdout_data) {
                 local_copy = strdup(op->stdout_data);
                 more = strlen(local_copy);
                 last = 0;
 
                 for (lpc = 0; lpc < more; lpc++) {
                     if (local_copy[lpc] == '\n' || local_copy[lpc] == 0) {
                         local_copy[lpc] = 0;
                         printf(" >  stdout: %s\n", local_copy + last);
                         last = lpc + 1;
                     }
                 }
                 free(local_copy);
             }
             if (op->stderr_data) {
                 local_copy = strdup(op->stderr_data);
                 more = strlen(local_copy);
                 last = 0;
 
                 for (lpc = 0; lpc < more; lpc++) {
                     if (local_copy[lpc] == '\n' || local_copy[lpc] == 0) {
                         local_copy[lpc] = 0;
                         printf(" >  stderr: %s\n", local_copy + last);
                         last = lpc + 1;
                     }
                 }
                 free(local_copy);
             }
         }
         rc = op->rc;
         services_action_free(op);
         return crm_exit(rc);
 
     } else if (rsc_cmd == 'A' || rsc_cmd == 'a') {
         GListPtr lpc = NULL;
         resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
         xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set.input);
 
         if (rsc == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
 
         unpack_constraints(cib_constraints, &data_set);
 
         for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
             resource_t *r = (resource_t *) lpc->data;
 
             clear_bit(r->flags, pe_rsc_allocating);
         }
 
         show_colocation(rsc, TRUE, rsc_cmd == 'A', 1);
 
         fprintf(stdout, "* %s\n", rsc->id);
         show_location(rsc, NULL);
 
         for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
             resource_t *r = (resource_t *) lpc->data;
 
             clear_bit(r->flags, pe_rsc_allocating);
         }
 
         show_colocation(rsc, FALSE, rsc_cmd == 'A', 1);
 
     } else if (rsc_cmd == 'c') {
         int found = 0;
         GListPtr lpc = NULL;
 
         rc = pcmk_ok;
         for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
             resource_t *rsc = (resource_t *) lpc->data;
 
             print_cts_rsc(rsc);
             found++;
         }
         print_cts_constraints(&data_set);
 
     } else if (rsc_cmd == 'F') {
         rc = fail_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set);
         if (rc == pcmk_ok) {
             start_mainloop();
         }
 
     } else if (rsc_cmd == 'O') {
         rc = list_resource_operations(rsc_id, host_uname, TRUE, &data_set);
 
     } else if (rsc_cmd == 'o') {
         rc = list_resource_operations(rsc_id, host_uname, FALSE, &data_set);
 
     } else if (rc == -ENXIO) {
         CMD_ERR("Resource '%s' not found: %s\n", crm_str(rsc_id), pcmk_strerror(rc));
 
     } else if (rsc_cmd == 'W') {
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         rc = do_find_resource(rsc_id, NULL, &data_set);
 
     } else if (rsc_cmd == 'q') {
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         rc = dump_resource(rsc_id, &data_set, TRUE);
 
     } else if (rsc_cmd == 'w') {
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         rc = dump_resource(rsc_id, &data_set, FALSE);
 
     } else if (rsc_cmd == 'U') {
         node_t *dest = NULL;
 
         if (rsc_id == NULL) {
             CMD_ERR("No value specified for --resource\n");
             rc = -ENXIO;
             goto bail;
         }
 
         if (host_uname) {
             dest = pe_find_node(data_set.nodes, host_uname);
             if (dest == NULL) {
                 CMD_ERR("Unknown node: %s\n", host_uname);
                 rc = -ENXIO;
                 goto bail;
             }
             rc = clear_resource(rsc_id, dest->details->uname, NULL, cib_conn);
 
         } else {
             rc = clear_resource(rsc_id, NULL, data_set.nodes, cib_conn);
         }
 
     } else if (rsc_cmd == 'M' && host_uname) {
         resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
         node_t *dest = pe_find_node(data_set.nodes, host_uname);
 
         rc = -EINVAL;
 
         if (rsc == NULL) {
             CMD_ERR("Resource '%s' not moved: not found\n", rsc_id);
             rc = -ENXIO;
             goto bail;
 
         } else if(rsc->variant == pe_clone) {
             CMD_ERR("Resource '%s' not moved: moving a clone makes no sense\n", rsc_id);
             goto bail;
 
         } else if (rsc->variant < pe_clone && g_list_length(rsc->running_on) > 1) {
             CMD_ERR("Resource '%s' not moved: active on multiple nodes\n", rsc_id);
             goto bail;
 
         } else if (rsc->variant < pe_clone && scope_master) {
             resource_t *p = uber_parent(rsc);
             if(p->variant == pe_master) {
                 CMD_ERR("Resource '%s' not moved: The --master option is not a valid for %s resources."
                         "  Did you mean '%s'?\n", rsc_id, get_resource_typename(rsc->variant), p->id);
             } else {
                 CMD_ERR("Resource '%s' not moved: The --master option is not a valid for %s resources.\n",
                         rsc_id, get_resource_typename(rsc->variant));
             }
             goto bail;
         }
 
         if(dest == NULL) {
             CMD_ERR("Error performing operation: node '%s' is unknown\n", host_uname);
             rc = -ENXIO;
             goto bail;
         }
 
         if(g_list_length(rsc->running_on) == 1) {
             node_t *current = rsc->running_on->data;
 
             if (safe_str_eq(current->details->uname, dest->details->uname)) {
                 CMD_ERR("Error performing operation: %s is already active on %s\n", rsc_id, dest->details->uname);
                 goto bail;
             }
             /* } else if (rsc->variant == pe_master) { Find the master and ban it */
         }
 
         /* Clear any previous constraints for 'dest' */
         clear_resource(rsc_id, dest->details->uname, data_set.nodes, cib_conn);
 
         /* Record an explicit preference for 'dest' */
         rc = prefer_resource(rsc_id, dest->details->uname, cib_conn);
 
         if(do_force && g_list_length(rsc->running_on) == 1) {
             node_t *current = rsc->running_on->data;
 
             /* Ban the original location */
             ban_resource(rsc_id, current->details->uname, NULL, cib_conn);
         }
 
     } else if (rsc_cmd == 'B' && host_uname) {
         resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
         node_t *dest = pe_find_node(data_set.nodes, host_uname);
 
         rc = -ENXIO;
         if (rsc_id == NULL) {
             CMD_ERR("No value specified for --resource\n");
             goto bail;
         } else if(rsc == NULL) {
             CMD_ERR("Resource '%s' not moved: unknown\n", rsc_id);
 
         } else if (dest == NULL) {
             CMD_ERR("Error performing operation: node '%s' is unknown\n", host_uname);
             goto bail;
         }
         rc = ban_resource(rsc_id, dest->details->uname, NULL, cib_conn);
 
     } else if (rsc_cmd == 'B' || rsc_cmd == 'M') {
         resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
 
         rc = -ENXIO;
         if (rsc_id == NULL) {
             CMD_ERR("No value specified for --resource\n");
             goto bail;
         }
 
         rc = -EINVAL;
         if(rsc == NULL) {
             CMD_ERR("Resource '%s' not moved: unknown\n", rsc_id);
 
         } else if(g_list_length(rsc->running_on) == 1) {
             node_t *current = rsc->running_on->data;
             rc = ban_resource(rsc_id, current->details->uname, NULL, cib_conn);
 
         } else if(rsc->variant == pe_master) {
             int count = 0;
             GListPtr iter = NULL;
             node_t *current = NULL;
 
             for(iter = rsc->children; iter; iter = iter->next) {
                 resource_t *child = (resource_t *)iter->data;
                 if(child->role == RSC_ROLE_MASTER) {
                     count++;
                     current = child->running_on->data;
                 }
             }
 
             if(count == 1 && current) {
                 rc = ban_resource(rsc_id, current->details->uname, NULL, cib_conn);
 
             } else {
                 CMD_ERR("Resource '%s' not moved: currently promoted in %d locations.\n", rsc_id, count);
                 CMD_ERR("You can prevent '%s' from being promoted at a specific location with:"
                         " --ban --master --host <name>\n", rsc_id);
             }
 
         } else {
             CMD_ERR("Resource '%s' not moved: active in %d locations.\n", rsc_id, g_list_length(rsc->running_on));
             CMD_ERR("You can prevent '%s' from running on a specific location with: --ban --host <name>\n", rsc_id);
 
             if(rsc->variant == pe_master && g_list_length(rsc->running_on) > 0) {
                 CMD_ERR("You can prevent '%s' from being promoted at its current location with: --ban --master\n", rsc_id);
                 CMD_ERR("You can prevent '%s' from being promoted at a specific location with:"
                         " --ban --master --host <name>\n", rsc_id);
             }
         }
 
     } else if (rsc_cmd == 'G') {
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         rc = dump_resource_prop(rsc_id, prop_name, &data_set);
 
     } else if (rsc_cmd == 'S') {
         xmlNode *msg_data = NULL;
 
         if (prop_value == NULL || strlen(prop_value) == 0) {
             CMD_ERR("You need to supply a value with the -v option\n");
             rc = -EINVAL;
             goto bail;
 
         } else if (cib_conn == NULL) {
             rc = -ENOTCONN;
             goto bail;
         }
 
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         CRM_LOG_ASSERT(rsc_type != NULL);
         CRM_LOG_ASSERT(prop_name != NULL);
         CRM_LOG_ASSERT(prop_value != NULL);
 
         msg_data = create_xml_node(NULL, rsc_type);
         crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
         crm_xml_add(msg_data, prop_name, prop_value);
 
         rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options);
         free_xml(msg_data);
 
     } else if (rsc_cmd == 'g') {
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         rc = dump_resource_attr(rsc_id, prop_name, &data_set);
 
     } else if (rsc_cmd == 'p') {
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         if (prop_value == NULL || strlen(prop_value) == 0) {
             CMD_ERR("You need to supply a value with the -v option\n");
             rc = -EINVAL;
             goto bail;
         }
 
         /* coverity[var_deref_model] False positive */
         rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name,
                                prop_value, recursive, cib_conn, &data_set);
 
     } else if (rsc_cmd == 'd') {
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
         }
         /* coverity[var_deref_model] False positive */
         rc = delete_resource_attr(rsc_id, prop_set, prop_id, prop_name, cib_conn, &data_set);
 
     } else if (rsc_cmd == 'C' && rsc_id) {
         resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
 
         crm_debug("Re-checking the state of %s on %s", rsc_id, host_uname);
         if(rsc) {
             rc = delete_lrm_rsc(cib_conn, crmd_channel, host_uname, rsc, &data_set);
         } else {
             rc = -ENODEV;
         }
 
         if (rc == pcmk_ok) {
             start_mainloop();
         }
 
     } else if (rsc_cmd == 'C') {
         xmlNode *cmd = create_request(CRM_OP_REPROBE, NULL, host_uname,
                                       CRM_SYSTEM_CRMD, crm_system_name, our_pid);
 
         crm_debug("Re-checking the state of all resources on %s", host_uname);
         if (crm_ipc_send(crmd_channel, cmd, 0, 0, NULL) > 0) {
             crmd_replies_needed++;
             start_mainloop();
         }
 
         free_xml(cmd);
 
     } else if (rsc_cmd == 'D') {
         xmlNode *msg_data = NULL;
 
         if (rsc_id == NULL) {
             CMD_ERR("Must supply a resource id with -r\n");
             rc = -ENXIO;
             goto bail;
 
         }
         if (rsc_type == NULL) {
             CMD_ERR("You need to specify a resource type with -t");
             rc = -ENXIO;
             goto bail;
 
         } else if (cib_conn == NULL) {
             rc = -ENOTCONN;
             goto bail;
         }
 
         msg_data = create_xml_node(NULL, rsc_type);
         crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
 
         rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options);
         free_xml(msg_data);
 
     } else {
         CMD_ERR("Unknown command: %c\n", rsc_cmd);
     }
 
   bail:
 
     if (cib_conn != NULL) {
         cleanup_alloc_calculations(&data_set);
         cib_conn->cmds->signoff(cib_conn);
         cib_delete(cib_conn);
     }
 
     if (rc == -pcmk_err_no_quorum) {
         CMD_ERR("Error performing operation: %s\n", pcmk_strerror(rc));
         CMD_ERR("Try using -f\n");
 
     } else if (rc != pcmk_ok) {
         CMD_ERR("Error performing operation: %s\n", pcmk_strerror(rc));
     }
 
     return crm_exit(rc);
 }
diff --git a/tools/crmadmin.c b/tools/crmadmin.c
index c7ac30f65d..1ed43a6a03 100644
--- a/tools/crmadmin.c
+++ b/tools/crmadmin.c
@@ -1,584 +1,584 @@
 
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 
 #include <crm/common/mainloop.h>
 
 #include <crm/cib.h>
 
 int message_timer_id = -1;
 int message_timeout_ms = 30 * 1000;
 
 GMainLoop *mainloop = NULL;
 crm_ipc_t *crmd_channel = NULL;
 char *admin_uuid = NULL;
 
 void usage(const char *cmd, int exit_status);
 gboolean do_init(void);
 int do_work(void);
 void crmadmin_ipc_connection_destroy(gpointer user_data);
 
 int admin_msg_callback(const char *buffer, ssize_t length, gpointer userdata);
 char *pluralSection(const char *a_section);
 xmlNode *handleCibMod(void);
 int do_find_node_list(xmlNode * xml_node);
 gboolean admin_message_timeout(gpointer data);
 gboolean is_node_online(xmlNode * node_state);
 
 enum debug {
     debug_none,
     debug_dec,
     debug_inc
 };
 
 gboolean BE_VERBOSE = FALSE;
 int expected_responses = 1;
 
 gboolean BASH_EXPORT = FALSE;
 gboolean DO_HEALTH = FALSE;
 gboolean DO_RESET = FALSE;
 gboolean DO_RESOURCE = FALSE;
 gboolean DO_ELECT_DC = FALSE;
 gboolean DO_WHOIS_DC = FALSE;
 gboolean DO_NODE_LIST = FALSE;
 gboolean BE_SILENT = FALSE;
 gboolean DO_RESOURCE_LIST = FALSE;
 enum debug DO_DEBUG = debug_none;
 const char *crmd_operation = NULL;
 
 xmlNode *msg_options = NULL;
 
 const char *standby_on_off = "on";
 const char *admin_verbose = XML_BOOLEAN_FALSE;
 char *id = NULL;
 char *disconnect = NULL;
 char *dest_node = NULL;
 char *rsc_name = NULL;
 char *crm_option = NULL;
 
 int operation_status = 0;
 const char *sys_to = NULL;
 
 /* *INDENT-OFF* */
 static struct crm_option long_options[] = {
     /* Top-level Options */
     {"help",    0, 0, '?', "\tThis text"},
     {"version", 0, 0, '$', "\tVersion information"  },
     {"quiet",   0, 0, 'q', "\tDisplay only the essential query information"},
     {"verbose", 0, 0, 'V', "\tIncrease debug output"},
     
     {"-spacer-",	1, 0, '-', "\nCommands:"},
     /* daemon options */
     {"debug_inc", 1, 0, 'i', "Increase the crmd's debug level on the specified host"},
     {"debug_dec", 1, 0, 'd', "Decrease the crmd's debug level on the specified host"},
     {"status",    1, 0, 'S', "Display the status of the specified node." },
     {"-spacer-",  1, 0, '-', "\n\tResult is the node's internal FSM state which can be useful for debugging\n"},
     {"dc_lookup", 0, 0, 'D', "Display the uname of the node co-ordinating the cluster."},
     {"-spacer-",  1, 0, '-', "\n\tThis is an internal detail and is rarely useful to administrators except when deciding on which node to examine the logs.\n"},
     {"nodes",     0, 0, 'N', "\tDisplay the uname of all member nodes"},
     {"election",  0, 0, 'E', "(Advanced) Start an election for the cluster co-ordinator"},
     {"kill",      1, 0, 'K', "(Advanced) Shut down the crmd (not the rest of the clusterstack ) on the specified node"},
     {"health",    0, 0, 'H', NULL, 1},
     
     {"-spacer-",	1, 0, '-', "\nAdditional Options:"},
     {XML_ATTR_TIMEOUT, 1, 0, 't', "Time (in milliseconds) to wait before declaring the operation failed"},
     {"bash-export", 0, 0, 'B', "Create Bash export entries of the form 'export uname=uuid'\n"},
 
     {"-spacer-",  1, 0, '-', "Notes:"},
     {"-spacer-",  1, 0, '-', " The -i,-d,-K and -E commands are rarely used and may be removed in future versions."},
 
     {0, 0, 0, 0}
 };
 /* *INDENT-ON* */
 
 int
 main(int argc, char **argv)
 {
     int option_index = 0;
     int argerr = 0;
     int flag;
 
     crm_log_cli_init("crmadmin");
     crm_set_options(NULL, "command [options]", long_options,
                     "Development tool for performing some crmd-specific commands."
                     "\n  Likely to be replaced by crm_node in the future");
     if (argc < 2) {
         crm_help('?', EX_USAGE);
     }
 
     while (1) {
         flag = crm_get_option(argc, argv, &option_index);
         if (flag == -1)
             break;
 
         switch (flag) {
             case 'V':
                 BE_VERBOSE = TRUE;
                 admin_verbose = XML_BOOLEAN_TRUE;
                 crm_bump_log_level(argc, argv);
                 break;
             case 't':
                 message_timeout_ms = atoi(optarg);
                 if (message_timeout_ms < 1) {
                     message_timeout_ms = 30 * 1000;
                 }
                 break;
 
             case '$':
             case '?':
                 crm_help(flag, EX_OK);
                 break;
             case 'D':
                 DO_WHOIS_DC = TRUE;
                 break;
             case 'B':
                 BASH_EXPORT = TRUE;
                 break;
             case 'K':
                 DO_RESET = TRUE;
                 crm_trace("Option %c => %s", flag, optarg);
                 dest_node = strdup(optarg);
                 crmd_operation = CRM_OP_LOCAL_SHUTDOWN;
                 break;
             case 'q':
                 BE_SILENT = TRUE;
                 break;
             case 'i':
                 DO_DEBUG = debug_inc;
                 crm_trace("Option %c => %s", flag, optarg);
                 dest_node = strdup(optarg);
                 break;
             case 'd':
                 DO_DEBUG = debug_dec;
                 crm_trace("Option %c => %s", flag, optarg);
                 dest_node = strdup(optarg);
                 break;
             case 'S':
                 DO_HEALTH = TRUE;
                 crm_trace("Option %c => %s", flag, optarg);
                 dest_node = strdup(optarg);
                 break;
             case 'E':
                 DO_ELECT_DC = TRUE;
                 break;
             case 'N':
                 DO_NODE_LIST = TRUE;
                 break;
             case 'H':
                 DO_HEALTH = TRUE;
                 break;
             default:
                 printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
                 ++argerr;
                 break;
         }
     }
 
     if (optind < argc) {
         printf("non-option ARGV-elements: ");
         while (optind < argc)
             printf("%s ", argv[optind++]);
         printf("\n");
     }
 
     if (optind > argc) {
         ++argerr;
     }
 
     if (argerr) {
         crm_help('?', EX_USAGE);
     }
 
     if (do_init()) {
         int res = 0;
 
         res = do_work();
         if (res > 0) {
             /* wait for the reply by creating a mainloop and running it until
              * the callbacks are invoked...
              */
             mainloop = g_main_new(FALSE);
             crm_trace("Waiting for %d replies from the local CRM", expected_responses);
 
             message_timer_id = g_timeout_add(message_timeout_ms, admin_message_timeout, NULL);
 
             g_main_run(mainloop);
 
         } else if (res < 0) {
             crm_err("No message to send");
             operation_status = -1;
         }
     } else {
         crm_warn("Init failed, could not perform requested operations");
         operation_status = -2;
     }
 
     crm_trace("%s exiting normally", crm_system_name);
     return operation_status;
 }
 
 int
 do_work(void)
 {
     int ret = 1;
 
     /* construct the request */
     xmlNode *msg_data = NULL;
     gboolean all_is_good = TRUE;
 
     msg_options = create_xml_node(NULL, XML_TAG_OPTIONS);
     crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose);
     crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 
     if (DO_HEALTH == TRUE) {
         crm_trace("Querying the system");
 
         sys_to = CRM_SYSTEM_DC;
 
         if (dest_node != NULL) {
             sys_to = CRM_SYSTEM_CRMD;
             crmd_operation = CRM_OP_PING;
 
             if (BE_VERBOSE) {
                 expected_responses = 1;
             }
 
             crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 
         } else {
             crm_info("Cluster-wide health not available yet");
             all_is_good = FALSE;
         }
 
     } else if (DO_ELECT_DC) {
         /* tell the local node to initiate an election */
 
         dest_node = NULL;
         sys_to = CRM_SYSTEM_CRMD;
         crmd_operation = CRM_OP_VOTE;
 
         crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
         ret = 0;                /* no return message */
 
     } else if (DO_WHOIS_DC) {
         dest_node = NULL;
         sys_to = CRM_SYSTEM_DC;
         crmd_operation = CRM_OP_PING;
         crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 
     } else if (DO_NODE_LIST) {
 
         cib_t *the_cib = cib_new();
         xmlNode *output = NULL;
 
         int rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
 
         if (rc != pcmk_ok) {
             return -1;
         }
 
         output = get_cib_copy(the_cib);
         do_find_node_list(output);
 
         free_xml(output);
         the_cib->cmds->signoff(the_cib);
         crm_exit(rc);
 
     } else if (DO_RESET) {
         /* tell dest_node to initiate the shutdown proceedure
          *
          * if dest_node is NULL, the request will be sent to the
          *   local node
          */
         sys_to = CRM_SYSTEM_CRMD;
         crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 
         ret = 0;                /* no return message */
 
     } else if (DO_DEBUG == debug_inc) {
         /* tell dest_node to increase its debug level
          *
          * if dest_node is NULL, the request will be sent to the
          *   local node
          */
         sys_to = CRM_SYSTEM_CRMD;
         crmd_operation = CRM_OP_DEBUG_UP;
 
         ret = 0;                /* no return message */
 
     } else if (DO_DEBUG == debug_dec) {
         /* tell dest_node to increase its debug level
          *
          * if dest_node is NULL, the request will be sent to the
          *   local node
          */
         sys_to = CRM_SYSTEM_CRMD;
         crmd_operation = CRM_OP_DEBUG_DOWN;
 
         ret = 0;                /* no return message */
 
     } else {
         crm_err("Unknown options");
         all_is_good = FALSE;
     }
 
     if (all_is_good == FALSE) {
         crm_err("Creation of request failed.  No message to send");
         return -1;
     }
 
 /* send it */
     if (crmd_channel == NULL) {
         crm_err("The IPC connection is not valid, cannot send anything");
         return -1;
     }
 
     if (sys_to == NULL) {
         if (dest_node != NULL) {
             sys_to = CRM_SYSTEM_CRMD;
         } else {
             sys_to = CRM_SYSTEM_DC;
         }
     }
 
     {
         xmlNode *cmd = create_request(crmd_operation, msg_data, dest_node, sys_to,
                                       crm_system_name, admin_uuid);
 
         crm_ipc_send(crmd_channel, cmd, 0, 0, NULL);
         free_xml(cmd);
     }
 
     return ret;
 }
 
 void
 crmadmin_ipc_connection_destroy(gpointer user_data)
 {
     crm_err("Connection to CRMd was terminated");
     if (mainloop) {
         g_main_quit(mainloop);
     } else {
         crm_exit(ENOTCONN);
     }
 }
 
 struct ipc_client_callbacks crm_callbacks = {
     .dispatch = admin_msg_callback,
     .destroy = crmadmin_ipc_connection_destroy
 };
 
 gboolean
 do_init(void)
 {
     mainloop_io_t *source =
-        mainloop_add_ipc_client(CRM_SYSTEM_CRMD, G_PRIORITY_DEFAULT, 0, NULL, &crm_callbacks);
+        mainloop_add_ipc_client(CRM_SYSTEM_CRMD, G_PRIORITY_DEFAULT, NULL, &crm_callbacks);
 
     admin_uuid = calloc(1, 11);
     if (admin_uuid != NULL) {
         snprintf(admin_uuid, 10, "%d", getpid());
         admin_uuid[10] = '\0';
     }
 
     crmd_channel = mainloop_get_ipc_client(source);
 
     if (DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) {
         return TRUE;
 
     } else if (crmd_channel != NULL) {
         xmlNode *xml = create_hello_message(admin_uuid, crm_system_name, "0", "1");
 
         crm_ipc_send(crmd_channel, xml, 0, 0, NULL);
         return TRUE;
     }
     return FALSE;
 }
 
 static bool
 validate_crm_message(xmlNode * msg, const char *sys, const char *uuid, const char *msg_type)
 {
     const char *type = NULL;
     const char *crm_msg_reference = NULL;
 
     if (msg == NULL) {
         return FALSE;
     }
 
     type = crm_element_value(msg, F_CRM_MSG_TYPE);
     crm_msg_reference = crm_element_value(msg, XML_ATTR_REFERENCE);
 
     if (type == NULL) {
         crm_info("No message type defined.");
         return FALSE;
 
     } else if (msg_type != NULL && strcasecmp(msg_type, type) != 0) {
         crm_info("Expecting a (%s) message but received a (%s).", msg_type, type);
         return FALSE;
     }
 
     if (crm_msg_reference == NULL) {
         crm_info("No message crm_msg_reference defined.");
         return FALSE;
     }
 
     return TRUE;
 }
 
 int
 admin_msg_callback(const char *buffer, ssize_t length, gpointer userdata)
 {
     static int received_responses = 0;
     const char *result = NULL;
     xmlNode *xml = string2xml(buffer);
 
     received_responses++;
     g_source_remove(message_timer_id);
 
     crm_log_xml_trace(xml, "ipc");
 
     if (xml == NULL) {
         crm_info("XML in IPC message was not valid... " "discarding.");
 
     } else if (validate_crm_message(xml, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) {
         crm_trace("Message was not a CRM response. Discarding.");
 
     } else {
         result = crm_element_value(xml, XML_ATTR_RESULT);
         if (result == NULL || strcasecmp(result, "ok") == 0) {
             result = "pass";
 
         } else {
             result = "fail";
         }
 
         if (DO_HEALTH) {
             xmlNode *data = get_message_xml(xml, F_CRM_DATA);
             const char *state = crm_element_value(data, "crmd_state");
 
             printf("Status of %s@%s: %s (%s)\n",
                    crm_element_value(data, XML_PING_ATTR_SYSFROM),
                    crm_element_value(xml, F_CRM_HOST_FROM),
                    state, crm_element_value(data, XML_PING_ATTR_STATUS));
 
             if (BE_SILENT && state != NULL) {
                 fprintf(stderr, "%s\n", state);
             }
 
         } else if (DO_WHOIS_DC) {
             const char *dc = crm_element_value(xml, F_CRM_HOST_FROM);
 
             printf("Designated Controller is: %s\n", dc);
             if (BE_SILENT && dc != NULL) {
                 fprintf(stderr, "%s\n", dc);
             }
             crm_exit(pcmk_ok);
         }
     }
 
     free_xml(xml);
 
     if (received_responses >= expected_responses) {
         crm_trace("Received expected number (%d) of messages from Heartbeat."
                   "  Exiting normally.", expected_responses);
         crm_exit(pcmk_ok);
     }
 
     message_timer_id = g_timeout_add(message_timeout_ms, admin_message_timeout, NULL);
     return 0;
 }
 
 gboolean
 admin_message_timeout(gpointer data)
 {
     fprintf(stderr, "No messages received in %d seconds.. aborting\n",
             (int)message_timeout_ms / 1000);
     crm_err("No messages received in %d seconds", (int)message_timeout_ms / 1000);
     operation_status = -3;
     g_main_quit(mainloop);
     return FALSE;
 }
 
 gboolean
 is_node_online(xmlNode * node_state)
 {
     const char *uname = crm_element_value(node_state, XML_ATTR_UNAME);
     const char *join_state = crm_element_value(node_state, XML_NODE_JOIN_STATE);
     const char *exp_state = crm_element_value(node_state, XML_NODE_EXPECTED);
     const char *crm_state = crm_element_value(node_state, XML_NODE_IS_PEER);
     const char *ccm_state = crm_element_value(node_state, XML_NODE_IN_CLUSTER);
 
     if (safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)
         && crm_is_true(ccm_state)
         && safe_str_eq(crm_state, "online")) {
         crm_trace("Node %s is online", uname);
         return TRUE;
     }
     crm_trace("Node %s: ccm=%s join=%s exp=%s crm=%s",
               uname, crm_str(ccm_state),
               crm_str(join_state), crm_str(exp_state), crm_str(crm_state));
     crm_trace("Node %s is offline", uname);
     return FALSE;
 }
 
 int
 do_find_node_list(xmlNode * xml_node)
 {
     int found = 0;
     xmlNode *node = NULL;
     xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
 
     for (node = __xml_first_child(nodes); node != NULL; node = __xml_next(node)) {
         if (crm_str_eq((const char *)node->name, XML_CIB_TAG_NODE, TRUE)) {
 
             if (BASH_EXPORT) {
                 printf("export %s=%s\n",
                        crm_element_value(node, XML_ATTR_UNAME),
                        crm_element_value(node, XML_ATTR_ID));
             } else {
                 printf("%s node: %s (%s)\n",
                        crm_element_value(node, XML_ATTR_TYPE),
                        crm_element_value(node, XML_ATTR_UNAME),
                        crm_element_value(node, XML_ATTR_ID));
             }
             found++;
         }
     }
 
     if (found == 0) {
         printf("NO nodes configured\n");
     }
 
     return found;
 }