diff --git a/include/crm/stonith-ng.h b/include/crm/stonith-ng.h
index a10b8b3448..70c0233532 100644
--- a/include/crm/stonith-ng.h
+++ b/include/crm/stonith-ng.h
@@ -1,559 +1,560 @@
 /*
  * Copyright 2004-2019 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
  * \file
  * \brief Fencing aka. STONITH
  * \ingroup fencing
  */
 
 #ifndef STONITH_NG__H
 #  define STONITH_NG__H
 
 #  include <dlfcn.h>
 #  include <errno.h>
 #  include <stdbool.h>  // bool
 #  include <stdint.h>   // uint32_t
 #  include <time.h>     // time_t
 
 #  include <crm/common/output.h>
 
 #  define T_STONITH_NOTIFY_DISCONNECT     "st_notify_disconnect"
 #  define T_STONITH_NOTIFY_FENCE          "st_notify_fence"
 #  define T_STONITH_NOTIFY_HISTORY        "st_notify_history"
 
 /* *INDENT-OFF* */
 enum stonith_state {
     stonith_connected_command,
     stonith_connected_query,
     stonith_disconnected,
 };
 
 enum stonith_call_options {
     st_opt_none            = 0x00000000,
     st_opt_verbose         = 0x00000001,
     st_opt_allow_suicide   = 0x00000002,
 
     st_opt_manual_ack      = 0x00000008,
     st_opt_discard_reply   = 0x00000010,
 /*    st_opt_all_replies     = 0x00000020, */
     st_opt_topology        = 0x00000040,
     st_opt_scope_local     = 0x00000100,
     st_opt_cs_nodeid       = 0x00000200,
     st_opt_sync_call       = 0x00001000,
     /*! Allow the timeout period for a callback to be adjusted
      *  based on the time the server reports the operation will take. */
     st_opt_timeout_updates = 0x00002000,
     /*! Only report back if operation is a success in callback */
     st_opt_report_only_success = 0x00004000,
     /* used where ever apropriate - e.g. cleanup of history */
     st_opt_cleanup         = 0x000080000,
     /* used where ever apropriate - e.g. send out a history query to all nodes */
     st_opt_broadcast       = 0x000100000,
 };
 
 /*! Order matters here, do not change values */
 enum op_state
 {
     st_query,
     st_exec,
     st_done,
     st_duplicate,
     st_failed,
 };
 
 // Supported fence agent interface standards
 enum stonith_namespace {
     st_namespace_invalid,
     st_namespace_any,
     st_namespace_internal,  // Implemented internally by Pacemaker
 
     /* Neither of these projects are active any longer, but the fence agent
      * interfaces they created are still in use and supported by Pacemaker.
      */
     st_namespace_rhcs,      // Red Hat Cluster Suite compatible
     st_namespace_lha,       // Linux-HA compatible
 };
 
 enum stonith_namespace stonith_text2namespace(const char *namespace_s);
 const char *stonith_namespace2text(enum stonith_namespace st_namespace);
 enum stonith_namespace stonith_get_namespace(const char *agent,
                                              const char *namespace_s);
 
 typedef struct stonith_key_value_s {
     char *key;
     char *value;
         struct stonith_key_value_s *next;
 } stonith_key_value_t;
 
 typedef struct stonith_history_s {
     char *target;
     char *action;
     char *origin;
     char *delegate;
     char *client;
     int state;
     time_t completed;
     struct stonith_history_s *next;
 } stonith_history_t;
 
 typedef struct stonith_s stonith_t;
 
 typedef struct stonith_event_s
 {
     char *id;
     char *type;
     char *message;
     char *operation;
 
     int result;
     char *origin;
     char *target;
     char *action;
     char *executioner;
 
     char *device;
 
     /*! The name of the client that initiated the action. */
     char *client_origin;
 
 } stonith_event_t;
 
 typedef struct stonith_callback_data_s
 {
     int rc;
     int call_id;
     void *userdata;
 } stonith_callback_data_t;
 
 typedef struct stonith_api_operations_s
 {
     /*!
      * \brief Destroy the stonith api structure.
      */
     int (*free) (stonith_t *st);
 
     /*!
      * \brief Connect to the local stonith daemon.
      *
      * \retval 0, success
      * \retval negative error code on failure
      */
     int (*connect) (stonith_t *st, const char *name, int *stonith_fd);
 
     /*!
      * \brief Disconnect from the local stonith daemon.
      *
      * \retval 0, success
      * \retval negative error code on failure
      */
     int (*disconnect)(stonith_t *st);
 
     /*!
      * \brief Remove a registered stonith device with the local stonith daemon.
      *
      * \note Synchronous, guaranteed to occur in daemon before function returns.
      *
      * \retval 0, success
      * \retval negative error code on failure
      */
     int (*remove_device)(
         stonith_t *st, int options, const char *name);
 
     /*!
      * \brief Register a stonith device with the local stonith daemon.
      *
      * \note Synchronous, guaranteed to occur in daemon before function returns.
      *
      * \retval 0, success
      * \retval negative error code on failure
      */
     int (*register_device)(
         stonith_t *st, int options, const char *id,
         const char *provider, const char *agent, stonith_key_value_t *params);
 
     /*!
      * \brief Remove a fencing level for a specific node.
      *
      * \note This feature is not available when stonith is in standalone mode.
      *
      * \retval 0, success
      * \retval negative error code on failure
      */
     int (*remove_level)(
         stonith_t *st, int options, const char *node, int level);
 
     /*!
      * \brief Register a fencing level containing the fencing devices to be used
      *        at that level for a specific node.
      *
      * \note This feature is not available when stonith is in standalone mode.
      *
      * \retval 0, success
      * \retval negative error code on failure
      */
     int (*register_level)(
         stonith_t *st, int options, const char *node, int level, stonith_key_value_t *device_list);
 
     /*!
      * \brief Get the metadata documentation for a resource.
      *
      * \note Value is returned in output.  Output must be freed when set.
      *
      * \retval 0 success
      * \retval negative error code on failure
      */
     int (*metadata)(stonith_t *st, int options,
             const char *device, const char *provider, char **output, int timeout);
 
     /*!
      * \brief Retrieve a list of installed stonith agents
      *
      * \note if provider is not provided, all known agents will be returned
      * \note list must be freed using stonith_key_value_freeall()
      * \note call_options parameter is not used, it is reserved for future use.
      *
      * \retval num items in list on success
      * \retval negative error code on failure
      */
     int (*list_agents)(stonith_t *stonith, int call_options, const char *provider,
             stonith_key_value_t **devices, int timeout);
 
     /*!
      * \brief Retrieve string listing hosts and port assignments from a local stonith device.
      *
      * \retval 0 on success
      * \retval negative error code on failure
      */
     int (*list)(stonith_t *st, int options, const char *id, char **list_output, int timeout);
 
     /*!
      * \brief Check to see if a local stonith device is reachable
      *
      * \retval 0 on success
      * \retval negative error code on failure
      */
     int (*monitor)(stonith_t *st, int options, const char *id, int timeout);
 
     /*!
      * \brief Check to see if a local stonith device's port is reachable
      *
      * \retval 0 on success
      * \retval negative error code on failure
      */
     int (*status)(stonith_t *st, int options, const char *id, const char *port, int timeout);
 
     /*!
      * \brief Retrieve a list of registered stonith devices.
      *
      * \note If node is provided, only devices that can fence the node id
      *       will be returned.
      *
      * \retval num items in list on success
      * \retval negative error code on failure
      */
     int (*query)(stonith_t *st, int options, const char *node,
             stonith_key_value_t **devices, int timeout);
 
     /*!
      * \brief Issue a fencing action against a node.
      *
      * \note Possible actions are, 'on', 'off', and 'reboot'.
      *
      * \param st, stonith connection
      * \param options, call options
      * \param node, The target node to fence
      * \param action, The fencing action to take
      * \param timeout, The default per device timeout to use with each device
      *                 capable of fencing the target.
      *
      * \retval 0 success
      * \retval negative error code on failure.
      */
     int (*fence)(stonith_t *st, int options, const char *node, const char *action,
                  int timeout, int tolerance);
 
     /*!
      * \brief Manually confirm that a node is down.
      *
      * \retval 0 success
      * \retval negative error code on failure.
      */
     int (*confirm)(stonith_t *st, int options, const char *node);
 
     /*!
      * \brief Retrieve a list of fencing operations that have occurred for a specific node.
      *
      * \note History is not available in standalone mode.
      *
      * \retval 0 success
      * \retval negative error code on failure.
      */
     int (*history)(stonith_t *st, int options, const char *node, stonith_history_t **output, int timeout);
 
     int (*register_notification)(
         stonith_t *st, const char *event,
         void (*notify)(stonith_t *st, stonith_event_t *e));
     int (*remove_notification)(stonith_t *st, const char *event);
 
     /*!
      * \brief Register a callback to receive the result of an asynchronous call
      *
      * \param[in] call_id        The call ID to register callback for
      * \param[in] timeout        Default time to wait until callback expires
      * \param[in] options        Bitmask of \c stonith_call_options (respects
      *                           \c st_opt_timeout_updates and
      *                           \c st_opt_report_only_success)
      * \param[in] userdata       Pointer that will be given to callback
      * \param[in] callback_name  Unique name to identify callback
      * \param[in] callback       The callback function to register
      *
      * \return \c TRUE on success, \c FALSE if call_id is negative, -errno otherwise
      *
      * \todo This function should return \c pcmk_ok on success, and \c call_id
      *       when negative, but that would break backward compatibility.
      */
     int (*register_callback)(stonith_t *st,
         int call_id,
         int timeout,
         int options,
         void *userdata,
         const char *callback_name,
         void (*callback)(stonith_t *st, stonith_callback_data_t *data));
 
     /*!
      * \brief Remove a registered callback for a given call id.
      */
     int (*remove_callback)(stonith_t *st, int call_id, bool all_callbacks);
 
     /*!
      * \brief Remove fencing level for specific node, node regex or attribute
      *
      * \param[in] st      Fencer connection to use
      * \param[in] options Bitmask of stonith_call_options to pass to the fencer
      * \param[in] node    If not NULL, target level by this node name
      * \param[in] pattern If not NULL, target by node name using this regex
      * \param[in] attr    If not NULL, target by this node attribute
      * \param[in] value   If not NULL, target by this node attribute value
      * \param[in] level   Index number of level to remove
      *
      * \return 0 on success, negative error code otherwise
      *
      * \note This feature is not available when stonith is in standalone mode.
      *       The caller should set only one of node, pattern or attr/value.
      */
     int (*remove_level_full)(stonith_t *st, int options,
                              const char *node, const char *pattern,
                              const char *attr, const char *value, int level);
 
     /*!
      * \brief Register fencing level for specific node, node regex or attribute
      *
      * \param[in] st          Fencer connection to use
      * \param[in] options     Bitmask of stonith_call_options to pass to fencer
      * \param[in] node        If not NULL, target level by this node name
      * \param[in] pattern     If not NULL, target by node name using this regex
      * \param[in] attr        If not NULL, target by this node attribute
      * \param[in] value       If not NULL, target by this node attribute value
      * \param[in] level       Index number of level to add
      * \param[in] device_list Devices to use in level
      *
      * \return 0 on success, negative error code otherwise
      *
      * \note This feature is not available when stonith is in standalone mode.
      *       The caller should set only one of node, pattern or attr/value.
      */
     int (*register_level_full)(stonith_t *st, int options,
                                const char *node, const char *pattern,
                                const char *attr, const char *value,
                                int level, stonith_key_value_t *device_list);
 
     /*!
      * \brief Validate an arbitrary stonith device configuration
      *
      * \param[in]  st            Stonithd connection to use
      * \param[in]  call_options  Bitmask of stonith_call_options to use with fencer
      * \param[in]  rsc_id        ID used to replace CIB secrets in params
      * \param[in]  namespace_s   Namespace of fence agent to validate (optional)
      * \param[in]  agent         Fence agent to validate
      * \param[in]  params        Configuration parameters to pass to fence agent
      * \param[in]  timeout       Fail if no response within this many seconds
      * \param[out] output        If non-NULL, where to store any agent output
      * \param[out] error_output  If non-NULL, where to store agent error output
      *
      * \return pcmk_ok if validation succeeds, -errno otherwise
      *
      * \note If pcmk_ok is returned, the caller is responsible for freeing
      *       the output (if requested).
      */
     int (*validate)(stonith_t *st, int call_options, const char *rsc_id,
                     const char *namespace_s, const char *agent,
                     stonith_key_value_t *params, int timeout, char **output,
                     char **error_output);
 
 } stonith_api_operations_t;
 
 struct stonith_s
 {
     enum stonith_state state;
 
     int call_id;
     int call_timeout;
     void *st_private;
 
     stonith_api_operations_t *cmds;
 };
 /* *INDENT-ON* */
 
 /* Core functions */
 stonith_t *stonith_api_new(void);
 void stonith_api_delete(stonith_t * st);
 
 void stonith_dump_pending_callbacks(stonith_t * st);
 
 // deprecated (use stonith_get_namespace() instead)
 const char *get_stonith_provider(const char *agent, const char *provider);
 
 bool stonith_dispatch(stonith_t * st);
 
 stonith_key_value_t *stonith_key_value_add(stonith_key_value_t * kvp, const char *key,
                                            const char *value);
 void stonith_key_value_freeall(stonith_key_value_t * kvp, int keys, int values);
 
 void stonith_history_free(stonith_history_t *history);
 
 /* Basic helpers that allows nodes to be fenced and the history to be
  * queried without mainloop or the caller understanding the full API
  *
  * At least one of nodeid and uname are required
  */
 int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off);
 time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress);
 
 /*
  * Helpers for using the above functions without install-time dependencies
  *
  * Usage:
  *  #include <crm/stonith-ng.h>
  *
  * To turn a node off by corosync nodeid:
  *  stonith_api_kick_helper(nodeid, 120, 1);
  *
  * To check the last fence date/time (also by nodeid):
  *  last = stonith_api_time_helper(nodeid, 0);
  *
  * To check if fencing is in progress:
  *  if(stonith_api_time_helper(nodeid, 1) > 0) { ... }
  *
  * eg.
 
  #include <stdio.h>
  #include <time.h>
  #include <crm/stonith-ng.h>
  int
  main(int argc, char ** argv)
  {
      int rc = 0;
      int nodeid = 102;
 
      rc = stonith_api_time_helper(nodeid, 0);
      printf("%d last fenced at %s\n", nodeid, ctime(rc));
 
      rc = stonith_api_kick_helper(nodeid, 120, 1);
      printf("%d fence result: %d\n", nodeid, rc);
 
      rc = stonith_api_time_helper(nodeid, 0);
      printf("%d last fenced at %s\n", nodeid, ctime(rc));
 
      return 0;
  }
 
  */
 
 #  define STONITH_LIBRARY "libstonithd.so.26"
 
 typedef int (*st_api_kick_fn) (int nodeid, const char *uname, int timeout, bool off);
 typedef time_t (*st_api_time_fn) (int nodeid, const char *uname, bool in_progress);
 
 static inline int
 stonith_api_kick_helper(uint32_t nodeid, int timeout, bool off)
 {
     static void *st_library = NULL;
     static st_api_kick_fn st_kick_fn;
 
     if (st_library == NULL) {
         st_library = dlopen(STONITH_LIBRARY, RTLD_LAZY);
     }
     if (st_library && st_kick_fn == NULL) {
         st_kick_fn = (st_api_kick_fn) dlsym(st_library, "stonith_api_kick");
     }
     if (st_kick_fn == NULL) {
 #ifdef ELIBACC
         return -ELIBACC;
 #else
         return -ENOSYS;
 #endif
     }
 
     return (*st_kick_fn) (nodeid, NULL, timeout, off);
 }
 
 static inline time_t
 stonith_api_time_helper(uint32_t nodeid, bool in_progress)
 {
     static void *st_library = NULL;
     static st_api_time_fn st_time_fn;
 
     if (st_library == NULL) {
         st_library = dlopen(STONITH_LIBRARY, RTLD_LAZY);
     }
     if (st_library && st_time_fn == NULL) {
         st_time_fn = (st_api_time_fn) dlsym(st_library, "stonith_api_time");
     }
     if (st_time_fn == NULL) {
         return 0;
     }
 
     return (*st_time_fn) (nodeid, NULL, in_progress);
 }
 
 /**
  * Does the given agent describe a stonith resource that can exist?
  *
  * \param[in] agent     What is the name of the agent?
  * \param[in] timeout   Timeout to use when querying.  If 0 is given,
  *                      use a default of 120.
  *
  * \return A boolean
  */
 bool stonith_agent_exists(const char *agent, int timeout);
 
 /*!
+ * \internal
  * \brief Register stonith-specific messages.
  *
  * \param out The output functions structure.
  */
-void stonith_register_messages(pcmk__output_t *out);
+void stonith__register_messages(pcmk__output_t *out);
 
 /*!
  * \brief Turn stonith action into a more readable string.
  *
  * \param action Stonith action
  */
 const char *stonith_action_str(const char *action);
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif
diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c
index 709c45cc4a..ae3d046fee 100644
--- a/lib/fencing/st_output.c
+++ b/lib/fencing/st_output.c
@@ -1,230 +1,235 @@
 /*
  * Copyright 2019 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <stdarg.h>
 
 #include <crm/stonith-ng.h>
 #include <crm/common/iso8601.h>
 #include <crm/common/output.h>
 #include <crm/common/util.h>
 #include <crm/common/xml.h>
 
 static int
 fence_target_text(pcmk__output_t *out, va_list args) {
     const char *hostname = va_arg(args, const char *);
     const char *uuid = va_arg(args, const char *);
     const char *status = va_arg(args, const char *);
 
     pcmk__indented_printf(out, "%s\t%s\t%s\n", hostname, uuid, status);
     return 0;
 }
 
 static int
 fence_target_xml(pcmk__output_t *out, va_list args) {
     xmlNodePtr node = NULL;
     const char *hostname = va_arg(args, const char *);
     const char *uuid = va_arg(args, const char *);
     const char *status = va_arg(args, const char *);
 
     node = xmlNewNode(NULL, (pcmkXmlStr) "target");
     xmlSetProp(node, (pcmkXmlStr) "hostname", (pcmkXmlStr) hostname);
     xmlSetProp(node, (pcmkXmlStr) "uuid", (pcmkXmlStr) uuid);
     xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) status);
 
     pcmk__xml_add_node(out, node);
     return 0;
 }
 
 static int
 last_fenced_text(pcmk__output_t *out, va_list args) {
     const char *target = va_arg(args, const char *);
     time_t when = va_arg(args, time_t);
 
     if (when) {
         pcmk__indented_printf(out, "Node %s last fenced at: %s", target, ctime(&when));
     } else {
         pcmk__indented_printf(out, "Node %s has never been fenced\n", target);
     }
 
     return 0;
 }
 
 static int
 last_fenced_xml(pcmk__output_t *out, va_list args) {
     const char *target = va_arg(args, const char *);
     time_t when = va_arg(args, time_t);
 
     if (when) {
         crm_time_t *crm_when = crm_time_new(NULL);
         xmlNodePtr node = xmlNewNode(NULL, (pcmkXmlStr) "last-fenced");
         char *buf = NULL;
 
         crm_time_set_timet(crm_when, &when);
         buf = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
 
         xmlSetProp(node, (pcmkXmlStr) "target", (pcmkXmlStr) target);
         xmlSetProp(node, (pcmkXmlStr) "when", (pcmkXmlStr) buf);
 
         pcmk__xml_add_node(out, node);
 
         crm_time_free(crm_when);
         free(buf);
     }
 
     return 0;
 }
 
 static int
 stonith_event_text(pcmk__output_t *out, va_list args) {
     stonith_history_t *event = va_arg(args, stonith_history_t *);
 
     switch (event->state) {
         case st_failed:
             pcmk__indented_printf(out, "%s failed %s node %s on behalf of %s from %s at %s",
                                   event->delegate ? event->delegate : "We",
                                   stonith_action_str(event->action), event->target,
                                   event->client, event->origin, ctime(&event->completed));
             break;
 
         case st_done:
             pcmk__indented_printf(out, "%s succeeded %s node %s on behalf of %s from %s at %s",
                                   event->delegate ? event->delegate : "This node",
                                   stonith_action_str(event->action), event->target,
                                   event->client, event->origin, ctime(&event->completed));
             break;
 
         default:
             /* ocf:pacemaker:controld depends on "wishes to" being
              * in this output, when used with older versions of DLM
              * that don't report stateful_merge_wait
              */
             pcmk__indented_printf(out, "%s at %s wishes to %s node %s - %d %lld\n",
                                   event->client, event->origin, stonith_action_str(event->action),
                                   event->target, event->state, (long long) event->completed);
             break;
     }
 
     return 0;
 }
 
 static int
 stonith_event_xml(pcmk__output_t *out, va_list args) {
     xmlNodePtr node = NULL;
     stonith_history_t *event = va_arg(args, stonith_history_t *);
     crm_time_t *crm_when = crm_time_new(NULL);
     char *buf = NULL;
 
     node = xmlNewNode(NULL, (pcmkXmlStr) "stonith-event");
 
     switch (event->state) {
         case st_failed:
             xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) "failed");
             break;
 
         case st_done:
             xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) "done");
             break;
 
         default: {
             char *state = crm_itoa(event->state);
             xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) state);
             free(state);
             break;
         }
     }
 
     if (event->delegate != NULL) {
         xmlSetProp(node, (pcmkXmlStr) "delegate", (pcmkXmlStr) event->delegate);
     }
 
     xmlSetProp(node, (pcmkXmlStr) "action", (pcmkXmlStr) event->action);
     xmlSetProp(node, (pcmkXmlStr) "target", (pcmkXmlStr) event->target);
     xmlSetProp(node, (pcmkXmlStr) "client", (pcmkXmlStr) event->client);
     xmlSetProp(node, (pcmkXmlStr) "origin", (pcmkXmlStr) event->origin);
 
     crm_time_set_timet(crm_when, &event->completed);
     buf = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
     xmlSetProp(node, (pcmkXmlStr) "when", (pcmkXmlStr) buf);
 
     pcmk__xml_add_node(out, node);
 
     crm_time_free(crm_when);
     free(buf);
     return 0;
 }
 
 static int
 validate_agent_text(pcmk__output_t *out, va_list args) {
     const char *agent = va_arg(args, const char *);
     const char *device = va_arg(args, const char *);
     const char *output = va_arg(args, const char *);
     const char *error_output = va_arg(args, const char *);
     int rc = va_arg(args, int);
 
     if (device) {
         pcmk__indented_printf(out, "Validation of %s on %s %s\n", agent, device,
                               rc ? "failed" : "succeeded");
     } else {
         pcmk__indented_printf(out, "Validation of %s %s\n", agent,
                               rc ? "failed" : "succeeded");
     }
 
     if (output) {
         puts(output);
     }
 
     if (error_output) {
         puts(error_output);
     }
 
     return rc;
 }
 
 static int
 validate_agent_xml(pcmk__output_t *out, va_list args) {
     xmlNodePtr node = NULL;
 
     const char *agent = va_arg(args, const char *);
     const char *device = va_arg(args, const char *);
     const char *output = va_arg(args, const char *);
     const char *error_output = va_arg(args, const char *);
     int rc = va_arg(args, int);
 
     node = xmlNewNode(NULL, (pcmkXmlStr) "validate");
     xmlSetProp(node, (pcmkXmlStr) "agent", (pcmkXmlStr) agent);
     if (device != NULL) {
         xmlSetProp(node, (pcmkXmlStr) "device", (pcmkXmlStr) device);
     }
     xmlSetProp(node, (pcmkXmlStr) "valid", (pcmkXmlStr) (rc ? "false" : "true"));
 
     pcmk__xml_push_parent(out, node);
     out->subprocess_output(out, rc, output, error_output);
     pcmk__xml_pop_parent(out);
 
     pcmk__xml_add_node(out, node);
     return rc;
 }
 
 static pcmk__message_entry_t fmt_functions[] = {
     { "fence-target", "text", fence_target_text },
     { "fence-target", "xml", fence_target_xml },
     { "last-fenced", "text", last_fenced_text },
     { "last-fenced", "xml", last_fenced_xml },
     { "stonith-event", "text", stonith_event_text },
     { "stonith-event", "xml", stonith_event_xml },
     { "validate", "text", validate_agent_text },
     { "validate", "xml", validate_agent_xml },
 
     { NULL, NULL, NULL }
 };
 
 void
-stonith_register_messages(pcmk__output_t *out) {
-    pcmk__register_messages(out, fmt_functions);
+stonith__register_messages(pcmk__output_t *out) {
+    static bool registered = FALSE;
+
+    if (!registered) {
+        pcmk__register_messages(out, fmt_functions);
+        registered = TRUE;
+    }
 }
diff --git a/tools/stonith_admin.c b/tools/stonith_admin.c
index cba467397f..07d903fd29 100644
--- a/tools/stonith_admin.c
+++ b/tools/stonith_admin.c
@@ -1,785 +1,785 @@
 /*
  * Copyright 2009-2019 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/utsname.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/ipc.h>
 #include <crm/cluster/internal.h>
 #include <crm/common/mainloop.h>
 #include <crm/common/output.h>
 
 #include <crm/stonith-ng.h>
 #include <crm/cib.h>
 #include <crm/pengine/status.h>
 
 #include <crm/common/xml.h>
 
 
 /* *INDENT-OFF* */
 static struct crm_option long_options[] = {
     {   "help", no_argument, NULL, '?',
         "\tDisplay this text and exit."
     },
     {   "version", no_argument, NULL, '$',
         "\tDisplay version information and exit."
     },
     {   "verbose", no_argument, NULL, 'V',
         "\tIncrease debug output (may be specified multiple times)."
     },
     {   "quiet", no_argument, NULL, 'q',
         "\tBe less descriptive in output."
     },
     {   "cleanup", no_argument, NULL, 'c',
         "\tCleanup wherever appropriate."
     },
     {   "broadcast", no_argument, NULL, 'b',
         "Broadcast wherever appropriate."
     },
     PCMK__OUTPUT_OPTIONS("text, xml"),
     {   "-spacer-", no_argument, NULL, '-', "\nDevice definition commands:" },
 
     {   "register", required_argument, NULL, 'R',
         "Register the named stonith device. Requires: --agent.\n"
         "\t\t\tOptional: --option, --env-option."
     },
     {   "deregister", required_argument, NULL, 'D',
         "De-register the named stonith device."
     },
     {   "register-level", required_argument, NULL, 'r',
         "Register a stonith level for the named target,\n"
         "\t\t\tspecified as one of NAME, @PATTERN, or ATTR=VALUE.\n"
         "\t\t\tRequires: --index and one or more --device entries."
     },
     {   "deregister-level", required_argument, NULL, 'd',
         "Unregister a stonith level for the named target,\n"
         "\t\t\tspecified as for --register-level. Requires: --index."
     },
 
     {   "-spacer-", no_argument, NULL, '-', "\nQueries:" },
 
     {   "list", required_argument, NULL, 'l',
         "List devices that can terminate the specified host.\n"
         "\t\t\tOptional: --timeout."
     },
     {   "list-registered", no_argument, NULL, 'L',
         "List all registered devices. Optional: --timeout."
     },
     {   "list-installed", no_argument, NULL, 'I',
         "List all installed devices. Optional: --timeout."
     },
     {   "list-targets", required_argument, NULL, 's',
         "List the targets that can be fenced by the\n"
         "\t\t\tnamed device. Optional: --timeout."
     },
     {   "metadata", no_argument, NULL, 'M',
         "\tShow agent metadata. Requires: --agent.\n"
         "\t\t\tOptional: --timeout."
     },
     {   "query", required_argument, NULL, 'Q',
         "Check the named device's status. Optional: --timeout."
     },
     {   "history", required_argument, NULL, 'H',
         "Show last successful fencing operation for named node\n"
         "\t\t\t(or '*' for all nodes). Optional: --timeout, --cleanup,\n"
         "\t\t\t--quiet (show only the operation's epoch timestamp),\n"
         "\t\t\t--verbose (show all recorded and pending operations),\n"
         "\t\t\t--broadcast (update history from all nodes available)."
     },
     {   "last", required_argument, NULL, 'h',
         "Indicate when the named node was last fenced.\n"
         "\t\t\tOptional: --as-node-id."
     },
     {   "validate", no_argument, NULL, 'K',
         "\tValidate a fence device configuration.\n"
         "\t\t\tRequires: --agent. Optional: --option, --env-option,\n"
         "\t\t\t--quiet (print no output, only return status).\n"
     },
 
     {   "-spacer-", no_argument, NULL, '-', "\nFencing Commands:" },
 
     {   "fence", required_argument, NULL, 'F',
         "Fence named host. Optional: --timeout, --tolerance."
     },
     {   "unfence", required_argument, NULL, 'U',
         "Unfence named host. Optional: --timeout, --tolerance."
     },
     {   "reboot", required_argument, NULL, 'B',
         "Reboot named host. Optional: --timeout, --tolerance."
     },
     {   "confirm", required_argument, NULL, 'C',
         "Tell cluster that named host is now safely down."
     },
 
     {   "-spacer-", no_argument, NULL, '-', "\nAdditional Options:" },
 
     {   "agent", required_argument, NULL, 'a',
         "The agent to use (for example, fence_xvm;\n"
         "\t\t\twith --register, --metadata, --validate)."
     },
     {   "option", required_argument, NULL, 'o',
         "Specify a device configuration parameter as NAME=VALUE\n"
         "\t\t\t(may be specified multiple times; with --register,\n"
         "\t\t\t--validate)."
     },
     {   "env-option", required_argument, NULL, 'e',
         "Specify a device configuration parameter with the\n"
         "\t\t\tspecified name, using the value of the\n"
         "\t\t\tenvironment variable of the same name prefixed with\n"
         "\t\t\tOCF_RESKEY_ (may be specified multiple times;\n"
         "\t\t\twith --register, --validate)."
     },
     {   "tag", required_argument, NULL, 'T',
         "Identify fencing operations in logs with the specified\n"
         "\t\t\ttag; useful when multiple entities might invoke\n"
         "\t\t\tstonith_admin (used with most commands)."
     },
     {   "device", required_argument, NULL, 'v',
         "Device ID (with --register-level, device to associate with\n"
         "\t\t\ta given host and level; may be specified multiple times)"
 #if SUPPORT_CIBSECRETS
         "\n\t\t\t(with --validate, name to use to load CIB secrets)"
 #endif
         "."
     },
     {   "index", required_argument, NULL, 'i',
         "The stonith level (1-9) (with --register-level,\n"
         "\t\t\t--deregister-level)."
     },
     {   "timeout", required_argument, NULL, 't',
         "Operation timeout in seconds (default 120;\n"
         "\t\t\tused with most commands)."
     },
     {   "as-node-id", no_argument, NULL, 'n',
         "(Advanced) The supplied node is the corosync node ID\n"
         "\t\t\t(with --last)."
     },
     {   "tolerance", required_argument, NULL,   0,
         "(Advanced) Do nothing if an equivalent --fence request\n"
         "\t\t\tsucceeded less than this many seconds earlier\n"
         "\t\t\t(with --fence, --unfence, --reboot)."
     },
 
     { 0, 0, 0, 0 }
 };
 /* *INDENT-ON* */
 
 static int st_opts = st_opt_sync_call | st_opt_allow_suicide;
 
 static GMainLoop *mainloop = NULL;
 struct {
     stonith_t *st;
     const char *target;
     const char *action;
     char *name;
     int timeout;
     int tolerance;
     int rc;
 } async_fence_data;
 
 static int
 try_mainloop_connect(void)
 {
     stonith_t *st = async_fence_data.st;
     int tries = 10;
     int i = 0;
     int rc = 0;
 
     for (i = 0; i < tries; i++) {
         crm_debug("Connecting as %s", async_fence_data.name);
         rc = st->cmds->connect(st, async_fence_data.name, NULL);
 
         if (!rc) {
             crm_debug("stonith client connection established");
             return 0;
         } else {
             crm_debug("stonith client connection failed");
         }
         sleep(1);
     }
 
     crm_err("Could not connect to the fencer");
     return -1;
 }
 
 static void
 notify_callback(stonith_t * st, stonith_event_t * e)
 {
     if (e->result != pcmk_ok) {
         return;
     }
 
     if (safe_str_eq(async_fence_data.target, e->target) &&
         safe_str_eq(async_fence_data.action, e->action)) {
 
         async_fence_data.rc = e->result;
         g_main_loop_quit(mainloop);
     }
 }
 
 static void
 fence_callback(stonith_t * stonith, stonith_callback_data_t * data)
 {
     async_fence_data.rc = data->rc;
 
     g_main_loop_quit(mainloop);
 }
 
 static gboolean
 async_fence_helper(gpointer user_data)
 {
     stonith_t *st = async_fence_data.st;
     int call_id = 0;
 
     if (try_mainloop_connect()) {
         g_main_loop_quit(mainloop);
         return TRUE;
     }
 
     st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, notify_callback);
 
     call_id = st->cmds->fence(st,
                               st_opt_allow_suicide,
                               async_fence_data.target,
                               async_fence_data.action,
                               async_fence_data.timeout, async_fence_data.tolerance);
 
     if (call_id < 0) {
         g_main_loop_quit(mainloop);
         return TRUE;
     }
 
     st->cmds->register_callback(st,
                                 call_id,
                                 async_fence_data.timeout,
                                 st_opt_timeout_updates, NULL, "callback", fence_callback);
 
     return TRUE;
 }
 
 static int
 mainloop_fencing(stonith_t * st, const char *target, const char *action, int timeout, int tolerance)
 {
     crm_trigger_t *trig;
 
     async_fence_data.st = st;
     async_fence_data.target = target;
     async_fence_data.action = action;
     async_fence_data.timeout = timeout;
     async_fence_data.tolerance = tolerance;
     async_fence_data.rc = -1;
 
     trig = mainloop_add_trigger(G_PRIORITY_HIGH, async_fence_helper, NULL);
     mainloop_set_trigger(trig);
 
     mainloop = g_main_loop_new(NULL, FALSE);
     g_main_loop_run(mainloop);
 
     return async_fence_data.rc;
 }
 
 static int
 handle_level(stonith_t *st, char *target, int fence_level,
              stonith_key_value_t *devices, bool added)
 {
     char *node = NULL;
     char *pattern = NULL;
     char *name = NULL;
     char *value = strchr(target, '=');
 
     /* Determine if targeting by attribute, node name pattern or node name */
     if (value != NULL)  {
         name = target;
         *value++ = '\0';
     } else if (*target == '@') {
         pattern = target + 1;
     } else {
         node = target;
     }
 
     /* Register or unregister level as appropriate */
     if (added) {
         return st->cmds->register_level_full(st, st_opts, node, pattern,
                                              name, value, fence_level,
                                              devices);
     }
     return st->cmds->remove_level_full(st, st_opts, node, pattern,
                                        name, value, fence_level);
 }
 
 static int
 handle_history(stonith_t *st, const char *target, int timeout, int quiet,
              int verbose, int cleanup, int broadcast, pcmk__output_t *out)
 {
     stonith_history_t *history = NULL, *hp, *latest = NULL;
     int rc = 0;
 
     if (!quiet) {
         if (cleanup) {
             out->info(out, "cleaning up fencing-history%s%s",
                       target ? " for node " : "", target ? target : "");
         }
         if (broadcast) {
             out->info(out, "gather fencing-history from all nodes");
         }
     }
 
     rc = st->cmds->history(st, st_opts | (cleanup?st_opt_cleanup:0) |
                            (broadcast?st_opt_broadcast:0),
                            (safe_str_eq(target, "*")? NULL : target),
                            &history, timeout);
 
     out->begin_list(out, "Fencing history", "event", "events");
 
     for (hp = history; hp; hp = hp->next) {
         if (hp->state == st_done) {
             latest = hp;
         }
 
         if (quiet || !verbose) {
             continue;
         }
 
         out->message(out, "stonith-event", hp);
     }
 
     if (latest) {
         if (quiet && out->supports_quiet) {
             out->info(out, "%lld", (long long) latest->completed);
         } else if (!verbose) { // already printed if verbose
             out->message(out, "stonith-event", latest);
         }
     }
 
     out->end_list(out);
 
     stonith_history_free(history);
     return rc;
 }
 
 static int
 validate(stonith_t *st, const char *agent, const char *id,
          stonith_key_value_t *params, int timeout, int quiet,
          pcmk__output_t *out)
 {
     int rc = 1;
     char *output = NULL;
     char *error_output = NULL;
 
     rc = st->cmds->validate(st, st_opt_sync_call, id, NULL, agent, params,
                             timeout, &output, &error_output);
 
     if (quiet) {
         return rc;
     }
 
     out->message(out, "validate", agent, id, output, error_output, rc); 
     return rc;
 }
 
 int
 main(int argc, char **argv)
 {
     int flag;
     int rc = 0;
     int quiet = 0;
     int cleanup = 0;
     int broadcast = 0;
     int verbose = 0;
     int argerr = 0;
     int timeout = 120;
     int option_index = 0;
     int fence_level = 0;
     int no_connect = 0;
     int tolerance = 0;
     int as_nodeid = FALSE;
     bool required_agent = false;
 
     char *name = NULL;
     char *value = NULL;
     char *target = NULL;
     char *lists = NULL;
     const char *agent = NULL;
     const char *device = NULL;
     const char *longname = NULL;
 
     char action = 0;
     crm_exit_t exit_code = CRM_EX_OK;
     stonith_t *st = NULL;
     stonith_key_value_t *params = NULL;
     stonith_key_value_t *devices = NULL;
     stonith_key_value_t *dIter = NULL;
 
     char *output_ty = NULL;
     char *output_dest = NULL;
     pcmk__output_t *out = NULL;
 
     crm_log_cli_init("stonith_admin");
     crm_set_options(NULL, "<command> [<options>]", long_options,
                     "access the Pacemaker fencing API");
 
     async_fence_data.name = strdup(crm_system_name);
 
     while (1) {
         flag = crm_get_option_long(argc, argv, &option_index, &longname);
         if (flag == -1)
             break;
 
         switch (flag) {
             case 'V':
                 verbose = 1;
                 crm_bump_log_level(argc, argv);
                 break;
             case '$':
             case '?':
                 crm_help(flag, CRM_EX_OK);
                 break;
 
             case 'K':
                 required_agent = true;
                 /* fall through */
             case 'I':
                 no_connect = 1;
                 /* fall through */
             case 'L':
                 action = flag;
                 break;
 
             case 'q':
                 quiet = 1;
                 break;
             case 'c':
                 cleanup = 1;
                 break;
             case 'b':
                 broadcast = 1;
                 break;
             case 'R':
                 required_agent = true;
                 /* fall through */
             case 'Q':
             case 'D':
             case 's':
                 action = flag;
                 device = optarg;
                 break;
             case 'T':
                 free(async_fence_data.name);
                 async_fence_data.name = crm_strdup_printf("%s.%s", crm_system_name, optarg);
                 break;
             case 'a':
                 agent = optarg;
                 break;
             case 'l':
                 target = optarg;
                 action = 'L';
                 break;
             case 'M':
                 no_connect = 1;
                 action = flag;
                 required_agent = true;
                 break;
             case 't':
                 timeout = crm_atoi(optarg, NULL);
                 break;
             case 'B':
             case 'F':
             case 'U':
                 /* using mainloop here */
                 no_connect = 1;
                 /* fall through */
             case 'C':
                 /* Always log the input arguments */
                 crm_log_args(argc, argv);
                 target = optarg;
                 action = flag;
                 break;
             case 'n':
                 as_nodeid = TRUE;
                 break;
             case 'h':
             case 'H':
             case 'r':
             case 'd':
                 target = optarg;
                 action = flag;
                 break;
             case 'i':
                 fence_level = crm_atoi(optarg, NULL);
                 break;
             case 'v':
                 devices = stonith_key_value_add(devices, NULL, optarg);
                 break;
             case 'o':
                 crm_info("Scanning: -o %s", optarg);
                 rc = pcmk_scan_nvpair(optarg, &name, &value);
 
                 if (rc != 2) {
                     crm_err("Invalid option: -o %s: %s", optarg, pcmk_strerror(rc));
                     ++argerr;
                 } else {
                     crm_info("Got: '%s'='%s'", name, value);
                     params = stonith_key_value_add(params, name, value);
                 }
                 free(value); value = NULL;
                 free(name); name = NULL;
                 break;
             case 'e':
                 {
                     char *key = crm_concat("OCF_RESKEY", optarg, '_');
                     const char *env = getenv(key);
 
                     if (env == NULL) {
                         crm_err("Invalid option: -e %s", optarg);
                         ++argerr;
                     } else {
                         crm_info("Got: '%s'='%s'", optarg, env);
                         params = stonith_key_value_add(params, optarg, env);
                     }
                     free(key);
                 }
                 break;
             case 0:
                 if (safe_str_eq("tolerance", longname)) {
                     tolerance = crm_get_msec(optarg) / 1000;    /* Send in seconds */
                 } else if (pcmk__parse_output_args(longname, optarg, &output_ty,
                                                    &output_dest) == false) {
                     fprintf(stderr, "Unknown long option used: %s\n", longname);
                     ++argerr;
                 }
 
                 break;
             default:
                 ++argerr;
                 break;
         }
     }
 
     if (optind > argc || action == 0) {
         ++argerr;
     }
 
     if (required_agent && agent == NULL) {
         fprintf(stderr, "Please specify an agent to query using -a,--agent [value]\n");
         ++argerr;
     }
 
     if (argerr) {
         crm_help('?', CRM_EX_USAGE);
     }
 
     CRM_ASSERT(pcmk__register_format("text", pcmk__mk_text_output) == 0);
     CRM_ASSERT(pcmk__register_format("xml", pcmk__mk_xml_output) == 0);
 
     rc = pcmk__output_new(&out, output_ty, output_dest, argv);
     if (rc != 0) {
         fprintf(stderr, "Error creating output format %s: %s\n", output_ty, pcmk_strerror(rc));
         exit_code = CRM_EX_ERROR;
         goto done;
     }
 
-    stonith_register_messages(out);
+    stonith__register_messages(out);
 
     st = stonith_api_new();
 
     if (!no_connect) {
         rc = st->cmds->connect(st, async_fence_data.name, NULL);
         if (rc < 0) {
             fprintf(stderr, "Could not connect to fencer: %s\n",
                     pcmk_strerror(rc));
             exit_code = CRM_EX_DISCONNECT;
             goto done;
         }
     }
 
     switch (action) {
         case 'I':
             rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout);
             if (rc < 0) {
                 fprintf(stderr, "Failed to list installed devices: %s\n", pcmk_strerror(rc));
                 break;
             }
 
             out->begin_list(out, "Installed fence devices", "fence device", "fence devices");
             for (dIter = devices; dIter; dIter = dIter->next) {
                 out->list_item(out, "device", dIter->value);
             }
 
             out->end_list(out);
             rc = 0;
 
             stonith_key_value_freeall(devices, 1, 1);
             break;
 
         case 'L':
             rc = st->cmds->query(st, st_opts, target, &devices, timeout);
             if (rc < 0) {
                 fprintf(stderr, "Failed to list registered devices: %s\n", pcmk_strerror(rc));
                 break;
             }
 
             out->begin_list(out, "Registered fence devices", "fence device", "fence devices");
             for (dIter = devices; dIter; dIter = dIter->next) {
                 out->list_item(out, "device", dIter->value);
             }
 
             out->end_list(out);
             rc = 0;
 
             stonith_key_value_freeall(devices, 1, 1);
             break;
 
         case 'Q':
             rc = st->cmds->monitor(st, st_opts, device, timeout);
             if (rc < 0) {
                 rc = st->cmds->list(st, st_opts, device, NULL, timeout);
             }
             break;
         case 's':
             rc = st->cmds->list(st, st_opts, device, &lists, timeout);
             if (rc == 0 && lists) {
                 char *head = lists;
                 char *eol = NULL;
 
                 out->begin_list(out, "Fence targets", "fence target", "fence targets");
 
                 do {
                     char *line = NULL;
                     char *elem = NULL;
 
                     char *hostname = NULL;
                     char *uuid = NULL;
                     char *status = NULL;
 
                     eol = strstr(head, "\\n");
                     line = strndup(head, eol-head);
 
                     while ((elem = strsep(&line, " ")) != NULL) {
                         if (strcmp(elem, "") == 0) {
                             continue;
                         }
 
                         if (hostname == NULL) {
                             hostname = elem;
                         } else if (uuid == NULL) {
                             uuid = elem;
                         } else if (status == NULL) {
                             char *end = NULL;
                             status = elem;
 
                             end = strchr(status, '\n');
                             if (end != NULL) {
                                 *end = '\0';
                             }
                         }
                     }
 
                     if (hostname != NULL && uuid != NULL && status != NULL) {
                         out->message(out, "fence-target", hostname, uuid, status);
                     }
 
                     free(line);
 
                     head = eol+2;
                 } while (eol != NULL);
 
                 out->end_list(out);
             } else if (rc != 0) {
                 fprintf(stderr, "List command returned error. rc : %d\n", rc);
             }
             break;
         case 'R':
             rc = st->cmds->register_device(st, st_opts, device, NULL, agent,
                                            params);
             break;
         case 'D':
             rc = st->cmds->remove_device(st, st_opts, device);
             break;
         case 'd':
         case 'r':
             rc = handle_level(st, target, fence_level, devices, action == 'r');
             break;
         case 'M':
             {
                 char *buffer = NULL;
 
                 rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer, timeout);
                 if (rc == pcmk_ok) {
                     out->output_xml(out, "metadata", buffer);
                 }
                 free(buffer);
             }
             break;
         case 'C':
             rc = st->cmds->confirm(st, st_opts, target);
             break;
         case 'B':
             rc = mainloop_fencing(st, target, "reboot", timeout, tolerance);
             break;
         case 'F':
             rc = mainloop_fencing(st, target, "off", timeout, tolerance);
             break;
         case 'U':
             rc = mainloop_fencing(st, target, "on", timeout, tolerance);
             break;
         case 'h':
             {
                 time_t when = 0;
 
                 if(as_nodeid) {
                     uint32_t nodeid = atol(target);
                     when = stonith_api_time(nodeid, NULL, FALSE);
                 } else {
                     when = stonith_api_time(0, target, FALSE);
                 }
 
                 out->message(out, "last-fenced", target, when);
             }
 
             break;
         case 'H':
             rc = handle_history(st, target, timeout, quiet,
                                 verbose, cleanup, broadcast, out);
             break;
         case 'K':
             device = (devices? devices->key : NULL);
             rc = validate(st, agent, device, params, timeout, quiet, out);
             break;
     }
 
     crm_info("Command returned: %s (%d)", pcmk_strerror(rc), rc);
     exit_code = crm_errno2exit(rc);
 
     pcmk__output_free(out, exit_code);
 
   done:
     free(async_fence_data.name);
     stonith_key_value_freeall(params, 1, 1);
 
     if (st != NULL) {
         st->cmds->disconnect(st);
         stonith_api_delete(st);
     }
 
     return exit_code;
 }