BSD 4_3_Reno release
[unix-history] / usr / src / lib / libc / gen / popen.c
index 633dba9..d33fdd0 100644 (file)
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)popen.c    5.5 (Berkeley) 9/30/87";
-#endif LIBC_SCCS and not lint
+static char sccsid[] = "@(#)popen.c    5.14 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
 
 
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <signal.h>
+#include <unistd.h>
+#include <paths.h>
 
 
-#define        tst(a,b)        (*mode == 'r'? (b) : (a))
-#define        RDR     0
-#define        WTR     1
-
-extern char *malloc();
-
-static int *popen_pid;
-static int nfiles;
+static pid_t *pids;
 
 FILE *
 
 FILE *
-popen(cmd,mode)
-       char *cmd;
-       char *mode;
+popen(program, type)
+       char *program, *type;
 {
 {
-       int p[2];
-       int myside, hisside, pid;
+       FILE *iop;
+       int pdes[2], fds, pid;
+       char *malloc();
+
+       if (*type != 'r' && *type != 'w' || type[1])
+               return (NULL);
 
 
-       if (nfiles <= 0)
-               nfiles = getdtablesize();
-       if (popen_pid == NULL) {
-               popen_pid = (int *)malloc(nfiles * sizeof *popen_pid);
-               if (popen_pid == NULL)
+       if (pids == NULL) {
+               if ((fds = getdtablesize()) <= 0)
                        return (NULL);
                        return (NULL);
-               for (pid = 0; pid < nfiles; pid++)
-                       popen_pid[pid] = -1;
+               if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
+                       return (NULL);
+               bzero((char *)pids, fds * sizeof(pid_t));
        }
        }
-       if (pipe(p) < 0)
+       if (pipe(pdes) < 0)
+               return (NULL);
+       switch (pid = vfork()) {
+       case -1:                        /* error */
+               (void) close(pdes[0]);
+               (void) close(pdes[1]);
                return (NULL);
                return (NULL);
-       myside = tst(p[WTR], p[RDR]);
-       hisside = tst(p[RDR], p[WTR]);
-       if ((pid = vfork()) == 0) {
-               /* myside and hisside reverse roles in child */
-               close(myside);
-               if (hisside != tst(0, 1)) {
-                       dup2(hisside, tst(0, 1));
-                       close(hisside);
+               /* NOTREACHED */
+       case 0:                         /* child */
+               if (*type == 'r') {
+                       if (pdes[1] != STDOUT_FILENO) {
+                               (void) dup2(pdes[1], STDOUT_FILENO);
+                               (void) close(pdes[1]);
+                       }
+                       (void) close(pdes[0]);
+               } else {
+                       if (pdes[0] != STDIN_FILENO) {
+                               (void) dup2(pdes[0], STDIN_FILENO);
+                               (void) close(pdes[0]);
+                       }
+                       (void) close(pdes[1]);
                }
                }
-               execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
+               execl(_PATH_BSHELL, "sh", "-c", program, NULL);
                _exit(127);
                _exit(127);
+               /* NOTREACHED */
        }
        }
-       if (pid == -1) {
-               close(myside);
-               close(hisside);
-               return (NULL);
+       /* parent; assume fdopen can't fail...  */
+       if (*type == 'r') {
+               iop = fdopen(pdes[0], type);
+               (void) close(pdes[1]);
+       } else {
+               iop = fdopen(pdes[1], type);
+               (void) close(pdes[0]);
        }
        }
-       popen_pid[myside] = pid;
-       close(hisside);
-       return (fdopen(myside, mode));
+       pids[fileno(iop)] = pid;
+       return (iop);
 }
 
 }
 
-pclose(ptr)
-       FILE *ptr;
+pclose(iop)
+       FILE *iop;
 {
 {
-       long omask;
-       int child, pid, status;
+       extern int errno;
+       register int fdes;
+       int omask;
+       union wait pstat;
+       pid_t pid, waitpid();
 
 
-       child = popen_pid[fileno(ptr)];
-       popen_pid[fileno(ptr)] = -1;
-       fclose(ptr);
-       if (child == -1)
+       /*
+        * pclose returns -1 if stream is not associated with a
+        * `popened' command, if already `pclosed', or waitpid
+        * returns an error.
+        */
+       if (pids == NULL || pids[fdes = fileno(iop)] == 0)
                return (-1);
                return (-1);
+       (void) fclose(iop);
        omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
        omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
-       while ((pid = wait(&status)) != child && pid != -1)
-               ;
+       do {
+               pid = waitpid(pids[fdes], &pstat, 0);
+       } while (pid == -1 && errno == EINTR);
        (void) sigsetmask(omask);
        (void) sigsetmask(omask);
-       return (pid == -1 ? -1 : status);
+       pids[fdes] = 0;
+       return (pid == -1 ? -1 : pstat.w_status);
 }
 }