Search code examples
cforkglibcstdio

Does stdio set file descriptor offset back to next unread position on file closing?


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:

  1. Call fork. Now parent and child share stdin.
  2. In the child process call scanf. By default stdin is block buffered, so scanf reads block.
  3. Inspect file offset in child.
  4. Exit from the child process.
  5. In parent process wait for the child process.
  6. Inspect file offset of 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

Solution

  • 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.