945d2e
From 7056ae08bfa5cafeec9c454cb40aefa7553af6df Mon Sep 17 00:00:00 2001
945d2e
From: Chris Lumens <clumens@redhat.com>
945d2e
Date: Thu, 16 Jul 2020 12:53:24 -0400
945d2e
Subject: [PATCH 1/4] Fix: libcrmcommon: Set out->priv to NULL in free_priv.
945d2e
945d2e
init won't do anything if priv is not NULL, so when the private data is
945d2e
freed, also set it to NULL.  This prevents segfaults when reset is
945d2e
called.
945d2e
---
945d2e
 lib/common/output_html.c | 1 +
945d2e
 lib/common/output_log.c  | 1 +
945d2e
 lib/common/output_text.c | 1 +
945d2e
 lib/common/output_xml.c  | 1 +
945d2e
 tools/crm_mon_curses.c   | 1 +
945d2e
 5 files changed, 5 insertions(+)
945d2e
945d2e
diff --git a/lib/common/output_html.c b/lib/common/output_html.c
945d2e
index c8f0088..fc06641 100644
945d2e
--- a/lib/common/output_html.c
945d2e
+++ b/lib/common/output_html.c
945d2e
@@ -72,6 +72,7 @@ html_free_priv(pcmk__output_t *out) {
945d2e
     g_queue_free(priv->parent_q);
945d2e
     g_slist_free(priv->errors);
945d2e
     free(priv);
945d2e
+    out->priv = NULL;
945d2e
 }
945d2e
 
945d2e
 static bool
945d2e
diff --git a/lib/common/output_log.c b/lib/common/output_log.c
945d2e
index 5b45ce4..0208046 100644
945d2e
--- a/lib/common/output_log.c
945d2e
+++ b/lib/common/output_log.c
945d2e
@@ -44,6 +44,7 @@ log_free_priv(pcmk__output_t *out) {
945d2e
 
945d2e
     g_queue_free(priv->prefixes);
945d2e
     free(priv);
945d2e
+    out->priv = NULL;
945d2e
 }
945d2e
 
945d2e
 static bool
945d2e
diff --git a/lib/common/output_text.c b/lib/common/output_text.c
945d2e
index 54c409a..8f15849 100644
945d2e
--- a/lib/common/output_text.c
945d2e
+++ b/lib/common/output_text.c
945d2e
@@ -43,6 +43,7 @@ text_free_priv(pcmk__output_t *out) {
945d2e
 
945d2e
     g_queue_free(priv->parent_q);
945d2e
     free(priv);
945d2e
+    out->priv = NULL;
945d2e
 }
945d2e
 
945d2e
 static bool
945d2e
diff --git a/lib/common/output_xml.c b/lib/common/output_xml.c
945d2e
index 8565bfe..858da3f 100644
945d2e
--- a/lib/common/output_xml.c
945d2e
+++ b/lib/common/output_xml.c
945d2e
@@ -54,6 +54,7 @@ xml_free_priv(pcmk__output_t *out) {
945d2e
     g_queue_free(priv->parent_q);
945d2e
     g_slist_free(priv->errors);
945d2e
     free(priv);
945d2e
+    out->priv = NULL;
945d2e
 }
945d2e
 
945d2e
 static bool
945d2e
diff --git a/tools/crm_mon_curses.c b/tools/crm_mon_curses.c
945d2e
index d93b847..e9cc023 100644
945d2e
--- a/tools/crm_mon_curses.c
945d2e
+++ b/tools/crm_mon_curses.c
945d2e
@@ -46,6 +46,7 @@ curses_free_priv(pcmk__output_t *out) {
945d2e
 
945d2e
     g_queue_free(priv->parent_q);
945d2e
     free(priv);
945d2e
+    out->priv = NULL;
945d2e
 }
945d2e
 
945d2e
 static bool
945d2e
-- 
945d2e
1.8.3.1
945d2e
945d2e
945d2e
From 3779152993ca0e88dc407c918882568217f1b630 Mon Sep 17 00:00:00 2001
945d2e
From: Chris Lumens <clumens@redhat.com>
945d2e
Date: Thu, 16 Jul 2020 13:50:24 -0400
945d2e
Subject: [PATCH 2/4] Fix: libcrmcommon: Make reset and finish work more
945d2e
 similarly.
945d2e
945d2e
When finish is called for HTML and XML output formats, various extra
945d2e
nodes and headers are added, errors are added, etc.  None of this stuff
945d2e
happens on reset.  For the HTML format, this also means things like the
945d2e
CGI headers and title don't get added when reset is called.  Make these
945d2e
two functions much more similar.
945d2e
945d2e
Regression in 2.0.3.
945d2e
945d2e
See: rhbz#1857728
945d2e
---
945d2e
 lib/common/output_html.c | 26 ++++++++++++++++----------
945d2e
 lib/common/output_xml.c  | 30 ++++++++++++++++--------------
945d2e
 2 files changed, 32 insertions(+), 24 deletions(-)
945d2e
945d2e
diff --git a/lib/common/output_html.c b/lib/common/output_html.c
945d2e
index fc06641..6127df2 100644
945d2e
--- a/lib/common/output_html.c
945d2e
+++ b/lib/common/output_html.c
945d2e
@@ -113,18 +113,11 @@ add_error_node(gpointer data, gpointer user_data) {
945d2e
 }
945d2e
 
945d2e
 static void
945d2e
-html_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
945d2e
+finish_reset_common(pcmk__output_t *out, crm_exit_t exit_status, bool print) {
945d2e
     private_data_t *priv = out->priv;
945d2e
     htmlNodePtr head_node = NULL;
945d2e
     htmlNodePtr charset_node = NULL;
945d2e
 
945d2e
-    /* If root is NULL, html_init failed and we are being called from pcmk__output_free
945d2e
-     * in the pcmk__output_new path.
945d2e
-     */
945d2e
-    if (priv == NULL || priv->root == NULL) {
945d2e
-        return;
945d2e
-    }
945d2e
-
945d2e
     if (cgi_output && print) {
945d2e
         fprintf(out->dest, "Content-Type: text/html\n\n");
945d2e
     }
945d2e
@@ -174,6 +167,20 @@ html_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy
945d2e
     if (print) {
945d2e
         htmlDocDump(out->dest, priv->root->doc);
945d2e
     }
945d2e
+}
945d2e
+
945d2e
+static void
945d2e
+html_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
945d2e
+    private_data_t *priv = out->priv;
945d2e
+
945d2e
+    /* If root is NULL, html_init failed and we are being called from pcmk__output_free
945d2e
+     * in the pcmk__output_new path.
945d2e
+     */
945d2e
+    if (priv == NULL || priv->root == NULL) {
945d2e
+        return;
945d2e
+    }
945d2e
+
945d2e
+    finish_reset_common(out, exit_status, print);
945d2e
 
945d2e
     if (copy_dest != NULL) {
945d2e
         *copy_dest = copy_xml(priv->root);
945d2e
@@ -185,8 +192,7 @@ html_reset(pcmk__output_t *out) {
945d2e
     CRM_ASSERT(out != NULL);
945d2e
 
945d2e
     if (out->priv != NULL) {
945d2e
-        private_data_t *priv = out->priv;
945d2e
-        htmlDocDump(out->dest, priv->root->doc);
945d2e
+        finish_reset_common(out, CRM_EX_OK, true);
945d2e
     }
945d2e
 
945d2e
     html_free_priv(out);
945d2e
diff --git a/lib/common/output_xml.c b/lib/common/output_xml.c
945d2e
index 858da3f..b64a71d 100644
945d2e
--- a/lib/common/output_xml.c
945d2e
+++ b/lib/common/output_xml.c
945d2e
@@ -106,17 +106,10 @@ add_error_node(gpointer data, gpointer user_data) {
945d2e
 }
945d2e
 
945d2e
 static void
945d2e
-xml_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
945d2e
+finish_reset_common(pcmk__output_t *out, crm_exit_t exit_status, bool print) {
945d2e
     xmlNodePtr node;
945d2e
     private_data_t *priv = out->priv;
945d2e
 
945d2e
-    /* If root is NULL, xml_init failed and we are being called from pcmk__output_free
945d2e
-     * in the pcmk__output_new path.
945d2e
-     */
945d2e
-    if (priv == NULL || priv->root == NULL) {
945d2e
-        return;
945d2e
-    }
945d2e
-
945d2e
     if (legacy_xml) {
945d2e
         GSList *node = priv->errors;
945d2e
 
945d2e
@@ -148,6 +141,20 @@ xml_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_
945d2e
         fprintf(out->dest, "%s", buf);
945d2e
         free(buf);
945d2e
     }
945d2e
+}
945d2e
+
945d2e
+static void
945d2e
+xml_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
945d2e
+    private_data_t *priv = out->priv;
945d2e
+
945d2e
+    /* If root is NULL, xml_init failed and we are being called from pcmk__output_free
945d2e
+     * in the pcmk__output_new path.
945d2e
+     */
945d2e
+    if (priv == NULL || priv->root == NULL) {
945d2e
+        return;
945d2e
+    }
945d2e
+
945d2e
+    finish_reset_common(out, exit_status, print);
945d2e
 
945d2e
     if (copy_dest != NULL) {
945d2e
         *copy_dest = copy_xml(priv->root);
945d2e
@@ -156,15 +163,10 @@ xml_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_
945d2e
 
945d2e
 static void
945d2e
 xml_reset(pcmk__output_t *out) {
945d2e
-    char *buf = NULL;
945d2e
-
945d2e
     CRM_ASSERT(out != NULL);
945d2e
 
945d2e
     if (out->priv != NULL) {
945d2e
-        private_data_t *priv = out->priv;
945d2e
-        buf = dump_xml_formatted_with_text(priv->root);
945d2e
-        fprintf(out->dest, "%s", buf);
945d2e
-        free(buf);
945d2e
+        finish_reset_common(out, CRM_EX_OK, true);
945d2e
     }
945d2e
 
945d2e
     xml_free_priv(out);
945d2e
-- 
945d2e
1.8.3.1
945d2e
945d2e
945d2e
From 0f8e4ca5d9a429c934f1e91a1bdf572efd07e0db Mon Sep 17 00:00:00 2001
945d2e
From: Chris Lumens <clumens@redhat.com>
945d2e
Date: Thu, 16 Jul 2020 16:09:08 -0400
945d2e
Subject: [PATCH 3/4] Fix: tools, libcrmcommon: Reopen the output dest on
945d2e
 reset.
945d2e
945d2e
This is needed when running crm_mon as a daemon.  When we do a reset,
945d2e
we need to clear out any existing output destination and start writing
945d2e
again from the beginning.  This really only matters when the destination
945d2e
is a file.
945d2e
945d2e
The extra freopen at the end of crm_mon is to handle when crm_mon is
945d2e
killed.  We need to reset the output file to its beginning before
945d2e
calling finish.
945d2e
---
945d2e
 lib/common/output_html.c | 3 +++
945d2e
 lib/common/output_log.c  | 3 +++
945d2e
 lib/common/output_text.c | 3 +++
945d2e
 lib/common/output_xml.c  | 3 +++
945d2e
 tools/crm_mon.c          | 9 +++++++++
945d2e
 5 files changed, 21 insertions(+)
945d2e
945d2e
diff --git a/lib/common/output_html.c b/lib/common/output_html.c
945d2e
index 6127df2..6e21031 100644
945d2e
--- a/lib/common/output_html.c
945d2e
+++ b/lib/common/output_html.c
945d2e
@@ -191,6 +191,9 @@ static void
945d2e
 html_reset(pcmk__output_t *out) {
945d2e
     CRM_ASSERT(out != NULL);
945d2e
 
945d2e
+    out->dest = freopen(NULL, "w", out->dest);
945d2e
+    CRM_ASSERT(out->dest != NULL);
945d2e
+
945d2e
     if (out->priv != NULL) {
945d2e
         finish_reset_common(out, CRM_EX_OK, true);
945d2e
     }
945d2e
diff --git a/lib/common/output_log.c b/lib/common/output_log.c
945d2e
index 0208046..8422ac2 100644
945d2e
--- a/lib/common/output_log.c
945d2e
+++ b/lib/common/output_log.c
945d2e
@@ -72,6 +72,9 @@ static void
945d2e
 log_reset(pcmk__output_t *out) {
945d2e
     CRM_ASSERT(out != NULL);
945d2e
 
945d2e
+    out->dest = freopen(NULL, "w", out->dest);
945d2e
+    CRM_ASSERT(out->dest != NULL);
945d2e
+
945d2e
     log_free_priv(out);
945d2e
     log_init(out);
945d2e
 }
945d2e
diff --git a/lib/common/output_text.c b/lib/common/output_text.c
945d2e
index 8f15849..2f7e5b0 100644
945d2e
--- a/lib/common/output_text.c
945d2e
+++ b/lib/common/output_text.c
945d2e
@@ -75,6 +75,9 @@ static void
945d2e
 text_reset(pcmk__output_t *out) {
945d2e
     CRM_ASSERT(out != NULL);
945d2e
 
945d2e
+    out->dest = freopen(NULL, "w", out->dest);
945d2e
+    CRM_ASSERT(out->dest != NULL);
945d2e
+
945d2e
     text_free_priv(out);
945d2e
     text_init(out);
945d2e
 }
945d2e
diff --git a/lib/common/output_xml.c b/lib/common/output_xml.c
945d2e
index b64a71d..9f8e01b 100644
945d2e
--- a/lib/common/output_xml.c
945d2e
+++ b/lib/common/output_xml.c
945d2e
@@ -165,6 +165,9 @@ static void
945d2e
 xml_reset(pcmk__output_t *out) {
945d2e
     CRM_ASSERT(out != NULL);
945d2e
 
945d2e
+    out->dest = freopen(NULL, "w", out->dest);
945d2e
+    CRM_ASSERT(out->dest != NULL);
945d2e
+
945d2e
     if (out->priv != NULL) {
945d2e
         finish_reset_common(out, CRM_EX_OK, true);
945d2e
     }
945d2e
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
945d2e
index b2e143b..10624c1 100644
945d2e
--- a/tools/crm_mon.c
945d2e
+++ b/tools/crm_mon.c
945d2e
@@ -2014,6 +2014,10 @@ mon_refresh_display(gpointer user_data)
945d2e
             break;
945d2e
     }
945d2e
 
945d2e
+    if (options.daemonize) {
945d2e
+        out->reset(out);
945d2e
+    }
945d2e
+
945d2e
     stonith_history_free(stonith_history);
945d2e
     stonith_history = NULL;
945d2e
     pe_reset_working_set(mon_data_set);
945d2e
@@ -2179,6 +2183,11 @@ clean_up(crm_exit_t exit_code)
945d2e
      * crm_mon to be able to do so.
945d2e
      */
945d2e
     if (out != NULL) {
945d2e
+        if (options.daemonize) {
945d2e
+            out->dest = freopen(NULL, "w", out->dest);
945d2e
+            CRM_ASSERT(out->dest != NULL);
945d2e
+        }
945d2e
+
945d2e
         switch (output_format) {
945d2e
             case mon_output_cgi:
945d2e
             case mon_output_html:
945d2e
-- 
945d2e
1.8.3.1
945d2e
945d2e
945d2e
From b655c039414d2c7af77c3532222b04684ef1f3d0 Mon Sep 17 00:00:00 2001
945d2e
From: Chris Lumens <clumens@redhat.com>
945d2e
Date: Fri, 17 Jul 2020 10:58:32 -0400
945d2e
Subject: [PATCH 4/4] Fix: tools: Add the http-equiv header to crm_mon at the
945d2e
 right time.
945d2e
945d2e
This header is only getting added on termination, which is not a lot of
945d2e
help if you're running crm_mon in daemonize mode.  Putting this header
945d2e
in at the right time requires a couple changes:
945d2e
945d2e
* pcmk__html_add_header doesn't need a parent argument.  It was not
945d2e
being used in the first place.
945d2e
945d2e
* The extra_headers list in output_html.c should not be freed in the
945d2e
reset function.  This means it would get freed after every time the
945d2e
daemonized output is refreshed, which means the header would have to be
945d2e
added every time too.  extra_headers will now only be freed when the
945d2e
program exits.  This is a behavior change, but I can't see why it's
945d2e
going to be a problem.
945d2e
945d2e
* To support that, we need to copy each item in the extra_headers list
945d2e
when it gets added to the output XML document.  This prevents segfaults
945d2e
when we later free that document.
945d2e
945d2e
* handle_html_output no longer needs to exist.  That function only
945d2e
existed to add the http-equiv header at the end, which is wrong.
945d2e
---
945d2e
 include/crm/common/output.h |  5 ++---
945d2e
 lib/common/output_html.c    |  7 ++++---
945d2e
 tools/crm_mon.c             | 26 +++++++-------------------
945d2e
 3 files changed, 13 insertions(+), 25 deletions(-)
945d2e
945d2e
diff --git a/include/crm/common/output.h b/include/crm/common/output.h
945d2e
index e7c9417..186bcfe 100644
945d2e
--- a/include/crm/common/output.h
945d2e
+++ b/include/crm/common/output.h
945d2e
@@ -703,15 +703,14 @@ pcmk__output_create_html_node(pcmk__output_t *out, const char *element_name, con
945d2e
  * the following code would generate the tag "<meta http-equiv='refresh' content='19'>":
945d2e
  *
945d2e
  * \code
945d2e
- * pcmk__html_add_header(parent, "meta", "http-equiv", "refresh", "content", "19", NULL);
945d2e
+ * pcmk__html_add_header("meta", "http-equiv", "refresh", "content", "19", NULL);
945d2e
  * \endcode
945d2e
  *
945d2e
- * \param[in,out] parent The node that will be the parent of the new node.
945d2e
  * \param[in]     name   The HTML tag for the new node.
945d2e
  * \param[in]     ...    A NULL-terminated key/value list of attributes.
945d2e
  */
945d2e
 void
945d2e
-pcmk__html_add_header(xmlNodePtr parent, const char *name, ...)
945d2e
+pcmk__html_add_header(const char *name, ...)
945d2e
 G_GNUC_NULL_TERMINATED;
945d2e
 
945d2e
 #ifdef __cplusplus
945d2e
diff --git a/lib/common/output_html.c b/lib/common/output_html.c
945d2e
index 6e21031..259e412 100644
945d2e
--- a/lib/common/output_html.c
945d2e
+++ b/lib/common/output_html.c
945d2e
@@ -139,7 +139,7 @@ finish_reset_common(pcmk__output_t *out, crm_exit_t exit_status, bool print) {
945d2e
 
945d2e
     /* Add any extra header nodes the caller might have created. */
945d2e
     for (int i = 0; i < g_slist_length(extra_headers); i++) {
945d2e
-        xmlAddChild(head_node, g_slist_nth_data(extra_headers, i));
945d2e
+        xmlAddChild(head_node, xmlCopyNode(g_slist_nth_data(extra_headers, i), 1));
945d2e
     }
945d2e
 
945d2e
     /* Stylesheets are included two different ways.  The first is via a built-in
945d2e
@@ -185,6 +185,8 @@ html_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy
945d2e
     if (copy_dest != NULL) {
945d2e
         *copy_dest = copy_xml(priv->root);
945d2e
     }
945d2e
+
945d2e
+    g_slist_free_full(extra_headers, (GDestroyNotify) xmlFreeNode);
945d2e
 }
945d2e
 
945d2e
 static void
945d2e
@@ -199,7 +201,6 @@ html_reset(pcmk__output_t *out) {
945d2e
     }
945d2e
 
945d2e
     html_free_priv(out);
945d2e
-    g_slist_free_full(extra_headers, (GDestroyNotify) xmlFreeNode);
945d2e
     html_init(out);
945d2e
 }
945d2e
 
945d2e
@@ -412,7 +413,7 @@ pcmk__output_create_html_node(pcmk__output_t *out, const char *element_name, con
945d2e
 }
945d2e
 
945d2e
 void
945d2e
-pcmk__html_add_header(xmlNodePtr parent, const char *name, ...) {
945d2e
+pcmk__html_add_header(const char *name, ...) {
945d2e
     htmlNodePtr header_node;
945d2e
     va_list ap;
945d2e
 
945d2e
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
945d2e
index 10624c1..7fd2b9c 100644
945d2e
--- a/tools/crm_mon.c
945d2e
+++ b/tools/crm_mon.c
945d2e
@@ -1346,6 +1346,12 @@ main(int argc, char **argv)
945d2e
         options.mon_ops |= mon_op_print_timing | mon_op_inactive_resources;
945d2e
     }
945d2e
 
945d2e
+    if ((output_format == mon_output_html || output_format == mon_output_cgi) &&
945d2e
+        out->dest != stdout) {
945d2e
+        pcmk__html_add_header("meta", "http-equiv", "refresh", "content",
945d2e
+                              crm_itoa(options.reconnect_msec/1000), NULL);
945d2e
+    }
945d2e
+
945d2e
     crm_info("Starting %s", crm_system_name);
945d2e
 
945d2e
     if (cib) {
945d2e
@@ -2106,15 +2112,6 @@ clean_up_connections(void)
945d2e
     }
945d2e
 }
945d2e
 
945d2e
-static void
945d2e
-handle_html_output(crm_exit_t exit_code) {
945d2e
-    xmlNodePtr html = NULL;
945d2e
-
945d2e
-    pcmk__html_add_header(html, "meta", "http-equiv", "refresh", "content",
945d2e
-                          crm_itoa(options.reconnect_msec/1000), NULL);
945d2e
-    out->finish(out, exit_code, true, (void **) &html);
945d2e
-}
945d2e
-
945d2e
 /*
945d2e
  * De-init ncurses, disconnect from the CIB manager, disconnect fencing,
945d2e
  * deallocate memory and show usage-message if requested.
945d2e
@@ -2188,16 +2185,7 @@ clean_up(crm_exit_t exit_code)
945d2e
             CRM_ASSERT(out->dest != NULL);
945d2e
         }
945d2e
 
945d2e
-        switch (output_format) {
945d2e
-            case mon_output_cgi:
945d2e
-            case mon_output_html:
945d2e
-                handle_html_output(exit_code);
945d2e
-                break;
945d2e
-
945d2e
-            default:
945d2e
-                out->finish(out, exit_code, true, NULL);
945d2e
-                break;
945d2e
-        }
945d2e
+        out->finish(out, exit_code, true, NULL);
945d2e
 
945d2e
         pcmk__output_free(out);
945d2e
         pcmk__unregister_formats();
945d2e
-- 
945d2e
1.8.3.1
945d2e