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
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.
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); }
reprioritize
assign to jakub