home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1683 < prev    next >
Internet Message Format  |  1990-12-28  |  7KB

  1. From: tchrist@convex.COM (Tom Christiansen)
  2. Newsgroups: comp.unix.questions,comp.unix.wizards,alt.sources
  3. Subject: Re: redirecting standard i/o from an exec'ed programme
  4. Message-ID: <105018@convex.convex.com>
  5. Date: 16 Aug 90 18:28:46 GMT
  6.  
  7. Hmm.. I think I posted this before, but it may have been five years ago.
  8. This is for systems with socketpair(), and you should read and consider
  9. the caveat section very carefully.  Also, contains non-ANSI cpp abuse,
  10. if that bugs you; what can I say?  I was young and foolish. :-)
  11.  
  12. --tom
  13.  
  14.  
  15. #! /bin/sh
  16. # This is a shell archive, meaning:
  17. # 1. Remove everything above the #! /bin/sh line.
  18. # 2. Save the resulting text in a file.
  19. # 3. Execute the file with /bin/sh (not csh) to create:
  20. #    process.c
  21. # This archive created: Thu Aug 16 13:17:01 1990
  22. export PATH; PATH=/bin:/usr/bin:$PATH
  23. echo shar: "extracting 'process.c'" '(4801 characters)'
  24. if test -f 'process.c'
  25. then
  26.     echo shar: "will not over-write existing file 'process.c'"
  27. else
  28. sed 's/^    X//' << \SHAR_EOF > 'process.c'
  29.     X/* process.c 
  30.     X *
  31.     X *    written by tom christiansen on Wed May 22 15:02:19 CDT 1985 to open
  32.     X *    a socket pair and let the user read and write from both sides.
  33.     X *    return -1 on error, otherwise put the correct file pointers
  34.     X *    into *input and *output.  
  35.     X *
  36.     X *    CAVEAT UTILITOR:
  37.     X *        you will block forever if one of the sides of the
  38.     X *        pipes blocks because of too much in the buffer.  
  39.     X */
  40.     X 
  41.     X#include <stdio.h>
  42.     X#include <signal.h>
  43.     X#include <sys/param.h>
  44.     X#include <sys/wait.h>
  45.     X#include <sys/socket.h>
  46.     X
  47.     X#define    READ    0
  48.     X#define    WRITE    1
  49.     X#define CHILD     0
  50.     X#define PARENT    1
  51.     X
  52.     X/*
  53.     X *    define QUIET if you don't want error messages
  54.     X *    to print out if something blows up due to test
  55.     X *    macros.  this assumes you will perror() it yourself
  56.     X *    when the routine returns.
  57.     X */
  58.     X#ifdef QUIET
  59.     X#    define announce(x)  /* nothing at all */
  60.     X#else
  61.     X#    define announce(x) perror(x)
  62.     X#endif QUIET
  63.     X
  64.     X/*
  65.     X *    first some macros to avoid lots of typing and ugly
  66.     X *    code.
  67.     X */
  68.     X#define test0(x)    \
  69.     X    if (!(x)) {    \
  70.     X        announce("process: x");    \
  71.     X        return -1;    \
  72.     X    }
  73.     X
  74.     X#define test(x)    \
  75.     X    if ( (x) < 0 ) {    \
  76.     X        announce("process: x");    \
  77.     X        return -1;    \
  78.     X    }
  79.     X
  80.     Xchar FD_READ[] = "r";
  81.     Xchar FD_WRITE[] = "w";
  82.     X
  83.     X/*
  84.     X *    first a static array to hold the pid of 
  85.     X *    the process we create so we can wait for
  86.     X *    it to die when we close up.  there is enough
  87.     X *    room for all possible file descriptors (NOFILE)
  88.     X *    so this function may be called repeatedly by
  89.     X *    a program with no ill effects.
  90.     X */
  91.     Xstatic    int    pids[NOFILE];
  92.     X
  93.     X/*****************************************************************
  94.     X *
  95.     X *    process - a function to do what popen does, but to 
  96.     X *              give you back file pointers for read as
  97.     X *              well as for write.
  98.     X *
  99.     X *****************************************************************/
  100.     X
  101.     Xint
  102.     Xprocess(cmd,input,output)
  103.     X    char    *cmd;
  104.     X    FILE    **input,**output;
  105.     X{
  106.     X    int sock[2];
  107.     X    register  pid;
  108.     X
  109.     X
  110.     X/*
  111.     X *    use connected socket pair so we can do reads and 
  112.     X *    writes on these things.  if we used a pipe() call,
  113.     X *    it would be unidirectional and we would have to 
  114.     X *    make two calls to get 4 file descriptors.
  115.     X */
  116.     X    test(socketpair(AF_UNIX,SOCK_STREAM,0,sock));
  117.     X
  118.     X/*
  119.     X *     fork for the child command.  don't bother doing
  120.     X *    a real fork, since we're just going to exec anyway,
  121.     X *    so borrow the parent's pages with a vfork.
  122.     X */
  123.     X    if((pid = vfork()) == CHILD) { 
  124.     X
  125.     X/*
  126.     X *    close old stdin and stdout to make room for socket
  127.     X *    descriptors.
  128.     X */
  129.     X        test(close(READ));    
  130.     X        test(close(WRITE));
  131.     X
  132.     X/*    
  133.     X *    the kid will use the CHILD end.  connect both his stdin
  134.     X *    and stdout to the CHILD socket, which is fine because 
  135.     X *    unix domain sockets are bidirectional.
  136.     X */
  137.     X        test(dup2(sock[CHILD], WRITE));
  138.     X        test(dup2(sock[CHILD], READ));
  139.     X
  140.     X/*
  141.     X *    don't need these anymore, and if we don't get rid of them, we 
  142.     X *    won't be happy later on, because the process doesn't seem to die.
  143.     X */
  144.     X        test(close(sock[CHILD]));
  145.     X        test(close(sock[PARENT]));
  146.     X/*
  147.     X *    now do the command.  use the csh for tilda's sake.
  148.     X */
  149.     X        execl("/bin/csh", "csh", "-fc", cmd, 0);
  150.     X        perror("process kid: execl");
  151.     X        _exit(1);
  152.     X    }
  153.     X
  154.     X/*
  155.     X *    -1 pid means we couldn't fork.
  156.     X */
  157.     X    if(pid == -1) {
  158.     X        perror("process: vfork");
  159.     X        (void) close(sock[CHILD]);
  160.     X        (void) close(sock[PARENT]);
  161.     X        return -1;
  162.     X    }
  163.     X
  164.     X/*
  165.     X *    otherwise, we are the parent and healthy;
  166.     X *    remember the kid pid for a later close.
  167.     X */
  168.     X    pids[sock[PARENT]] = pid;
  169.     X
  170.     X/*
  171.     X *    connect up the user's input and output file
  172.     X *    pointers to our end of the socket connection.
  173.     X *    give him one for read and one for write.
  174.     X */
  175.     X    test0(*input = fdopen(sock[PARENT],FD_READ));
  176.     X    test0(*output = fdopen(sock[PARENT],FD_WRITE));
  177.     X
  178.     X    test(close(sock[CHILD]));
  179.     X
  180.     X    return 0;
  181.     X}
  182.     X
  183.     X
  184.     X/****************************************************************
  185.     X *    close up the passed file and wait for the 
  186.     X *    child to die.
  187.     X ***************************************************************/
  188.     X
  189.     X#undef test
  190.     X#define test(x)    \
  191.     X    if ( (x) < 0 ) {    \
  192.     X        announce("process_close: x");    \
  193.     X        return -1;    \
  194.     X    }
  195.     X
  196.     X/*
  197.     X *    don't need them both since they are the 
  198.     X *     same thing
  199.     X */
  200.     Xint
  201.     Xprocess_close(input)
  202.     XFILE *input;
  203.     X{
  204.     X    register f,r, (*hstat)(), (*istat)(), (*qstat)();
  205.     X    int status;
  206.     X
  207.     X    f = fileno(input);
  208.     X    test(fclose(input)); 
  209.     X/*
  210.     X *    don't need to close also output, as it is the same 
  211.     X */
  212.     X
  213.     X/*
  214.     X *    protect ourselves from unfriendly signals while
  215.     X *    waiting for child's death.
  216.     X */
  217.     X    istat = signal(SIGINT, SIG_IGN);
  218.     X    qstat = signal(SIGQUIT, SIG_IGN);
  219.     X    hstat = signal(SIGHUP, SIG_IGN);
  220.     X
  221.     X/*
  222.     X *    wait for the child to die, keeping track of status.
  223.     X *    we saved the kid pid in the pids[] array when we 
  224.     X *    first did the process call.
  225.     X */
  226.     X    while((r = wait((union wait *)&status)) != pids[f] && r == -1)
  227.     X        ;
  228.     X    if(r == -1)
  229.     X        status = -1;
  230.     X
  231.     X/*    
  232.     X *    restore old sig values.
  233.     X */
  234.     X    (void) signal(SIGINT, istat);
  235.     X    (void) signal(SIGQUIT, qstat);
  236.     X    (void) signal(SIGHUP, hstat);
  237.     X
  238.     X    return(status);
  239.     X
  240.     X}
  241.     X
  242.     X
  243.     X/* lint output:
  244.     Xprocess.c:
  245.     X*/
  246.     X
  247.     X/*
  248.     X *    yes, folks, unlike the kernel, this file lints clean!
  249.     X */
  250. SHAR_EOF
  251. if test 4801 -ne "`wc -c < 'process.c'`"
  252. then
  253.     echo shar: "error transmitting 'process.c'" '(should have been 4801 characters)'
  254. fi
  255. chmod 644 'process.c'
  256. fi
  257. exit 0
  258. #    End of shell archive
  259. --
  260. Tom Christiansen                       {uunet,uiucdcs,sun}!convex!tchrist 
  261. Convex Computer Corporation                            tchrist@convex.COM
  262.   "UNIX was never designed to keep people from doing stupid things,
  263.    because that policy would also keep them from doing clever things." [gwyn]
  264.