]> git.saurik.com Git - apple/libc.git/blame - gen/FreeBSD/popen.c
Libc-763.13.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.
e9ce8d39
A
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
9385eb3d
A
33#if defined(LIBC_SCCS) && !defined(lint)
34static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
35#endif /* LIBC_SCCS and not lint */
36#include <sys/cdefs.h>
1f2f436a 37__FBSDID("$FreeBSD: src/lib/libc/gen/popen.c,v 1.21 2009/05/27 19:28:04 ed Exp $");
9385eb3d
A
38
39#include "namespace.h"
e9ce8d39 40#include <sys/param.h>
1f2f436a 41#include <sys/queue.h>
e9ce8d39 42#include <sys/wait.h>
e9ce8d39
A
43
44#include <signal.h>
45#include <errno.h>
46#include <unistd.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <paths.h>
9385eb3d
A
51#include <pthread.h>
52#include "un-namespace.h"
53#include "libc_private.h"
3b2a1fe8 54
9385eb3d 55extern char **environ;
e9ce8d39 56
1f2f436a
A
57struct pid {
58 SLIST_ENTRY(pid) next;
e9ce8d39
A
59 FILE *fp;
60 pid_t pid;
1f2f436a
A
61};
62static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
9385eb3d
A
63static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
64
65#define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex)
66#define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex)
67
e9ce8d39
A
68FILE *
69popen(command, type)
70 const char *command, *type;
71{
72 struct pid *cur;
73 FILE *iop;
74 int pdes[2], pid, twoway;
3b2a1fe8
A
75 char *argv[4];
76 struct pid *p;
e9ce8d39 77
9385eb3d
A
78 /*
79 * Lite2 introduced two-way popen() pipes using _socketpair().
80 * FreeBSD's pipe() is bidirectional, so we use that.
81 */
e9ce8d39
A
82 if (strchr(type, '+')) {
83 twoway = 1;
84 type = "r+";
e9ce8d39
A
85 } else {
86 twoway = 0;
3b2a1fe8 87 if ((*type != 'r' && *type != 'w') || type[1])
e9ce8d39
A
88 return (NULL);
89 }
3b2a1fe8
A
90 if (pipe(pdes) < 0)
91 return (NULL);
e9ce8d39 92
3b2a1fe8 93 if ((cur = malloc(sizeof(struct pid))) == NULL) {
9385eb3d
A
94 (void)_close(pdes[0]);
95 (void)_close(pdes[1]);
e9ce8d39 96 return (NULL);
3b2a1fe8
A
97 }
98
99 argv[0] = "sh";
100 argv[1] = "-c";
101 argv[2] = (char *)command;
102 argv[3] = NULL;
e9ce8d39 103
9385eb3d 104 THREAD_LOCK();
e9ce8d39
A
105 switch (pid = vfork()) {
106 case -1: /* Error. */
9385eb3d
A
107 THREAD_UNLOCK();
108 (void)_close(pdes[0]);
109 (void)_close(pdes[1]);
3b2a1fe8 110 free(cur);
e9ce8d39
A
111 return (NULL);
112 /* NOTREACHED */
113 case 0: /* Child. */
114 if (*type == 'r') {
3b2a1fe8
A
115 /*
116 * The _dup2() to STDIN_FILENO is repeated to avoid
117 * writing to pdes[1], which might corrupt the
118 * parent's copy. This isn't good enough in
119 * general, since the _exit() is no return, so
120 * the compiler is free to corrupt all the local
121 * variables.
122 */
9385eb3d 123 (void)_close(pdes[0]);
e9ce8d39 124 if (pdes[1] != STDOUT_FILENO) {
9385eb3d
A
125 (void)_dup2(pdes[1], STDOUT_FILENO);
126 (void)_close(pdes[1]);
3b2a1fe8 127 if (twoway)
9385eb3d 128 (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
3b2a1fe8 129 } else if (twoway && (pdes[1] != STDIN_FILENO))
9385eb3d 130 (void)_dup2(pdes[1], STDIN_FILENO);
e9ce8d39
A
131 } else {
132 if (pdes[0] != STDIN_FILENO) {
9385eb3d
A
133 (void)_dup2(pdes[0], STDIN_FILENO);
134 (void)_close(pdes[0]);
3b2a1fe8 135 }
9385eb3d
A
136 (void)_close(pdes[1]);
137 }
1f2f436a 138 SLIST_FOREACH(p, &pidlist, next)
9385eb3d 139 (void)_close(fileno(p->fp));
9385eb3d 140 _execve(_PATH_BSHELL, argv, environ);
e9ce8d39
A
141 _exit(127);
142 /* NOTREACHED */
143 }
9385eb3d 144 THREAD_UNLOCK();
e9ce8d39
A
145
146 /* Parent; assume fdopen can't fail. */
147 if (*type == 'r') {
148 iop = fdopen(pdes[0], type);
9385eb3d 149 (void)_close(pdes[1]);
e9ce8d39
A
150 } else {
151 iop = fdopen(pdes[1], type);
9385eb3d 152 (void)_close(pdes[0]);
e9ce8d39
A
153 }
154
155 /* Link into list of file descriptors. */
156 cur->fp = iop;
9385eb3d
A
157 cur->pid = pid;
158 THREAD_LOCK();
1f2f436a 159 SLIST_INSERT_HEAD(&pidlist, cur, next);
9385eb3d 160 THREAD_UNLOCK();
e9ce8d39
A
161
162 return (iop);
163}
164
165/*
166 * pclose --
167 * Pclose returns -1 if stream is not associated with a `popened' command,
168 * if already `pclosed', or waitpid returns an error.
169 */
170int
171pclose(iop)
172 FILE *iop;
173{
1f2f436a 174 struct pid *cur, *last = NULL;
e9ce8d39
A
175 int pstat;
176 pid_t pid;
177
9385eb3d
A
178 /*
179 * Find the appropriate file pointer and remove it from the list.
180 */
181 THREAD_LOCK();
1f2f436a 182 SLIST_FOREACH(cur, &pidlist, next) {
e9ce8d39
A
183 if (cur->fp == iop)
184 break;
1f2f436a
A
185 last = cur;
186 }
9385eb3d
A
187 if (cur == NULL) {
188 THREAD_UNLOCK();
e9ce8d39 189 return (-1);
9385eb3d
A
190 }
191 if (last == NULL)
1f2f436a 192 SLIST_REMOVE_HEAD(&pidlist, next);
9385eb3d 193 else
1f2f436a 194 SLIST_REMOVE_AFTER(last, next);
9385eb3d 195 THREAD_UNLOCK();
e9ce8d39
A
196
197 (void)fclose(iop);
198
199 do {
9385eb3d 200 pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
e9ce8d39
A
201 } while (pid == -1 && errno == EINTR);
202
e9ce8d39 203 free(cur);
9385eb3d 204
e9ce8d39
A
205 return (pid == -1 ? -1 : pstat);
206}