File pacemaker-libcrmcommon-tools-improve-XML-write-error-handling.patch of Package pacemaker

commit bdaf392a077586b55961f57ef649a2841c51b297
Author: Ken Gaillot <kgaillot@redhat.com>
Date:   Fri Jan 5 12:19:22 2018 -0600

    Fix: libcrmcommon,tools: improve XML write error handling
    
    The write_xml_*() functions previously would return -1 on error
    (only sometimes setting errno for more information) and sometimes
    0 (when compressed) or the number of bytes written (when uncompressed) on
    success.
    
    Some callers were relying on the return value being -errno, others relied on
    errno being set if the return value was negative, and others relied on positive
    values indicating success.
    
    Now, the functions always return -errno on error, and the number of bytes
    written (whether compressed or uncompressed) on success, and callers treat it
    as such.
    
    Also, error log messages have been improved.

diff --git a/lib/common/xml.c b/lib/common/xml.c
index 07ee2f319..9e99619af 100644
--- a/lib/common/xml.c
+++ b/lib/common/xml.c
@@ -3039,6 +3039,17 @@ crm_xml_set_id(xmlNode *xml, const char *format, ...)
     free(id);
 }
 
+/*!
+ * \internal
+ * \brief Write XML to a file stream
+ *
+ * \param[in] xml_node  XML to write
+ * \param[in] filename  Name of file being written (for logging only)
+ * \param[in] stream    Open file stream corresponding to filename
+ * \param[in] compress  Whether to compress XML before writing
+ *
+ * \return Number of bytes written on success, -errno otherwise
+ */
 static int
 write_xml_stream(xmlNode * xml_node, const char *filename, FILE * stream, gboolean compress)
 {
@@ -3046,20 +3057,12 @@ write_xml_stream(xmlNode * xml_node, const char *filename, FILE * stream, gboole
     char *buffer = NULL;
     unsigned int out = 0;
 
-    CRM_CHECK(stream != NULL, return -1);
-
-    crm_trace("Writing XML out to %s", filename);
-    if (xml_node == NULL) {
-        crm_err("Cannot write NULL to %s", filename);
-        fclose(stream);
-        return -1;
-    }
-
-
-    crm_log_xml_trace(xml_node, "Writing out");
+    crm_log_xml_trace(xml_node, "writing");
 
     buffer = dump_xml_formatted(xml_node);
-    CRM_CHECK(buffer != NULL && strlen(buffer) > 0, crm_log_xml_warn(xml_node, "dump:failed");
+    CRM_CHECK(buffer && strlen(buffer),
+              crm_log_xml_warn(xml_node, "formatting failed");
+              res = -pcmk_err_generic;
               goto bail);
 
     if (compress) {
@@ -3070,32 +3073,38 @@ write_xml_stream(xmlNode * xml_node, const char *filename, FILE * stream, gboole
 
         bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
         if (rc != BZ_OK) {
-            crm_err("bzWriteOpen failed: %d", rc);
+            crm_warn("Not compressing %s: could not prepare file stream "
+                     CRM_XS " bzerror=%d", filename, rc);
         } else {
             BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
             if (rc != BZ_OK) {
-                crm_err("bzWrite() failed: %d", rc);
+                crm_warn("Not compressing %s: could not compress data "
+                         CRM_XS " bzerror=%d errno=%d", filename, rc, errno);
             }
         }
 
         if (rc == BZ_OK) {
             BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out);
             if (rc != BZ_OK) {
-                crm_err("bzWriteClose() failed: %d", rc);
-                out = -1;
+                crm_warn("Not compressing %s: could not write compressed data "
+                         CRM_XS " bzerror=%d errno=%d", filename, rc, errno);
+                out = -1; // retry without compression
             } else {
-                crm_trace("%s: In: %d, out: %d", filename, in, out);
+                res = (int) out;
+                crm_trace("Compressed XML for %s from %d bytes to %d",
+                          filename, in, out);
             }
         }
 #else
-        crm_err("Cannot write compressed files:" " bzlib was not available at compile time");
+        crm_warn("Not compressing %s: not built with bzlib support", filename);
 #endif
     }
 
     if (out <= 0) {
         res = fprintf(stream, "%s", buffer);
         if (res < 0) {
-            crm_perror(LOG_ERR, "Cannot write output to %s", filename);
+            res = -errno;
+            crm_perror(LOG_ERR, "writing %s", filename);
             goto bail;
         }
     }
@@ -3103,41 +3112,67 @@ write_xml_stream(xmlNode * xml_node, const char *filename, FILE * stream, gboole
   bail:
 
     if (fflush(stream) != 0) {
-        crm_perror(LOG_ERR, "fflush for %s failed", filename);
-        res = -1;
+        res = -errno;
+        crm_perror(LOG_ERR, "flushing %s", filename);
     }
 
     /* Don't report error if the file does not support synchronization */
     if (fsync(fileno(stream)) < 0 && errno != EROFS  && errno != EINVAL) {
-        crm_perror(LOG_ERR, "fsync for %s failed", filename);
-        res = -1;
+        res = -errno;
+        crm_perror(LOG_ERR, "synchronizing %s", filename);
     }
 
     fclose(stream);
 
-    crm_trace("Saved %d bytes to the Cib as XML", res);
+    crm_trace("Saved %d bytes%s to %s as XML",
+              res, ((out > 0)? " (compressed)" : ""), filename);
     free(buffer);
 
     return res;
 }
 
+/*!
+ * \brief Write XML to a file descriptor
+ *
+ * \param[in] xml_node  XML to write
+ * \param[in] filename  Name of file being written (for logging only)
+ * \param[in] fd        Open file descriptor corresponding to filename
+ * \param[in] compress  Whether to compress XML before writing
+ *
+ * \return Number of bytes written on success, -errno otherwise
+ */
 int
 write_xml_fd(xmlNode * xml_node, const char *filename, int fd, gboolean compress)
 {
     FILE *stream = NULL;
 
-    CRM_CHECK(fd > 0, return -1);
+    CRM_CHECK(xml_node && (fd > 0), return -EINVAL);
     stream = fdopen(fd, "w");
+    if (stream == NULL) {
+        return -errno;
+    }
     return write_xml_stream(xml_node, filename, stream, compress);
 }
 
+/*!
+ * \brief Write XML to a file
+ *
+ * \param[in] xml_node  XML to write
+ * \param[in] filename  Name of file to write
+ * \param[in] compress  Whether to compress XML before writing
+ *
+ * \return Number of bytes written on success, -errno otherwise
+ */
 int
 write_xml_file(xmlNode * xml_node, const char *filename, gboolean compress)
 {
     FILE *stream = NULL;
 
+    CRM_CHECK(xml_node && filename, return -EINVAL);
     stream = fopen(filename, "w");
-
+    if (stream == NULL) {
+        return -errno;
+    }
     return write_xml_stream(xml_node, filename, stream, compress);
 }
 
diff --git a/tools/cib_shadow.c b/tools/cib_shadow.c
index 2fe66f130..d0853ccce 100644
--- a/tools/cib_shadow.c
+++ b/tools/cib_shadow.c
@@ -382,7 +382,7 @@ main(int argc, char **argv)
         if (rc < 0) {
             fprintf(stderr, "Could not %s the shadow instance '%s': %s\n",
                     command == 'r' ? "reset" : "create",
-                    shadow, strerror(errno));
+                    shadow, pcmk_strerror(rc));
             goto done;
         }
         shadow_setup(shadow, FALSE);
diff --git a/tools/crm_simulate.c b/tools/crm_simulate.c
index 5473e316d..e2130ae49 100644
--- a/tools/crm_simulate.c
+++ b/tools/crm_simulate.c
@@ -445,7 +445,8 @@ setup_input(const char *input, const char *output)
     cib_object = NULL;
 
     if (rc < 0) {
-        fprintf(stderr, "Could not create '%s': %s\n", output, strerror(errno));
+        fprintf(stderr, "Could not create '%s': %s\n",
+                output, pcmk_strerror(rc));
         crm_exit(rc);
     }
     setenv("CIB_file", output, 1);
@@ -857,7 +858,8 @@ main(int argc, char **argv)
     if (input_file != NULL) {
         rc = write_xml_file(input, input_file, FALSE);
         if (rc < 0) {
-            fprintf(stderr, "Could not create '%s': %s\n", input_file, strerror(errno));
+            fprintf(stderr, "Could not create '%s': %s\n",
+                    input_file, pcmk_strerror(rc));
             goto done;
         }
     }