home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / npopen.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  5KB  |  266 lines

  1. /*    npopen:  like popen, but grabs stderr, too
  2.  *        written by John Hutchinson, heavily modified by Paul Fox
  3.  *
  4.  * $Log: npopen.c,v $
  5.  * Revision 1.15  1992/12/04  09:21:52  foxharp
  6.  * don't close the half of a child's io that we're _not_ using
  7.  *
  8.  * Revision 1.14  1992/12/03  00:32:59  foxharp
  9.  * new system_SHELL and exec_sh_c routines
  10.  *
  11.  * Revision 1.13  1992/05/25  21:07:48  foxharp
  12.  * extern func declarations moved to header
  13.  *
  14.  * Revision 1.12  1992/05/16  12:00:31  pgf
  15.  * prototypes/ansi/void-int stuff/microsoftC
  16.  *
  17.  * Revision 1.11  1992/03/25  19:13:17  pgf
  18.  * BSD portability changes
  19.  *
  20.  * Revision 1.10  1992/03/19  23:25:04  pgf
  21.  * linux port, and default NOFILE to 20 (bogus)
  22.  *
  23.  * Revision 1.9  1991/11/18  08:33:25  pgf
  24.  * added missing arg to strrchr
  25.  *
  26.  * Revision 1.8  1991/11/16  18:36:46  pgf
  27.  * no #define for strrchr needed here
  28.  *
  29.  * Revision 1.7  1991/10/22  14:08:23  pgf
  30.  * took out old ifdef BEFORE code
  31.  *
  32.  * Revision 1.6  1991/10/21  13:39:54  pgf
  33.  * plugged file descriptor leak
  34.  *
  35.  * Revision 1.5  1991/08/07  12:35:07  pgf
  36.  * added RCS log messages
  37.  *
  38.  * revision 1.4
  39.  * date: 1991/08/06 15:30:25;
  40.  * took out setbuf(NULL)'s, as an experiment, on Dave's suggestion
  41.  * 
  42.  * revision 1.3
  43.  * date: 1991/06/25 14:22:33;
  44.  * defensinve checks against fdopen failure
  45.  * 
  46.  * revision 1.2
  47.  * date: 1991/04/04 09:38:39;
  48.  * support for bidirectional pipes
  49.  * 
  50.  * revision 1.1
  51.  * date: 1990/09/21 10:25:49;
  52.  * initial vile RCS revision
  53.  */
  54.  
  55. #include <stdio.h>
  56. #include "estruct.h"
  57. #include "edef.h"
  58.  
  59. #if UNIX
  60.  
  61. #include <signal.h>
  62. #include <errno.h>
  63. #include <sys/param.h>
  64.  
  65. #define R 0
  66. #define W 1
  67.  
  68. static int pipe_pid;
  69.  
  70.  
  71. FILE *
  72. npopen (cmd, type)
  73. char *cmd, *type;
  74. {
  75.     FILE *ff;
  76.  
  77.     if (*type != 'r' && *type != 'w')
  78.         return NULL;
  79.  
  80.     if (*type == 'r') {
  81.         if (inout_popen(&ff, NULL, cmd) != TRUE)
  82.             return NULL;
  83.         return ff;
  84.     } else {
  85.         if (inout_popen(NULL, &ff, cmd) != TRUE)
  86.             return NULL;
  87.         return ff;
  88.     }
  89. }
  90.  
  91. int
  92. inout_popen(fr, fw, cmd)
  93. FILE **fr, **fw;
  94. char *cmd;
  95. {
  96.     int rp[2];
  97.     int wp[2];
  98.     
  99.  
  100.     if (pipe(rp))
  101.         return FALSE;
  102.     if (pipe(wp))
  103.         return FALSE;
  104.         
  105.     pipe_pid = softfork();
  106.     if (pipe_pid < 0)
  107.         return FALSE;
  108.  
  109.     if (pipe_pid) { /* parent */
  110.  
  111.         if (fr) {
  112.             *fr = fdopen (rp[0], "r");
  113.             if (*fr == NULL) {
  114.                 fprintf(stderr,"fdopen r failed\n");
  115.                 abort();
  116.             }
  117.         } else {
  118.             (void)close(rp[0]);
  119.         }
  120.         (void) close (rp[1]);
  121.  
  122.         if (fw) {
  123.             *fw = fdopen (wp[1], "w");
  124.             if (*fw == NULL) {
  125.                 fprintf(stderr,"fdopen w failed\n");
  126.                 abort();
  127.             }
  128.         } else {
  129.             (void)close(wp[1]);
  130.         }
  131.         (void) close (wp[0]);
  132.         return TRUE;
  133.  
  134.     } else {            /* child */
  135.  
  136.         if (fw) {
  137.             (void)close (0);
  138.             if (dup (wp[0]) != 0) {
  139.                 write(2,"dup 0 failed\r\n",15);
  140.                 exit(-1);
  141.             }
  142.         }
  143.         (void) close (wp[1]);
  144.         if (fr) {
  145.             (void)close (1);
  146.             if (dup (rp[1]) != 1) {
  147.                 write(2,"dup 1 failed\r\n",15);
  148.                 exit(-1);
  149.             }
  150.             (void)close (2);
  151.             if (dup (rp[1]) != 2) {
  152.                 write(1,"dup 2 failed\r\n",15);
  153.                 exit(-1);
  154.             }
  155.         } else {
  156.             (void) close (rp[1]);
  157.         }
  158.         (void) close (rp[0]);
  159.         exec_sh_c(cmd);
  160.  
  161.     }
  162.     return TRUE;
  163. }
  164.  
  165. void
  166. npclose (fp)
  167. FILE *fp;
  168. {
  169.     extern int errno;
  170.     int child;
  171.     fflush(fp);
  172.     fclose(fp);
  173.     while ((child = wait ((int *)0)) != pipe_pid) {
  174.         if (child < 0 && errno == EINTR) {
  175.             (void) kill (SIGKILL, pipe_pid);
  176.         }
  177.     }
  178. }
  179.  
  180. void
  181. exec_sh_c(cmd)
  182. char *cmd;
  183. {
  184.     static char *sh, *shname;
  185.     int i;
  186.  
  187. #ifndef NOFILE
  188. # define NOFILE 20
  189. #endif
  190.     /* Make sure there are no upper inherited file descriptors */
  191.     for (i = 3; i < NOFILE; i++)
  192.         (void) close (i);
  193.  
  194.     if (sh == NULL) {
  195.         if ((sh = getenv("SHELL")) == NULL || *sh == '\0') {
  196.             sh = "/bin/sh";
  197.             shname = "sh";
  198.         } else {
  199.             shname = strrchr(sh,'/');
  200.             if (shname == NULL) {
  201.                 shname = sh;
  202.             } else {
  203.                 shname++;
  204.                 if (*shname == '\0')
  205.                     shname = sh;
  206.             }
  207.         }
  208.     }
  209.  
  210.     if (cmd)
  211.         (void) execlp (sh, shname, "-c", cmd, 0);
  212.     else
  213.         (void) execlp (sh, shname, 0);
  214.     write(2,"exec failed\r\n",14);
  215.     exit (-1);
  216. }
  217.  
  218. int
  219. system_SHELL(cmd)
  220. char *cmd;
  221. {
  222.     int cpid;
  223.  
  224.     cpid = softfork();
  225.     if (cpid < 0) {
  226.         write(2,"cannot fork\n",13);
  227.         return cpid;
  228.     }
  229.  
  230.     if (cpid) { /* parent */
  231.         int child;
  232.         while ((child = wait ((int *)0)) != cpid) {
  233.             if (child < 0 && errno == EINTR) {
  234.                 (void) kill (SIGKILL, cpid);
  235.             }
  236.         }
  237.         return 0;
  238.     } else {
  239.         exec_sh_c(cmd);
  240.         write(2,"cannot exec\n",13);
  241.         return -1;
  242.     }
  243.  
  244. }
  245.  
  246. int
  247. softfork()
  248. {
  249.     /* Try & fork 5 times, backing off 1, 2, 4 .. seconds each try */
  250.     int fpid;
  251.     int tries = 5;
  252.     unsigned slp = 1;
  253.  
  254.     while ((fpid = fork ()) < 0) {
  255.         if (--tries == 0)
  256.             return -1;
  257.         (void) sleep (slp);
  258.         slp <<= 1;
  259.     }
  260.     return fpid;
  261. }
  262.  
  263. #else
  264. npopenhello() {}
  265. #endif
  266.