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",&parameter);
		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