While nbd_internal_fork_safe_perror() must indeed call write(), and
arguably justifiedly ignores the return value of write(), we can still
make the write operations slightly more robust. Let's do that by
introducing xwrite():

- don't call write() with nbyte > SSIZE_MAX, for avoiding
  implementation-defined behavior,

- handle partial writes,

- cope with EINTR and EAGAIN errors. (A busy loop around EAGAIN on a
  non-blocking file is not great in the general case, but it's good enough
  for writing out diagnostics before giving up.)

Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 lib/utils.c | 39 ++++++++++++++++++--
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/lib/utils.c b/lib/utils.c
index bba4b3846e77..7fb16f6402d1 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -25,6 +25,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 
 #include "minmax.h"
 
@@ -181,6 +182,36 @@ nbd_internal_fork_safe_itoa (long v, char *buf, size_t 
bufsize)
 #pragma GCC diagnostic ignored "-Wunused-result"
 #endif
 
+/* "Best effort" function for writing out a buffer to a file descriptor.
+ * Chunking with SSIZE_MAX (for avoiding implementation-defined behavior),
+ * partial writes, and EINTR and EAGAIN failures are handled internally. No
+ * value is returned; only use this for writing diagnostic data on error paths,
+ * when giving up on a higher-level action anyway. Note that this function is
+ * supposed to remain async-signal-safe.
+ */
+static void
+xwrite (int fd, const void *buf, size_t count)
+{
+  const unsigned char *pos;
+  size_t left;
+
+  pos = buf;
+  left = count;
+  while (left > 0) {
+    ssize_t written;
+
+    do
+      written = write (fd, pos, MIN (left, SSIZE_MAX));
+    while (written == -1 && (errno == EINTR || errno == EAGAIN));
+
+    if (written == -1)
+      return;
+
+    pos += written;
+    left -= written;
+  };
+}
+
 /* Fork-safe version of perror.  ONLY use this after fork and before
  * exec, the rest of the time use set_error().
  */
@@ -191,8 +222,8 @@ nbd_internal_fork_safe_perror (const char *s)
   const char *m = NULL;
   char buf[32];
 
-  write (2, s, strlen (s));
-  write (2, ": ", 2);
+  xwrite (2, s, strlen (s));
+  xwrite (2, ": ", 2);
 #ifdef HAVE_STRERRORDESC_NP
   m = strerrordesc_np (errno);
 #else
@@ -202,8 +233,8 @@ nbd_internal_fork_safe_perror (const char *s)
 #endif
   if (!m)
     m = nbd_internal_fork_safe_itoa ((long) errno, buf, sizeof buf);
-  write (2, m, strlen (m));
-  write (2, "\n", 1);
+  xwrite (2, m, strlen (m));
+  xwrite (2, "\n", 1);
 
   /* Restore original errno in case it was disturbed by the system
    * calls above.

_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://listman.redhat.com/mailman/listinfo/libguestfs

Reply via email to