File pacemaker#3361-0002-Fix-libcrmcommon-pcmk__xml_read-recovery-works-for-s.patch of Package pacemaker

From 0c8ad521a48561ebbb81967552eaa74c65a1aa5a Mon Sep 17 00:00:00 2001
From: Reid Wahl <nrwahl@protonmail.com>
Date: Fri, 9 Feb 2024 12:43:28 -0800
Subject: [PATCH 2/2] Fix: libcrmcommon: pcmk__xml_read() recovery works for
 stdin

Regression introduced in 2.1.7 by 596297a.

Previously, if pcmk__xml_read() was called with an argument of NULL or
"-", we told libxml2 to read from stdin's file descriptor and parse XML
from it. If this failed, we tried the same thing again.

The problem is that the data from stdin has already been read and
discarded on the first attempt. So the second attempt with
XML_PARSE_RECOVER finds an empty document.

Signed-off-by: Reid Wahl <nrwahl@protonmail.com>
---
 lib/common/xml.c | 67 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 45 insertions(+), 22 deletions(-)

Index: pacemaker-2.1.7+20231219.0f7f88312/lib/common/xml.c
===================================================================
--- pacemaker-2.1.7+20231219.0f7f88312.orig/lib/common/xml.c
+++ pacemaker-2.1.7+20231219.0f7f88312/lib/common/xml.c
@@ -867,32 +867,44 @@ string2xml(const char *input)
     return xml;
 }
 
-xmlNode *
-stdin2xml(void)
+/*!
+ * \internal
+ * \brief Read from \c stdin until EOF or error
+ *
+ * \return Newly allocated string containing the bytes read from \c stdin, or
+ *         \c NULL on error
+ *
+ * \note The caller is responsible for freeing the return value using \c free().
+ */
+static char *
+read_stdin(void)
 {
-    size_t data_length = 0;
-    size_t read_chars = 0;
-
-    char *xml_buffer = NULL;
-    xmlNode *xml_obj = NULL;
+    char *buf = NULL;
+    size_t length = 0;
 
     do {
-        xml_buffer = pcmk__realloc(xml_buffer, data_length + PCMK__BUFFER_SIZE);
-        read_chars = fread(xml_buffer + data_length, 1, PCMK__BUFFER_SIZE,
-                           stdin);
-        data_length += read_chars;
-    } while (read_chars == PCMK__BUFFER_SIZE);
-
-    if (data_length == 0) {
-        crm_warn("No XML supplied on stdin");
-        free(xml_buffer);
-        return NULL;
+        buf = pcmk__realloc(buf, length + PCMK__BUFFER_SIZE + 1);
+        length += fread(buf + length, 1, PCMK__BUFFER_SIZE, stdin);
+    } while ((feof(stdin) == 0) && (ferror(stdin) == 0));
+
+    if (ferror(stdin) != 0) {
+        crm_err("Error reading input from stdin");
+        free(buf);
+        buf = NULL;
+    } else {
+        buf[length] = '\0';
     }
+    clearerr(stdin);
+    return buf;
+}
 
-    xml_buffer[data_length] = '\0';
-    xml_obj = string2xml(xml_buffer);
-    free(xml_buffer);
+xmlNode *
+stdin2xml(void)
+{
+    char *xml_buffer = read_stdin();
+    xmlNode *xml_obj = string2xml(xml_buffer);
 
+    free(xml_buffer);
     crm_log_xml_trace(xml_obj, "Created fragment");
     return xml_obj;
 }
@@ -1008,16 +1020,28 @@ filename2xml(const char *filename)
 
     if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) {
         /* STDIN_FILENO == fileno(stdin) */
-        output = xmlCtxtReadFd(ctxt, STDIN_FILENO, "unknown.xml", NULL,
-                               PCMK__XML_PARSE_OPTS_WITHOUT_RECOVER);
-
-        if (output == NULL) {
-            output = xmlCtxtReadFd(ctxt, STDIN_FILENO, "unknown.xml", NULL,
-                                   PCMK__XML_PARSE_OPTS_WITH_RECOVER);
-            if (output) {
-                crm_warn("Successfully recovered from XML errors "
-                         "(note: a future release will treat this as a fatal failure)");
+        /* @COMPAT After dropping XML_PARSE_RECOVER, we can avoid capturing
+         * stdin into a buffer and instead call
+         * xmlCtxtReadFd(ctxt, STDIN_FILENO, NULL, NULL, XML_PARSE_NOBLANKS);
+         *
+         * For now we have to save the input so that we can use it twice.
+         */
+        char *input = read_stdin();
+
+        if (input != NULL) {
+            output = xmlCtxtReadDoc(ctxt, (pcmkXmlStr) input, "unknown.xml", NULL,
+                                    PCMK__XML_PARSE_OPTS_WITHOUT_RECOVER);
+
+            if (output == NULL) {
+                output = xmlCtxtReadDoc(ctxt, (pcmkXmlStr) input, "unknown.xml", NULL,
+                                        PCMK__XML_PARSE_OPTS_WITH_RECOVER);
+                if (output) {
+                    crm_warn("Successfully recovered from XML errors "
+                             "(note: a future release will treat this as a fatal failure)");
+                }
             }
+
+            free(input);
         }
 
     } else if (uncompressed) {
openSUSE Build Service is sponsored by