587943
From a32b6e14ba51fefbda2d4a699cf1c48dd3a1bb5a Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Thu, 7 Jan 2021 11:37:51 -0500
587943
Subject: [PATCH 01/10] Fix: tools: Don't pass stonith history to
587943
 print_simple_status.
587943
587943
It's not being used.
587943
---
587943
 tools/crm_mon.c | 7 +++----
587943
 1 file changed, 3 insertions(+), 4 deletions(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index 4555516..729f6a1 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -1,5 +1,5 @@
587943
 /*
587943
- * Copyright 2004-2020 the Pacemaker project contributors
587943
+ * Copyright 2004-2021 the Pacemaker project contributors
587943
  *
587943
  * The version control history for this file may have further details.
587943
  *
587943
@@ -1451,14 +1451,13 @@ main(int argc, char **argv)
587943
  * \brief Print one-line status suitable for use with monitoring software
587943
  *
587943
  * \param[in] data_set  Working set of CIB state
587943
- * \param[in] history   List of stonith actions
587943
  *
587943
  * \note This function's output (and the return code when the program exits)
587943
  *       should conform to https://www.monitoring-plugins.org/doc/guidelines.html
587943
  */
587943
 static void
587943
 print_simple_status(pcmk__output_t *out, pe_working_set_t * data_set,
587943
-                    stonith_history_t *history, unsigned int mon_ops)
587943
+                    unsigned int mon_ops)
587943
 {
587943
     GListPtr gIter = NULL;
587943
     int nodes_online = 0;
587943
@@ -2012,7 +2011,7 @@ mon_refresh_display(gpointer user_data)
587943
             break;
587943
 
587943
         case mon_output_monitor:
587943
-            print_simple_status(out, mon_data_set, stonith_history, options.mon_ops);
587943
+            print_simple_status(out, mon_data_set, options.mon_ops);
587943
             if (pcmk_is_set(options.mon_ops, mon_op_has_warnings)) {
587943
                 clean_up(MON_STATUS_WARN);
587943
                 return FALSE;
587943
-- 
587943
1.8.3.1
587943
587943
587943
From 8b9c47089c70295bc0529671ba5991c6d831e14b Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Thu, 7 Jan 2021 13:17:04 -0500
587943
Subject: [PATCH 02/10] Refactor: tools: Don't pass output_format to
587943
 mon_refresh_display.
587943
587943
output_format is a global variable.
587943
---
587943
 tools/crm_mon.c | 2 +-
587943
 1 file changed, 1 insertion(+), 1 deletion(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index 729f6a1..b801560 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -827,7 +827,7 @@ cib_connect(gboolean full)
587943
 
587943
         rc = cib->cmds->query(cib, NULL, &current_cib, cib_scope_local | cib_sync_call);
587943
         if (rc == pcmk_ok) {
587943
-            mon_refresh_display(&output_format);
587943
+            mon_refresh_display(NULL);
587943
         }
587943
 
587943
         if (rc == pcmk_ok && full) {
587943
-- 
587943
1.8.3.1
587943
587943
587943
From a1b14ad96f12746167da8588dc086b20e6f6d1d6 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Thu, 7 Jan 2021 13:20:14 -0500
587943
Subject: [PATCH 03/10] Refactor: tools: Remove unnecessary checks for cib !=
587943
 NULL.
587943
587943
cib is guaranteed to not be NULL at these points, so there's no need to
587943
do an additional check.  This code was leftover from a previous
587943
reorganization that changed when the cib variable gets initialized.
587943
---
587943
 tools/crm_mon.c | 41 +++++++++++++++++++----------------------
587943
 1 file changed, 19 insertions(+), 22 deletions(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index b801560..1eedd38 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -1346,7 +1346,7 @@ main(int argc, char **argv)
587943
 
587943
     /* Extra sanity checks when in CGI mode */
587943
     if (output_format == mon_output_cgi) {
587943
-        if (cib && cib->variant == cib_file) {
587943
+        if (cib->variant == cib_file) {
587943
             g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE, "CGI mode used with CIB file");
587943
             return clean_up(CRM_EX_USAGE);
587943
         } else if (options.external_agent != NULL) {
587943
@@ -1370,33 +1370,30 @@ main(int argc, char **argv)
587943
 
587943
     crm_info("Starting %s", crm_system_name);
587943
 
587943
-    if (cib) {
587943
-
587943
-        do {
587943
-            if (!pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
587943
-                print_as(output_format ,"Waiting until cluster is available on this node ...\n");
587943
-            }
587943
-            rc = cib_connect(!pcmk_is_set(options.mon_ops, mon_op_one_shot));
587943
+    do {
587943
+        if (!pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
587943
+            print_as(output_format ,"Waiting until cluster is available on this node ...\n");
587943
+        }
587943
+        rc = cib_connect(!pcmk_is_set(options.mon_ops, mon_op_one_shot));
587943
 
587943
-            if (pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
587943
-                break;
587943
+        if (pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
587943
+            break;
587943
 
587943
-            } else if (rc != pcmk_ok) {
587943
-                sleep(options.reconnect_msec / 1000);
587943
+        } else if (rc != pcmk_ok) {
587943
+            sleep(options.reconnect_msec / 1000);
587943
 #if CURSES_ENABLED
587943
-                if (output_format == mon_output_console) {
587943
-                    clear();
587943
-                    refresh();
587943
-                }
587943
+            if (output_format == mon_output_console) {
587943
+                clear();
587943
+                refresh();
587943
+            }
587943
 #endif
587943
-            } else {
587943
-                if (output_format == mon_output_html && out->dest != stdout) {
587943
-                    printf("Writing html to %s ...\n", args->output_dest);
587943
-                }
587943
+        } else {
587943
+            if (output_format == mon_output_html && out->dest != stdout) {
587943
+                printf("Writing html to %s ...\n", args->output_dest);
587943
             }
587943
+        }
587943
 
587943
-        } while (rc == -ENOTCONN);
587943
-    }
587943
+    } while (rc == -ENOTCONN);
587943
 
587943
     if (rc != pcmk_ok) {
587943
         if (output_format == mon_output_monitor) {
587943
-- 
587943
1.8.3.1
587943
587943
587943
From fe5284a12765e775905bdfe58711c5733a063132 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Thu, 7 Jan 2021 14:15:40 -0500
587943
Subject: [PATCH 04/10] Fix: tools: mon_refresh_display should return an int.
587943
587943
While GSourceFunc is defined as returning a boolean, our public API
587943
mainloop function expect the dispatch function to return an int.  So
587943
change mon_refresh_display to do so.
587943
---
587943
 tools/crm_mon.c | 12 ++++++------
587943
 1 file changed, 6 insertions(+), 6 deletions(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index 1eedd38..8657a89 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -125,7 +125,7 @@ struct {
587943
 static void clean_up_connections(void);
587943
 static crm_exit_t clean_up(crm_exit_t exit_code);
587943
 static void crm_diff_update(const char *event, xmlNode * msg);
587943
-static gboolean mon_refresh_display(gpointer user_data);
587943
+static int mon_refresh_display(gpointer user_data);
587943
 static int cib_connect(gboolean full);
587943
 static void mon_st_callback_event(stonith_t * st, stonith_event_t * e);
587943
 static void mon_st_callback_display(stonith_t * st, stonith_event_t * e);
587943
@@ -1925,7 +1925,7 @@ crm_diff_update(const char *event, xmlNode * msg)
587943
     kick_refresh(cib_updated);
587943
 }
587943
 
587943
-static gboolean
587943
+static int
587943
 mon_refresh_display(gpointer user_data)
587943
 {
587943
     xmlNode *cib_copy = copy_xml(current_cib);
587943
@@ -1940,7 +1940,7 @@ mon_refresh_display(gpointer user_data)
587943
         }
587943
         out->err(out, "Upgrade failed: %s", pcmk_strerror(-pcmk_err_schema_validation));
587943
         clean_up(CRM_EX_CONFIG);
587943
-        return FALSE;
587943
+        return 0;
587943
     }
587943
 
587943
     /* get the stonith-history if there is evidence we need it
587943
@@ -1966,7 +1966,7 @@ mon_refresh_display(gpointer user_data)
587943
         }
587943
         free_xml(cib_copy);
587943
         out->err(out, "Reading stonith-history failed");
587943
-        return FALSE;
587943
+        return 0;
587943
     }
587943
 
587943
     if (mon_data_set == NULL) {
587943
@@ -1995,7 +1995,7 @@ mon_refresh_display(gpointer user_data)
587943
                                   options.only_node, options.only_rsc) != 0) {
587943
                 g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_CANTCREAT, "Critical: Unable to output html file");
587943
                 clean_up(CRM_EX_CANTCREAT);
587943
-                return FALSE;
587943
+                return 0;
587943
             }
587943
             break;
587943
 
587943
@@ -2044,7 +2044,7 @@ mon_refresh_display(gpointer user_data)
587943
     stonith_history_free(stonith_history);
587943
     stonith_history = NULL;
587943
     pe_reset_working_set(mon_data_set);
587943
-    return TRUE;
587943
+    return 1;
587943
 }
587943
 
587943
 static void
587943
-- 
587943
1.8.3.1
587943
587943
587943
From 7f88a5a428ed73fb5161096ece2517abe1119f06 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Thu, 7 Jan 2021 16:59:02 -0500
587943
Subject: [PATCH 05/10] Refactor: tools: Change a conditional in cib_connect.
587943
587943
This allows unindenting everything that occurs inside that conditional,
587943
which I think makes it a little bit easier to understand what is going
587943
on.
587943
---
587943
 tools/crm_mon.c | 86 +++++++++++++++++++++++++++++----------------------------
587943
 1 file changed, 44 insertions(+), 42 deletions(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index 8657a89..b8ba56b 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -804,55 +804,57 @@ cib_connect(gboolean full)
587943
         }
587943
     }
587943
 
587943
-    if (cib->state != cib_connected_query && cib->state != cib_connected_command) {
587943
-        crm_trace("Connecting to the CIB");
587943
-
587943
-        /* Hack: the CIB signon will print the prompt for a password if needed,
587943
-         * but to stderr. If we're in curses, show it on the screen instead.
587943
-         *
587943
-         * @TODO Add a password prompt (maybe including input) function to
587943
-         *       pcmk__output_t and use it in libcib.
587943
-         */
587943
-        if ((output_format == mon_output_console) && need_pass && (cib->variant == cib_remote)) {
587943
-            need_pass = FALSE;
587943
-            print_as(output_format, "Password:");
587943
-        }
587943
+    if (cib->state == cib_connected_query || cib->state == cib_connected_command) {
587943
+        return rc;
587943
+    }
587943
 
587943
-        rc = cib->cmds->signon(cib, crm_system_name, cib_query);
587943
-        if (rc != pcmk_ok) {
587943
-            out->err(out, "Could not connect to the CIB: %s",
587943
-                     pcmk_strerror(rc));
587943
-            return rc;
587943
-        }
587943
+    crm_trace("Connecting to the CIB");
587943
 
587943
-        rc = cib->cmds->query(cib, NULL, &current_cib, cib_scope_local | cib_sync_call);
587943
-        if (rc == pcmk_ok) {
587943
-            mon_refresh_display(NULL);
587943
-        }
587943
+    /* Hack: the CIB signon will print the prompt for a password if needed,
587943
+     * but to stderr. If we're in curses, show it on the screen instead.
587943
+     *
587943
+     * @TODO Add a password prompt (maybe including input) function to
587943
+     *       pcmk__output_t and use it in libcib.
587943
+     */
587943
+    if ((output_format == mon_output_console) && need_pass && (cib->variant == cib_remote)) {
587943
+        need_pass = FALSE;
587943
+        print_as(output_format, "Password:");
587943
+    }
587943
 
587943
-        if (rc == pcmk_ok && full) {
587943
-            if (rc == pcmk_ok) {
587943
-                rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
587943
-                if (rc == -EPROTONOSUPPORT) {
587943
-                    print_as
587943
-                        (output_format, "Notification setup not supported, won't be able to reconnect after failure");
587943
-                    if (output_format == mon_output_console) {
587943
-                        sleep(2);
587943
-                    }
587943
-                    rc = pcmk_ok;
587943
-                }
587943
+    rc = cib->cmds->signon(cib, crm_system_name, cib_query);
587943
+    if (rc != pcmk_ok) {
587943
+        out->err(out, "Could not connect to the CIB: %s",
587943
+                 pcmk_strerror(rc));
587943
+        return rc;
587943
+    }
587943
 
587943
-            }
587943
+    rc = cib->cmds->query(cib, NULL, &current_cib, cib_scope_local | cib_sync_call);
587943
+    if (rc == pcmk_ok) {
587943
+        mon_refresh_display(NULL);
587943
+    }
587943
 
587943
-            if (rc == pcmk_ok) {
587943
-                cib->cmds->del_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
587943
-                rc = cib->cmds->add_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
587943
+    if (rc == pcmk_ok && full) {
587943
+        if (rc == pcmk_ok) {
587943
+            rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
587943
+            if (rc == -EPROTONOSUPPORT) {
587943
+                print_as
587943
+                    (output_format, "Notification setup not supported, won't be able to reconnect after failure");
587943
+                if (output_format == mon_output_console) {
587943
+                    sleep(2);
587943
+                }
587943
+                rc = pcmk_ok;
587943
             }
587943
 
587943
-            if (rc != pcmk_ok) {
587943
-                out->err(out, "Notification setup failed, could not monitor CIB actions");
587943
-                clean_up_connections();
587943
-            }
587943
+        }
587943
+
587943
+        if (rc == pcmk_ok) {
587943
+            cib->cmds->del_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
587943
+            rc = cib->cmds->add_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
587943
+        }
587943
+
587943
+        if (rc != pcmk_ok) {
587943
+            out->err(out, "Notification setup failed, could not monitor CIB actions");
587943
+            clean_up_connections();
587943
         }
587943
     }
587943
     return rc;
587943
-- 
587943
1.8.3.1
587943
587943
587943
From 178ba17e4ee62bef28f8e71cad2c002f823661b5 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Thu, 7 Jan 2021 17:37:36 -0500
587943
Subject: [PATCH 06/10] Refactor: tools: Remove an unnecessary conditional in
587943
 cib_connect.
587943
587943
---
587943
 tools/crm_mon.c | 17 +++++++----------
587943
 1 file changed, 7 insertions(+), 10 deletions(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index b8ba56b..36249e8 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -834,17 +834,14 @@ cib_connect(gboolean full)
587943
     }
587943
 
587943
     if (rc == pcmk_ok && full) {
587943
-        if (rc == pcmk_ok) {
587943
-            rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
587943
-            if (rc == -EPROTONOSUPPORT) {
587943
-                print_as
587943
-                    (output_format, "Notification setup not supported, won't be able to reconnect after failure");
587943
-                if (output_format == mon_output_console) {
587943
-                    sleep(2);
587943
-                }
587943
-                rc = pcmk_ok;
587943
+        rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
587943
+        if (rc == -EPROTONOSUPPORT) {
587943
+            print_as
587943
+                (output_format, "Notification setup not supported, won't be able to reconnect after failure");
587943
+            if (output_format == mon_output_console) {
587943
+                sleep(2);
587943
             }
587943
-
587943
+            rc = pcmk_ok;
587943
         }
587943
 
587943
         if (rc == pcmk_ok) {
587943
-- 
587943
1.8.3.1
587943
587943
587943
From 33bac5886417afc5c7bbf56f4d31e0e36f8ae947 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Fri, 8 Jan 2021 10:00:50 -0500
587943
Subject: [PATCH 07/10] Refactor: tools: Simplify another conditional in
587943
 crm_mon.
587943
587943
---
587943
 tools/crm_mon.c | 6 ++----
587943
 1 file changed, 2 insertions(+), 4 deletions(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index 36249e8..8b47bbc 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -1386,10 +1386,8 @@ main(int argc, char **argv)
587943
                 refresh();
587943
             }
587943
 #endif
587943
-        } else {
587943
-            if (output_format == mon_output_html && out->dest != stdout) {
587943
-                printf("Writing html to %s ...\n", args->output_dest);
587943
-            }
587943
+        } else if (output_format == mon_output_html && out->dest != stdout) {
587943
+            printf("Writing html to %s ...\n", args->output_dest);
587943
         }
587943
 
587943
     } while (rc == -ENOTCONN);
587943
-- 
587943
1.8.3.1
587943
587943
587943
From 40bc8b3147e7ebef4318211fa69973a8b5d32e79 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Fri, 8 Jan 2021 12:12:37 -0500
587943
Subject: [PATCH 08/10] Refactor: libcrmcommon,tools,daemons: Put common xpath
587943
 code in one place.
587943
587943
---
587943
 configure.ac                                      |  1 +
587943
 daemons/controld/controld_te_callbacks.c          | 26 +++-----------
587943
 include/crm/common/xml_internal.h                 | 14 +++++++-
587943
 lib/common/tests/Makefile.am                      |  2 +-
587943
 lib/common/tests/xpath/Makefile.am                | 29 +++++++++++++++
587943
 lib/common/tests/xpath/pcmk__xpath_node_id_test.c | 43 +++++++++++++++++++++++
587943
 lib/common/xpath.c                                | 34 +++++++++++++++++-
587943
 tools/crm_mon.c                                   | 25 ++-----------
587943
 8 files changed, 127 insertions(+), 47 deletions(-)
587943
 create mode 100644 lib/common/tests/xpath/Makefile.am
587943
 create mode 100644 lib/common/tests/xpath/pcmk__xpath_node_id_test.c
587943
587943
diff --git a/configure.ac b/configure.ac
587943
index 5959116..ce0f1fe 100644
587943
--- a/configure.ac
587943
+++ b/configure.ac
587943
@@ -1920,6 +1920,7 @@ AC_CONFIG_FILES(Makefile                                            \
587943
                 lib/common/tests/operations/Makefile                \
587943
                 lib/common/tests/strings/Makefile                   \
587943
                 lib/common/tests/utils/Makefile                     \
587943
+                lib/common/tests/xpath/Makefile                     \
587943
                 lib/cluster/Makefile                                \
587943
                 lib/cib/Makefile                                    \
587943
                 lib/gnu/Makefile                                    \
587943
diff --git a/daemons/controld/controld_te_callbacks.c b/daemons/controld/controld_te_callbacks.c
587943
index 66fc645..4e3e4e6 100644
587943
--- a/daemons/controld/controld_te_callbacks.c
587943
+++ b/daemons/controld/controld_te_callbacks.c
587943
@@ -1,5 +1,5 @@
587943
 /*
587943
- * Copyright 2004-2020 the Pacemaker project contributors
587943
+ * Copyright 2004-2021 the Pacemaker project contributors
587943
  *
587943
  * The version control history for this file may have further details.
587943
  *
587943
@@ -276,24 +276,6 @@ process_resource_updates(const char *node, xmlNode *xml, xmlNode *change,
587943
     }
587943
 }
587943
 
587943
-#define NODE_PATT "/lrm[@id="
587943
-static char *get_node_from_xpath(const char *xpath) 
587943
-{
587943
-    char *nodeid = NULL;
587943
-    char *tmp = strstr(xpath, NODE_PATT);
587943
-
587943
-    if(tmp) {
587943
-        tmp += strlen(NODE_PATT);
587943
-        tmp += 1;
587943
-
587943
-        nodeid = strdup(tmp);
587943
-        tmp = strstr(nodeid, "\'");
587943
-        CRM_ASSERT(tmp);
587943
-        tmp[0] = 0;
587943
-    }
587943
-    return nodeid;
587943
-}
587943
-
587943
 static char *extract_node_uuid(const char *xpath) 
587943
 {
587943
     char *mutable_path = strdup(xpath);
587943
@@ -522,19 +504,19 @@ te_update_diff_v2(xmlNode *diff)
587943
             process_resource_updates(ID(match), match, change, op, xpath);
587943
 
587943
         } else if (strcmp(name, XML_LRM_TAG_RESOURCES) == 0) {
587943
-            char *local_node = get_node_from_xpath(xpath);
587943
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
587943
 
587943
             process_resource_updates(local_node, match, change, op, xpath);
587943
             free(local_node);
587943
 
587943
         } else if (strcmp(name, XML_LRM_TAG_RESOURCE) == 0) {
587943
-            char *local_node = get_node_from_xpath(xpath);
587943
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
587943
 
587943
             process_lrm_resource_diff(match, local_node);
587943
             free(local_node);
587943
 
587943
         } else if (strcmp(name, XML_LRM_TAG_RSC_OP) == 0) {
587943
-            char *local_node = get_node_from_xpath(xpath);
587943
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
587943
 
587943
             process_graph_event(match, local_node);
587943
             free(local_node);
587943
diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h
587943
index 1e80bc6..d8694ee 100644
587943
--- a/include/crm/common/xml_internal.h
587943
+++ b/include/crm/common/xml_internal.h
587943
@@ -1,5 +1,5 @@
587943
 /*
587943
- * Copyright 2017-2020 the Pacemaker project contributors
587943
+ * Copyright 2017-2021 the Pacemaker project contributors
587943
  *
587943
  * The version control history for this file may have further details.
587943
  *
587943
@@ -273,4 +273,16 @@ pcmk__xe_first_attr(const xmlNode *xe)
587943
     return (xe == NULL)? NULL : xe->properties;
587943
 }
587943
 
587943
+/*!
587943
+ * \internal
587943
+ * \brief Extract the ID attribute from an XML element
587943
+ *
587943
+ * \param[in] xpath String to search
587943
+ * \param[in] node  Node to get the ID for
587943
+ *
587943
+ * \return ID attribute of \p node in xpath string \p xpath
587943
+ */
587943
+char *
587943
+pcmk__xpath_node_id(const char *xpath, const char *node);
587943
+
587943
 #endif // PCMK__XML_INTERNAL__H
587943
diff --git a/lib/common/tests/Makefile.am b/lib/common/tests/Makefile.am
587943
index 2c33cc5..4c6e8b4 100644
587943
--- a/lib/common/tests/Makefile.am
587943
+++ b/lib/common/tests/Makefile.am
587943
@@ -1 +1 @@
587943
-SUBDIRS = agents cmdline flags operations strings utils
587943
+SUBDIRS = agents cmdline flags operations strings utils xpath
587943
diff --git a/lib/common/tests/xpath/Makefile.am b/lib/common/tests/xpath/Makefile.am
587943
new file mode 100644
587943
index 0000000..7a53683
587943
--- /dev/null
587943
+++ b/lib/common/tests/xpath/Makefile.am
587943
@@ -0,0 +1,29 @@
587943
+#
587943
+# Copyright 2021 the Pacemaker project contributors
587943
+#
587943
+# The version control history for this file may have further details.
587943
+#
587943
+# This source code is licensed under the GNU General Public License version 2
587943
+# or later (GPLv2+) WITHOUT ANY WARRANTY.
587943
+#
587943
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
587943
+LDADD = $(top_builddir)/lib/common/libcrmcommon.la
587943
+
587943
+include $(top_srcdir)/mk/glib-tap.mk
587943
+
587943
+# Add each test program here.  Each test should be written as a little standalone
587943
+# program using the glib unit testing functions.  See the documentation for more
587943
+# information.
587943
+#
587943
+# https://developer.gnome.org/glib/unstable/glib-Testing.html
587943
+#
587943
+# Add "_test" to the end of all test program names to simplify .gitignore.
587943
+test_programs =	pcmk__xpath_node_id_test
587943
+
587943
+# If any extra data needs to be added to the source distribution, add it to the
587943
+# following list.
587943
+dist_test_data =
587943
+
587943
+# If any extra data needs to be used by tests but should not be added to the
587943
+# source distribution, add it to the following list.
587943
+test_data =
587943
diff --git a/lib/common/tests/xpath/pcmk__xpath_node_id_test.c b/lib/common/tests/xpath/pcmk__xpath_node_id_test.c
587943
new file mode 100644
587943
index 0000000..f6b5c10
587943
--- /dev/null
587943
+++ b/lib/common/tests/xpath/pcmk__xpath_node_id_test.c
587943
@@ -0,0 +1,43 @@
587943
+/*
587943
+ * Copyright 2021 the Pacemaker project contributors
587943
+ *
587943
+ * The version control history for this file may have further details.
587943
+ *
587943
+ * This source code is licensed under the GNU Lesser General Public License
587943
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
587943
+ */
587943
+
587943
+#include <crm_internal.h>
587943
+#include <crm/common/xml_internal.h>
587943
+
587943
+static void
587943
+empty_input(void) {
587943
+    g_assert_null(pcmk__xpath_node_id(NULL, "lrm"));
587943
+    g_assert_null(pcmk__xpath_node_id("", "lrm"));
587943
+    g_assert_null(pcmk__xpath_node_id("/blah/blah", NULL));
587943
+    g_assert_null(pcmk__xpath_node_id("/blah/blah", ""));
587943
+    g_assert_null(pcmk__xpath_node_id(NULL, NULL));
587943
+}
587943
+
587943
+static void
587943
+not_present(void) {
587943
+    g_assert_null(pcmk__xpath_node_id("/some/xpath/string[@id='xyz']", "lrm"));
587943
+    g_assert_null(pcmk__xpath_node_id("/some/xpath/containing[@id='lrm']", "lrm"));
587943
+}
587943
+
587943
+static void
587943
+present(void) {
587943
+    g_assert_cmpint(strcmp(pcmk__xpath_node_id("/some/xpath/containing/lrm[@id='xyz']", "lrm"), "xyz"), ==, 0);
587943
+    g_assert_cmpint(strcmp(pcmk__xpath_node_id("/some/other/lrm[@id='xyz']/xpath", "lrm"), "xyz"), ==, 0);
587943
+}
587943
+
587943
+int
587943
+main(int argc, char **argv)
587943
+{
587943
+    g_test_init(&argc, &argv, NULL);
587943
+
587943
+    g_test_add_func("/common/xpath/node_id/empty_input", empty_input);
587943
+    g_test_add_func("/common/xpath/node_id/not_present", not_present);
587943
+    g_test_add_func("/common/xpath/node_id/present", present);
587943
+    return g_test_run();
587943
+}
587943
diff --git a/lib/common/xpath.c b/lib/common/xpath.c
587943
index 6fa4941..7851a7c 100644
587943
--- a/lib/common/xpath.c
587943
+++ b/lib/common/xpath.c
587943
@@ -1,5 +1,5 @@
587943
 /*
587943
- * Copyright 2004-2020 the Pacemaker project contributors
587943
+ * Copyright 2004-2021 the Pacemaker project contributors
587943
  *
587943
  * The version control history for this file may have further details.
587943
  *
587943
@@ -11,6 +11,7 @@
587943
 #include <stdio.h>
587943
 #include <string.h>
587943
 #include <crm/msg_xml.h>
587943
+#include <crm/common/xml_internal.h>
587943
 #include "crmcommon_private.h"
587943
 
587943
 /*
587943
@@ -297,3 +298,34 @@ xml_get_path(xmlNode *xml)
587943
     }
587943
     return NULL;
587943
 }
587943
+
587943
+char *
587943
+pcmk__xpath_node_id(const char *xpath, const char *node)
587943
+{
587943
+    char *retval = NULL;
587943
+    char *patt = NULL;
587943
+    char *start = NULL;
587943
+    char *end = NULL;
587943
+
587943
+    if (node == NULL || xpath == NULL) {
587943
+        return retval;
587943
+    }
587943
+
587943
+    patt = crm_strdup_printf("/%s[@id=", node);
587943
+    start = strstr(xpath, patt);
587943
+
587943
+    if (!start) {
587943
+        free(patt);
587943
+        return retval;
587943
+    }
587943
+
587943
+    start += strlen(patt);
587943
+    start++;
587943
+
587943
+    end = strstr(start, "\'");
587943
+    CRM_ASSERT(end);
587943
+    retval = strndup(start, end-start);
587943
+
587943
+    free(patt);
587943
+    return retval;
587943
+}
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index 8b47bbc..ff1b86b 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -1719,25 +1719,6 @@ mon_trigger_refresh(gpointer user_data)
587943
     return FALSE;
587943
 }
587943
 
587943
-#define NODE_PATT "/lrm[@id="
587943
-static char *
587943
-get_node_from_xpath(const char *xpath)
587943
-{
587943
-    char *nodeid = NULL;
587943
-    char *tmp = strstr(xpath, NODE_PATT);
587943
-
587943
-    if(tmp) {
587943
-        tmp += strlen(NODE_PATT);
587943
-        tmp += 1;
587943
-
587943
-        nodeid = strdup(tmp);
587943
-        tmp = strstr(nodeid, "\'");
587943
-        CRM_ASSERT(tmp);
587943
-        tmp[0] = 0;
587943
-    }
587943
-    return nodeid;
587943
-}
587943
-
587943
 static void
587943
 crm_diff_update_v2(const char *event, xmlNode * msg)
587943
 {
587943
@@ -1822,19 +1803,19 @@ crm_diff_update_v2(const char *event, xmlNode * msg)
587943
             handle_rsc_op(match, node);
587943
 
587943
         } else if(strcmp(name, XML_LRM_TAG_RESOURCES) == 0) {
587943
-            char *local_node = get_node_from_xpath(xpath);
587943
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
587943
 
587943
             handle_rsc_op(match, local_node);
587943
             free(local_node);
587943
 
587943
         } else if(strcmp(name, XML_LRM_TAG_RESOURCE) == 0) {
587943
-            char *local_node = get_node_from_xpath(xpath);
587943
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
587943
 
587943
             handle_rsc_op(match, local_node);
587943
             free(local_node);
587943
 
587943
         } else if(strcmp(name, XML_LRM_TAG_RSC_OP) == 0) {
587943
-            char *local_node = get_node_from_xpath(xpath);
587943
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
587943
 
587943
             handle_rsc_op(match, local_node);
587943
             free(local_node);
587943
-- 
587943
1.8.3.1
587943
587943
587943
From b0126373d8b2a739ec5b985a7e1f530e850618d3 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Mon, 11 Jan 2021 10:20:11 -0500
587943
Subject: [PATCH 09/10] Refactor: libpacemaker: Move reduce_stonith_history
587943
 into the library.
587943
587943
And also rename it to pcmk__reduce_fence_history.  I don't see anywhere
587943
else that could use this function at the moment, but it seems too
587943
generic to keep in crm_mon.
587943
---
587943
 include/pcmki/pcmki_fence.h | 16 +++++++++++++-
587943
 lib/pacemaker/pcmk_fence.c  | 45 ++++++++++++++++++++++++++++++++++++++-
587943
 tools/crm_mon.c             | 52 +--------------------------------------------
587943
 3 files changed, 60 insertions(+), 53 deletions(-)
587943
587943
diff --git a/include/pcmki/pcmki_fence.h b/include/pcmki/pcmki_fence.h
587943
index 241d030..d4cef68 100644
587943
--- a/include/pcmki/pcmki_fence.h
587943
+++ b/include/pcmki/pcmki_fence.h
587943
@@ -1,5 +1,5 @@
587943
 /*
587943
- * Copyright 2019-2020 the Pacemaker project contributors
587943
+ * Copyright 2019-2021 the Pacemaker project contributors
587943
  *
587943
  * The version control history for this file may have further details.
587943
  *
587943
@@ -219,4 +219,18 @@ int pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent,
587943
                          const char *id, stonith_key_value_t *params,
587943
                          unsigned int timeout);
587943
 
587943
+/**
587943
+ * \brief Reduce the STONITH history
587943
+ *
587943
+ * STONITH history is reduced as follows:
587943
+ *  - The last successful action of every action-type and target is kept
587943
+ *  - For failed actions, who failed is kept
587943
+ *  - All actions in progress are kept
587943
+ *
587943
+ * \param[in] history List of STONITH actions
587943
+ *
587943
+ * \return The reduced history
587943
+ */
587943
+stonith_history_t *
587943
+pcmk__reduce_fence_history(stonith_history_t *history);
587943
 #endif
587943
diff --git a/lib/pacemaker/pcmk_fence.c b/lib/pacemaker/pcmk_fence.c
587943
index d591379..34540cc 100644
587943
--- a/lib/pacemaker/pcmk_fence.c
587943
+++ b/lib/pacemaker/pcmk_fence.c
587943
@@ -1,5 +1,5 @@
587943
 /*
587943
- * Copyright 2009-2020 the Pacemaker project contributors
587943
+ * Copyright 2009-2021 the Pacemaker project contributors
587943
  *
587943
  * The version control history for this file may have further details.
587943
  *
587943
@@ -520,3 +520,46 @@ pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent,
587943
     return rc;
587943
 }
587943
 #endif
587943
+
587943
+stonith_history_t *
587943
+pcmk__reduce_fence_history(stonith_history_t *history)
587943
+{
587943
+    stonith_history_t *new, *hp, *np;
587943
+
587943
+    if (!history) {
587943
+        return history;
587943
+    }
587943
+
587943
+    new = history;
587943
+    hp = new->next;
587943
+    new->next = NULL;
587943
+
587943
+    while (hp) {
587943
+        stonith_history_t *hp_next = hp->next;
587943
+
587943
+        hp->next = NULL;
587943
+
587943
+        for (np = new; ; np = np->next) {
587943
+            if ((hp->state == st_done) || (hp->state == st_failed)) {
587943
+                /* action not in progress */
587943
+                if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei) &&
587943
+                    pcmk__str_eq(hp->action, np->action, pcmk__str_casei) &&
587943
+                    (hp->state == np->state) &&
587943
+                    ((hp->state == st_done) ||
587943
+                     pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) {
587943
+                        /* purge older hp */
587943
+                        stonith_history_free(hp);
587943
+                        break;
587943
+                }
587943
+            }
587943
+
587943
+            if (!np->next) {
587943
+                np->next = hp;
587943
+                break;
587943
+            }
587943
+        }
587943
+        hp = hp_next;
587943
+    }
587943
+
587943
+    return new;
587943
+}
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index ff1b86b..2179f53 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -1520,56 +1520,6 @@ print_simple_status(pcmk__output_t *out, pe_working_set_t * data_set,
587943
     /* coverity[leaked_storage] False positive */
587943
 }
587943
 
587943
-/*!
587943
- * \internal
587943
- * \brief Reduce the stonith-history
587943
- *        for successful actions we keep the last of every action-type & target
587943
- *        for failed actions we record as well who had failed
587943
- *        for actions in progress we keep full track
587943
- *
587943
- * \param[in] history    List of stonith actions
587943
- *
587943
- */
587943
-static stonith_history_t *
587943
-reduce_stonith_history(stonith_history_t *history)
587943
-{
587943
-    stonith_history_t *new = history, *hp, *np;
587943
-
587943
-    if (new) {
587943
-        hp = new->next;
587943
-        new->next = NULL;
587943
-
587943
-        while (hp) {
587943
-            stonith_history_t *hp_next = hp->next;
587943
-
587943
-            hp->next = NULL;
587943
-
587943
-            for (np = new; ; np = np->next) {
587943
-                if ((hp->state == st_done) || (hp->state == st_failed)) {
587943
-                    /* action not in progress */
587943
-                    if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei) &&
587943
-                        pcmk__str_eq(hp->action, np->action, pcmk__str_casei) &&
587943
-                        (hp->state == np->state) &&
587943
-                        ((hp->state == st_done) ||
587943
-                         pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) {
587943
-                            /* purge older hp */
587943
-                            stonith_history_free(hp);
587943
-                            break;
587943
-                    }
587943
-                }
587943
-
587943
-                if (!np->next) {
587943
-                    np->next = hp;
587943
-                    break;
587943
-                }
587943
-            }
587943
-            hp = hp_next;
587943
-        }
587943
-    }
587943
-
587943
-    return new;
587943
-}
587943
-
587943
 static int
587943
 send_custom_trap(const char *node, const char *rsc, const char *task, int target_rc, int rc,
587943
                  int status, const char *desc)
587943
@@ -1935,7 +1885,7 @@ mon_refresh_display(gpointer user_data)
587943
                 if (!pcmk_is_set(options.mon_ops, mon_op_fence_full_history)
587943
                     && (output_format != mon_output_xml)) {
587943
 
587943
-                    stonith_history = reduce_stonith_history(stonith_history);
587943
+                    stonith_history = pcmk__reduce_fence_history(stonith_history);
587943
                 }
587943
                 break; /* all other cases are errors */
587943
             }
587943
-- 
587943
1.8.3.1
587943
587943
587943
From af3f1368bc76eb498c2c96b3eda9324b579c9380 Mon Sep 17 00:00:00 2001
587943
From: Chris Lumens <clumens@redhat.com>
587943
Date: Tue, 12 Jan 2021 15:46:55 -0500
587943
Subject: [PATCH 10/10] Low: tools: Adjust fencing shown indicator in crm_mon.
587943
587943
If any of the various fencing flags are set, but not all of them, no '*'
587943
will be shown next to the fencing line in the interactive change screen.
587943
This makes it seem like fencing should not be shown, and hitting 'm'
587943
should toggle the fencing display on.  However, that's not the case and
587943
hitting 'm' will actually toggle fencing off.  Hitting it again will
587943
toggle it on and the '*' will appear.
587943
587943
This is confusing, so just display the '*' if any fencing flag is set.
587943
---
587943
 tools/crm_mon.c | 5 ++++-
587943
 1 file changed, 4 insertions(+), 1 deletion(-)
587943
587943
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
587943
index 2179f53..8ec97bb 100644
587943
--- a/tools/crm_mon.c
587943
+++ b/tools/crm_mon.c
587943
@@ -984,7 +984,10 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, gpointer user_dat
587943
         print_option_help(out, 'R', pcmk_is_set(options.mon_ops, mon_op_print_clone_detail));
587943
         print_option_help(out, 'b', pcmk_is_set(options.mon_ops, mon_op_print_brief));
587943
         print_option_help(out, 'j', pcmk_is_set(options.mon_ops, mon_op_print_pending));
587943
-        print_option_help(out, 'm', pcmk_is_set(show, mon_show_fencing_all));
587943
+        print_option_help(out, 'm', pcmk_any_flags_set(show,
587943
+                                                       mon_show_fence_failed
587943
+                                                      |mon_show_fence_pending
587943
+                                                      |mon_show_fence_worked));
587943
         out->info(out, "%s", "\nToggle fields via field letter, type any other key to return");
587943
     }
587943
 
587943
-- 
587943
1.8.3.1
587943