According to the Linux Programmer's Manual, after calling fork
, parent and child processes share opened file descriptors and file offsets.
On the other hand, it is known, that glibc's stdio implements bufferisation. Therefore, call to scanf
can result in moving file offset (reading) much further then number of bytes returned to the end user, remaining data will be stored in buffer for the next call.
But what happens when I do the following:
fork
. Now parent and child share stdin
.scanf
. By default stdin
is block buffered, so scanf
reads block.stdin
in the parent.According to the glibc manual, when main
returns,
all opened streams are closed properly.
and on closing
any buffered input is discarded
So I expect parent's stdin
file offset to be at position where child's scanf
stoped reading (really stoped reading). But I get parent's stdin
file offset moved back to position of end of input returned to user.
I searched trough the manuals and the internet and didn't find any information describing this behavior. Is it specified?
Here is my code:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
int main() {
int fd = fileno(stdin);
printf("Begin pos: %ld\n", lseek(fd, 0, SEEK_CUR));
pid_t pid = fork();
if (pid == 0) {
char buffer[4096] = {};
int readed = scanf("%s", buffer);
printf("Child readed: %d, pos: %ld\n", readed, lseek(fd, 0, SEEK_CUR));
return 0;
}
int status = 0;
wait(&status);
printf("Parent pos: %ld\n", lseek(fd, 0, SEEK_CUR));
return 0;
}
Here is output:
> echo "aaa bbb ccc" > test
> ./a.out < test
Begin pos: 0
Child readed: 1, pos: 12
Parent pos: 3
The observed behavior conforms to the POSIX requirements for the fclose
function:
If the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be set to the file position of the stream if the stream is the active handle to the underlying file description.