[alt.sources] redirecting standard i/o from and exec'ed programme

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