bin/164947: tee looses data when writing to non-blocking file descriptors

Diomidis Spinellis dds at aueb.gr
Fri Feb 10 07:10:09 UTC 2012


>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 at 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:


More information about the freebsd-bugs mailing list