home *** CD-ROM | disk | FTP | other *** search
- From: tchrist@convex.COM (Tom Christiansen)
- Newsgroups: comp.unix.questions,comp.unix.wizards,alt.sources
- Subject: Re: redirecting standard i/o from an exec'ed programme
- Message-ID: <105018@convex.convex.com>
- Date: 16 Aug 90 18:28:46 GMT
-
- Hmm.. I think I posted this before, but it may have been five years ago.
- This is for systems with socketpair(), and you should read and consider
- the caveat section very carefully. Also, contains non-ANSI cpp abuse,
- if that bugs you; what can I say? I was young and foolish. :-)
-
- --tom
-
-
- #! /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:
- # process.c
- # This archive created: Thu Aug 16 13:17:01 1990
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'process.c'" '(4801 characters)'
- if test -f 'process.c'
- then
- echo shar: "will not over-write existing file 'process.c'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'process.c'
- X/* process.c
- X *
- X * written by tom christiansen on Wed May 22 15:02:19 CDT 1985 to open
- X * a socket pair and let the user read and write from both sides.
- X * return -1 on error, otherwise put the correct file pointers
- X * into *input and *output.
- X *
- X * CAVEAT UTILITOR:
- X * you will block forever if one of the sides of the
- X * pipes blocks because of too much in the buffer.
- X */
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#include <sys/param.h>
- X#include <sys/wait.h>
- X#include <sys/socket.h>
- X
- X#define READ 0
- X#define WRITE 1
- X#define CHILD 0
- X#define PARENT 1
- X
- X/*
- X * define QUIET if you don't want error messages
- X * to print out if something blows up due to test
- X * macros. this assumes you will perror() it yourself
- X * when the routine returns.
- X */
- X#ifdef QUIET
- X# define announce(x) /* nothing at all */
- X#else
- X# define announce(x) perror(x)
- X#endif QUIET
- X
- X/*
- X * first some macros to avoid lots of typing and ugly
- X * code.
- X */
- X#define test0(x) \
- X if (!(x)) { \
- X announce("process: x"); \
- X return -1; \
- X }
- X
- X#define test(x) \
- X if ( (x) < 0 ) { \
- X announce("process: x"); \
- X return -1; \
- X }
- X
- Xchar FD_READ[] = "r";
- Xchar FD_WRITE[] = "w";
- X
- X/*
- X * first a static array to hold the pid of
- X * the process we create so we can wait for
- X * it to die when we close up. there is enough
- X * room for all possible file descriptors (NOFILE)
- X * so this function may be called repeatedly by
- X * a program with no ill effects.
- X */
- Xstatic int pids[NOFILE];
- X
- X/*****************************************************************
- X *
- X * process - a function to do what popen does, but to
- X * give you back file pointers for read as
- X * well as for write.
- X *
- X *****************************************************************/
- X
- Xint
- Xprocess(cmd,input,output)
- X char *cmd;
- X FILE **input,**output;
- X{
- X int sock[2];
- X register pid;
- X
- X
- X/*
- X * use connected socket pair so we can do reads and
- X * writes on these things. if we used a pipe() call,
- X * it would be unidirectional and we would have to
- X * make two calls to get 4 file descriptors.
- X */
- X test(socketpair(AF_UNIX,SOCK_STREAM,0,sock));
- X
- X/*
- X * fork for the child command. don't bother doing
- X * a real fork, since we're just going to exec anyway,
- X * so borrow the parent's pages with a vfork.
- X */
- X if((pid = vfork()) == CHILD) {
- X
- X/*
- X * close old stdin and stdout to make room for socket
- X * descriptors.
- X */
- X test(close(READ));
- X test(close(WRITE));
- X
- X/*
- X * the kid will use the CHILD end. connect both his stdin
- X * and stdout to the CHILD socket, which is fine because
- X * unix domain sockets are bidirectional.
- X */
- X test(dup2(sock[CHILD], WRITE));
- X test(dup2(sock[CHILD], READ));
- X
- X/*
- X * don't need these anymore, and if we don't get rid of them, we
- X * won't be happy later on, because the process doesn't seem to die.
- X */
- X test(close(sock[CHILD]));
- X test(close(sock[PARENT]));
- X/*
- X * now do the command. use the csh for tilda's sake.
- X */
- X execl("/bin/csh", "csh", "-fc", cmd, 0);
- X perror("process kid: execl");
- X _exit(1);
- X }
- X
- X/*
- X * -1 pid means we couldn't fork.
- X */
- X if(pid == -1) {
- X perror("process: vfork");
- X (void) close(sock[CHILD]);
- X (void) close(sock[PARENT]);
- X return -1;
- X }
- X
- X/*
- X * otherwise, we are the parent and healthy;
- X * remember the kid pid for a later close.
- X */
- X pids[sock[PARENT]] = pid;
- X
- X/*
- X * connect up the user's input and output file
- X * pointers to our end of the socket connection.
- X * give him one for read and one for write.
- X */
- X test0(*input = fdopen(sock[PARENT],FD_READ));
- X test0(*output = fdopen(sock[PARENT],FD_WRITE));
- X
- X test(close(sock[CHILD]));
- X
- X return 0;
- X}
- X
- X
- X/****************************************************************
- X * close up the passed file and wait for the
- X * child to die.
- X ***************************************************************/
- X
- X#undef test
- X#define test(x) \
- X if ( (x) < 0 ) { \
- X announce("process_close: x"); \
- X return -1; \
- X }
- X
- X/*
- X * don't need them both since they are the
- X * same thing
- X */
- Xint
- Xprocess_close(input)
- XFILE *input;
- X{
- X register f,r, (*hstat)(), (*istat)(), (*qstat)();
- X int status;
- X
- X f = fileno(input);
- X test(fclose(input));
- X/*
- X * don't need to close also output, as it is the same
- X */
- X
- X/*
- X * protect ourselves from unfriendly signals while
- X * waiting for child's death.
- X */
- X istat = signal(SIGINT, SIG_IGN);
- X qstat = signal(SIGQUIT, SIG_IGN);
- X hstat = signal(SIGHUP, SIG_IGN);
- X
- X/*
- X * wait for the child to die, keeping track of status.
- X * we saved the kid pid in the pids[] array when we
- X * first did the process call.
- X */
- X while((r = wait((union wait *)&status)) != pids[f] && r == -1)
- X ;
- X if(r == -1)
- X status = -1;
- X
- X/*
- X * restore old sig values.
- X */
- X (void) signal(SIGINT, istat);
- X (void) signal(SIGQUIT, qstat);
- X (void) signal(SIGHUP, hstat);
- X
- X return(status);
- X
- X}
- X
- X
- X/* lint output:
- Xprocess.c:
- X*/
- X
- X/*
- X * yes, folks, unlike the kernel, this file lints clean!
- X */
- SHAR_EOF
- if test 4801 -ne "`wc -c < 'process.c'`"
- then
- echo shar: "error transmitting 'process.c'" '(should have been 4801 characters)'
- fi
- chmod 644 'process.c'
- fi
- exit 0
- # End of shell archive
- --
- Tom Christiansen {uunet,uiucdcs,sun}!convex!tchrist
- Convex Computer Corporation tchrist@convex.COM
- "UNIX was never designed to keep people from doing stupid things,
- because that policy would also keep them from doing clever things." [gwyn]
-