]> git.saurik.com Git - apple/libc.git/blame - gen/FreeBSD/popen.c
Libc-339.tar.gz
[apple/libc.git] / gen / FreeBSD / popen.c
CommitLineData
e9ce8d39
A
1/*
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. 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
9385eb3d
A
37#if defined(LIBC_SCCS) && !defined(lint)
38static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
39#endif /* LIBC_SCCS and not lint */
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: src/lib/libc/gen/popen.c,v 1.18 2003/01/04 00:15:15 tjr Exp $");
42
43#include "namespace.h"
e9ce8d39
A
44#include <sys/param.h>
45#include <sys/wait.h>
e9ce8d39
A
46
47#include <signal.h>
48#include <errno.h>
49#include <unistd.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <paths.h>
9385eb3d
A
54#include <pthread.h>
55#include "un-namespace.h"
56#include "libc_private.h"
3b2a1fe8 57
9385eb3d 58extern char **environ;
e9ce8d39
A
59
60static struct pid {
61 struct pid *next;
62 FILE *fp;
63 pid_t pid;
9385eb3d
A
64} *pidlist;
65static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
66
67#define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex)
68#define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex)
69
e9ce8d39
A
70FILE *
71popen(command, type)
72 const char *command, *type;
73{
74 struct pid *cur;
75 FILE *iop;
76 int pdes[2], pid, twoway;
3b2a1fe8
A
77 char *argv[4];
78 struct pid *p;
e9ce8d39 79
9385eb3d
A
80 /*
81 * Lite2 introduced two-way popen() pipes using _socketpair().
82 * FreeBSD's pipe() is bidirectional, so we use that.
83 */
e9ce8d39
A
84 if (strchr(type, '+')) {
85 twoway = 1;
86 type = "r+";
e9ce8d39
A
87 } else {
88 twoway = 0;
3b2a1fe8 89 if ((*type != 'r' && *type != 'w') || type[1])
e9ce8d39
A
90 return (NULL);
91 }
3b2a1fe8
A
92 if (pipe(pdes) < 0)
93 return (NULL);
e9ce8d39 94
3b2a1fe8 95 if ((cur = malloc(sizeof(struct pid))) == NULL) {
9385eb3d
A
96 (void)_close(pdes[0]);
97 (void)_close(pdes[1]);
e9ce8d39 98 return (NULL);
3b2a1fe8
A
99 }
100
101 argv[0] = "sh";
102 argv[1] = "-c";
103 argv[2] = (char *)command;
104 argv[3] = NULL;
e9ce8d39 105
9385eb3d 106 THREAD_LOCK();
e9ce8d39
A
107 switch (pid = vfork()) {
108 case -1: /* Error. */
9385eb3d
A
109 THREAD_UNLOCK();
110 (void)_close(pdes[0]);
111 (void)_close(pdes[1]);
3b2a1fe8 112 free(cur);
e9ce8d39
A
113 return (NULL);
114 /* NOTREACHED */
115 case 0: /* Child. */
116 if (*type == 'r') {
3b2a1fe8
A
117 /*
118 * The _dup2() to STDIN_FILENO is repeated to avoid
119 * writing to pdes[1], which might corrupt the
120 * parent's copy. This isn't good enough in
121 * general, since the _exit() is no return, so
122 * the compiler is free to corrupt all the local
123 * variables.
124 */
9385eb3d 125 (void)_close(pdes[0]);
e9ce8d39 126 if (pdes[1] != STDOUT_FILENO) {
9385eb3d
A
127 (void)_dup2(pdes[1], STDOUT_FILENO);
128 (void)_close(pdes[1]);
3b2a1fe8 129 if (twoway)
9385eb3d 130 (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
3b2a1fe8 131 } else if (twoway && (pdes[1] != STDIN_FILENO))
9385eb3d 132 (void)_dup2(pdes[1], STDIN_FILENO);
e9ce8d39
A
133 } else {
134 if (pdes[0] != STDIN_FILENO) {
9385eb3d
A
135 (void)_dup2(pdes[0], STDIN_FILENO);
136 (void)_close(pdes[0]);
3b2a1fe8 137 }
9385eb3d
A
138 (void)_close(pdes[1]);
139 }
3b2a1fe8 140 for (p = pidlist; p; p = p->next) {
9385eb3d 141 (void)_close(fileno(p->fp));
e9ce8d39 142 }
9385eb3d 143 _execve(_PATH_BSHELL, argv, environ);
e9ce8d39
A
144 _exit(127);
145 /* NOTREACHED */
146 }
9385eb3d 147 THREAD_UNLOCK();
e9ce8d39
A
148
149 /* Parent; assume fdopen can't fail. */
150 if (*type == 'r') {
151 iop = fdopen(pdes[0], type);
9385eb3d 152 (void)_close(pdes[1]);
e9ce8d39
A
153 } else {
154 iop = fdopen(pdes[1], type);
9385eb3d 155 (void)_close(pdes[0]);
e9ce8d39
A
156 }
157
158 /* Link into list of file descriptors. */
159 cur->fp = iop;
9385eb3d
A
160 cur->pid = pid;
161 THREAD_LOCK();
e9ce8d39
A
162 cur->next = pidlist;
163 pidlist = cur;
9385eb3d 164 THREAD_UNLOCK();
e9ce8d39
A
165
166 return (iop);
167}
168
169/*
170 * pclose --
171 * Pclose returns -1 if stream is not associated with a `popened' command,
172 * if already `pclosed', or waitpid returns an error.
173 */
174int
175pclose(iop)
176 FILE *iop;
177{
9385eb3d 178 struct pid *cur, *last;
e9ce8d39
A
179 int pstat;
180 pid_t pid;
181
9385eb3d
A
182 /*
183 * Find the appropriate file pointer and remove it from the list.
184 */
185 THREAD_LOCK();
e9ce8d39
A
186 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
187 if (cur->fp == iop)
188 break;
9385eb3d
A
189 if (cur == NULL) {
190 THREAD_UNLOCK();
e9ce8d39 191 return (-1);
9385eb3d
A
192 }
193 if (last == NULL)
194 pidlist = cur->next;
195 else
196 last->next = cur->next;
197 THREAD_UNLOCK();
e9ce8d39
A
198
199 (void)fclose(iop);
200
201 do {
9385eb3d 202 pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
e9ce8d39
A
203 } while (pid == -1 && errno == EINTR);
204
e9ce8d39 205 free(cur);
9385eb3d 206
e9ce8d39
A
207 return (pid == -1 ? -1 : pstat);
208}