]> git.saurik.com Git - apple/libc.git/blob - gen/FreeBSD/popen.c
Libc-498.tar.gz
[apple/libc.git] / gen / FreeBSD / popen.c
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
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static 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"
44 #include <sys/param.h>
45 #include <sys/wait.h>
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>
54 #include <pthread.h>
55 #include "un-namespace.h"
56 #include "libc_private.h"
57
58 extern char **environ;
59
60 static struct pid {
61 struct pid *next;
62 FILE *fp;
63 pid_t pid;
64 } *pidlist;
65 static 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
70 FILE *
71 popen(command, type)
72 const char *command, *type;
73 {
74 struct pid *cur;
75 FILE *iop;
76 int pdes[2], pid, twoway;
77 char *argv[4];
78 struct pid *p;
79
80 /*
81 * Lite2 introduced two-way popen() pipes using _socketpair().
82 * FreeBSD's pipe() is bidirectional, so we use that.
83 */
84 if (strchr(type, '+')) {
85 twoway = 1;
86 type = "r+";
87 } else {
88 twoway = 0;
89 if ((*type != 'r' && *type != 'w') || type[1])
90 return (NULL);
91 }
92 if (pipe(pdes) < 0)
93 return (NULL);
94
95 if ((cur = malloc(sizeof(struct pid))) == NULL) {
96 (void)_close(pdes[0]);
97 (void)_close(pdes[1]);
98 return (NULL);
99 }
100
101 argv[0] = "sh";
102 argv[1] = "-c";
103 argv[2] = (char *)command;
104 argv[3] = NULL;
105
106 THREAD_LOCK();
107 switch (pid = vfork()) {
108 case -1: /* Error. */
109 THREAD_UNLOCK();
110 (void)_close(pdes[0]);
111 (void)_close(pdes[1]);
112 free(cur);
113 return (NULL);
114 /* NOTREACHED */
115 case 0: /* Child. */
116 if (*type == 'r') {
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 */
125 (void)_close(pdes[0]);
126 if (pdes[1] != STDOUT_FILENO) {
127 (void)_dup2(pdes[1], STDOUT_FILENO);
128 (void)_close(pdes[1]);
129 if (twoway)
130 (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
131 } else if (twoway && (pdes[1] != STDIN_FILENO))
132 (void)_dup2(pdes[1], STDIN_FILENO);
133 } else {
134 if (pdes[0] != STDIN_FILENO) {
135 (void)_dup2(pdes[0], STDIN_FILENO);
136 (void)_close(pdes[0]);
137 }
138 (void)_close(pdes[1]);
139 }
140 for (p = pidlist; p; p = p->next) {
141 (void)_close(fileno(p->fp));
142 }
143 _execve(_PATH_BSHELL, argv, environ);
144 _exit(127);
145 /* NOTREACHED */
146 }
147 THREAD_UNLOCK();
148
149 /* Parent; assume fdopen can't fail. */
150 if (*type == 'r') {
151 iop = fdopen(pdes[0], type);
152 (void)_close(pdes[1]);
153 } else {
154 iop = fdopen(pdes[1], type);
155 (void)_close(pdes[0]);
156 }
157
158 /* Link into list of file descriptors. */
159 cur->fp = iop;
160 cur->pid = pid;
161 THREAD_LOCK();
162 cur->next = pidlist;
163 pidlist = cur;
164 THREAD_UNLOCK();
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 */
174 int
175 pclose(iop)
176 FILE *iop;
177 {
178 struct pid *cur, *last;
179 int pstat;
180 pid_t pid;
181
182 /*
183 * Find the appropriate file pointer and remove it from the list.
184 */
185 THREAD_LOCK();
186 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
187 if (cur->fp == iop)
188 break;
189 if (cur == NULL) {
190 THREAD_UNLOCK();
191 return (-1);
192 }
193 if (last == NULL)
194 pidlist = cur->next;
195 else
196 last->next = cur->next;
197 THREAD_UNLOCK();
198
199 (void)fclose(iop);
200
201 do {
202 pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
203 } while (pid == -1 && errno == EINTR);
204
205 free(cur);
206
207 return (pid == -1 ? -1 : pstat);
208 }