popen.c revision 165903
1323530Savg/* 2323530Savg * Copyright (c) 1988, 1993 3323530Savg * The Regents of the University of California. All rights reserved. 4323530Savg * 5323530Savg * This code is derived from software written by Ken Arnold and 6323530Savg * published in UNIX Review, Vol. 6, No. 8. 7323530Savg * 8323530Savg * Redistribution and use in source and binary forms, with or without 9323530Savg * modification, are permitted provided that the following conditions 10323530Savg * are met: 11323530Savg * 1. Redistributions of source code must retain the above copyright 12323530Savg * notice, this list of conditions and the following disclaimer. 13323530Savg * 2. Redistributions in binary form must reproduce the above copyright 14323530Savg * notice, this list of conditions and the following disclaimer in the 15323530Savg * documentation and/or other materials provided with the distribution. 16323530Savg * 4. Neither the name of the University nor the names of its contributors 17323530Savg * may be used to endorse or promote products derived from this software 18323530Savg * without specific prior written permission. 19323530Savg * 20323530Savg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21323530Savg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22323530Savg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23323530Savg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24323530Savg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25323530Savg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26323530Savg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27323530Savg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28323530Savg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29323530Savg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30323530Savg * SUCH DAMAGE. 31323530Savg */ 32323530Savg 33323530Savg#if defined(LIBC_SCCS) && !defined(lint) 34323530Savgstatic char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95"; 35323530Savg#endif /* LIBC_SCCS and not lint */ 36323530Savg#include <sys/cdefs.h> 37323530Savg__FBSDID("$FreeBSD: head/lib/libc/gen/popen.c 165903 2007-01-09 00:28:16Z imp $"); 38323530Savg 39323530Savg#include "namespace.h" 40323530Savg#include <sys/param.h> 41323530Savg#include <sys/wait.h> 42323530Savg 43323530Savg#include <signal.h> 44323530Savg#include <errno.h> 45323530Savg#include <unistd.h> 46323530Savg#include <stdio.h> 47323530Savg#include <stdlib.h> 48323530Savg#include <string.h> 49323530Savg#include <paths.h> 50323530Savg#include <pthread.h> 51323530Savg#include "un-namespace.h" 52323530Savg#include "libc_private.h" 53323530Savg 54323530Savgextern char **environ; 55323530Savg 56323530Savgstatic struct pid { 57323530Savg struct pid *next; 58323530Savg FILE *fp; 59323530Savg pid_t pid; 60323530Savg} *pidlist; 61323530Savgstatic pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER; 62323530Savg 63323530Savg#define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex) 64323530Savg#define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex) 65323530Savg 66323530SavgFILE * 67323530Savgpopen(command, type) 68323530Savg const char *command, *type; 69323530Savg{ 70323530Savg struct pid *cur; 71323530Savg FILE *iop; 72323530Savg int pdes[2], pid, twoway; 73323530Savg char *argv[4]; 74323530Savg struct pid *p; 75323530Savg 76323530Savg /* 77323530Savg * Lite2 introduced two-way popen() pipes using _socketpair(). 78323530Savg * FreeBSD's pipe() is bidirectional, so we use that. 79323530Savg */ 80323530Savg if (strchr(type, '+')) { 81323530Savg twoway = 1; 82323530Savg type = "r+"; 83323530Savg } else { 84323530Savg twoway = 0; 85323530Savg if ((*type != 'r' && *type != 'w') || type[1]) 86323530Savg return (NULL); 87323530Savg } 88323530Savg if (pipe(pdes) < 0) 89323530Savg return (NULL); 90323530Savg 91323530Savg if ((cur = malloc(sizeof(struct pid))) == NULL) { 92323530Savg (void)_close(pdes[0]); 93323530Savg (void)_close(pdes[1]); 94323530Savg return (NULL); 95323530Savg } 96323530Savg 97323530Savg argv[0] = "sh"; 98323530Savg argv[1] = "-c"; 99323530Savg argv[2] = (char *)command; 100323530Savg argv[3] = NULL; 101323530Savg 102323530Savg THREAD_LOCK(); 103323530Savg switch (pid = vfork()) { 104323530Savg case -1: /* Error. */ 105323530Savg THREAD_UNLOCK(); 106323530Savg (void)_close(pdes[0]); 107323530Savg (void)_close(pdes[1]); 108323530Savg free(cur); 109323530Savg return (NULL); 110323530Savg /* NOTREACHED */ 111323530Savg case 0: /* Child. */ 112323530Savg if (*type == 'r') { 113323530Savg /* 114323530Savg * The _dup2() to STDIN_FILENO is repeated to avoid 115323530Savg * writing to pdes[1], which might corrupt the 116323530Savg * parent's copy. This isn't good enough in 117323530Savg * general, since the _exit() is no return, so 118323530Savg * the compiler is free to corrupt all the local 119323530Savg * variables. 120323530Savg */ 121323530Savg (void)_close(pdes[0]); 122323530Savg if (pdes[1] != STDOUT_FILENO) { 123323530Savg (void)_dup2(pdes[1], STDOUT_FILENO); 124323530Savg (void)_close(pdes[1]); 125323530Savg if (twoway) 126323530Savg (void)_dup2(STDOUT_FILENO, STDIN_FILENO); 127323530Savg } else if (twoway && (pdes[1] != STDIN_FILENO)) 128323530Savg (void)_dup2(pdes[1], STDIN_FILENO); 129323530Savg } else { 130323530Savg if (pdes[0] != STDIN_FILENO) { 131323530Savg (void)_dup2(pdes[0], STDIN_FILENO); 132323530Savg (void)_close(pdes[0]); 133323530Savg } 134323530Savg (void)_close(pdes[1]); 135323530Savg } 136323530Savg for (p = pidlist; p; p = p->next) { 137323530Savg (void)_close(fileno(p->fp)); 138323530Savg } 139323530Savg _execve(_PATH_BSHELL, argv, environ); 140323530Savg _exit(127); 141323530Savg /* NOTREACHED */ 142323530Savg } 143323530Savg THREAD_UNLOCK(); 144323530Savg 145323530Savg /* Parent; assume fdopen can't fail. */ 146323530Savg if (*type == 'r') { 147323530Savg iop = fdopen(pdes[0], type); 148323530Savg (void)_close(pdes[1]); 149323530Savg } else { 150323530Savg iop = fdopen(pdes[1], type); 151323530Savg (void)_close(pdes[0]); 152323530Savg } 153323530Savg 154323530Savg /* Link into list of file descriptors. */ 155323530Savg cur->fp = iop; 156323530Savg cur->pid = pid; 157323530Savg THREAD_LOCK(); 158323530Savg cur->next = pidlist; 159323530Savg pidlist = cur; 160323530Savg THREAD_UNLOCK(); 161323530Savg 162323530Savg return (iop); 163323530Savg} 164323530Savg 165323530Savg/* 166323530Savg * pclose -- 167323530Savg * Pclose returns -1 if stream is not associated with a `popened' command, 168323530Savg * if already `pclosed', or waitpid returns an error. 169323530Savg */ 170323530Savgint 171323530Savgpclose(iop) 172323530Savg FILE *iop; 173323530Savg{ 174323530Savg struct pid *cur, *last; 175323530Savg int pstat; 176323530Savg pid_t pid; 177323530Savg 178323530Savg /* 179323530Savg * Find the appropriate file pointer and remove it from the list. 180323530Savg */ 181323530Savg THREAD_LOCK(); 182323530Savg for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 183323530Savg if (cur->fp == iop) 184323530Savg break; 185323530Savg if (cur == NULL) { 186323530Savg THREAD_UNLOCK(); 187323530Savg return (-1); 188323530Savg } 189323530Savg if (last == NULL) 190323530Savg pidlist = cur->next; 191323530Savg else 192323530Savg last->next = cur->next; 193323530Savg THREAD_UNLOCK(); 194323530Savg 195323530Savg (void)fclose(iop); 196323530Savg 197323530Savg do { 198323530Savg pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0); 199323530Savg } while (pid == -1 && errno == EINTR); 200323530Savg 201323530Savg free(cur); 202323530Savg 203323530Savg return (pid == -1 ? -1 : pstat); 204323530Savg} 205323530Savg