lib/utils: introduce xwritel() as a more robust and convenient write()
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 and convenient. Let's do
that by introducing xwritel():
- Let the caller pass a list of NUL-terminated strings, via stdarg /
ellipsis notation in the parameter list.
- 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.)
- In the common case, handle an nbd_internal_fork_safe_perror() call with
a single xwritel() -> writev() call chain, rather than with four
separate write() calls. In practice, this tends to make the error
message written to a regular file contiguous, even if other threads are
writing to the same file. Multiple separate write() calls tend to
interleave chunks of data from different threads.
As a side bonus, remove the path in nbd_internal_fork_safe_perror() where
at least one of the first two write() syscalls fails, and overwrites
"errno", before we get to formatting the error string from "errno".
Thanks to Eric Blake for helping me understand the scope of Austin Group
bug reports.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <
20230315110157.357958-2-lersek@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[lersek@redhat.com: add __attribute__ ((sentinel)), suggested by Eric]