2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
6 * This code is derived from software written by Ken Arnold and
7 * published in UNIX Review, Vol. 6, No. 8.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * $FreeBSD: src/lib/libc/gen/popen.c,v 1.14 2000/01/27 23:06:19 jasone Exp $
34 * $Id: popen.c,v 1.6 2005/02/06 06:57:30 cpressey Exp $
36 * @(#)popen.c 8.3 (Berkeley) 5/3/95
38 * A modified version of the standard popen()/pclose() functions
39 * which adds a third function, pgetpid(), which allows the program
40 * which used popen() to obtain the pid of the process on the other
44 #include <sys/param.h>
46 #include <sys/types.h>
60 extern char **environ
;
69 aura_popen(const char *fmt
, const char *type
, ...)
78 volatile enum { READ
, WRITE
, TWO_WAY
} pipedir
;
81 * Lite2 introduced two-way popen() pipes using socketpair().
82 * FreeBSD's pipe() is bidirectional, so we use that.
84 if (strchr(type
, '+')) {
91 else if (*type
== 'w')
100 if ((cur
= malloc(sizeof(struct pid
))) == NULL
) {
106 va_start(args
, type
);
107 vasprintf(&command
, fmt
, args
);
115 switch (pid
= vfork()) {
116 case -1: /* Error. */
124 if (pipedir
== READ
|| pipedir
== TWO_WAY
) {
126 * The dup2() to STDIN_FILENO is repeated to avoid
127 * writing to pdes[1], which might corrupt the
128 * parent's copy. This isn't good enough in
129 * general, since the _exit() is no return, so
130 * the compiler is free to corrupt all the local
134 if (pdes
[1] != STDOUT_FILENO
) {
135 dup2(pdes
[1], STDOUT_FILENO
);
137 if (pipedir
== TWO_WAY
)
138 dup2(STDOUT_FILENO
, STDIN_FILENO
);
139 } else if (pipedir
== TWO_WAY
&&
140 (pdes
[1] != STDIN_FILENO
)) {
141 dup2(pdes
[1], STDIN_FILENO
);
144 if (pdes
[0] != STDIN_FILENO
) {
145 dup2(pdes
[0], STDIN_FILENO
);
150 for (p
= pidlist
; p
; p
= p
->next
) {
151 close(fileno(p
->fp
));
153 execve(_PATH_BSHELL
, __DECONST(char **, argv
), environ
);
158 /* Parent; assume fdopen can't fail. */
159 if (pipedir
== READ
|| pipedir
== TWO_WAY
) {
160 iop
= fdopen(pdes
[0], type
);
163 iop
= fdopen(pdes
[1], type
);
167 /* Link into list of file descriptors. */
179 * Pclose returns -1 if stream is not associated with a `popened' command,
180 * if already `pclosed', or waitpid returns an error.
183 aura_pclose(FILE *iop
)
185 struct pid
*cur
, *last
;
189 /* Find the appropriate file pointer. */
190 for (last
= NULL
, cur
= pidlist
; cur
; last
= cur
, cur
= cur
->next
) {
201 pid
= wait4(cur
->pid
, &pstat
, 0, (struct rusage
*)0);
202 } while (pid
== -1 && errno
== EINTR
);
204 /* Remove the entry from the linked list. */
208 last
->next
= cur
->next
;
211 return (pid
== -1 ? -1 : pstat
);
215 aura_pgetpid(FILE *iop
)
219 /* Find the appropriate file pointer. */
220 for (cur
= pidlist
; cur
; cur
= cur
->next
)
230 * 1 if all went well.
231 * 0 if an error occurred, in which case err is set to:
232 * AURA_PGETS_TIMEOUT: select() timed out.
233 * AURA_PGETS_SELECT_ERR: a select() error occurred.
234 * AURA_PGETS_EOF: end of file condition on pipe.
235 * AURA_PGETS_FGETS_ERR: a fgets() error occurred.
238 aura_pgets(FILE *p
, char *buf
, size_t len
, long msec
, int *err
)
245 tv
.tv_sec
= msec
/ 1000;
246 tv
.tv_usec
= (msec
% 1000) * 1000;
247 tvp
= (msec
< 0 ? NULL
: &tv
);
250 FD_SET(fileno(p
), &r
);
256 *err
= AURA_PGETS_EOF
;
260 *err
= AURA_PGETS_FGETS_ERR
;
264 n
= select(fileno(p
) + 1, &r
, NULL
, NULL
, tvp
);
267 *err
= AURA_PGETS_TIMEOUT
;
270 *err
= AURA_PGETS_SELECT_ERR
;
273 /* Data came in; read it. */
274 if (fgets(buf
, len
, p
) == NULL
) {
276 *err
= AURA_PGETS_EOF
;
278 *err
= AURA_PGETS_FGETS_ERR
;