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: * Redistribution and use in source and binary forms, with or without 9: * modification, are permitted provided that the following conditions 10: * are met: 11: * 1. Redistributions of source code must retain the above copyright 12: * notice, this list of conditions and the following disclaimer. 13: * 2. Redistributions in binary form must reproduce the above copyright 14: * notice, this list of conditions and the following disclaimer in the 15: * documentation and/or other materials provided with the distribution. 16: * 3. All advertising materials mentioning features or use of this software 17: * must display the following acknowledgement: 18: * This product includes software developed by the University of 19: * California, Berkeley and its contributors. 20: * 4. Neither the name of the University nor the names of its contributors 21: * may be used to endorse or promote products derived from this software 22: * without specific prior written permission. 23: * 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34: * SUCH DAMAGE. 35: */ 36: 37: #if defined(LIBC_SCCS) && !defined(lint) 38: static char sccsid[] = "@(#)popen.c 5.15.1 (2.11BSD) 1999/10/24"; 39: #endif /* LIBC_SCCS and not lint */ 40: 41: #include <errno.h> 42: #include <sys/signal.h> 43: #include <sys/types.h> 44: #include <sys/wait.h> 45: #include <stdio.h> 46: 47: static int *pids; 48: 49: FILE * 50: popen(program, type) 51: char *program; 52: register char *type; 53: { 54: register FILE *iop; 55: int pdes[2], fds, pid; 56: 57: if (*type != 'r' && *type != 'w' || type[1]) 58: return (NULL); 59: 60: if (pids == NULL) { 61: if ((fds = getdtablesize()) <= 0) 62: return (NULL); 63: if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 64: return (NULL); 65: bzero((char *)pids, fds * sizeof(int)); 66: } 67: if (pipe(pdes) < 0) 68: return (NULL); 69: switch (pid = vfork()) { 70: case -1: /* error */ 71: (void) close(pdes[0]); 72: (void) close(pdes[1]); 73: return (NULL); 74: /* NOTREACHED */ 75: case 0: /* child */ 76: if (*type == 'r') { 77: if (pdes[1] != fileno(stdout)) { 78: (void) dup2(pdes[1], fileno(stdout)); 79: (void) close(pdes[1]); 80: } 81: (void) close(pdes[0]); 82: } else { 83: if (pdes[0] != fileno(stdin)) { 84: (void) dup2(pdes[0], fileno(stdin)); 85: (void) close(pdes[0]); 86: } 87: (void) close(pdes[1]); 88: } 89: execl("/bin/sh", "sh", "-c", program, NULL); 90: _exit(127); 91: /* NOTREACHED */ 92: } 93: /* parent; assume fdopen can't fail... */ 94: if (*type == 'r') { 95: iop = fdopen(pdes[0], type); 96: (void) close(pdes[1]); 97: } else { 98: iop = fdopen(pdes[1], type); 99: (void) close(pdes[0]); 100: } 101: pids[fileno(iop)] = pid; 102: return (iop); 103: } 104: 105: int 106: pclose(iop) 107: FILE *iop; 108: { 109: register int fdes; 110: sigset_t omask, nmask; 111: union wait pstat; 112: register int pid; 113: 114: /* 115: * pclose returns -1 if stream is not associated with a 116: * `popened' command, if already `pclosed', or waitpid 117: * returns an error. 118: */ 119: if (pids == NULL || pids[fdes = fileno(iop)] == 0) 120: return (-1); 121: (void) fclose(iop); 122: sigemptyset(&nmask); 123: sigaddset(&nmask, SIGINT); 124: sigaddset(&nmask, SIGQUIT); 125: sigaddset(&nmask, SIGHUP); 126: (void) sigprocmask(SIG_BLOCK, &nmask, &omask); 127: do { 128: pid = waitpid(pids[fdes], (int *) &pstat, 0); 129: } while (pid == -1 && errno == EINTR); 130: (void) sigprocmask(SIG_SETMASK, &omask, NULL); 131: pids[fdes] = 0; 132: return (pid == -1 ? -1 : pstat.w_status); 133: }