redirecting standard i/o from an exec'ed programme
George Bogatko
bogatko at lzga.ATT.COM
Wed Aug 15 22:39:54 AEST 1990
HI:
This posting is in response to:
"michael at 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?
**********
Popen is expensive. It requires a shell for 'system' and then
another shell to run your request in. On large systems with many
users, this is death.
I did it another way, which doesn't require any sub-shells. However
It will not handle complicated piping schemes, which 'popen()' does.
GB
********** 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
More information about the Comp.unix.questions
mailing list