This is an article that I had posted in my livejournal on . I’m trying to migrate the most valuable stuff to wordpress.
Hi everyone,
I have been asking this particular question to everyone for some time, the solution of which I found just now. What I wanted was to capture the standard file streams of a child process. Also that, I wanted not to use any named pipes for this purpose. One of the many ways I found was using a popen() system call. But, it seem to give to the parent either of stdin or stdout, but not both, and most importantly never stderr.
I used to wonder how various IDE’s used to execute compilers and debuggers in the background providing them with proper input and interpret their output. Anyway, I could find a solution to my problem. The basic fact is that “the child process always inherits the parent’s file descriptors”. ie, if a child can be made to inherit the file descriptors 0, 1 and 2, which actually points to some pipes with their other end in the parent process, the the parent effectively captures the child’s standard file descriptors.
So, what should be done is that, before fork(), the parent has to create the required number of pipes(one pipe for each stream) and make its own standard descriptors point to the file descriptors of the child end(supposed) of the pipes. After doing the fork(), the child will have its standard descriptors as what the parent had till the fork is called(ie, one of the ends of pipes).
Suppose you have to write something to the stdin of a child program. The steps to follow are as given below:
1. Create a pipe – use pipe() – the pipe will have a read end and a write end – two descriptors
2. Duplicate parent’s stdin – use oldstream=dup(). this is just like to save our original stream
3. Close stdin – So that we can assign the read end(child’s stdin) of the pipe to file descriptor 0
4. Make read end of pipe as stdin – use dup2() to duplicate the read end fd as 0
5. do the fork() – From now on whatever the parent and child reads from stdin will come from the read end of pipe.
6. Close unnecessary fds – Close the read and write end file descriptors from the child – it’ll use only stdin from now on. You may also close read end from parent since the parent is only going to write to the pipe.
7. Restore parent’s stdin – close the fd 0, use dup2() to use the saved(oldstream) copy of the parent’s stdin.
8. Start writing to child – Now start writing to the write end of the pipe to write to the stdin of child.
The above steps may be confusing. But if spent little time to think, you’ll surely get the idea. For more help see the code given below which captures both stdin and stdout of the child which is here the ‘bc’ calculator:
#include <unistd.h>
#include <stdio.h>
main()
{
int outfd[2];
int infd[2];
int oldstdin, oldstdout;
pipe(outfd); // Where the parent is going to write to
pipe(infd); // From where parent is going to read
oldstdin = dup(0); // Save current stdin
oldstdout = dup(1); // Save stdout
close(0);
close(1);
dup2(outfd[0], 0); // Make the read end of outfd pipe as stdin
dup2(infd[1],1); // Make the write end of infd as stdout
if(!fork())
{
char *argv[]={“/usr/bin/bc”,
“-q”,
0};close(outfd[0]); // Not required for the child
close(outfd[1]);
close(infd[0]);
close(infd[1]);
execv(argv[0],argv);
}
else
{
char input[100];close(0); // Restore the original std fds of parent
close(1);
dup2(oldstdin, 0);
dup2(oldstdout, 1);
close(outfd[0]); // These are being used by the child
close(infd[1]);
write(outfd[1],”2^32\n”,5); // Write to child’s stdin
input[read(infd[0],input,100)] = 0; // Read from child’s stdout
printf(“%s”,input);
}
}
I apologise for such a lengthy post.
bye for now.