1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software written by Ken Arnold and 6 * published in UNIX Review, Vol. 6, No. 8. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)popen.c 5.14 (Berkeley) 06/01/90"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <sys/param.h> 16 #include <sys/signal.h> 17 #include <sys/wait.h> 18 #include <errno.h> 19 #include <stdio.h> 20 #include <unistd.h> 21 #include <paths.h> 22 23 static pid_t *pids; 24 25 FILE * 26 popen(program, type) 27 char *program, *type; 28 { 29 FILE *iop; 30 int pdes[2], fds, pid; 31 char *malloc(); 32 33 if (*type != 'r' && *type != 'w' || type[1]) 34 return (NULL); 35 36 if (pids == NULL) { 37 if ((fds = getdtablesize()) <= 0) 38 return (NULL); 39 if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL) 40 return (NULL); 41 bzero((char *)pids, fds * sizeof(pid_t)); 42 } 43 if (pipe(pdes) < 0) 44 return (NULL); 45 switch (pid = vfork()) { 46 case -1: /* error */ 47 (void) close(pdes[0]); 48 (void) close(pdes[1]); 49 return (NULL); 50 /* NOTREACHED */ 51 case 0: /* child */ 52 if (*type == 'r') { 53 if (pdes[1] != STDOUT_FILENO) { 54 (void) dup2(pdes[1], STDOUT_FILENO); 55 (void) close(pdes[1]); 56 } 57 (void) close(pdes[0]); 58 } else { 59 if (pdes[0] != STDIN_FILENO) { 60 (void) dup2(pdes[0], STDIN_FILENO); 61 (void) close(pdes[0]); 62 } 63 (void) close(pdes[1]); 64 } 65 execl(_PATH_BSHELL, "sh", "-c", program, NULL); 66 _exit(127); 67 /* NOTREACHED */ 68 } 69 /* parent; assume fdopen can't fail... */ 70 if (*type == 'r') { 71 iop = fdopen(pdes[0], type); 72 (void) close(pdes[1]); 73 } else { 74 iop = fdopen(pdes[1], type); 75 (void) close(pdes[0]); 76 } 77 pids[fileno(iop)] = pid; 78 return (iop); 79 } 80 81 pclose(iop) 82 FILE *iop; 83 { 84 extern int errno; 85 register int fdes; 86 int omask; 87 union wait pstat; 88 pid_t pid, waitpid(); 89 90 /* 91 * pclose returns -1 if stream is not associated with a 92 * `popened' command, if already `pclosed', or waitpid 93 * returns an error. 94 */ 95 if (pids == NULL || pids[fdes = fileno(iop)] == 0) 96 return (-1); 97 (void) fclose(iop); 98 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 99 do { 100 pid = waitpid(pids[fdes], &pstat, 0); 101 } while (pid == -1 && errno == EINTR); 102 (void) sigsetmask(omask); 103 pids[fdes] = 0; 104 return (pid == -1 ? -1 : pstat.w_status); 105 } 106