diff --git a/daemons/attrd/attrd_alerts.c b/daemons/attrd/attrd_alerts.c
index 3e4fd42127..55cb477c22 100644
--- a/daemons/attrd/attrd_alerts.c
+++ b/daemons/attrd/attrd_alerts.c
@@ -1,135 +1,135 @@
 /*
  * Copyright 2015-2024 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 <crm/crm.h>
 #include <crm/cib/internal.h>
 #include <crm/cluster/internal.h>
 #include <crm/cluster/election_internal.h>
 #include <crm/common/alerts_internal.h>
 #include <crm/common/cib_internal.h>
 #include <crm/common/xml.h>
 #include <crm/lrmd_internal.h>
 #include "pacemaker-attrd.h"
 
 static GList *attrd_alert_list = NULL;
 
 static void
 attrd_lrmd_callback(lrmd_event_data_t * op)
 {
     CRM_CHECK(op != NULL, return);
     switch (op->type) {
         case lrmd_event_disconnect:
             crm_info("Lost connection to executor");
             attrd_lrmd_disconnect();
             break;
         default:
             break;
     }
 }
 
 static lrmd_t *
 attrd_lrmd_connect(void)
 {
     if (the_lrmd == NULL) {
         the_lrmd = lrmd_api_new();
         the_lrmd->cmds->set_callback(the_lrmd, attrd_lrmd_callback);
     }
 
     if (!the_lrmd->cmds->is_connected(the_lrmd)) {
         const unsigned int max_attempts = 10;
         int ret = -ENOTCONN;
 
         for (int fails = 0; fails < max_attempts; ++fails) {
             ret = the_lrmd->cmds->connect(the_lrmd, PCMK__VALUE_ATTRD, NULL);
             if (ret == pcmk_ok) {
                 break;
             }
 
             crm_debug("Could not connect to executor, %d tries remaining",
                       (max_attempts - fails));
             /* @TODO We don't want to block here with sleep, but we should wait
              * some time between connection attempts. We could possibly add a
              * timer with a callback, but then we'd likely need an alert queue.
              */
         }
 
         if (ret != pcmk_ok) {
             attrd_lrmd_disconnect();
         }
     }
 
     return the_lrmd;
 }
 
 void
 attrd_lrmd_disconnect(void) {
     if (the_lrmd) {
         lrmd_t *conn = the_lrmd;
 
         the_lrmd = NULL; /* in case we're called recursively */
         lrmd_api_delete(conn); /* will disconnect if necessary */
     }
 }
 
 static void
 config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     xmlNode *crmalerts = NULL;
 
     if (rc == -ENXIO) {
         crm_debug("Local CIB has no alerts section");
         return;
     } else if (rc != pcmk_ok) {
         crm_notice("Could not query local CIB: %s", pcmk_strerror(rc));
         return;
     }
 
     crmalerts = output;
     if ((crmalerts != NULL) && !pcmk__xe_is(crmalerts, PCMK_XE_ALERTS)) {
         crmalerts = pcmk__xe_first_child(crmalerts, PCMK_XE_ALERTS, NULL, NULL);
     }
     if (!crmalerts) {
         crm_notice("CIB query result has no " PCMK_XE_ALERTS " section");
         return;
     }
 
-    pe_free_alert_list(attrd_alert_list);
+    pcmk__free_alerts(attrd_alert_list);
     attrd_alert_list = pcmk__unpack_alerts(crmalerts);
 }
 
 gboolean
 attrd_read_options(gpointer user_data)
 {
     int call_id;
 
     CRM_CHECK(the_cib != NULL, return TRUE);
 
     call_id = the_cib->cmds->query(the_cib,
                                    pcmk__cib_abs_xpath_for(PCMK_XE_ALERTS),
                                    NULL, cib_xpath);
 
     the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, NULL,
                                           "config_query_callback",
                                           config_query_callback, free);
 
     crm_trace("Querying the CIB... call %d", call_id);
     return TRUE;
 }
 
 int
 attrd_send_attribute_alert(const char *node, int nodeid,
                            const char *attr, const char *value)
 {
     if (attrd_alert_list == NULL) {
         return pcmk_ok;
     }
     return lrmd_send_attribute_alert(attrd_lrmd_connect(), attrd_alert_list,
                                      node, nodeid, attr, value);
 }
diff --git a/daemons/controld/controld_alerts.c b/daemons/controld/controld_alerts.c
index 35531fc464..2d364fb619 100644
--- a/daemons/controld/controld_alerts.c
+++ b/daemons/controld/controld_alerts.c
@@ -1,88 +1,88 @@
 /*
  * Copyright 2012-2024 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 <glib.h>
 #include <libxml/tree.h>
 
 #include <crm/common/alerts_internal.h>
 #include <crm/fencing/internal.h>
 #include <crm/lrmd.h>
 #include <crm/lrmd_internal.h>
 #include <crm/pengine/status.h>
 #include <crm/stonith-ng.h>
 
 #include <pacemaker-controld.h>
 
 static GList *crmd_alert_list = NULL;
 
 void
 crmd_unpack_alerts(xmlNode *alerts)
 {
-    pe_free_alert_list(crmd_alert_list);
+    pcmk__free_alerts(crmd_alert_list);
     crmd_alert_list = pcmk__unpack_alerts(alerts);
 }
 
 void
 crmd_alert_node_event(pcmk__node_status_t *node)
 {
     lrm_state_t *lrm_state;
 
     if (crmd_alert_list == NULL) {
         return;
     }
 
     lrm_state = controld_get_executor_state(NULL, false);
     if (lrm_state == NULL) {
         return;
     }
 
     lrmd_send_node_alert((lrmd_t *) lrm_state->conn, crmd_alert_list,
                          node->name, node->cluster_layer_id, node->state);
 }
 
 void
 crmd_alert_fencing_op(stonith_event_t * e)
 {
     char *desc;
     lrm_state_t *lrm_state;
 
     if (crmd_alert_list == NULL) {
         return;
     }
 
     lrm_state = controld_get_executor_state(NULL, false);
     if (lrm_state == NULL) {
         return;
     }
 
     desc = stonith__event_description(e);
     lrmd_send_fencing_alert((lrmd_t *) lrm_state->conn, crmd_alert_list,
                             e->target, e->operation, desc, e->result);
     free(desc);
 }
 
 void
 crmd_alert_resource_op(const char *node, lrmd_event_data_t * op)
 {
     lrm_state_t *lrm_state;
 
     if (crmd_alert_list == NULL) {
         return;
     }
 
     lrm_state = controld_get_executor_state(NULL, false);
     if (lrm_state == NULL) {
         return;
     }
 
     lrmd_send_resource_alert((lrmd_t *) lrm_state->conn, crmd_alert_list, node,
                              op);
 }
diff --git a/include/crm/common/alerts_internal.h b/include/crm/common/alerts_internal.h
index 0c987a67fa..359fca2086 100644
--- a/include/crm/common/alerts_internal.h
+++ b/include/crm/common/alerts_internal.h
@@ -1,105 +1,105 @@
 /*
  * Copyright 2015-2024 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.
  */
 
 #ifndef PCMK__CRM_COMMON_ALERTS_INTERNAL__H
 #define PCMK__CRM_COMMON_ALERTS_INTERNAL__H
 
 #include <stdbool.h>
 #include <stdint.h>         // uint32_t
 
 #include <glib.h>           // GList, GHashTable
 #include <libxml/tree.h>    // xmlNode
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /* Default-Timeout to use before killing a alerts script (in milliseconds) */
 #define PCMK__ALERT_DEFAULT_TIMEOUT_MS (30000)
 
 /* Default-Format-String used to pass timestamps to the alerts scripts */
 #define PCMK__ALERT_DEFAULT_TSTAMP_FORMAT "%H:%M:%S.%06N"
 
 enum pcmk__alert_flags {
     pcmk__alert_none         = 0,
     pcmk__alert_node         = (1 << 0),
     pcmk__alert_fencing      = (1 << 1),
     pcmk__alert_resource     = (1 << 2),
     pcmk__alert_attribute    = (1 << 3),
     pcmk__alert_default      = pcmk__alert_node|pcmk__alert_fencing|
                                pcmk__alert_resource,
 };
 
 typedef struct {
     char *id;
     char *path;
     char *tstamp_format;
     char *recipient;
     char **select_attribute_name;
     GHashTable *envvars;
     int timeout;
     uint32_t flags;
 } pcmk__alert_t;
 
 enum pcmk__alert_keys_e {
     PCMK__alert_key_recipient = 0,
     PCMK__alert_key_node,
     PCMK__alert_key_nodeid,
     PCMK__alert_key_rsc,
     PCMK__alert_key_task,
     PCMK__alert_key_interval,
     PCMK__alert_key_desc,
     PCMK__alert_key_status,
     PCMK__alert_key_target_rc,
     PCMK__alert_key_rc,
     PCMK__alert_key_kind,
     PCMK__alert_key_version,
     PCMK__alert_key_node_sequence,
     PCMK__alert_key_timestamp,
     PCMK__alert_key_attribute_name,
     PCMK__alert_key_attribute_value,
     PCMK__alert_key_timestamp_epoch,
     PCMK__alert_key_timestamp_usec,
     PCMK__alert_key_exec_time,
     PCMK__alert_key_select_kind,
     PCMK__alert_key_select_attribute_name
 };
 
 #define PCMK__ALERT_INTERNAL_KEY_MAX 19
 #define PCMK__ALERT_NODE_SEQUENCE "CRM_alert_node_sequence"
 
 extern const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX];
 
 pcmk__alert_t *pcmk__dup_alert(const pcmk__alert_t *entry);
 pcmk__alert_t *pcmk__alert_new(const char *id, const char *path);
 void pcmk__free_alert(pcmk__alert_t *entry);
 void pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name,
                          const char *value);
 void pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name,
                              int value);
 GList *pcmk__unpack_alerts(const xmlNode *alerts);
-void pe_free_alert_list(GList *alert_list);
+void pcmk__free_alerts(GList *alert_list);
 
 static inline const char *
 pcmk__alert_flag2text(enum pcmk__alert_flags flag)
 {
     switch (flag) {
         case pcmk__alert_node:      return "node";
         case pcmk__alert_fencing:   return "fencing";
         case pcmk__alert_resource:  return "resource";
         case pcmk__alert_attribute: return "attribute";
         default:                    return "unknown";
     }
 }
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif // PCMK__CRM_COMMON_ALERTS_INTERNAL__H
diff --git a/lib/common/alerts.c b/lib/common/alerts.c
index c3b264c6f4..d9e18f4d09 100644
--- a/lib/common/alerts.c
+++ b/lib/common/alerts.c
@@ -1,437 +1,437 @@
 /*
  * Copyright 2015-2024 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 <crm_internal.h>
 #include <crm/crm.h>
 #include <crm/lrmd.h>
 #include <crm/common/xml.h>
 #include <crm/common/alerts_internal.h>
 #include <crm/common/cib_internal.h>
 #include <crm/common/xml_internal.h>
 
 const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX] = {
     [PCMK__alert_key_recipient] = "CRM_alert_recipient",
     [PCMK__alert_key_node] = "CRM_alert_node",
     [PCMK__alert_key_nodeid] = "CRM_alert_nodeid",
     [PCMK__alert_key_rsc] = "CRM_alert_rsc",
     [PCMK__alert_key_task] = "CRM_alert_task",
     [PCMK__alert_key_interval] = "CRM_alert_interval",
     [PCMK__alert_key_desc] = "CRM_alert_desc",
     [PCMK__alert_key_status] = "CRM_alert_status",
     [PCMK__alert_key_target_rc] = "CRM_alert_target_rc",
     [PCMK__alert_key_rc] = "CRM_alert_rc",
     [PCMK__alert_key_kind] = "CRM_alert_kind",
     [PCMK__alert_key_version] = "CRM_alert_version",
     [PCMK__alert_key_node_sequence] = PCMK__ALERT_NODE_SEQUENCE,
     [PCMK__alert_key_timestamp] = "CRM_alert_timestamp",
     [PCMK__alert_key_attribute_name] = "CRM_alert_attribute_name",
     [PCMK__alert_key_attribute_value] = "CRM_alert_attribute_value",
     [PCMK__alert_key_timestamp_epoch] = "CRM_alert_timestamp_epoch",
     [PCMK__alert_key_timestamp_usec] = "CRM_alert_timestamp_usec",
     [PCMK__alert_key_exec_time] = "CRM_alert_exec_time",
 };
 
 /*!
  * \brief Create a new alert entry structure
  *
  * \param[in] id  ID to use
  * \param[in] path  Path to alert agent executable
  *
  * \return Pointer to newly allocated alert entry
  * \note Non-string fields will be filled in with defaults.
  *       It is the caller's responsibility to free the result,
  *       using pcmk__free_alert().
  */
 pcmk__alert_t *
 pcmk__alert_new(const char *id, const char *path)
 {
     pcmk__alert_t *entry = pcmk__assert_alloc(1, sizeof(pcmk__alert_t));
 
     pcmk__assert((id != NULL) && (path != NULL));
     entry->id = pcmk__str_copy(id);
     entry->path = pcmk__str_copy(path);
     entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
     entry->flags = pcmk__alert_default;
     return entry;
 }
 
 void
 pcmk__free_alert(pcmk__alert_t *entry)
 {
     if (entry) {
         free(entry->id);
         free(entry->path);
         free(entry->tstamp_format);
         free(entry->recipient);
 
         g_strfreev(entry->select_attribute_name);
         if (entry->envvars) {
             g_hash_table_destroy(entry->envvars);
         }
         free(entry);
     }
 }
 
 /*!
  * \internal
  * \brief Duplicate an alert entry
  *
  * \param[in] entry  Alert entry to duplicate
  *
  * \return Duplicate of alert entry
  */
 pcmk__alert_t *
 pcmk__dup_alert(const pcmk__alert_t *entry)
 {
     pcmk__alert_t *new_entry = pcmk__alert_new(entry->id, entry->path);
 
     new_entry->timeout = entry->timeout;
     new_entry->flags = entry->flags;
     new_entry->envvars = pcmk__str_table_dup(entry->envvars);
     new_entry->tstamp_format = pcmk__str_copy(entry->tstamp_format);
     new_entry->recipient = pcmk__str_copy(entry->recipient);
     if (entry->select_attribute_name) {
         new_entry->select_attribute_name = g_strdupv(entry->select_attribute_name);
     }
     return new_entry;
 }
 
 void
 pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name,
                     const char *value)
 {
     pcmk__assert((table != NULL) && (name >= 0)
                  && (name < PCMK__ALERT_INTERNAL_KEY_MAX));
     if (value == NULL) {
         crm_trace("Removing alert key %s", pcmk__alert_keys[name]);
         g_hash_table_remove(table, pcmk__alert_keys[name]);
     } else {
         crm_trace("Inserting alert key %s = '%s'",
                   pcmk__alert_keys[name], value);
         pcmk__insert_dup(table, pcmk__alert_keys[name], value);
     }
 }
 
 void
 pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name,
                         int value)
 {
     pcmk__assert((table != NULL) && (name >= 0)
                  && (name < PCMK__ALERT_INTERNAL_KEY_MAX));
     crm_trace("Inserting alert key %s = %d", pcmk__alert_keys[name], value);
     g_hash_table_insert(table, pcmk__str_copy(pcmk__alert_keys[name]),
                         pcmk__itoa(value));
 }
 
 #define READABLE_DEFAULT pcmk__readable_interval(PCMK__ALERT_DEFAULT_TIMEOUT_MS)
 
 /*!
  * \internal
  * \brief Unpack options for an alert or alert recipient from its
  *        meta-attributes in the CIB XML configuration
  *
  * \param[in,out] xml          Alert or recipient XML
  * \param[in,out] entry        Where to store unpacked values
  * \param[in,out] max_timeout  Max timeout of all alerts and recipients thus far
  *
  * \return Standard Pacemaker return code
  */
 static int
 unpack_alert_options(xmlNode *xml, pcmk__alert_t *entry, guint *max_timeout)
 {
     GHashTable *config_hash = pcmk__strkey_table(free, free);
     crm_time_t *now = crm_time_new(NULL);
     const char *value = NULL;
     int rc = pcmk_rc_ok;
 
     pcmk_rule_input_t rule_input = {
         .now = now,
     };
 
     pcmk_unpack_nvpair_blocks(xml, PCMK_XE_META_ATTRIBUTES, NULL, &rule_input,
                               config_hash, NULL);
     crm_time_free(now);
 
     value = g_hash_table_lookup(config_hash, PCMK_META_ENABLED);
     if ((value != NULL) && !crm_is_true(value)) {
         // No need to continue unpacking
         rc = pcmk_rc_disabled;
         goto done;
     }
 
     value = g_hash_table_lookup(config_hash, PCMK_META_TIMEOUT);
     if (value != NULL) {
         long long timeout_ms = crm_get_msec(value);
 
         entry->timeout = (int) QB_MIN(timeout_ms, INT_MAX);
         if (entry->timeout <= 0) {
             if (entry->timeout == 0) {
                 crm_trace("Alert %s uses default timeout (%s)",
                           entry->id, READABLE_DEFAULT);
             } else {
                 pcmk__config_warn("Using default timeout (%s) for alert %s "
                                   "because '%s' is not a valid timeout",
                                   entry->id, value, READABLE_DEFAULT);
             }
             entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
         } else {
             crm_trace("Alert %s uses timeout of %s",
                       entry->id, pcmk__readable_interval(entry->timeout));
         }
         if (entry->timeout > *max_timeout) {
             *max_timeout = entry->timeout;
         }
     }
     value = g_hash_table_lookup(config_hash, PCMK_META_TIMESTAMP_FORMAT);
     if (value != NULL) {
         /* hard to do any checks here as merely anything can
          * can be a valid time-format-string
          */
         entry->tstamp_format = strdup(value);
         crm_trace("Alert %s uses timestamp format '%s'",
                   entry->id, entry->tstamp_format);
     }
 
 done:
     g_hash_table_destroy(config_hash);
     return rc;
 }
 
 /*!
  * \internal
  * \brief Unpack agent parameters for an alert or alert recipient into an
  *        environment variable list based on its CIB XML configuration
  *
  * \param[in]     xml    Alert or recipient XML
  * \param[in,out] entry  Alert entry to create environment variables for
  */
 static void
 unpack_alert_parameters(const xmlNode *xml, pcmk__alert_t *entry)
 {
     xmlNode *child;
 
     if ((xml == NULL) || (entry == NULL)) {
         return;
     }
 
     child = pcmk__xe_first_child(xml, PCMK_XE_INSTANCE_ATTRIBUTES, NULL,
                                  NULL);
     if (child == NULL) {
         return;
     }
 
     if (entry->envvars == NULL) {
         entry->envvars = pcmk__strkey_table(free, free);
     }
 
     for (child = pcmk__xe_first_child(child, PCMK_XE_NVPAIR, NULL, NULL);
          child != NULL; child = pcmk__xe_next(child, PCMK_XE_NVPAIR)) {
 
         const char *name = crm_element_value(child, PCMK_XA_NAME);
         const char *value = crm_element_value(child, PCMK_XA_VALUE);
 
         if (value == NULL) {
             value = "";
         }
         pcmk__insert_dup(entry->envvars, name, value);
         crm_trace("Alert %s: added environment variable %s='%s'",
                   entry->id, name, value);
     }
 }
 
 /*!
  * \internal
  * \brief Create filters for an alert or alert recipient based on its
  *        configuration in CIB XML
  *
  * \param[in]     xml    Alert or recipient XML
  * \param[in,out] entry  Alert entry to create filters for
  */
 static void
 unpack_alert_filter(xmlNode *xml, pcmk__alert_t *entry)
 {
     xmlNode *select = pcmk__xe_first_child(xml, PCMK_XE_SELECT, NULL, NULL);
     xmlNode *event_type = NULL;
     uint32_t flags = pcmk__alert_none;
 
     for (event_type = pcmk__xe_first_child(select, NULL, NULL, NULL);
          event_type != NULL; event_type = pcmk__xe_next(event_type, NULL)) {
 
         if (pcmk__xe_is(event_type, PCMK_XE_SELECT_FENCING)) {
             flags |= pcmk__alert_fencing;
 
         } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_NODES)) {
             flags |= pcmk__alert_node;
 
         } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_RESOURCES)) {
             flags |= pcmk__alert_resource;
 
         } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_ATTRIBUTES)) {
             xmlNode *attr;
             const char *attr_name;
             int nattrs = 0;
 
             flags |= pcmk__alert_attribute;
             for (attr = pcmk__xe_first_child(event_type, PCMK_XE_ATTRIBUTE,
                                              NULL, NULL);
                  attr != NULL; attr = pcmk__xe_next(attr, PCMK_XE_ATTRIBUTE)) {
 
                 attr_name = crm_element_value(attr, PCMK_XA_NAME);
                 if (attr_name) {
                     if (nattrs == 0) {
                         g_strfreev(entry->select_attribute_name);
                         entry->select_attribute_name = NULL;
                     }
                     ++nattrs;
                     entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
                                                                  (nattrs + 1) * sizeof(char*));
                     entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
                     entry->select_attribute_name[nattrs] = NULL;
                 }
             }
         }
     }
 
     if (flags != pcmk__alert_none) {
         entry->flags = flags;
         crm_debug("Alert %s receives events: attributes:%s%s%s%s",
                   entry->id,
                   (pcmk_is_set(flags, pcmk__alert_attribute)?
                    (entry->select_attribute_name? "some" : "all") : "none"),
                   (pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
                   (pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
                   (pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
     }
 }
 
 /*!
  * \internal
  * \brief Unpack an alert or an alert recipient
  *
  * \param[in,out] alert        Alert or recipient XML
  * \param[in,out] entry        Where to store unpacked values
  * \param[in,out] max_timeout  Max timeout of all alerts and recipients thus far
  *
  * \return Standard Pacemaker return code
  */
 static int
 unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
 {
     int rc = pcmk_rc_ok;
 
     unpack_alert_parameters(alert, entry);
     rc = unpack_alert_options(alert, entry, max_timeout);
     if (rc == pcmk_rc_ok) {
         unpack_alert_filter(alert, entry);
     }
     return rc;
 }
 
 /*!
  * \internal
  * \brief Unpack a CIB alerts section into a list of alert entries
  *
  * \param[in] alerts  XML of CIB alerts section
  *
  * \return List of unpacked alert entries
  */
 GList *
 pcmk__unpack_alerts(const xmlNode *alerts)
 {
     xmlNode *alert;
     pcmk__alert_t *entry;
     guint max_timeout = 0U;
     GList *alert_list = NULL;
 
     for (alert = pcmk__xe_first_child(alerts, PCMK_XE_ALERT, NULL, NULL);
          alert != NULL; alert = pcmk__xe_next(alert, PCMK_XE_ALERT)) {
 
         xmlNode *recipient = NULL;
         int recipients = 0;
         const char *alert_id = pcmk__xe_id(alert);
         const char *alert_path = crm_element_value(alert, PCMK_XA_PATH);
 
         // Not possible with schema validation enabled
         if (alert_id == NULL) {
             pcmk__config_err("Ignoring invalid alert without " PCMK_XA_ID);
             continue;
         }
         if (alert_path == NULL) {
             pcmk__config_err("Ignoring invalid alert %s without " PCMK_XA_PATH,
                              alert_id);
             continue;
         }
 
         entry = pcmk__alert_new(alert_id, alert_path);
 
         if (unpack_alert(alert, entry, &max_timeout) != pcmk_rc_ok) {
             // Don't allow recipients to override if entire alert is disabled
             crm_debug("Alert %s is disabled", entry->id);
             pcmk__free_alert(entry);
             continue;
         }
 
         if (entry->tstamp_format == NULL) {
             entry->tstamp_format =
                 pcmk__str_copy(PCMK__ALERT_DEFAULT_TSTAMP_FORMAT);
         }
 
         crm_debug("Alert %s: path=%s timeout=%s tstamp-format='%s'",
                   entry->id, entry->path,
                   pcmk__readable_interval(entry->timeout),
                   entry->tstamp_format);
 
         for (recipient = pcmk__xe_first_child(alert, PCMK_XE_RECIPIENT, NULL,
                                               NULL);
              recipient != NULL;
              recipient = pcmk__xe_next(recipient, PCMK_XE_RECIPIENT)) {
 
             pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
 
             recipients++;
             recipient_entry->recipient = crm_element_value_copy(recipient,
                                                                 PCMK_XA_VALUE);
 
             if (unpack_alert(recipient, recipient_entry,
                              &max_timeout) != pcmk_rc_ok) {
                 crm_debug("Alert %s: recipient %s is disabled",
                           entry->id, recipient_entry->id);
                 pcmk__free_alert(recipient_entry);
                 continue;
             }
             alert_list = g_list_prepend(alert_list, recipient_entry);
             crm_debug("Alert %s has recipient %s with value %s and %d envvars",
                       entry->id, pcmk__xe_id(recipient),
                       recipient_entry->recipient,
                       (recipient_entry->envvars?
                        g_hash_table_size(recipient_entry->envvars) : 0));
         }
 
         if (recipients == 0) {
             alert_list = g_list_prepend(alert_list, entry);
         } else { // Recipients were prepended individually above
             pcmk__free_alert(entry);
         }
     }
     return alert_list;
 }
 
 /*!
  * \internal
  * \brief Free an alert list generated by pcmk__unpack_alerts()
  *
  * \param[in,out] alert_list  Alert list to free
  */
 void
-pe_free_alert_list(GList *alert_list)
+pcmk__free_alerts(GList *alert_list)
 {
-    if (alert_list) {
+    if (alert_list != NULL) {
         g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
     }
 }