No need to loop over atomic_writev(), it guarantees to write all
data or return an error. Fix handling of stdout/stderr that contains "\r\n" and handle a "\r\n" pair that spans a buffer.
This commit is contained in:
@@ -247,7 +247,7 @@ main(int argc, char *argv[])
|
|||||||
char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
|
char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
|
||||||
double seconds, to_wait, speed = 1.0, max_wait = 0;
|
double seconds, to_wait, speed = 1.0, max_wait = 0;
|
||||||
sigaction_t sa;
|
sigaction_t sa;
|
||||||
size_t len, nbytes, nread, nwritten, off;
|
size_t len, nbytes, nread;
|
||||||
struct log_info *li;
|
struct log_info *li;
|
||||||
struct iovec *iov = NULL;
|
struct iovec *iov = NULL;
|
||||||
int iovcnt = 0, iovmax = 0;
|
int iovcnt = 0, iovmax = 0;
|
||||||
@@ -412,6 +412,8 @@ main(int argc, char *argv[])
|
|||||||
#else
|
#else
|
||||||
while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) {
|
while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) {
|
||||||
#endif
|
#endif
|
||||||
|
char last_char = '\0';
|
||||||
|
|
||||||
if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes))
|
if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes))
|
||||||
errorx(1, _("invalid timing file line: %s"), buf);
|
errorx(1, _("invalid timing file line: %s"), buf);
|
||||||
|
|
||||||
@@ -444,51 +446,59 @@ main(int argc, char *argv[])
|
|||||||
nread = fread(buf, 1, len, io_fds[idx].f);
|
nread = fread(buf, 1, len, io_fds[idx].f);
|
||||||
#endif
|
#endif
|
||||||
nbytes -= nread;
|
nbytes -= nread;
|
||||||
off = 0;
|
|
||||||
do {
|
|
||||||
/* Convert newline to carriage return + linefeed if needed. */
|
|
||||||
if (need_nlcr) {
|
|
||||||
size_t linelen;
|
|
||||||
cp = buf + off;
|
|
||||||
iovcnt = 0;
|
|
||||||
while ((ep = memchr(cp, '\n', nread - off)) != NULL) {
|
|
||||||
/* Is there already a carriage return? */
|
|
||||||
if (cp != ep && ep[-1] == '\r')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Store the line in iov followed by \r\n pair. */
|
/* Convert newline to carriage return + linefeed if needed. */
|
||||||
if (iovcnt + 3 > iovmax) {
|
if (need_nlcr) {
|
||||||
iovmax <<= 1;
|
size_t remainder = nread;
|
||||||
iov = erealloc3(iov, iovmax, sizeof(*iov));
|
size_t linelen;
|
||||||
}
|
iovcnt = 0;
|
||||||
linelen = (size_t)(ep - cp);
|
cp = buf;
|
||||||
iov[iovcnt].iov_base = cp;
|
ep = cp - 1;
|
||||||
iov[iovcnt].iov_len = linelen;
|
/* Handle a "\r\n" pair that spans a buffer. */
|
||||||
iovcnt++;
|
if (last_char == '\r' && buf[0] == '\n') {
|
||||||
iov[iovcnt].iov_base = "\r\n";
|
ep++;
|
||||||
iov[iovcnt].iov_len = 2;
|
remainder--;
|
||||||
iovcnt++;
|
|
||||||
off += linelen + 1;
|
|
||||||
cp = ep + 1;
|
|
||||||
}
|
|
||||||
if (nread - off != 0) {
|
|
||||||
linelen = nread - off;
|
|
||||||
iov[iovcnt].iov_base = cp;
|
|
||||||
iov[iovcnt].iov_len = linelen;
|
|
||||||
iovcnt++;
|
|
||||||
off += linelen;
|
|
||||||
}
|
|
||||||
/* Note: off already adjusted above. */
|
|
||||||
(void)atomic_writev(STDOUT_FILENO, iov, iovcnt);
|
|
||||||
} else {
|
|
||||||
/* No conversion needed. */
|
|
||||||
iov[0].iov_base = buf + off;
|
|
||||||
iov[0].iov_len = nread - off;
|
|
||||||
iovcnt = 1;
|
|
||||||
nwritten = atomic_writev(STDOUT_FILENO, iov, iovcnt);
|
|
||||||
off += nwritten;
|
|
||||||
}
|
}
|
||||||
} while (nread > off);
|
while ((ep = memchr(ep + 1, '\n', remainder)) != NULL) {
|
||||||
|
/* Is there already a carriage return? */
|
||||||
|
if (cp != ep && ep[-1] == '\r') {
|
||||||
|
remainder = (size_t)(&buf[nread - 1] - ep);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the line in iov followed by \r\n pair. */
|
||||||
|
if (iovcnt + 3 > iovmax) {
|
||||||
|
iovmax <<= 1;
|
||||||
|
iov = erealloc3(iov, iovmax, sizeof(*iov));
|
||||||
|
}
|
||||||
|
linelen = (size_t)(ep - cp) + 1;
|
||||||
|
iov[iovcnt].iov_base = cp;
|
||||||
|
iov[iovcnt].iov_len = linelen - 1; /* not including \n */
|
||||||
|
iovcnt++;
|
||||||
|
iov[iovcnt].iov_base = "\r\n";
|
||||||
|
iov[iovcnt].iov_len = 2;
|
||||||
|
iovcnt++;
|
||||||
|
cp = ep + 1;
|
||||||
|
remainder -= linelen;
|
||||||
|
}
|
||||||
|
if (cp - buf != nread) {
|
||||||
|
/*
|
||||||
|
* Partial line without a linefeed or multiple lines
|
||||||
|
* with \r\n pairs.
|
||||||
|
*/
|
||||||
|
iov[iovcnt].iov_base = cp;
|
||||||
|
iov[iovcnt].iov_len = nread - (cp - buf);
|
||||||
|
iovcnt++;
|
||||||
|
}
|
||||||
|
last_char = buf[nread - 1]; /* stash last char of old buffer */
|
||||||
|
} else {
|
||||||
|
/* No conversion needed. */
|
||||||
|
iov[0].iov_base = buf;
|
||||||
|
iov[0].iov_len = nread;
|
||||||
|
iovcnt = 1;
|
||||||
|
}
|
||||||
|
if (atomic_writev(STDOUT_FILENO, iov, iovcnt) == -1)
|
||||||
|
error(1, _("writing to standard output"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
term_restore(STDIN_FILENO, 1);
|
term_restore(STDIN_FILENO, 1);
|
||||||
@@ -594,7 +604,8 @@ atomic_writev(int fd, struct iovec *iov, int iovcnt)
|
|||||||
}
|
}
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
error(1, "writing to standard output");
|
nwritten = -1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
debug_return_size_t(nwritten);
|
debug_return_size_t(nwritten);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user