Running stdin/out through a pipe to a child process

John P. Nelson jpn at teddy.UUCP
Tue Jan 13 03:25:33 AEST 1987


Wanted:
>
>                      +-------------------+
>                      |                   |
>                      |  Parent Process   |
>                      |                   |
>                      +-------------------+
>               Pipe that   |         ^ Pipe that
>               feeds stdin V         | reads stdout
>                      +-------------------+
>                      |                   |
>                      |   Child Process   |
>                      |                   |
>                      |   (could be a     |
>                      |    filter like    |
>                      |    sed or cat,    |
>                      |    or a shell)    |
>                      |                   |
>                      +-------------------+
>

Here is a code fragment that does what you need.  Don't worry about the
fact that I am using low-level UNIX descriptors 0,1,2 instead of stdin,
stdout, stderr - your child task will not know the difference.

Note, however, that while this sets stdin and stdout descriptors to be
pipes, that the stdio package buffers pipes as if they were files, not
like terminals.  This means that the filter program must fflush it's
output periodically (or setbuf appropriately), or deadlock can occur
(both programs expecting input from other program).  Unfortunately, the
stdio buffering state does not inherit across exec(), so it can't be
preset.

Bottom line:  This technique is only useful with "well-behaved" child
processes - it does not work in the general case.

If your version of unix has psuedo-terminals, you will be MUCH better
off putting a psuedo terminal in the middle, rather than a pair of pipes.

------------------------------------------------------------------------
    int infds[0];	/* in relative to PARENT task */
    int outfds[0];	/* out relative to PARENT task */
#ifdef OPTIONAL
    FILE *input, *output;
#endif
 ...

    pipe(infds);	/* create one pipe */
    pipe(outfds);	/* create the other pipe */
    if (fork() == 0)
	{
	/* child task */
	/* close old stdin, stdout, stderr */
	close(0); close(1); close(2);
	/* use dup to set stdin, stdout, stderr */
	dup(outfds[0]);		/* outfds[0] -> stdin */
	dup(infds[1]);		/* infds[1] -> stdout */
	dup(infds[1]);		/* infds[1] -> stderr */
	/* close unused pipe ends */
	close(outfds[0]); close(outfds[1]); close(infds[0]); close(infds[0]);
	exec......
	exit(1);		/* exec fails */
	}
    else
	{
	/* parent */
	/* close unused descriptors */
	close(outfds[0]); close(infds[1]);
	/* now use read on infds[0], and write on outfds[1] */
#ifdef OPTIONAL
	/* create stdio type descriptors for parent to fread/fwrite */
	input = fdopen(infds[0], "r");
	output = fdopen(outfds[1], "w");
	/* of course, similar close of 0,1,2 followed by dups as above */
	/* in child task could make descriptors available as stdin, stdout */
#endif
	}



More information about the Comp.unix.questions mailing list