xref: /csrg-svn/lib/libc/gen/popen.c (revision 40870)
122101Smckusick /*
235451Sbostic  * Copyright (c) 1988 The Regents of the University of California.
335451Sbostic  * All rights reserved.
435451Sbostic  *
535458Sbostic  * This code is derived from software written by Ken Arnold and
635458Sbostic  * published in UNIX Review, Vol. 6, No. 8.
735451Sbostic  *
835451Sbostic  * Redistribution and use in source and binary forms are permitted
935451Sbostic  * provided that the above copyright notice and this paragraph are
1035451Sbostic  * duplicated in all such forms and that any documentation,
1135451Sbostic  * advertising materials, and other materials related to such
1235451Sbostic  * distribution and use acknowledge that the software was developed
1335451Sbostic  * by the University of California, Berkeley.  The name of the
1435451Sbostic  * University may not be used to endorse or promote products derived
1535451Sbostic  * from this software without specific prior written permission.
1635451Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1735451Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1835451Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1922101Smckusick  */
2016676Ssam 
2126575Sdonn #if defined(LIBC_SCCS) && !defined(lint)
22*40870Skarels static char sccsid[] = "@(#)popen.c	5.13 (Berkeley) 04/10/90";
2335451Sbostic #endif /* LIBC_SCCS and not lint */
2422101Smckusick 
2535458Sbostic #include <sys/param.h>
2635458Sbostic #include <sys/signal.h>
2735458Sbostic #include <sys/wait.h>
2840829Sbostic #include <errno.h>
292024Swnj #include <stdio.h>
3039651Sbostic #include <unistd.h>
3139261Sbostic #include <paths.h>
3216676Ssam 
3336302Skarels static pid_t *pids;
342024Swnj 
352024Swnj FILE *
3635451Sbostic popen(program, type)
3735458Sbostic 	char *program, *type;
382024Swnj {
3935458Sbostic 	FILE *iop;
40*40870Skarels 	int pdes[2], fds, pid;
4135458Sbostic 	char *malloc();
422024Swnj 
4335458Sbostic 	if (*type != 'r' && *type != 'w' || type[1])
44*40870Skarels 		return (NULL);
4535458Sbostic 
4636302Skarels 	if (pids == NULL) {
4735458Sbostic 		if ((fds = getdtablesize()) <= 0)
48*40870Skarels 			return (NULL);
4936302Skarels 		if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
50*40870Skarels 			return (NULL);
5136302Skarels 		bzero((char *)pids, fds * sizeof(pid_t));
5235458Sbostic 	}
5335451Sbostic 	if (pipe(pdes) < 0)
54*40870Skarels 		return (NULL);
5536302Skarels 	switch (pid = vfork()) {
5635458Sbostic 	case -1:			/* error */
57*40870Skarels 		(void) close(pdes[0]);
58*40870Skarels 		(void) close(pdes[1]);
59*40870Skarels 		return (NULL);
6035458Sbostic 		/* NOTREACHED */
6135458Sbostic 	case 0:				/* child */
6235451Sbostic 		if (*type == 'r') {
6339651Sbostic 			if (pdes[1] != STDOUT_FILENO) {
64*40870Skarels 				(void) dup2(pdes[1], STDOUT_FILENO);
65*40870Skarels 				(void) close(pdes[1]);
6635458Sbostic 			}
67*40870Skarels 			(void) close(pdes[0]);
6835458Sbostic 		} else {
6939651Sbostic 			if (pdes[0] != STDIN_FILENO) {
70*40870Skarels 				(void) dup2(pdes[0], STDIN_FILENO);
71*40870Skarels 				(void) close(pdes[0]);
7235458Sbostic 			}
73*40870Skarels 			(void) close(pdes[1]);
7414718Ssam 		}
7539261Sbostic 		execl(_PATH_BSHELL, "sh", "-c", program, NULL);
7635458Sbostic 		_exit(127);
7735451Sbostic 		/* NOTREACHED */
782024Swnj 	}
7935458Sbostic 	/* parent; assume fdopen can't fail...  */
8035458Sbostic 	if (*type == 'r') {
8135458Sbostic 		iop = fdopen(pdes[0], type);
82*40870Skarels 		(void) close(pdes[1]);
8335458Sbostic 	} else {
8435458Sbostic 		iop = fdopen(pdes[1], type);
85*40870Skarels 		(void) close(pdes[0]);
8615073Skarels 	}
8735458Sbostic 	pids[fileno(iop)] = pid;
88*40870Skarels 	return (iop);
892024Swnj }
902024Swnj 
9135451Sbostic pclose(iop)
9235458Sbostic 	FILE *iop;
932024Swnj {
9440829Sbostic 	extern int errno;
9535458Sbostic 	register int fdes;
9636302Skarels 	int omask;
9736309Sbostic 	union wait pstat;
9836309Sbostic 	pid_t pid, waitpid();
992024Swnj 
10035458Sbostic 	/*
10135458Sbostic 	 * pclose returns -1 if stream is not associated with a
10236309Sbostic 	 * `popened' command, if already `pclosed', or waitpid
10336309Sbostic 	 * returns an error.
10435458Sbostic 	 */
10536302Skarels 	if (pids == NULL || pids[fdes = fileno(iop)] == 0)
106*40870Skarels 		return (-1);
107*40870Skarels 	(void) fclose(iop);
10835458Sbostic 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
10940829Sbostic 	do {
11040829Sbostic 		pid = waitpid(pids[fdes], &pstat, 0);
11140829Sbostic 	} while (pid == -1 && errno == EINTR);
112*40870Skarels 	(void) sigsetmask(omask);
11335458Sbostic 	pids[fdes] = 0;
114*40870Skarels 	return (pid == -1 ? -1 : pstat.w_status);
1152024Swnj }
116