[BACK]Return to popen.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / gen

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libc/gen/popen.c between version 1.30 and 1.33

version 1.30, 2010/11/14 18:11:42 version 1.33, 2015/01/20 17:28:00
Line 54  __RCSID("$NetBSD$");
Line 54  __RCSID("$NetBSD$");
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   #include <fcntl.h>
   
 #include "env.h"  #include "env.h"
 #include "reentrant.h"  #include "reentrant.h"
Line 76  static struct pid {
Line 77  static struct pid {
 static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;  static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
 #endif  #endif
   
 FILE *  static struct pid *
 popen(const char *command, const char *type)  pdes_get(int *pdes, const char **type)
 {  {
         struct pid *cur, *old;          struct pid *cur;
         FILE *iop;          int flags = strchr(*type, 'e') ? O_CLOEXEC : 0;
         const char * volatile xtype = type;          int serrno;
         int pdes[2], pid, serrno;  
         volatile int twoway;          if (strchr(*type, '+')) {
                   int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM;
         _DIAGASSERT(command != NULL);                  *type = "r+";
         _DIAGASSERT(xtype != NULL);                  if (socketpair(AF_LOCAL, stype, 0, pdes) < 0)
                           return NULL;
         if (strchr(xtype, '+')) {  
                 twoway = 1;  
                 type = "r+";  
                 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pdes) < 0)  
                         return (NULL);  
         } else  {          } else  {
                 twoway = 0;                  *type = strrchr(*type, 'r') ? "r" : "w";
                 if ((*xtype != 'r' && *xtype != 'w') || xtype[1] ||                  if (pipe2(pdes, flags) == -1)
                     (pipe(pdes) < 0)) {                          return NULL;
                         errno = EINVAL;  
                         return (NULL);  
                 }  
         }          }
   
         if ((cur = malloc(sizeof(struct pid))) == NULL) {          if ((cur = malloc(sizeof(*cur))) != NULL)
                 (void)close(pdes[0]);                  return cur;
                 (void)close(pdes[1]);          serrno = errno;
                 errno = ENOMEM;          (void)close(pdes[0]);
                 return (NULL);          (void)close(pdes[1]);
         }          errno = serrno;
           return NULL;
   }
   
         (void)rwlock_rdlock(&pidlist_lock);  static void
         (void)__readlockenv();  pdes_child(int *pdes, const char *type)
         switch (pid = vfork()) {  {
         case -1:                        /* Error. */          struct pid *old;
                 serrno = errno;  
                 (void)__unlockenv();          /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
                 (void)rwlock_unlock(&pidlist_lock);             from previous popen() calls that remain open in the
                 free(cur);             parent process are closed in the new child process. */
                 (void)close(pdes[0]);          for (old = pidlist; old; old = old->next)
                 (void)close(pdes[1]);  
                 errno = serrno;  
                 return (NULL);  
                 /* NOTREACHED */  
         case 0:                         /* Child. */  
                 /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams  
                    from previous popen() calls that remain open in the  
                    parent process are closed in the new child process. */  
                 for (old = pidlist; old; old = old->next)  
 #ifdef _REENTRANT  #ifdef _REENTRANT
                         close(old->fd); /* don't allow a flush */                  (void)close(old->fd); /* don't allow a flush */
 #else  #else
                         close(fileno(old->fp)); /* don't allow a flush */                  (void)close(fileno(old->fp)); /* don't allow a flush */
 #endif  #endif
   
                 if (*xtype == 'r') {          if (type[0] == 'r') {
                         (void)close(pdes[0]);                  (void)close(pdes[0]);
                         if (pdes[1] != STDOUT_FILENO) {                  if (pdes[1] != STDOUT_FILENO) {
                                 (void)dup2(pdes[1], STDOUT_FILENO);                          (void)dup2(pdes[1], STDOUT_FILENO);
                                 (void)close(pdes[1]);  
                         }  
                         if (twoway)  
                                 (void)dup2(STDOUT_FILENO, STDIN_FILENO);  
                 } else {  
                         (void)close(pdes[1]);                          (void)close(pdes[1]);
                         if (pdes[0] != STDIN_FILENO) {  
                                 (void)dup2(pdes[0], STDIN_FILENO);  
                                 (void)close(pdes[0]);  
                         }  
                 }                  }
                   if (type[1] == '+')
                 execl(_PATH_BSHELL, "sh", "-c", command, NULL);                          (void)dup2(STDOUT_FILENO, STDIN_FILENO);
                 _exit(127);          } else {
                 /* NOTREACHED */                  (void)close(pdes[1]);
                   if (pdes[0] != STDIN_FILENO) {
                           (void)dup2(pdes[0], STDIN_FILENO);
                           (void)close(pdes[0]);
                   }
         }          }
         (void)__unlockenv();  }
   
   static void
   pdes_parent(int *pdes, struct pid *cur, pid_t pid, const char *type)
   {
           FILE *iop;
   
         /* Parent; assume fdopen can't fail. */          /* Parent; assume fdopen can't fail. */
         if (*xtype == 'r') {          if (*type == 'r') {
                 iop = fdopen(pdes[0], xtype);                  iop = fdopen(pdes[0], type);
 #ifdef _REENTRANT  #ifdef _REENTRANT
                 cur->fd = pdes[0];                  cur->fd = pdes[0];
 #endif  #endif
                 (void)close(pdes[1]);                  (void)close(pdes[1]);
         } else {          } else {
                 iop = fdopen(pdes[1], xtype);                  iop = fdopen(pdes[1], type);
 #ifdef _REENTRANT  #ifdef _REENTRANT
                 cur->fd = pdes[1];                  cur->fd = pdes[1];
 #endif  #endif
Line 175  popen(const char *command, const char *t
Line 161  popen(const char *command, const char *t
         cur->pid =  pid;          cur->pid =  pid;
         cur->next = pidlist;          cur->next = pidlist;
         pidlist = cur;          pidlist = cur;
   }
   
   static void
   pdes_error(int *pdes, struct pid *cur)
   {
           free(cur);
           (void)close(pdes[0]);
           (void)close(pdes[1]);
   }
   
   FILE *
   popen(const char *cmd, const char *type)
   {
           struct pid *cur;
           int pdes[2], serrno;
           pid_t pid;
   
           _DIAGASSERT(cmd != NULL);
           _DIAGASSERT(type != NULL);
   
           if ((cur = pdes_get(pdes, &type)) == NULL)
                   return NULL;
   
   #ifdef _REENTRANT
           (void)rwlock_rdlock(&pidlist_lock);
   #endif
           (void)__readlockenv();
           switch (pid = vfork()) {
           case -1:                        /* Error. */
                   serrno = errno;
                   (void)__unlockenv();
   #ifdef _REENTRANT
                   (void)rwlock_unlock(&pidlist_lock);
   #endif
                   errno = serrno;
                   return NULL;
                   /* NOTREACHED */
           case 0:                         /* Child. */
                   pdes_child(pdes, type);
                   execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
                   _exit(127);
                   /* NOTREACHED */
           }
           (void)__unlockenv();
   
           pdes_parent(pdes, cur, pid, type);
   
   #ifdef _REENTRANT
           (void)rwlock_unlock(&pidlist_lock);
   #endif
   
           return cur->fp;
   }
   
   FILE *
   popenve(const char *cmd, char *const *argv, char *const *envp, const char *type)
   {
           struct pid *cur;
           int pdes[2], serrno;
           pid_t pid;
   
           _DIAGASSERT(cmd != NULL);
           _DIAGASSERT(type != NULL);
   
           if ((cur = pdes_get(pdes, &type)) == NULL)
                   return NULL;
   
   #ifdef _REENTRANT
           (void)rwlock_rdlock(&pidlist_lock);
   #endif
           switch (pid = vfork()) {
           case -1:                        /* Error. */
                   serrno = errno;
   #ifdef _REENTRANT
                   (void)rwlock_unlock(&pidlist_lock);
   #endif
                   pdes_error(pdes, cur);
                   errno = serrno;
                   return NULL;
                   /* NOTREACHED */
           case 0:                         /* Child. */
                   pdes_child(pdes, type);
                   execve(cmd, argv, envp);
                   _exit(127);
                   /* NOTREACHED */
           }
   
           pdes_parent(pdes, cur, pid, type);
   
   #ifdef _REENTRANT
         (void)rwlock_unlock(&pidlist_lock);          (void)rwlock_unlock(&pidlist_lock);
   #endif
   
         return (iop);          return cur->fp;
 }  }
   
 /*  /*
Line 186  popen(const char *command, const char *t
Line 263  popen(const char *command, const char *t
  *      if already `pclosed', or waitpid returns an error.   *      if already `pclosed', or waitpid returns an error.
  */   */
 int  int
 pclose(iop)  pclose(FILE *iop)
         FILE *iop;  
 {  {
         struct pid *cur, *last;          struct pid *cur, *last;
         int pstat;          int pstat;
Line 195  pclose(iop)
Line 271  pclose(iop)
   
         _DIAGASSERT(iop != NULL);          _DIAGASSERT(iop != NULL);
   
   #ifdef _REENTRANT
         rwlock_wrlock(&pidlist_lock);          rwlock_wrlock(&pidlist_lock);
   #endif
   
         /* Find the appropriate file pointer. */          /* Find the appropriate file pointer. */
         for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)          for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
                 if (cur->fp == iop)                  if (cur->fp == iop)
                         break;                          break;
         if (cur == NULL) {          if (cur == NULL) {
   #ifdef _REENTRANT
                 (void)rwlock_unlock(&pidlist_lock);                  (void)rwlock_unlock(&pidlist_lock);
                 return (-1);  #endif
                   errno = ESRCH;
                   return -1;
         }          }
   
         (void)fclose(iop);          (void)fclose(iop);
Line 214  pclose(iop)
Line 295  pclose(iop)
         else          else
                 last->next = cur->next;                  last->next = cur->next;
   
   #ifdef _REENTRANT
         (void)rwlock_unlock(&pidlist_lock);          (void)rwlock_unlock(&pidlist_lock);
   #endif
   
         do {          do {
                 pid = waitpid(cur->pid, &pstat, 0);                  pid = waitpid(cur->pid, &pstat, 0);
Line 222  pclose(iop)
Line 305  pclose(iop)
   
         free(cur);          free(cur);
   
         return (pid == -1 ? -1 : pstat);          return pid == -1 ? -1 : pstat;
 }  }

Legend:
Removed from v.1.30  
changed lines
  Added in v.1.33

CVSweb <webmaster@jp.NetBSD.org>