Bug 7932

Summary: POSIX conformance error: fscanf(3) + O_NONBLOCK + empty pipe
Product: [Retired] Red Hat Linux Reporter: Jay Turner <jturner>
Component: glibcAssignee: Jakub Jelinek <jakub>
Status: CLOSED CURRENTRELEASE QA Contact:
Severity: low Docs Contact:
Priority: low    
Version: 6.0CC: fweimer, srevivo
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2002-12-13 19:19:04 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Glen Foster 1999-12-21 18:15:46 UTC
In the PCTS (POSIX Conformance Test Suite), the fscanf(3) tests fail
on test-case #5 -- reading from a pipe with O_NONBLOCK set.

To reproduce:

	int p[2];
	FILE *fp;
	char buf[64];
/* ... */
	pipe(p);
	flags = fcntl(p[0], F_GETFL);
	fcntl(p[0], F_SETFL, flags | O_NONBLOCK);
	fp = fdopen(p[0], "r");
	fscanf(fp, "%s", inbuf);

... the fscanf(3) is supposed to fail (e.g., return -1) and
set errno to EAGAIN.  Instead, fscanf(3) returns 0 and errno
is not set to anything.  This is a POSIX conformance defect.

POSIX.1 (1996) wording: under read(2), p. 151, lines 157-161

When attempting to read from an empty pipe (or FIFO):

    (1) If no process has the pipe open for writing, read()
        shall return zero to indicate end-of-file.
    (2) If some process has the pipe open for writing and
        O_NONBLOCK is set, read() shall return -1 and set
        errno to EAGAIN.

... let me know if I can clear anything up.

Glen

Comment 1 Cristian Gafton 2000-01-05 02:52:59 UTC
this looks correct to me. Did  any process have the pipe open for writting? If
not, returning 0 is the right thing to do, as the paragraph you quoted states.

Please send complete small testcase and repoen if disagree.

Comment 2 Glen Foster 2000-01-05 15:18:59 UTC
The pipe in the listed code fragment *is* open for writing; it's in p[1],
the write-side of the pipe (it was never closed).  I have included below a
more detailed test-case that proves the point of the original defect filed.

Note that when compiled "as is" *and* when compiled -DREAD_ONLY (to close the
write-side of the pipe before calling scanf()), BOTH cases result in errno
29 (ESPIPE == Illegal seek) from the scanf() call.  This return is acceptable
if the write-side is closed but POSIX clearly states that when the write-side
is open, errno EAGAIN is to be returned when there's (a) no data available
and (b) O_NONBLOCK is set.

Newer test code follows -- let me know if you have any questions.  (Glen)
[snip]
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

#define STRING  "This is a string"

main()
{
        int flags, val, p[2], len = strlen(STRING);
        FILE *fp;
        char inbuf[64];

        if (pipe(p) < 0) {
                perror("pipe");
                exit(1);
        }
        if ((flags = fcntl(p[0], F_GETFL)) < 0) {
                perror("fcntl(F_GETFL)");
                exit(1);
        }
        if (fcntl(p[0], F_SETFL, flags | O_NONBLOCK) < 0) {
                perror("fcntl(F_SETFL)");
                exit(1);
        }
        if ((fp = fdopen(p[0], "r")) == (FILE *) NULL) {
                perror("fdopen");
                exit(1);
        }
#ifdef  READ_ONLY
        printf("DEBUG: Closing write-side of pipe...\n");
        if (close(p[1]) < 0) {
                perror("close");
                exit(1);
        }
#endif  /* READ_ONLY */
#ifdef  FORCE_FEED
        printf("DEBUG: Forcing data into pipe: \"%s\"\n", STRING);
        if (write(p[1], STRING, len) != len) {
                perror("write");
                exit(1);
        }
#elif   DEBUG_READ
        printf("DEBUG: calling read() instead of fscanf()\n");
        if (read(p[0], inbuf, BUFSIZ) < 0) {
                perror("read");
                if (errno == EAGAIN) {
                        printf("Proper return failure from read()\n");
                        exit(0);
                }
        }
        exit(1);
#endif  /* DEBUG_READ */
        if ((val = fscanf(fp, "%s", inbuf)) == EOF) {
                if (errno != EAGAIN) {
                        perror("fscanf");
                        exit(1);
                }
                printf("errno = EAGAIN (%d), correct ala POSIX\n", errno);
                exit(0);
        }
        fprintf(stderr, "fscanf() returns %d\n", val);
        fprintf(stderr, "fscanf() found data: \"%s\"\n", inbuf);
#ifdef  FORCE_FEED
        exit(0);
#endif  /* FORCE_FEED */
        exit(1);
}

Comment 3 Elliot Lee 2000-02-03 16:59:59 UTC
reprioritize

Comment 4 Cristian Gafton 2000-05-22 14:52:59 UTC
assign to jakub