src/lib/bpipe.c
BPIPE *open_bpipe(char *prog, int wait, const char *mode, char *envp[])
{
   char *bargv[MAX_ARGV];
   int bargc, i;
   int readp[2], writep[2], errp[2];
   POOLMEM *tprog;
   int mode_map = 0;
   BPIPE *bpipe;
   int save_errno;
   struct rlimit rl;
   int64_t rlimitResult=0;

   if (!prog || !*prog) {
      /* execve(3) A component of the file does not name an existing file or file is an empty string. */
      errno = ENOENT; 
      return NULL;
   }

   bpipe = (BPIPE *)malloc(sizeof(BPIPE));
   memset(bpipe, 0, sizeof(BPIPE));
   if (strchr(mode,'r')) mode_map|=MODE_READ;
   if (strchr(mode,'w')) mode_map|=MODE_WRITE;
   if (strchr(mode,'s')) mode_map|=MODE_SHELL;
   if (strchr(mode,'e')) mode_map|=MODE_STDERR;

   /* Build arguments for running program. */
   tprog = get_pool_memory(PM_FNAME);
   pm_strcpy(tprog, prog);
   if (mode_map & MODE_SHELL) {
      build_sh_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
   } else {
      build_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
   }

   /* Unable to parse the command, avoid segfault after the fork() */
   if (bargc == 0 || bargv[0] == NULL) {
      free_pool_memory(tprog);
      free(bpipe);
      /* execve(3) A component of the file does not name an existing file or file is an empty string. */
      errno = ENOENT;
      return NULL;
   }

#ifdef  xxxxxx
   printf("argc=%d\n", bargc);
   for (i=0; i<bargc; i++) {
      printf("argc=%d argv=%s:\n", i, bargv[i]);
   }
#endif

   /* Each pipe is one way, write one end, read the other, so we need two */
   if ((mode_map & MODE_WRITE) && pipe(writep) == -1) {
      save_errno = errno;
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;
   }
   if ((mode_map & MODE_READ) && pipe(readp) == -1) {
      save_errno = errno;
      if (mode_map & MODE_WRITE) {
         close(writep[0]);
         close(writep[1]);
      }
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;
   }
   if ((mode_map & MODE_STDERR) && pipe(errp) == -1) {
      save_errno = errno;
      if (mode_map & MODE_WRITE) {
         close(writep[0]);
         close(writep[1]);
      }
      if (mode_map & MODE_READ) {
         close(readp[0]);
         close(readp[1]);
      }
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;
   }

   /* Many systems doesn't have the correct system call
    * to determine the FD list to close.
    */
#if !defined(HAVE_FCNTL_F_CLOSEM) && !defined(HAVE_CLOSEFROM)
   if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
      rlimitResult = sysconf(_SC_OPEN_MAX);
   } else {
      rlimitResult = rl.rlim_max;
   }
#endif

   /* Start worker process */
   switch (bpipe->worker_pid = fork()) {
   case -1:                           /* error */
      save_errno = errno;
      if (mode_map & MODE_WRITE) {
         close(writep[0]);
         close(writep[1]);
      }
      if (mode_map & MODE_READ) {
         close(readp[0]);
         close(readp[1]);
      }
      if (mode_map & MODE_STDERR) {
         close(errp[0]);
         close(errp[1]);
      }
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;

   case 0:                            /* child */
      if (mode_map & MODE_WRITE) {
         close(writep[1]);
         dup2(writep[0], 0);          /* Dup our write to his stdin */
      }
      if (mode_map & MODE_READ) {
         close(readp[0]);             /* Close unused child fds */
         dup2(readp[1], 1);           /* dup our read to his stdout */
         if (mode_map & MODE_STDERR) {  /*   and handle stderr */
            close(errp[0]); 
            dup2(errp[1], 2);
         } else {
            dup2(readp[1], 2);
         }
      }

#if HAVE_FCNTL_F_CLOSEM
      fcntl(3, F_CLOSEM);
#elif HAVE_CLOSEFROM
      closefrom(3);
#else
      for (i=rlimitResult; i >= 3; i--) {
         close(i);
      }
#endif

      /* Setup the environment if requested, we do not use execvpe()
       * because it's not wildly available
       * TODO: Implement envp to windows version of bpipe
       */
      setup_env(envp);

      execvp(bargv[0], bargv);        /* call the program */
      /* Convert errno into an exit code for later analysis */
      for (i=0; i< num_execvp_errors; i++) {
         if (execvp_errors[i] == errno) {
            _exit(200 + i);            /* exit code => errno */
         }
      }
      /* Do not flush stdio */
      _exit(255);                      /* unknown errno */

   default:                           /* parent */
      break;
   }
   free_pool_memory(tprog);
   if (mode_map & MODE_READ) {
      close(readp[1]);                /* close unused parent fds */
      set_keepalive(readp[0]);
      bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
   }
   if (mode_map & MODE_STDERR) {
      close(errp[1]);                /* close unused parent fds */
      set_keepalive(errp[0]);
      bpipe->efd = fdopen(errp[0], "r"); /* open file descriptor */
   }
   if (mode_map & MODE_WRITE) {
      close(writep[0]);
      set_keepalive(writep[1]);
      bpipe->wfd = fdopen(writep[1], "w");
   }
   bpipe->worker_stime = time(NULL);
   bpipe->wait = wait;
   if (wait > 0) {
      bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
   }
   return bpipe;
}
/*
 * Run an external program. Optionally wait a specified number
 *   of seconds. Program killed if wait exceeded. We open
 *   a bi-directional pipe so that the user can read from and
 *   write to the program.
 */
Run an external program. Optionally wait a specified number
of seconds. Program killed if wait exceeded. We open
a bi-directional pipe so that the user can read from and
write to the program.
Run an external program . Optionally wait a specified number of seconds . Program killed if wait exceeded . We open a bi - directional pipe so that the user can read from and write to the program .
BPIPE *open_bpipe(char *prog, int wait, const char *mode, char *envp[])
{
   char *bargv[MAX_ARGV];
   int bargc, i;
   int readp[2], writep[2], errp[2];
   POOLMEM *tprog;
   int mode_map = 0;
   BPIPE *bpipe;
   int save_errno;
   struct rlimit rl;
   int64_t rlimitResult=0;
   if (!prog || !*prog) {
      errno = ENOENT; 
      return NULL;
   }
   bpipe = (BPIPE *)malloc(sizeof(BPIPE));
   memset(bpipe, 0, sizeof(BPIPE));
   if (strchr(mode,'r')) mode_map|=MODE_READ;
   if (strchr(mode,'w')) mode_map|=MODE_WRITE;
   if (strchr(mode,'s')) mode_map|=MODE_SHELL;
   if (strchr(mode,'e')) mode_map|=MODE_STDERR;
   tprog = get_pool_memory(PM_FNAME);
   pm_strcpy(tprog, prog);
   if (mode_map & MODE_SHELL) {
      build_sh_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
   } else {
      build_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
   }
   if (bargc == 0 || bargv[0] == NULL) {
      free_pool_memory(tprog);
      free(bpipe);
      errno = ENOENT;
      return NULL;
   }
#ifdef  xxxxxx
   printf("argc=%d\n", bargc);
   for (i=0; i<bargc; i++) {
      printf("argc=%d argv=%s:\n", i, bargv[i]);
   }
#endif
   if ((mode_map & MODE_WRITE) && pipe(writep) == -1) {
      save_errno = errno;
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;
   }
   if ((mode_map & MODE_READ) && pipe(readp) == -1) {
      save_errno = errno;
      if (mode_map & MODE_WRITE) {
         close(writep[0]);
         close(writep[1]);
      }
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;
   }
   if ((mode_map & MODE_STDERR) && pipe(errp) == -1) {
      save_errno = errno;
      if (mode_map & MODE_WRITE) {
         close(writep[0]);
         close(writep[1]);
      }
      if (mode_map & MODE_READ) {
         close(readp[0]);
         close(readp[1]);
      }
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;
   }
#if !defined(HAVE_FCNTL_F_CLOSEM) && !defined(HAVE_CLOSEFROM)
   if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
      rlimitResult = sysconf(_SC_OPEN_MAX);
   } else {
      rlimitResult = rl.rlim_max;
   }
#endif
   switch (bpipe->worker_pid = fork()) {
   case -1:                           
      save_errno = errno;
      if (mode_map & MODE_WRITE) {
         close(writep[0]);
         close(writep[1]);
      }
      if (mode_map & MODE_READ) {
         close(readp[0]);
         close(readp[1]);
      }
      if (mode_map & MODE_STDERR) {
         close(errp[0]);
         close(errp[1]);
      }
      free(bpipe);
      free_pool_memory(tprog);
      errno = save_errno;
      return NULL;
   case 0:                            
      if (mode_map & MODE_WRITE) {
         close(writep[1]);
         dup2(writep[0], 0);          
      }
      if (mode_map & MODE_READ) {
         close(readp[0]);             
         dup2(readp[1], 1);           
         if (mode_map & MODE_STDERR) {  
            close(errp[0]); 
            dup2(errp[1], 2);
         } else {
            dup2(readp[1], 2);
         }
      }
#if HAVE_FCNTL_F_CLOSEM
      fcntl(3, F_CLOSEM);
#elif HAVE_CLOSEFROM
      closefrom(3);
#else
      for (i=rlimitResult; i >= 3; i--) {
         close(i);
      }
#endif
      setup_env(envp);
      execvp(bargv[0], bargv);        
      for (i=0; i< num_execvp_errors; i++) {
         if (execvp_errors[i] == errno) {
            _exit(200 + i);            
         }
      }
      _exit(255);                      
   default:                           
      break;
   }
   free_pool_memory(tprog);
   if (mode_map & MODE_READ) {
      close(readp[1]);                
      set_keepalive(readp[0]);
      bpipe->rfd = fdopen(readp[0], "r"); 
   }
   if (mode_map & MODE_STDERR) {
      close(errp[1]);                
      set_keepalive(errp[0]);
      bpipe->efd = fdopen(errp[0], "r"); 
   }
   if (mode_map & MODE_WRITE) {
      close(writep[0]);
      set_keepalive(writep[1]);
      bpipe->wfd = fdopen(writep[1], "w");
   }
   bpipe->worker_stime = time(NULL);
   bpipe->wait = wait;
   if (wait > 0) {
      bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
   }
   return bpipe;
}
BPIPE * open_bpipe ( char * prog , int wait , const char * mode , char * envp [ ] ) { char * bargv [ MAX_ARGV ] ; int bargc , i ; int readp [ 2 ] , writep [ 2 ] , errp [ 2 ] ; POOLMEM * tprog ; int mode_map = 0 ; BPIPE * bpipe ; int save_errno ; struct rlimit rl ; int64_t rlimitResult = 0 ; if ( ! prog || ! * prog ) { errno = ENOENT ; return NULL ; } bpipe = ( BPIPE * ) malloc ( sizeof ( BPIPE ) ) ; memset ( bpipe , 0 , sizeof ( BPIPE ) ) ; if ( strchr ( mode , ' ' ) ) mode_map |= MODE_READ ; if ( strchr ( mode , ' ' ) ) mode_map |= MODE_WRITE ; if ( strchr ( mode , ' ' ) ) mode_map |= MODE_SHELL ; if ( strchr ( mode , ' ' ) ) mode_map |= MODE_STDERR ; tprog = get_pool_memory ( PM_FNAME ) ; pm_strcpy ( tprog , prog ) ; if ( mode_map & MODE_SHELL ) { build_sh_argc_argv ( tprog , & bargc , bargv , MAX_ARGV ) ; } else { build_argc_argv ( tprog , & bargc , bargv , MAX_ARGV ) ; } if ( bargc == 0 || bargv [ 0 ] == NULL ) { free_pool_memory ( tprog ) ; free ( bpipe ) ; errno = ENOENT ; return NULL ; } #ifdef xxxxxx printf ( " \n " , bargc ) ; for ( i = 0 ; i < bargc ; i ++ ) { printf ( " \n " , i , bargv [ i ] ) ; } #endif if ( ( mode_map & MODE_WRITE ) && pipe ( writep ) == -1 ) { save_errno = errno ; free ( bpipe ) ; free_pool_memory ( tprog ) ; errno = save_errno ; return NULL ; } if ( ( mode_map & MODE_READ ) && pipe ( readp ) == -1 ) { save_errno = errno ; if ( mode_map & MODE_WRITE ) { close ( writep [ 0 ] ) ; close ( writep [ 1 ] ) ; } free ( bpipe ) ; free_pool_memory ( tprog ) ; errno = save_errno ; return NULL ; } if ( ( mode_map & MODE_STDERR ) && pipe ( errp ) == -1 ) { save_errno = errno ; if ( mode_map & MODE_WRITE ) { close ( writep [ 0 ] ) ; close ( writep [ 1 ] ) ; } if ( mode_map & MODE_READ ) { close ( readp [ 0 ] ) ; close ( readp [ 1 ] ) ; } free ( bpipe ) ; free_pool_memory ( tprog ) ; errno = save_errno ; return NULL ; } #if ! defined ( HAVE_FCNTL_F_CLOSEM ) && ! defined ( HAVE_CLOSEFROM ) if ( getrlimit ( RLIMIT_NOFILE , & rl ) == -1 ) { rlimitResult = sysconf ( _SC_OPEN_MAX ) ; } else { rlimitResult = rl . rlim_max ; } #endif switch ( bpipe -> worker_pid = fork ( ) ) { case -1 : save_errno = errno ; if ( mode_map & MODE_WRITE ) { close ( writep [ 0 ] ) ; close ( writep [ 1 ] ) ; } if ( mode_map & MODE_READ ) { close ( readp [ 0 ] ) ; close ( readp [ 1 ] ) ; } if ( mode_map & MODE_STDERR ) { close ( errp [ 0 ] ) ; close ( errp [ 1 ] ) ; } free ( bpipe ) ; free_pool_memory ( tprog ) ; errno = save_errno ; return NULL ; case 0 : if ( mode_map & MODE_WRITE ) { close ( writep [ 1 ] ) ; dup2 ( writep [ 0 ] , 0 ) ; } if ( mode_map & MODE_READ ) { close ( readp [ 0 ] ) ; dup2 ( readp [ 1 ] , 1 ) ; if ( mode_map & MODE_STDERR ) { close ( errp [ 0 ] ) ; dup2 ( errp [ 1 ] , 2 ) ; } else { dup2 ( readp [ 1 ] , 2 ) ; } } #if HAVE_FCNTL_F_CLOSEM fcntl ( 3 , F_CLOSEM ) ; #elif HAVE_CLOSEFROM closefrom ( 3 ) ; #else for ( i = rlimitResult ; i >= 3 ; i -- ) { close ( i ) ; } #endif setup_env ( envp ) ; execvp ( bargv [ 0 ] , bargv ) ; for ( i = 0 ; i < num_execvp_errors ; i ++ ) { if ( execvp_errors [ i ] == errno ) { _exit ( 200 + i ) ; } } _exit ( 255 ) ; default : break ; } free_pool_memory ( tprog ) ; if ( mode_map & MODE_READ ) { close ( readp [ 1 ] ) ; set_keepalive ( readp [ 0 ] ) ; bpipe -> rfd = fdopen ( readp [ 0 ] , " " ) ; } if ( mode_map & MODE_STDERR ) { close ( errp [ 1 ] ) ; set_keepalive ( errp [ 0 ] ) ; bpipe -> efd = fdopen ( errp [ 0 ] , " " ) ; } if ( mode_map & MODE_WRITE ) { close ( writep [ 0 ] ) ; set_keepalive ( writep [ 1 ] ) ; bpipe -> wfd = fdopen ( writep [ 1 ] , " " ) ; } bpipe -> worker_stime = time ( NULL ) ; bpipe -> wait = wait ; if ( wait > 0 ) { bpipe -> timer_id = start_child_timer ( NULL , bpipe -> worker_pid , wait ) ; } return bpipe ; }
Run an external program.
Run an external program .
/* execve(3) A component of the file does not name an existing file or file is an empty string. */ /* Build arguments for running program. */ /* Unable to parse the command, avoid segfault after the fork() */ /* execve(3) A component of the file does not name an existing file or file is an empty string. */ /* Each pipe is one way, write one end, read the other, so we need two */ /* Many systems doesn't have the correct system call
    * to determine the FD list to close.
    */ /* Start worker process */ /* error */ /* child */ /* Dup our write to his stdin */ /* Close unused child fds */ /* dup our read to his stdout */ /*   and handle stderr */ /* Setup the environment if requested, we do not use execvpe()
       * because it's not wildly available
       * TODO: Implement envp to windows version of bpipe
       */ /* call the program */ /* Convert errno into an exit code for later analysis */ /* exit code => errno */ /* Do not flush stdio */ /* unknown errno */ /* parent */ /* close unused parent fds */ /* open file descriptor */ /* close unused parent fds */ /* open file descriptor */