bogatko@lzga.ATT.COM (George Bogatko) (08/15/90)
HI: This posting is in response to: "michael@fe2o3.UUCP (Michael Katzmann @ Rusty's BSD machine at home)" found in comp.unix.questions I have a task that requires the ability to fork off another programme but to supply it's standard input and output. . . . However there doesn't seem to be any way to use popen() to do both similtaneously. What is the usual way to to this? ********** Here is how I did it. ********** CUT HERE ********** CUT HERE ********** CUT HERE ********** CUT HERE #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # makefile # fcopy.c # fpipe.c # fpipe.h # main.c # tst.c # This archive created: Tue Feb 27 13:44:14 1990 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'makefile' then echo shar: "will not over-write existing file 'makefile'" else cat << \SHAR_EOF > 'makefile' CFLAGS=-I. LIBS= OBJS=\ main.o \ fpipe.o \ fcopy.o OUTPUT=\ main $(OUTPUT): $(OBJS) cc -o $(OUTPUT) $(OBJS) $(LIBS) SHAR_EOF fi if test -f 'fcopy.c' then echo shar: "will not over-write existing file 'fcopy.c'" else cat << \SHAR_EOF > 'fcopy.c' /****************************************************************************** * * * fcopy.c * * * ******************************************************************************/ /*-------------------------- INITIAL CODING DATE ----------------------------- Thu Nov 10 10:56:37 EST 1988 by George M. Bogatko -------------------------------- HEADER FILES -----------------------------*/ #include <stdio.h> #include <fpipe.h> #include <fcntl.h> /*------------------ TYPEDEF'S, DEFINES, STRUCTURE DEF'S ------------------*/ /*---------------- IMPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ extern char *fgets(); /*---------------- EXPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ /*---------------- INTERNAL GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ #ident "%W% %G% - George M. Bogatko -" /*----------------------------------------------------------------------------- SYNOPSIS: fcopy(in_fd, out_fname, flag) DESCRIPTION: FCOPY copies lines from an IN_FD (maybe a pipe) to a standard file. The arguments are: in_fd - a 'FILE *' type file descriptor out_fname - The file you want to write to flag - Whether your want the READ to be BLOCK or NON_BLOCK with BLOCK, the fgets will block (in the case of pipes, a block occurs if there is nothing in the pipe to read. with NON_BLOCK, the first READ is BLOCKED, (to allow pipe synchronization) and subsequent reads are NON_BLOCK. RETURN: 0 on success -1 on error (use perror()) =============================================================================*/ int fcopy(in_fp, outname, blockflag) FILE *in_fp; char *outname; int blockflag; { FILE *out_fp; char buf[BUFSIZ]; enum {first, next} time = first; if( (out_fp = fopen(outname, "w")) == (FILE *)NULL ) return -1; while( fgets(buf, BUFSIZ, in_fp) != (char *)NULL ) { if( time == first ) { if( blockflag == NO_BLOCK ) { if(fcntl( fileno(in_fp), F_SETFL, O_NDELAY ) == -1 ) { perror(""); fclose(out_fp); return -1; } } time = next; } fputs(buf, out_fp); } fclose(out_fp); return 0; } SHAR_EOF fi if test -f 'fpipe.c' then echo shar: "will not over-write existing file 'fpipe.c'" else cat << \SHAR_EOF > 'fpipe.c' /****************************************************************************** * * * fpipe.c * * * ******************************************************************************/ /*-------------------------- INITIAL CODING DATE ----------------------------- Thu Nov 10 10:30:22 EST 1988 by George M. Bogatko -------------------------------- HEADER FILES -----------------------------*/ #include <stdio.h> #include <fpipe.h> #include <fcntl.h> #include <varargs.h> /*------------------ TYPEDEF'S, DEFINES, STRUCTURE DEF'S ------------------*/ /*---------------- IMPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ /*---------------- EXPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ /*---------------- INTERNAL GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ #ident "%W% %G% - George M. Bogatko -" /*----------------------------------------------------------------------------- SYNOPSIS: int fpipe(flag, arg_array, program, arg1, arg2, ... argn, 0 ); DESCRIPTION: FPIPE creates a two way pipe between a calling process and a child process. That child process should expect to read from STANDARD IN and write to STANDARD OUT. The arguments are: flag - one of STD_ERR_SCR or STD_ERR_NUL. STD_ERR_SCR will put STANDARD ERR to the screen, STD_ERR_NUL will put STANDARD ERR to "/dev/null" arg_array - an array of 2 'FILE *' type pointers EX: FILE *arg_array[2]; When the function returns, arg_array[0] will contain the READING end of the pipe connected to the process's standard output, and arg_array[1] will contain the WRITING end of the pipe connected to the process's standard input. program - the full path of the program you want to invoke. arg1 ... argN - all the arguments to your program 0 - the termination point of the arg1 ... argN sequence. RETURN: the PROCESS ID of the created child on success, -1 on any error (use "perror()" to find out what happened). CAVEATS: The LAST argument MUST be 0 =============================================================================*/ int fpipe(flag, arg_array, va_alist) int flag; FILE *arg_array[]; va_dcl { char **args; int in_pfd[2]; int out_pfd[2]; FILE *read_fp, *write_fp; char *file; int i; int proc_id = 0; if( pipe(in_pfd) == (-1) ) return(-1); if( pipe(out_pfd) == (-1) ) return(-1); args = (char **)&va_alist; /* won't work on Pyramid */ switch( proc_id = fork() ) { case -1: return(-1); case 0: close(0); dup(out_pfd[0]); close(1); dup(in_pfd[1]); if( flag == STD_ERR_NUL ) { close(2); if(open("/dev/null", O_WRONLY) == -1) return(-1); } close(in_pfd[0]); close(in_pfd[1]); close(out_pfd[0]); close(out_pfd[1]); execv(args[0], args); return(-1); default: close(in_pfd[1]); close(out_pfd[0]); if( (read_fp = fdopen( in_pfd[0], "r" )) == (FILE *)NULL ) return(-1); if( (write_fp = fdopen( out_pfd[1], "w" )) == (FILE *)NULL ) return(-1); arg_array[0] = read_fp; arg_array[1] = write_fp; return(proc_id); } } SHAR_EOF fi if test -f 'fpipe.h' then echo shar: "will not over-write existing file 'fpipe.h'" else cat << \SHAR_EOF > 'fpipe.h' /****************************************************************************** * * * fpipe.h * * * ******************************************************************************/ /*-------------------------- INITIAL CODING DATE ----------------------------- Thu Nov 10 11:01:32 EST 1988 by George M. Bogatko -------------------------------- HEADER FILES -----------------------------*/ /*------------------ TYPEDEF'S, DEFINES, STRUCTURE DEF'S ------------------*/ #define STD_ERR_SCR 0 #define STD_ERR_NUL 1 #define NO_BLOCK 0 #define BLOCK 1 #ident "%W% %G% - George M. Bogatko -" /*----------------------------------------------------------------------------- SYNOPSIS: #include <fpipe.h> DESCRIPTION: This includes #define's used by FCOPY and FPIPE CAVEATS: =============================================================================*/ SHAR_EOF fi if test -f 'main.c' then echo shar: "will not over-write existing file 'main.c'" else cat << \SHAR_EOF > 'main.c' #include <stdio.h> #include <fcntl.h> #include <fpipe.h> #include <signal.h> #define READ_END 0 #define WRITE_END 1 extern int fpipe(); extern char *fgets(); char buf[BUFSIZ]; main() { FILE *args[2]; enum {first, next} time = first; int pid; /* if( (pid = fpipe(STD_ERR_SCR, args, "./tst",0)) == -1 ) */ if( (pid = fpipe(STD_ERR_NUL, args, "/usr/bin/mailx", "-u", "gb", "-f","$HOME/mbox",0)) == -1 ) { puts("AARRRRRGGGG!!!!"); exit(-1); } for(;;) { fcopy(args[READ_END], "/dev/tty", NO_BLOCK); printf("enter command\n"); gets(buf); if( *buf == 27 ) break; fprintf(args[WRITE_END], "%s\n", buf); fflush(args[WRITE_END]); } /* * closing the file pointers also sends 'CTRL-D' (EOF) to the child * process. In the case of 'mailx' this will kill it. */ fcopy(args[READ_END], "/dev/tty", NO_BLOCK); fclose(args[READ_END]); fclose(args[WRITE_END]); return 0; } SHAR_EOF fi if test -f 'tst.c' then echo shar: "will not over-write existing file 'tst.c'" else cat << \SHAR_EOF > 'tst.c' #include <stdio.h> main() { fprintf(stdout, "THIS TO STANDARD OUT\n"); fprintf(stderr, "THIS TO STANDARD ERR\n"); } SHAR_EOF fi exit 0 # End of shell archive