Date: Fri, 10 Feb 2012 07:04:41 GMT From: Diomidis Spinellis <dds@aueb.gr> To: freebsd-gnats-submit@FreeBSD.org Subject: bin/164947: tee looses data when writing to non-blocking file descriptors Message-ID: <201202100704.q1A74f98051744@red.freebsd.org> Resent-Message-ID: <201202100710.q1A7A92d073907@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 164947 >Category: bin >Synopsis: tee looses data when writing to non-blocking file descriptors >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Feb 10 07:10:09 UTC 2012 >Closed-Date: >Last-Modified: >Originator: Diomidis Spinellis >Release: 8.1 >Organization: AUEB >Environment: FreeBSD istlab.dmst.aueb.gr 8.1-RELEASE-p6 FreeBSD 8.1-RELEASE-p6 #0: Tue Nov 1 15:16:34 EET 2011 dds@istlab.dmst.aueb.gr:/usr/obj/usr/src/sys/ISTLAB i386 You have new mail in /var/mail/dds >Description: When tee(1) tries to write to a file descriptor that has been set to non-blocking mode the write(2) call may fail with EAGAIN. Instead of retrying the operation, tee will throw that chunk of data away. >How-To-Repeat: Run the following: #!/usr/local/bin/bash # bash needed for the >(...) functionality # ssh apparently sets O_NONBLOCK # Remove the 2>/dev/null to see tee complaining dd count=100000 if=/dev/zero | tee >(ssh localhost dd of=/dev/null) 2>/dev/null | (ssh localhost dd of=/dev/null) 100000+0 records in 100000+0 records out 51200000 bytes transferred in 9.224390 secs (5550503 bytes/sec) 100000+0 records in 100000+0 records out 51200000 bytes transferred in 9.061471 secs (5650297 bytes/sec) 92080+0 records in 92080+0 records out 47144960 bytes transferred in 9.101738 secs (5179776 bytes/sec) >Fix: I attach a patch that fixes the problem. Patch attached with submission follows: --- tee.c 2012/02/08 14:50:10 1.1 +++ tee.c 2012/02/08 14:59:10 @@ -46,8 +46,10 @@ #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> @@ -64,6 +66,7 @@ void add(int, const char *); static void usage(void); +static void waitfor(int fd); int main(int argc, char *argv[]) @@ -110,9 +113,14 @@ 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); @@ -141,3 +149,15 @@ 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"); +} >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202100704.q1A74f98051744>