Diff for /libelwix/src/pio.c between versions 1.1 and 1.1.2.1

version 1.1, 2013/12/05 14:56:42 version 1.1.2.1, 2013/12/05 14:56:42
Line 0 Line 1
   #include "global.h"
   
   
   extern char **environ;
   
   pio_pid_t pio_pidlist = = SLIST_HEAD_INITIALIZER(pio_pidlist);
   static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
   
   #define THREAD_LOCK()   if (__isthreaded) pthread_mutex_lock(&pidlist_mutex)
   #define THREAD_UNLOCK() if (__isthreaded) pthread_mutex_unlock(&pidlist_mutex)
   
   
   /*
    * e_popen() - ELWIX replacement of standard popen
    *
    * @command = command
    * @type = type
    * @ppid = return pid of child program
    * return: NULL error or !=NULL open program
    */
   FILE *
   e_popen(const char *command, const char *type, pid_t *ppid)
   {
           struct tagPIOPID *cur;
           FILE *iop;
           int pdes[2], pid, twoway, cloexec;
           char *argv[4];
           struct pid *p;
   
           cloexec = strchr(type, 'e') != NULL;
           /*
            * Lite2 introduced two-way popen() pipes using _socketpair().
            * FreeBSD's pipe() is bidirectional, so we use that.
            */
           if (strchr(type, '+')) {
                   twoway = 1;
                   type = "r+";
           } else  {
                   twoway = 0;
                   if ((*type != 'r' && *type != 'w') ||
                       (type[1] && (type[1] != 'e' || type[2])))
                           return (NULL);
           }
           if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0)
                   return (NULL);
   
           if ((cur = e_malloc(sizeof(struct pid))) == NULL) {
                   close(pdes[0]);
                   close(pdes[1]);
                   return (NULL);
           }
   
           argv[0] = "sh";
           argv[1] = "-c";
           argv[2] = (char *)command;
           argv[3] = NULL;
   
           THREAD_LOCK();
           switch (pid = vfork()) {
           case -1:                        /* Error. */
                   THREAD_UNLOCK();
                   close(pdes[0]);
                   close(pdes[1]);
                   e_free(cur);
                   return (NULL);
                   /* NOTREACHED */
           case 0:                         /* Child. */
                   if (*type == 'r') {
                           /*
                            * The _dup2() to STDIN_FILENO is repeated to avoid
                            * writing to pdes[1], which might corrupt the
                            * parent's copy.  This isn't good enough in
                            * general, since the _exit() is no return, so
                            * the compiler is free to corrupt all the local
                            * variables.
                            */
                           if (!cloexec)
                                   close(pdes[0]);
                           if (pdes[1] != STDOUT_FILENO) {
                                   dup2(pdes[1], STDOUT_FILENO);
                                   if (!cloexec)
                                           close(pdes[1]);
                                   if (twoway)
                                           dup2(STDOUT_FILENO, STDIN_FILENO);
                           } else if (twoway && (pdes[1] != STDIN_FILENO)) {
                                   dup2(pdes[1], STDIN_FILENO);
                                   if (cloexec)
                                           fcntl(pdes[1], F_SETFD, 0);
                           } else if (cloexec)
                                   fcntl(pdes[1], F_SETFD, 0);
                   } else {
                           if (pdes[0] != STDIN_FILENO) {
                                   dup2(pdes[0], STDIN_FILENO);
                                   if (!cloexec)
                                           close(pdes[0]);
                           } else if (cloexec)
                                   fcntl(pdes[0], F_SETFD, 0);
                           if (!cloexec)
                                   close(pdes[1]);
                   }
                   SLIST_FOREACH(p, &pio_pidlist, next)
                           close(fileno(p->fp));
                   execve(_PATH_BSHELL, argv, environ);
                   _exit(127);
                   /* NOTREACHED */
           default:
                   if (ppid)
                           *ppid = pid;
           }
           THREAD_UNLOCK();
   
           /* Parent; assume fdopen can't fail. */
           if (*type == 'r') {
                   iop = fdopen(pdes[0], type);
                   close(pdes[1]);
           } else {
                   iop = fdopen(pdes[1], type);
                   close(pdes[0]);
           }
   
           /* Link into list of file descriptors. */
           cur->fp = iop;
           cur->pid = pid;
           THREAD_LOCK();
           SLIST_INSERT_HEAD(&pio_pidlist, cur, next);
           THREAD_UNLOCK();
   
           return (iop);
   }
   
   /*
    * e_pclose() - ELWIX replacement of standard pclose
    *
    * @iop = popen handle
    * return: -1 error or !=-1 pid status
    */
   int
   e_pclose(FILE *iop)
   {
           struct pid *cur, *last = NULL;
           int pstat;
           pid_t pid;
   
           /*
            * Find the appropriate file pointer and remove it from the list.
            */
           THREAD_LOCK();
           SLIST_FOREACH(cur, &pio_pidlist, next) {
                   if (cur->fp == iop)
                           break;
                   last = cur;
           }
           if (cur == NULL) {
                   THREAD_UNLOCK();
                   return (-1);
           }
           if (last == NULL)
                   SLIST_REMOVE_HEAD(&pio_pidlist, next);
           else
                   SLIST_REMOVE_AFTER(last, next);
           THREAD_UNLOCK();
   
           fclose(iop);
   
           do {
                   pid = wait4(cur->pid, &pstat, 0, (struct rusage *)0);
           } while (pid == -1 && errno == EINTR);
   
           e_free(cur);
   
           return (pid == -1 ? -1 : pstat);
   }

Removed from v.1.1  
changed lines
  Added in v.1.1.2.1


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>