Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!cmcl2!yale!husc6!mit-eddie!genrad!panda!teddy!jpn From: jpn@teddy.UUCP (John P. Nelson) Newsgroups: comp.unix.questions Subject: Re: Running stdin/out through a pipe to a child process Message-ID: <3662@teddy.UUCP> Date: Mon, 12-Jan-87 12:25:33 EST Article-I.D.: teddy.3662 Posted: Mon Jan 12 12:25:33 1987 Date-Received: Thu, 15-Jan-87 03:06:16 EST References: <136@cogent.UUCP> Reply-To: jpn@teddy.UUCP (John P. Nelson) Distribution: world Organization: GenRad, Inc., Concord, Mass. Lines: 78 Keywords: popen, fork, exec, pipes, stdio, arrrrgh! 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 }