Annotation of src/lib/libc/gen/popen.c, Revision 1.29
1.29 ! christos 1: /* $NetBSD: popen.c,v 1.28 2003/09/15 22:30:38 cl Exp $ */
1.10 cgd 2:
1.1 cgd 3: /*
1.7 jtc 4: * Copyright (c) 1988, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * This code is derived from software written by Ken Arnold and
8: * published in UNIX Review, Vol. 6, No. 8.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.27 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
1.13 christos 35: #include <sys/cdefs.h>
1.1 cgd 36: #if defined(LIBC_SCCS) && !defined(lint)
1.10 cgd 37: #if 0
1.16 perry 38: static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
1.10 cgd 39: #else
1.29 ! christos 40: __RCSID("$NetBSD: popen.c,v 1.28 2003/09/15 22:30:38 cl Exp $");
1.10 cgd 41: #endif
1.1 cgd 42: #endif /* LIBC_SCCS and not lint */
43:
1.14 jtc 44: #include "namespace.h"
1.1 cgd 45: #include <sys/param.h>
46: #include <sys/wait.h>
1.16 perry 47: #include <sys/socket.h>
1.7 jtc 48:
1.23 lukem 49: #include <assert.h>
50: #include <errno.h>
51: #include <paths.h>
1.7 jtc 52: #include <signal.h>
1.1 cgd 53: #include <stdio.h>
54: #include <stdlib.h>
55: #include <string.h>
1.23 lukem 56: #include <unistd.h>
1.26 nathanw 57: #include "reentrant.h"
1.14 jtc 58:
59: #ifdef __weak_alias
1.25 mycroft 60: __weak_alias(popen,_popen)
61: __weak_alias(pclose,_pclose)
1.14 jtc 62: #endif
1.1 cgd 63:
1.26 nathanw 64: #ifdef _REENTRANT
65: extern rwlock_t __environ_lock;
66: #endif
67:
1.7 jtc 68: static struct pid {
69: struct pid *next;
70: FILE *fp;
1.28 cl 71: #ifdef _REENTRANT
72: int fd;
73: #endif
1.7 jtc 74: pid_t pid;
75: } *pidlist;
76:
1.28 cl 77: #ifdef _REENTRANT
78: static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
79: #endif
80:
1.1 cgd 81: FILE *
1.29 ! christos 82: popen(const char *command, const char *type)
1.1 cgd 83: {
1.15 thorpej 84: struct pid *cur, *old;
1.1 cgd 85: FILE *iop;
1.29 ! christos 86: const char * volatile xtype = type;
! 87: int pdes[2], pid, serrno;
! 88: volatile int twoway;
1.23 lukem 89:
90: _DIAGASSERT(command != NULL);
1.29 ! christos 91: _DIAGASSERT(xtype != NULL);
1.18 perry 92:
1.29 ! christos 93: if (strchr(xtype, '+')) {
1.16 perry 94: twoway = 1;
95: type = "r+";
1.22 lukem 96: if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pdes) < 0)
1.16 perry 97: return (NULL);
98: } else {
99: twoway = 0;
1.29 ! christos 100: if ((*xtype != 'r' && *xtype != 'w') || xtype[1] ||
1.16 perry 101: (pipe(pdes) < 0)) {
102: errno = EINVAL;
103: return (NULL);
104: }
1.9 jtc 105: }
1.1 cgd 106:
1.20 tron 107: if ((cur = malloc(sizeof(struct pid))) == NULL) {
108: (void)close(pdes[0]);
109: (void)close(pdes[1]);
1.23 lukem 110: errno = ENOMEM;
1.7 jtc 111: return (NULL);
1.20 tron 112: }
1.7 jtc 113:
1.28 cl 114: rwlock_rdlock(&pidlist_lock);
1.26 nathanw 115: rwlock_rdlock(&__environ_lock);
1.1 cgd 116: switch (pid = vfork()) {
1.7 jtc 117: case -1: /* Error. */
1.23 lukem 118: serrno = errno;
1.26 nathanw 119: rwlock_unlock(&__environ_lock);
1.28 cl 120: rwlock_unlock(&pidlist_lock);
1.20 tron 121: free(cur);
1.7 jtc 122: (void)close(pdes[0]);
123: (void)close(pdes[1]);
1.23 lukem 124: errno = serrno;
1.1 cgd 125: return (NULL);
126: /* NOTREACHED */
1.7 jtc 127: case 0: /* Child. */
1.21 tv 128: /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
129: from previous popen() calls that remain open in the
130: parent process are closed in the new child process. */
131: for (old = pidlist; old; old = old->next)
1.28 cl 132: #ifdef _REENTRANT
133: close(old->fd); /* don't allow a flush */
134: #else
1.21 tv 135: close(fileno(old->fp)); /* don't allow a flush */
1.28 cl 136: #endif
1.21 tv 137:
1.29 ! christos 138: if (*xtype == 'r') {
1.21 tv 139: (void)close(pdes[0]);
1.1 cgd 140: if (pdes[1] != STDOUT_FILENO) {
1.7 jtc 141: (void)dup2(pdes[1], STDOUT_FILENO);
142: (void)close(pdes[1]);
1.1 cgd 143: }
1.20 tron 144: if (twoway)
145: (void)dup2(STDOUT_FILENO, STDIN_FILENO);
1.1 cgd 146: } else {
1.21 tv 147: (void)close(pdes[1]);
1.1 cgd 148: if (pdes[0] != STDIN_FILENO) {
1.7 jtc 149: (void)dup2(pdes[0], STDIN_FILENO);
150: (void)close(pdes[0]);
1.1 cgd 151: }
152: }
1.12 jtc 153:
1.17 perry 154: execl(_PATH_BSHELL, "sh", "-c", command, NULL);
1.1 cgd 155: _exit(127);
156: /* NOTREACHED */
157: }
1.26 nathanw 158: rwlock_unlock(&__environ_lock);
1.7 jtc 159:
160: /* Parent; assume fdopen can't fail. */
1.29 ! christos 161: if (*xtype == 'r') {
! 162: iop = fdopen(pdes[0], xtype);
1.28 cl 163: #ifdef _REENTRANT
164: cur->fd = pdes[0];
165: #endif
1.7 jtc 166: (void)close(pdes[1]);
1.1 cgd 167: } else {
1.29 ! christos 168: iop = fdopen(pdes[1], xtype);
1.28 cl 169: #ifdef _REENTRANT
170: cur->fd = pdes[1];
171: #endif
1.7 jtc 172: (void)close(pdes[0]);
1.1 cgd 173: }
1.7 jtc 174:
175: /* Link into list of file descriptors. */
176: cur->fp = iop;
177: cur->pid = pid;
178: cur->next = pidlist;
179: pidlist = cur;
1.28 cl 180: rwlock_unlock(&pidlist_lock);
1.7 jtc 181:
1.1 cgd 182: return (iop);
183: }
184:
1.7 jtc 185: /*
186: * pclose --
187: * Pclose returns -1 if stream is not associated with a `popened' command,
188: * if already `pclosed', or waitpid returns an error.
189: */
1.1 cgd 190: int
191: pclose(iop)
192: FILE *iop;
193: {
1.19 perry 194: struct pid *cur, *last;
1.9 jtc 195: int pstat;
1.1 cgd 196: pid_t pid;
1.23 lukem 197:
198: _DIAGASSERT(iop != NULL);
1.1 cgd 199:
1.28 cl 200: rwlock_wrlock(&pidlist_lock);
201:
1.7 jtc 202: /* Find the appropriate file pointer. */
203: for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
204: if (cur->fp == iop)
205: break;
1.28 cl 206: if (cur == NULL) {
207: rwlock_unlock(&pidlist_lock);
1.1 cgd 208: return (-1);
1.28 cl 209: }
1.16 perry 210:
211: (void)fclose(iop);
1.7 jtc 212:
213: /* Remove the entry from the linked list. */
214: if (last == NULL)
215: pidlist = cur->next;
216: else
217: last->next = cur->next;
1.28 cl 218:
219: rwlock_unlock(&pidlist_lock);
220:
221: do {
222: pid = waitpid(cur->pid, &pstat, 0);
223: } while (pid == -1 && errno == EINTR);
224:
1.7 jtc 225: free(cur);
1.28 cl 226:
1.9 jtc 227: return (pid == -1 ? -1 : pstat);
1.1 cgd 228: }
CVSweb <webmaster@jp.NetBSD.org>