+/*
+ * Call writev(), restarting as needed and handling EAGAIN since
+ * fd may be in non-blocking mode.
+ */
+static size_t
+atomic_writev(int fd, struct iovec *iov, int iovcnt)
+{
+ ssize_t n, nwritten = 0;
+ size_t count, remainder, nbytes = 0;
+ int i;
+ debug_decl(atomic_writev, SUDO_DEBUG_UTIL)
+
+ for (i = 0; i < iovcnt; i++)
+ nbytes += iov[i].iov_len;
+
+ for (;;) {
+ n = writev(STDOUT_FILENO, iov, iovcnt);
+ if (n > 0) {
+ nwritten += n;
+ remainder = nbytes - nwritten;
+ if (remainder == 0)
+ break;
+ /* short writev, adjust iov and do the rest. */
+ count = 0;
+ i = iovcnt;
+ while (i--) {
+ count += iov[i].iov_len;
+ if (count == remainder) {
+ iov += i;
+ iovcnt -= i;
+ break;
+ }
+ if (count > remainder) {
+ size_t off = (count - remainder);
+ /* XXX - side effect prevents iov from being const */
+ iov[i].iov_base = (char *)iov[i].iov_base + off;
+ iov[i].iov_len -= off;
+ iov += i;
+ iovcnt -= i;
+ break;
+ }
+ }
+ continue;
+ }
+ if (n == 0 || errno == EAGAIN) {
+ int nready;
+ fd_set fdsw;
+ FD_ZERO(&fdsw);
+ FD_SET(STDOUT_FILENO, &fdsw);
+ do {
+ nready = select(STDOUT_FILENO + 1, NULL, &fdsw, NULL, NULL);
+ } while (nready == -1 && errno == EINTR);
+ if (nready == 1)
+ continue;
+ }
+ if (errno == EINTR)
+ continue;
+ nwritten = -1;
+ break;
+ }
+ debug_return_size_t(nwritten);
+}
+