Home | History | Annotate | Line # | Download | only in gen
popen.c revision 1.12.2.1
      1  1.12.2.1  jtc /*	$NetBSD: popen.c,v 1.12.2.1 1996/09/19 20:03:27 jtc Exp $	*/
      2      1.10  cgd 
      3       1.1  cgd /*
      4       1.7  jtc  * Copyright (c) 1988, 1993
      5       1.7  jtc  *	The Regents of the University of California.  All rights reserved.
      6       1.1  cgd  *
      7       1.1  cgd  * This code is derived from software written by Ken Arnold and
      8       1.1  cgd  * published in UNIX Review, Vol. 6, No. 8.
      9       1.1  cgd  *
     10       1.1  cgd  * Redistribution and use in source and binary forms, with or without
     11       1.1  cgd  * modification, are permitted provided that the following conditions
     12       1.1  cgd  * are met:
     13       1.1  cgd  * 1. Redistributions of source code must retain the above copyright
     14       1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     15       1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  cgd  *    documentation and/or other materials provided with the distribution.
     18       1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     19       1.1  cgd  *    must display the following acknowledgement:
     20       1.1  cgd  *	This product includes software developed by the University of
     21       1.1  cgd  *	California, Berkeley and its contributors.
     22       1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     23       1.1  cgd  *    may be used to endorse or promote products derived from this software
     24       1.1  cgd  *    without specific prior written permission.
     25       1.1  cgd  *
     26       1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27       1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28       1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29       1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30       1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31       1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32       1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33       1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34       1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35       1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36       1.1  cgd  * SUCH DAMAGE.
     37       1.1  cgd  */
     38       1.1  cgd 
     39       1.1  cgd #if defined(LIBC_SCCS) && !defined(lint)
     40      1.10  cgd #if 0
     41      1.10  cgd static char sccsid[] = "@(#)popen.c	8.1 (Berkeley) 6/4/93";
     42      1.10  cgd #else
     43  1.12.2.1  jtc static char rcsid[] = "$NetBSD: popen.c,v 1.12.2.1 1996/09/19 20:03:27 jtc Exp $";
     44      1.10  cgd #endif
     45       1.1  cgd #endif /* LIBC_SCCS and not lint */
     46       1.1  cgd 
     47  1.12.2.1  jtc #include "namespace.h"
     48       1.1  cgd #include <sys/param.h>
     49       1.1  cgd #include <sys/wait.h>
     50       1.7  jtc 
     51       1.7  jtc #include <signal.h>
     52       1.1  cgd #include <errno.h>
     53       1.7  jtc #include <unistd.h>
     54       1.1  cgd #include <stdio.h>
     55       1.1  cgd #include <stdlib.h>
     56       1.1  cgd #include <string.h>
     57       1.1  cgd #include <paths.h>
     58  1.12.2.1  jtc 
     59  1.12.2.1  jtc #ifdef __weak_alias
     60  1.12.2.1  jtc __weak_alias(popen,_popen);
     61  1.12.2.1  jtc __weak_alias(pclose,_pclose);
     62  1.12.2.1  jtc #endif
     63       1.1  cgd 
     64       1.7  jtc static struct pid {
     65       1.7  jtc 	struct pid *next;
     66       1.7  jtc 	FILE *fp;
     67       1.7  jtc 	pid_t pid;
     68       1.7  jtc } *pidlist;
     69       1.7  jtc 
     70       1.1  cgd FILE *
     71       1.8  cgd popen(program, type)
     72       1.8  cgd 	const char *program;
     73       1.1  cgd 	const char *type;
     74       1.1  cgd {
     75       1.7  jtc 	struct pid *cur;
     76       1.1  cgd 	FILE *iop;
     77       1.7  jtc 	int pdes[2], pid;
     78       1.1  cgd 
     79       1.9  jtc 	if (*type != 'r' && *type != 'w' || type[1]) {
     80       1.9  jtc 		errno = EINVAL;
     81       1.1  cgd 		return (NULL);
     82       1.9  jtc 	}
     83       1.1  cgd 
     84       1.7  jtc 	if ((cur = malloc(sizeof(struct pid))) == NULL)
     85       1.7  jtc 		return (NULL);
     86       1.7  jtc 
     87       1.7  jtc 	if (pipe(pdes) < 0) {
     88      1.11  jtc 		free(cur);
     89       1.7  jtc 		return (NULL);
     90       1.1  cgd 	}
     91       1.7  jtc 
     92       1.1  cgd 	switch (pid = vfork()) {
     93       1.7  jtc 	case -1:			/* Error. */
     94       1.7  jtc 		(void)close(pdes[0]);
     95       1.7  jtc 		(void)close(pdes[1]);
     96      1.11  jtc 		free(cur);
     97       1.1  cgd 		return (NULL);
     98       1.1  cgd 		/* NOTREACHED */
     99       1.7  jtc 	case 0:				/* Child. */
    100       1.1  cgd 		if (*type == 'r') {
    101       1.1  cgd 			if (pdes[1] != STDOUT_FILENO) {
    102       1.7  jtc 				(void)dup2(pdes[1], STDOUT_FILENO);
    103       1.7  jtc 				(void)close(pdes[1]);
    104       1.1  cgd 			}
    105       1.1  cgd 			(void) close(pdes[0]);
    106       1.1  cgd 		} else {
    107       1.1  cgd 			if (pdes[0] != STDIN_FILENO) {
    108       1.7  jtc 				(void)dup2(pdes[0], STDIN_FILENO);
    109       1.7  jtc 				(void)close(pdes[0]);
    110       1.1  cgd 			}
    111       1.7  jtc 			(void)close(pdes[1]);
    112       1.1  cgd 		}
    113      1.12  jtc 
    114      1.12  jtc 		/* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
    115      1.12  jtc 		   from previous popen() calls that remain open in the
    116      1.12  jtc 		   parent process are closed in the new child process. */
    117      1.12  jtc 		for (cur = pidlist; cur; cur = cur->next)
    118      1.12  jtc 			close(fileno(cur->fp));
    119      1.12  jtc 
    120      1.10  cgd 		execl(_PATH_BSHELL, "sh", "-c", program, NULL);
    121       1.1  cgd 		_exit(127);
    122       1.1  cgd 		/* NOTREACHED */
    123       1.1  cgd 	}
    124       1.7  jtc 
    125       1.7  jtc 	/* Parent; assume fdopen can't fail. */
    126       1.1  cgd 	if (*type == 'r') {
    127       1.1  cgd 		iop = fdopen(pdes[0], type);
    128       1.7  jtc 		(void)close(pdes[1]);
    129       1.1  cgd 	} else {
    130       1.1  cgd 		iop = fdopen(pdes[1], type);
    131       1.7  jtc 		(void)close(pdes[0]);
    132       1.1  cgd 	}
    133       1.7  jtc 
    134       1.7  jtc 	/* Link into list of file descriptors. */
    135       1.7  jtc 	cur->fp = iop;
    136       1.7  jtc 	cur->pid =  pid;
    137       1.7  jtc 	cur->next = pidlist;
    138       1.7  jtc 	pidlist = cur;
    139       1.7  jtc 
    140       1.1  cgd 	return (iop);
    141       1.1  cgd }
    142       1.1  cgd 
    143       1.7  jtc /*
    144       1.7  jtc  * pclose --
    145       1.7  jtc  *	Pclose returns -1 if stream is not associated with a `popened' command,
    146       1.7  jtc  *	if already `pclosed', or waitpid returns an error.
    147       1.7  jtc  */
    148       1.1  cgd int
    149       1.1  cgd pclose(iop)
    150       1.1  cgd 	FILE *iop;
    151       1.1  cgd {
    152       1.7  jtc 	register struct pid *cur, *last;
    153       1.9  jtc 	int pstat;
    154       1.1  cgd 	pid_t pid;
    155       1.1  cgd 
    156       1.8  cgd 	(void)fclose(iop);
    157       1.8  cgd 
    158       1.7  jtc 	/* Find the appropriate file pointer. */
    159       1.7  jtc 	for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
    160       1.7  jtc 		if (cur->fp == iop)
    161       1.7  jtc 			break;
    162       1.7  jtc 	if (cur == NULL)
    163       1.1  cgd 		return (-1);
    164       1.7  jtc 
    165       1.1  cgd 	do {
    166       1.9  jtc 		pid = waitpid(cur->pid, &pstat, 0);
    167       1.1  cgd 	} while (pid == -1 && errno == EINTR);
    168       1.7  jtc 
    169       1.7  jtc 	/* Remove the entry from the linked list. */
    170       1.7  jtc 	if (last == NULL)
    171       1.7  jtc 		pidlist = cur->next;
    172       1.7  jtc 	else
    173       1.7  jtc 		last->next = cur->next;
    174       1.7  jtc 	free(cur);
    175       1.7  jtc 
    176       1.9  jtc 	return (pid == -1 ? -1 : pstat);
    177       1.1  cgd }
    178