[PATCH 1/1] stdio: fix named pipe issue

Jian Peng jipeng2005 at gmail.com
Thu Jun 16 18:54:45 UTC 2011


This is follow-up of my investigation and proposed
fix at
http://old.nabble.com/named-pipe-is-borken-and-proposed-fix-td31753483.html#a31753483

The testing programs worked well with glibc, but failed in uClibc-0.9.32.

As Laurent pointed out, this is undefined in standard. For the sake of
application developers who want to port apps from glibc to uClibc without
worrying about the subtle difference, it is nice to help them out with
following patch.

The problem is that FIFO is a special file type, and the conventional EOF
is useless, and should not be set.

The fix is to avoid setting __FLAG_EOF for stream associated with FIFO file
after all senders were closed.

Signed-off-by: Jian Peng <jipeng2005 at gmail.com>
---
 libc/stdio/_READ.c                            |   29 ++++++++++++++++++++++++-
 libc/sysdeps/linux/common/bits/uClibc_stdio.h |    1 +
 2 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/libc/stdio/_READ.c b/libc/stdio/_READ.c
index 02601c0..2ecc920 100644
--- a/libc/stdio/_READ.c
+++ b/libc/stdio/_READ.c
@@ -6,7 +6,25 @@
  */
 
 #include "_stdio.h"
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "xstatconv.h"
 
+#define __NR___syscall_fstat __NR_fstat
+static __inline__ _syscall2(int, __syscall_fstat, int, fd, struct kernel_stat *, buf)
+
+int _my_fstat(int fd, struct stat *buf)
+{
+	int result;
+	struct kernel_stat kbuf;
+
+	result = __syscall_fstat(fd, &kbuf);
+	if (result == 0) {
+		__xstat_conv(&kbuf, buf);
+	}
+	return result;
+}
 
 /* Given a reading stream without its end-of-file indicator set and
  * with no buffered input or ungots, read at most 'bufsize' bytes
@@ -44,7 +62,16 @@ size_t attribute_hidden __stdio_READ(register FILE *stream,
 /* 	RETRY: */
 		if ((rv = __READ(stream, (char *) buf, bufsize)) <= 0) {
 			if (rv == 0) {
-				__STDIO_STREAM_SET_EOF(stream);
+				struct stat stat;
+
+				if( (stream->__modeflags & __FLAG_FIFOFILE) ||
+					_my_fstat(stream->__filedes, &stat) >= 0) {
+					if(S_ISFIFO(stat.st_mode))
+						stream->__modeflags |= __FLAG_FIFOFILE;
+				}
+
+				if(!(stream->__modeflags & __FLAG_FIFOFILE))
+					__STDIO_STREAM_SET_EOF(stream);
 			} else {
 /* 				if (errno == EINTR) goto RETRY; */
 				__STDIO_STREAM_SET_ERROR(stream);
diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
index a8cf4eb..1d2cc11 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
@@ -331,6 +331,7 @@ struct __STDIO_FILE_STRUCT {
 #define __FLAG_FREEBUF		0x4000U
 #define __FLAG_LARGEFILE	0x8000U /* fixed! == 0_LARGEFILE for linux */
 #define __FLAG_FAILED_FREOPEN	__FLAG_LARGEFILE
+#define __FLAG_FIFOFILE		0x1000U /* handle FIFO differently */
 
 /* Note: In no-buffer mode, it would be possible to pack the necessary
  * flags into one byte.  Since we wouldn't be buffering and there would
-- 
1.7.4.1




More information about the uClibc mailing list