I am writing a porgram with takes two arguments - the name of commands. The program should redirect the output of the first to a file 'tmp' than execute it, than redirect the stdin of the second command to 'tmp' and execute the second command.
#include<unistd.h>
#include<fcntl.h>
#include<wait.h>
#include<stdio.h>
int main(int argc, char** argv){
int fd = open("tmp", O_RDWR |O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
int cpid = fork();
if(cpid == 0){
dup2(fd, 1);
execlp(argv[1], "", NULL);
}
wait(NULL);
//If we uncoment this line the program gives correct output
//fd = open("tmp", O_RDWR, S_IRUSR | S_IWUSR);
dup2(fd, 0);
execlp(argv[2], "", NULL);
}
However when i run the program like ./main ls wc
instead of
5 5 50
i get output 0 0 0
which means the wc
command reads 0 bytes from stdin.
But if I instead create the file descriptor anew on the same file 'tmp' the program gives the correct output. How can this behaviour be explained?
This question is basically a duplicate of Can anyone explain a simple description regarding 'file descriptor' after fork()? but since this is a bit subtle I'll explain this specific case.
At the end of step 2, the file position on this file description is the end of the file. So at step 3, the parent starts reading at the end of the file.
If you add a call to rewind(fd)
after wait(NULL)
, the child will read from the beginning of the file.
If you open the same file with a new open
call, this creates a new file description. open
puts the position on the new file description at the beginning of the file unless you set append mode.
The same file descriptions can be accessed through any number of file descriptors, potentially in different processes. The file position is a property of the file description, so anything that moves it (reading, writing, seeking) through one file descriptor also moves it for the other file descriptors, even in different processes.