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