Dissimilar Program Interaction?
Chris Torek
chris at umcp-cs.UUCP
Tue Oct 7 01:45:39 AEST 1986
In article <5263 at cbneb.UUCP> adm at cbneb.UUCP writes:
> /* The following code does not do any error checking */
It is also not quite right:
> int fildes[2];
> int pid;
> int c;
Note the type of `c' ...
> pipe (fildes);
We now have one (1) pipe. The pair of pipe descriptors are each
unidirectional: whatever you write on fildes[1] appears on fildes[0]
for reading.
> if( (pid = fork()) == 0 )
> {
> /* CHILD */
> close(0);
> dup (fildes[0]); /* Redirect stdin of child from parent*/
> close(1);
> dup (fildes[1]); /* Redirect stdout of child to parent */
The child'd stdout is now connected to the child's stdin. This tends
not to be useful.
[stuff deleted]
> /* PARENT */
> while(read(fildes[0], &c, 1))
> {
> munch (c);
> }
Read takes a pointer to char, not a pointer to int. This code breaks
on 68000s (something similar appears in older UUCPs) due to byte order
problems.
The basic idea is right: create a pipe or two, and pass the appropriate
end or ends to the child process, which can be an arbitrary program.
If, e.g., you need only read from a program, the code in `child' should
be changed to
(void) close(1);
(void) dup(fildes[1]);
...
and the type of c to `char'.
There are a few important potential errors, including failure of any
of the system calls; but there is also this to consider: The original
program might not have a stdin or stdout. In this case, fildes[1]
might well be 1 already, and the close above will discard it. So, a
more realistic example:
/* file descriptors for speaking with our progeny */
int to_child, from_child;
int
doit()
{
int pid, p0[2], p1[2];
if (pipe(p0)) /* oops */
return (-1);
if (pipe(p1)) {
(void) close(p0[0]);
(void) close(p0[1]);
return (-1);
}
switch (pid = fork()) {
case -1: /* oops */
(void) close(p1[0]);
(void) close(p1[1]);
(void) close(p0[0]);
(void) close(p0[1]);
return (-1);
case 0: /* child */
/*
* Set child's stdin to read from p0.
* Discard p0 write descriptor.
*/
if (p0[0] != 0) {
(void) close(0);
/*
* Not much to do if the dup fails,
* hence the `(void)'.
*/
(void) dup(p0[0]);
(void) close(p0[0]);
}
(void) close(p0[1]);
/*
* Set child's stdout to write to p1;
* discard p1 read descriptor.
*
* Note that p1[0] and p1[1] must be at
* least 2 and 3 respectively (0 and 1
* having been consumed by p0).
*/
(void) close(1);
(void) dup(p1[1]);
(void) close(p1[1]);
(void) close(p1[0]);
/*
* Fire up child. If not there, quit.
*/
execl("foo", "foo", (char *) NULL);
_exit(1);
/* NOTREACHED */
}
/*
* Parent. Discard read end of pipe to child's stdin,
* and write end of pipe to child's stdout. Set those
* global variables so we know which descriptors talk
* to the child.
*/
(void) close(p0[0]);
(void) close(p1[1]);
to_child = p0[1];
from_child = p1[0];
return (pid); /* success */
}
Rather longer than the previous version; but that is what happens
when one adds error checks....
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP: seismo!umcp-cs!chris
CSNet: chris at umcp-cs ARPA: chris at mimsy.umd.edu
More information about the Comp.unix
mailing list