11573Srgrimes/* 21573Srgrimes * Copyright (c) 1988, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * This code is derived from software written by Ken Arnold and 61573Srgrimes * published in UNIX Review, Vol. 6, No. 8. 71573Srgrimes * 81573Srgrimes * Redistribution and use in source and binary forms, with or without 91573Srgrimes * modification, are permitted provided that the following conditions 101573Srgrimes * are met: 111573Srgrimes * 1. Redistributions of source code must retain the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer. 131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in the 151573Srgrimes * documentation and/or other materials provided with the distribution. 161573Srgrimes * 4. Neither the name of the University nor the names of its contributors 171573Srgrimes * may be used to endorse or promote products derived from this software 181573Srgrimes * without specific prior written permission. 191573Srgrimes * 201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 311573Srgrimes */ 321573Srgrimes 331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 3423668Speterstatic char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95"; 351573Srgrimes#endif /* LIBC_SCCS and not lint */ 3690041Sobrien#include <sys/cdefs.h> 3790041Sobrien__FBSDID("$FreeBSD$"); 381573Srgrimes 3971579Sdeischen#include "namespace.h" 401573Srgrimes#include <sys/param.h> 41180963Sed#include <sys/queue.h> 421573Srgrimes#include <sys/wait.h> 431573Srgrimes 441573Srgrimes#include <signal.h> 451573Srgrimes#include <errno.h> 46250827Sjilles#include <fcntl.h> 471573Srgrimes#include <unistd.h> 481573Srgrimes#include <stdio.h> 491573Srgrimes#include <stdlib.h> 501573Srgrimes#include <string.h> 511573Srgrimes#include <paths.h> 52108580Stjr#include <pthread.h> 5371579Sdeischen#include "un-namespace.h" 54108580Stjr#include "libc_private.h" 551573Srgrimes 5640219Speterextern char **environ; 5740219Speter 58180963Sedstruct pid { 59180963Sed SLIST_ENTRY(pid) next; 601573Srgrimes FILE *fp; 611573Srgrimes pid_t pid; 62180963Sed}; 63180963Sedstatic SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist); 64108580Stjrstatic pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER; 658870Srgrimes 66108580Stjr#define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex) 67108580Stjr#define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex) 68108580Stjr 691573SrgrimesFILE * 7023668Speterpopen(command, type) 7123668Speter const char *command, *type; 721573Srgrimes{ 731573Srgrimes struct pid *cur; 741573Srgrimes FILE *iop; 75250827Sjilles int pdes[2], pid, twoway, cloexec; 7640219Speter char *argv[4]; 7740367Smsmith struct pid *p; 781573Srgrimes 79250827Sjilles cloexec = strchr(type, 'e') != NULL; 8023668Speter /* 8171579Sdeischen * Lite2 introduced two-way popen() pipes using _socketpair(). 8223668Speter * FreeBSD's pipe() is bidirectional, so we use that. 8323668Speter */ 8423668Speter if (strchr(type, '+')) { 8523668Speter twoway = 1; 8623668Speter type = "r+"; 8723668Speter } else { 8823668Speter twoway = 0; 89250827Sjilles if ((*type != 'r' && *type != 'w') || 90250827Sjilles (type[1] && (type[1] != 'e' || type[2]))) 9123668Speter return (NULL); 9223668Speter } 93250827Sjilles if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0) 941573Srgrimes return (NULL); 951573Srgrimes 9623734Sbde if ((cur = malloc(sizeof(struct pid))) == NULL) { 9756698Sjasone (void)_close(pdes[0]); 9856698Sjasone (void)_close(pdes[1]); 991573Srgrimes return (NULL); 10023734Sbde } 1011573Srgrimes 10240219Speter argv[0] = "sh"; 10340219Speter argv[1] = "-c"; 10440219Speter argv[2] = (char *)command; 10540219Speter argv[3] = NULL; 10640219Speter 107108580Stjr THREAD_LOCK(); 10840219Speter switch (pid = vfork()) { 1091573Srgrimes case -1: /* Error. */ 110108580Stjr THREAD_UNLOCK(); 11156698Sjasone (void)_close(pdes[0]); 11256698Sjasone (void)_close(pdes[1]); 1139272Shsu free(cur); 1141573Srgrimes return (NULL); 1151573Srgrimes /* NOTREACHED */ 1161573Srgrimes case 0: /* Child. */ 1171573Srgrimes if (*type == 'r') { 11824975Sdyson /* 11971579Sdeischen * The _dup2() to STDIN_FILENO is repeated to avoid 12025063Sdyson * writing to pdes[1], which might corrupt the 12125063Sdyson * parent's copy. This isn't good enough in 12225063Sdyson * general, since the _exit() is no return, so 12325063Sdyson * the compiler is free to corrupt all the local 12425063Sdyson * variables. 12524975Sdyson */ 126250827Sjilles if (!cloexec) 127250827Sjilles (void)_close(pdes[0]); 12825063Sdyson if (pdes[1] != STDOUT_FILENO) { 12971579Sdeischen (void)_dup2(pdes[1], STDOUT_FILENO); 130250827Sjilles if (!cloexec) 131250827Sjilles (void)_close(pdes[1]); 13225084Sbde if (twoway) 13371579Sdeischen (void)_dup2(STDOUT_FILENO, STDIN_FILENO); 134250827Sjilles } else if (twoway && (pdes[1] != STDIN_FILENO)) { 13571579Sdeischen (void)_dup2(pdes[1], STDIN_FILENO); 136250827Sjilles if (cloexec) 137250827Sjilles (void)_fcntl(pdes[1], F_SETFD, 0); 138250827Sjilles } else if (cloexec) 139250827Sjilles (void)_fcntl(pdes[1], F_SETFD, 0); 1401573Srgrimes } else { 1411573Srgrimes if (pdes[0] != STDIN_FILENO) { 14271579Sdeischen (void)_dup2(pdes[0], STDIN_FILENO); 143250827Sjilles if (!cloexec) 144250827Sjilles (void)_close(pdes[0]); 145250827Sjilles } else if (cloexec) 146250827Sjilles (void)_fcntl(pdes[0], F_SETFD, 0); 147250827Sjilles if (!cloexec) 148250827Sjilles (void)_close(pdes[1]); 1491573Srgrimes } 150180963Sed SLIST_FOREACH(p, &pidlist, next) 15156698Sjasone (void)_close(fileno(p->fp)); 15271579Sdeischen _execve(_PATH_BSHELL, argv, environ); 1531573Srgrimes _exit(127); 1541573Srgrimes /* NOTREACHED */ 1551573Srgrimes } 156108580Stjr THREAD_UNLOCK(); 1571573Srgrimes 1581573Srgrimes /* Parent; assume fdopen can't fail. */ 1591573Srgrimes if (*type == 'r') { 1601573Srgrimes iop = fdopen(pdes[0], type); 16156698Sjasone (void)_close(pdes[1]); 1621573Srgrimes } else { 1631573Srgrimes iop = fdopen(pdes[1], type); 16456698Sjasone (void)_close(pdes[0]); 1651573Srgrimes } 1661573Srgrimes 1671573Srgrimes /* Link into list of file descriptors. */ 1681573Srgrimes cur->fp = iop; 169108580Stjr cur->pid = pid; 170108580Stjr THREAD_LOCK(); 171180963Sed SLIST_INSERT_HEAD(&pidlist, cur, next); 172108580Stjr THREAD_UNLOCK(); 1731573Srgrimes 1741573Srgrimes return (iop); 1751573Srgrimes} 1761573Srgrimes 1771573Srgrimes/* 1781573Srgrimes * pclose -- 1791573Srgrimes * Pclose returns -1 if stream is not associated with a `popened' command, 1801573Srgrimes * if already `pclosed', or waitpid returns an error. 1811573Srgrimes */ 1821573Srgrimesint 1831573Srgrimespclose(iop) 1841573Srgrimes FILE *iop; 1851573Srgrimes{ 186180963Sed struct pid *cur, *last = NULL; 18723668Speter int pstat; 1881573Srgrimes pid_t pid; 1891573Srgrimes 190108580Stjr /* 191108580Stjr * Find the appropriate file pointer and remove it from the list. 192108580Stjr */ 193108580Stjr THREAD_LOCK(); 194180963Sed SLIST_FOREACH(cur, &pidlist, next) { 1951573Srgrimes if (cur->fp == iop) 1961573Srgrimes break; 197180963Sed last = cur; 198180963Sed } 199108580Stjr if (cur == NULL) { 200108580Stjr THREAD_UNLOCK(); 2011573Srgrimes return (-1); 202108580Stjr } 203108580Stjr if (last == NULL) 204180963Sed SLIST_REMOVE_HEAD(&pidlist, next); 205108580Stjr else 206192926Sed SLIST_REMOVE_AFTER(last, next); 207108580Stjr THREAD_UNLOCK(); 2081573Srgrimes 20923668Speter (void)fclose(iop); 21023668Speter 2111573Srgrimes do { 21256698Sjasone pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0); 2131573Srgrimes } while (pid == -1 && errno == EINTR); 2141573Srgrimes 2151573Srgrimes free(cur); 2168870Srgrimes 21723668Speter return (pid == -1 ? -1 : pstat); 2181573Srgrimes} 219