diff options
author | cracauer <cracauer@FreeBSD.org> | 2012-02-10 22:16:17 +0000 |
---|---|---|
committer | cracauer <cracauer@FreeBSD.org> | 2012-02-10 22:16:17 +0000 |
commit | e278c3bff09ee6207fa5f822cd64ede7b6083189 (patch) | |
tree | 4a532a5243c9df623882b873cda0cbe54b6385df | |
parent | 290f0204ae95d6dc92ba9c15fafe090e9d4338af (diff) | |
download | FreeBSD-src-e278c3bff09ee6207fa5f822cd64ede7b6083189.zip FreeBSD-src-e278c3bff09ee6207fa5f822cd64ede7b6083189.tar.gz |
Fix bin/164947: tee looses data when writing to non-blocking file descriptors
tee was not handling EAGAIN
patch submitted by Diomidis Spinellis <dds@aueb.gr>. Thanks so much
reproduced and re-tested locally
-rw-r--r-- | usr.bin/tee/tee.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/usr.bin/tee/tee.c b/usr.bin/tee/tee.c index 6b5c00c..61d7f76 100644 --- a/usr.bin/tee/tee.c +++ b/usr.bin/tee/tee.c @@ -42,8 +42,10 @@ static const char rcsid[] = #endif /* not lint */ #include <sys/types.h> +#include <sys/select.h> #include <sys/stat.h> #include <err.h> +#include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdio.h> @@ -60,6 +62,7 @@ static LIST *head; static void add(int, const char *); static void usage(void); +static void waitfor(int fd); int main(int argc, char *argv[]) @@ -106,9 +109,14 @@ main(int argc, char *argv[]) bp = buf; do { if ((wval = write(p->fd, bp, n)) == -1) { - warn("%s", p->name); - exitval = 1; - break; + if (errno == EAGAIN) { + waitfor(p->fd); + wval = 0; + } else { + warn("%s", p->name); + exitval = 1; + break; + } } bp += wval; } while (n -= wval); @@ -137,3 +145,15 @@ add(int fd, const char *name) p->next = head; head = p; } + +/* Wait for the specified fd to be ready for writing */ +static void +waitfor(int fd) +{ + fd_set writefds; + + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + if (select(fd + 1, NULL, &writefds, NULL, NULL) == -1) + err(1, "select"); +} |