Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!umcp-cs!chris From: chris@umcp-cs.UUCP (Chris Torek) Newsgroups: net.unix Subject: Re: Dissimilar Program Interaction? Message-ID: <3702@umcp-cs.UUCP> Date: Mon, 6-Oct-86 11:45:39 EDT Article-I.D.: umcp-cs.3702 Posted: Mon Oct 6 11:45:39 1986 Date-Received: Wed, 8-Oct-86 06:42:39 EDT References: <5263@cbneb.UUCP> Organization: Computer Sci. Dept, U of Maryland, College Park, MD Lines: 136 In article <5263@cbneb.UUCP> adm@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@umcp-cs ARPA: chris@mimsy.umd.edu