[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.2 and 1.35

version 1.2, 1993/07/30 08:23:01 version 1.35, 2015/02/02 22:07:05
Line 1 
Line 1 
   /*      $NetBSD$        */
   
 /*  /*
  * Copyright (c) 1988 The Regents of the University of California.   * Copyright (c) 1988, 1993
  * All rights reserved.   *      The Regents of the University of California.  All rights reserved.
  *   *
  * This code is derived from software written by Ken Arnold and   * This code is derived from software written by Ken Arnold and
  * published in UNIX Review, Vol. 6, No. 8.   * published in UNIX Review, Vol. 6, No. 8.
Line 13 
Line 15 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software   * 3. Neither the name of the University nor the names of its contributors
  *    must display the following acknowledgement:  
  *      This product includes software developed by the University of  
  *      California, Berkeley and its contributors.  
  * 4. Neither the name of the University nor the names of its contributors  
  *    may be used to endorse or promote products derived from this software   *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.   *    without specific prior written permission.
  *   *
Line 34 
Line 32 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
   #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)  #if defined(LIBC_SCCS) && !defined(lint)
 /*static char sccsid[] = "from: @(#)popen.c     5.15 (Berkeley) 2/23/91";*/  #if 0
 static char rcsid[] = "$Id$";  static char sccsid[] = "@(#)popen.c     8.3 (Berkeley) 5/3/95";
   #else
   __RCSID("$NetBSD$");
   #endif
 #endif /* LIBC_SCCS and not lint */  #endif /* LIBC_SCCS and not lint */
   
   #include "namespace.h"
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/signal.h>  
 #include <sys/wait.h>  #include <sys/wait.h>
   #include <sys/socket.h>
   
   #include <assert.h>
 #include <errno.h>  #include <errno.h>
   #include <paths.h>
   #include <signal.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
 #include <paths.h>  #include <fcntl.h>
   
 static pid_t *pids;  #include "env.h"
   
 FILE *  #ifdef __weak_alias
 popen(program, type)  __weak_alias(popen,_popen)
         const char *program;  __weak_alias(pclose,_pclose)
         const char *type;  #endif
 {  
         FILE *iop;  
         int pdes[2], fds, pid;  
   
         if (*type != 'r' && *type != 'w' || type[1])  static struct pid {
                 return (NULL);          struct pid *next;
           FILE *fp;
   #ifdef _REENTRANT
           int fd;
   #endif
           pid_t pid;
   } *pidlist;
   
   #ifdef _REENTRANT
   static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
   #endif
   
   static struct pid *
   pdes_get(int *pdes, const char **type)
   {
           struct pid *cur;
           int flags = strchr(*type, 'e') ? O_CLOEXEC : 0;
           int serrno;
   
         if (pids == NULL) {          if (strchr(*type, '+')) {
                 if ((fds = getdtablesize()) <= 0)                  int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM;
                         return (NULL);                  *type = "r+";
                 if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)                  if (socketpair(AF_LOCAL, stype, 0, pdes) < 0)
                         return (NULL);                          return NULL;
                 bzero((char *)pids, fds * sizeof(pid_t));          } else  {
                   *type = strrchr(*type, 'r') ? "r" : "w";
                   if (pipe2(pdes, flags) == -1)
                           return NULL;
         }          }
         if (pipe(pdes) < 0)  
                 return (NULL);          if ((cur = malloc(sizeof(*cur))) != NULL)
         switch (pid = vfork()) {                  return cur;
         case -1:                        /* error */          serrno = errno;
                 (void) close(pdes[0]);          (void)close(pdes[0]);
                 (void) close(pdes[1]);          (void)close(pdes[1]);
                 return (NULL);          errno = serrno;
                 /* NOTREACHED */          return NULL;
         case 0:                         /* child */  }
                 if (*type == 'r') {  
                         if (pdes[1] != STDOUT_FILENO) {  static void
                                 (void) dup2(pdes[1], STDOUT_FILENO);  pdes_child(int *pdes, const char *type)
                                 (void) close(pdes[1]);  {
                         }          struct pid *old;
                         (void) close(pdes[0]);  
                 } else {          /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
                         if (pdes[0] != STDIN_FILENO) {             from previous popen() calls that remain open in the
                                 (void) dup2(pdes[0], STDIN_FILENO);             parent process are closed in the new child process. */
                                 (void) close(pdes[0]);          for (old = pidlist; old; old = old->next)
                         }  #ifdef _REENTRANT
                         (void) close(pdes[1]);                  (void)close(old->fd); /* don't allow a flush */
   #else
                   (void)close(fileno(old->fp)); /* don't allow a flush */
   #endif
   
           if (type[0] == 'r') {
                   (void)close(pdes[0]);
                   if (pdes[1] != STDOUT_FILENO) {
                           (void)dup2(pdes[1], STDOUT_FILENO);
                           (void)close(pdes[1]);
                   }
                   if (type[1] == '+')
                           (void)dup2(STDOUT_FILENO, STDIN_FILENO);
           } else {
                   (void)close(pdes[1]);
                   if (pdes[0] != STDIN_FILENO) {
                           (void)dup2(pdes[0], STDIN_FILENO);
                           (void)close(pdes[0]);
                 }                  }
                 execl(_PATH_BSHELL, "sh", "-c", program, NULL);  
                 _exit(127);  
                 /* NOTREACHED */  
         }          }
         /* parent; assume fdopen can't fail...  */  }
   
   static void
   pdes_parent(int *pdes, struct pid *cur, pid_t pid, const char *type)
   {
           FILE *iop;
   
           /* Parent; assume fdopen can't fail. */
         if (*type == 'r') {          if (*type == 'r') {
                 iop = fdopen(pdes[0], type);                  iop = fdopen(pdes[0], type);
                 (void) close(pdes[1]);  #ifdef _REENTRANT
                   cur->fd = pdes[0];
   #endif
                   (void)close(pdes[1]);
         } else {          } else {
                 iop = fdopen(pdes[1], type);                  iop = fdopen(pdes[1], type);
                 (void) close(pdes[0]);  #ifdef _REENTRANT
                   cur->fd = pdes[1];
   #endif
                   (void)close(pdes[0]);
         }          }
         pids[fileno(iop)] = pid;  
         return (iop);          /* Link into list of file descriptors. */
           cur->fp = iop;
           cur->pid =  pid;
           cur->next = pidlist;
           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
                   pdes_error(pdes, cur);
                   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);
   #endif
   
           return cur->fp;
   }
   
   /*
    * pclose --
    *      Pclose returns -1 if stream is not associated with a `popened' command,
    *      if already `pclosed', or waitpid returns an error.
    */
 int  int
 pclose(iop)  pclose(FILE *iop)
         FILE *iop;  
 {  {
         register int fdes;          struct pid *cur, *last;
         int omask;          int pstat;
         union wait pstat;  
         pid_t pid;          pid_t pid;
   
         /*          _DIAGASSERT(iop != NULL);
          * pclose returns -1 if stream is not associated with a  
          * `popened' command, if already `pclosed', or waitpid  #ifdef _REENTRANT
          * returns an error.          rwlock_wrlock(&pidlist_lock);
          */  #endif
         if (pids == NULL || pids[fdes = fileno(iop)] == 0)  
                 return (-1);          /* Find the appropriate file pointer. */
         (void) fclose(iop);          for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
         omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));                  if (cur->fp == iop)
                           break;
           if (cur == NULL) {
   #ifdef _REENTRANT
                   (void)rwlock_unlock(&pidlist_lock);
   #endif
                   errno = ESRCH;
                   return -1;
           }
   
           (void)fclose(iop);
   
           /* Remove the entry from the linked list. */
           if (last == NULL)
                   pidlist = cur->next;
           else
                   last->next = cur->next;
   
   #ifdef _REENTRANT
           (void)rwlock_unlock(&pidlist_lock);
   #endif
   
         do {          do {
                 pid = waitpid(pids[fdes], (int *) &pstat, 0);                  pid = waitpid(cur->pid, &pstat, 0);
         } while (pid == -1 && errno == EINTR);          } while (pid == -1 && errno == EINTR);
         (void) sigsetmask(omask);  
         pids[fdes] = 0;          free(cur);
         return (pid == -1 ? -1 : pstat.w_status);  
           return pid == -1 ? -1 : pstat;
 }  }

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.35

CVSweb <webmaster@jp.NetBSD.org>