Running stdin/out through a pipe to a child process
Charlie Havener
charlie at condor.UUCP
Tue Jan 13 07:38:58 AEST 1987
In article <136 at cogent.UUCP> mark at cogent.UUCP (Mark Steven Jeghers) writes:
>I need to know how I might create a child process with 2 pipes connected to
>it, one with which the parent process feeds a stream to the childs stdin,
>and one from which the parent reads a stream from the childs stdout. I
>understand how to use popen() to connect either stdin OR stdout between
>processes, but I need to have BOTH.
Here is the source code of a program that will do what you request:
--------------------------------------------------------------------
/* Sample pipe master diagnostic control program - cdh April 29 1985 */
/* this program shows how to spawn other programs, pass them command line */
/* arguments, and attach to their standard input and output so all */
/* I/O goes thru the parent program. This program works on both */
/* the Berkeley 4.2BSD and on the 68000 Unisoft Sys V UNIX */
/* this is a framework to be modified as you wish. It has more comment */
/* messages than you will want to keep in a finished product */
/* This is all the result of one day's experimenting. */
#include <stdio.h>
#include <signal.h>
char *pgms[] = /* here is an array of programs this one will try to invoke */
{
"test2",
"test1",
0,
};
char *argsv[]= /* here are some sample command line arguments which */
{ /* will be passed to the programs that are spawned */
"vi",
"fi",
"fo",
"fum",
0,
};
/* we will use two pipes for two way communication */
int fd1[2]; /* pipe channel from child to parent */
int fd2[2]; /* pipe channel from parent to child */
/*--------------------------------------------------------*/
main(argc,argv,envp)
int argc;
char **argv, **envp;
{
int i,k;
char *pgmptr; /* pointer to a test program name */
int pid;
int suicide_note; /* where the child exit status goes */
int death_note; /* where the child exit status goes */
int ch;
char chr;
char c;
int status;
int pid_listen;
int pid_talker;
int pid_program;
int fda,fdb,fdc;
for ( k=0 ; k < sizeof(pgms) ; k++ )
{
pgmptr = pgms[k]; /* get the name of a program to run */
if ( pgmptr == 0 )
{
printf("No more test programs to execute\n");
exit(0);
}
if ( (access(pgmptr,01) != 0) ) /* see if it is there before making pipes */
{
printf("test program %s not found\n",pgmptr);
continue;
}
printf("now trying to get pipes for %s\n",pgms[k]);
if ( pipe(fd1) < 0 )
{
perror("pipemaster");
printf("Couldn't get pipe file descriptors\n");
exit();
}
if ( pipe(fd2) < 0 )
{
perror("pipemaster");
printf("Couldn't get pipe file descriptors\n");
exit();
}
printf("Got two pipes successfully\n");
printf("In pipemaster diagnostic control program, fork() is next\n");
/* don't use vfork() for this tricky stuff. No vfork on 68k anyway */
if ( ( pid_program = fork()) < 0 ) /* fork failed */
{
printf("Couldn't fork");
exit();
}
if ( pid_program == 0 ) /* the diagnostic program i.e. the child */
{
close(0);
close(1);
close(2); /* close original stdin, stdout, stderr */
fda = dup(fd2[0]); /* dup into childs stdin */
if ( fda == -1 )
printf("dup returned error\n");
fdb = dup(fd1[1]); /* dup into childs stdout */
if ( fdb == -1 )
printf("dup returned error\n");
fdc = dup(fd1[1]); /* dup into childs stderr */
if ( fdc == -1 )
printf("dup returned error\n");
printf("fda=%d fdb=%d fdc=%d\n",fda,fdb,fdc);
/* close all extra descriptors */
close(fd1[0]);
close(fd1[1]);
close(fd2[0]);
close(fd2[1]);
execve(pgmptr,argsv,envp); /* never returns if it works */
exit(0200); /* report to parent that the exec failed */
}
else /* the parent, set up talker and listener processes */
{
close(fd2[0]);
close(fd1[1]); /* close unused pipe ends for safety */
printf("Will now set up talker and listener processes\n");
if ( ( pid_talker = fork()) < 0 ) /* fork failed */
{
printf("Couldn't fork the 2nd time");
exit();
}
if ( pid_talker != 0 ) /* the parent, listen to pipe and echo */
{
while ( (status = read(fd1[0],&c,1) ) > 0 )
{
putchar(c);
}
printf("sending kill signal to pid_talker process\n");
kill(pid_talker,SIGKILL); /* kill the child */
pid = wait(&death_note); /* so no zombies left around */
printf("pid %d, the wait status from death_note was %o\n",pid,death_note );
printf("wait for death_note completed, death_note = %d\n",death_note);
}
else /* the child talker, reads stdin and writes down the pipe */
{
while ( (ch = getchar()) != EOF )
{
chr = ch; /* the 68000 byte ordering requires */
/* addr of char not int!! */
if ( write(fd2[1],&chr,1) != 1 )
printf("Couldn't write to pipe\n");
}
close(fd2[1]);
printf("willingly leaving the talker subprocess\n");
exit(0);
}
}
printf("in pipemaster main program, waiting for child to finish\n");
pid = wait(&suicide_note); /* wait for child to finish */
printf("pid %d, the wait status was %o\n",pid,suicide_note );
if ( (suicide_note >> 8) == 0200 )
printf("the exec failed\n");
close(fd2[1]);
close(fd1[0]); /* clean up */
printf("clean up complete, end of for loop\n");
}
printf("exiting pipemaster main program\n");
}
----------------------------------------------------------------------
here are some sample programs for it to invoke
----------------------------------------------------------------
#include <stdio.h>
/* test1 - a sample program too be invoked by the expert system */
/* Global Data , Defined here and used in other modules */
char *version = "V1.00"; /* string built at initialize time */
int debuglevel = 0; /* used to turn debug printouts on and off */
int expert = 0; /* set to 1 if program is to run in expert mode */
int parameter = 0;
int subtest = 0;
/*-------------------------------------------------------------------*/
main(argc,argv)
int argc;
char *argv[];
{
int c;
char buf[80];
char *u;
int status;
setbuf(stdout,NULL);
printf("argc = %d, argv[0] = %s, argv[1] = %s\n",argc,argv[0],argv[1]);
while ( --argc > 0 && (*++argv)[0] == '-')
for ( u = argv[0] + 1 ; *u != '\0' ; u++ ) switch(*u)
{
case 'd': /* turns on debug */
debuglevel++; /* the more d's the higher the debug level */
break;
case 'v':
printf("\nVersion %s\n",version);
exit(1);
break;
case 's':
sscanf(*++argv,"%d",&subtest);
if ( debuglevel )
printf("subtest = %d\n",subtest);
break;
case 'x':
expert = 1;
break;
case 'p':
sscanf(*++argv,"%d",¶meter);
if ( debuglevel )
printf("parameter = %d\n",parameter);
break;
case 'f':
/* replace description with your programs function */
printf("This test verifies that the ibus is functional by\n");
printf("reading and writing the page register on both T bus\n");
printf("driver boards if both are present\n");
exit(0);
default:
printf("\nIllegal option -%c\n", *u);
case 'h': /* help */
printf("usage: -v -h -d -x -s # -p # -f\n");
printf(" -d The more d's the higher the debug e.g. -ddddd \n");
printf(" -v reports the version number of the program\n");
printf(" -x invokes program in 'expert' mode\n");
printf(" -h help, provides this flag option list\n");
printf(" -s # where # is a number means do sub-test #\n");
printf(" -p # is a parameter number for use by the program\n");
printf(" -f print a brief functional description of test\n");
exit(1);
}
printf("I am test1\n");
while ( argc-- )
{
printf("arg%d = %s\n",argc,argv[argc]);
}
c = 'a';
printf("enter text: ");
/* fflush(stdout); */
gets(buf);
/* while ( (status = read(0,&c,1)) > 0 )
{
printf("%c",c);
fflush(stdout);
} */
printf("\nI am leaving test1 now\n");
}
--------------------------------------------------------------------------
#include <stdio.h>
main(argc,argv)
int argc;
char *argv[];
{
setbuf(stdout,NULL); /* note that you should do this when using pipes */
printf("I am test2\n");
printf("argc = %d, argv[0] = %s, argv[1] = %s\n",argc,argv[0],argv[1]);
while ( argc-- )
{
printf("arg%d = %s\n",argc,argv[argc]);
}
printf("I am leaving test2 now\n");
}
More information about the Comp.unix.questions
mailing list