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