xref: /csrg-svn/lib/libc/gen/popen.c (revision 42625)
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  *
8*42625Sbostic  * %sccs.include.redist.c%
922101Smckusick  */
1016676Ssam 
1126575Sdonn #if defined(LIBC_SCCS) && !defined(lint)
12*42625Sbostic static char sccsid[] = "@(#)popen.c	5.14 (Berkeley) 06/01/90";
1335451Sbostic #endif /* LIBC_SCCS and not lint */
1422101Smckusick 
1535458Sbostic #include <sys/param.h>
1635458Sbostic #include <sys/signal.h>
1735458Sbostic #include <sys/wait.h>
1840829Sbostic #include <errno.h>
192024Swnj #include <stdio.h>
2039651Sbostic #include <unistd.h>
2139261Sbostic #include <paths.h>
2216676Ssam 
2336302Skarels static pid_t *pids;
242024Swnj 
252024Swnj FILE *
2635451Sbostic popen(program, type)
2735458Sbostic 	char *program, *type;
282024Swnj {
2935458Sbostic 	FILE *iop;
3040870Skarels 	int pdes[2], fds, pid;
3135458Sbostic 	char *malloc();
322024Swnj 
3335458Sbostic 	if (*type != 'r' && *type != 'w' || type[1])
3440870Skarels 		return (NULL);
3535458Sbostic 
3636302Skarels 	if (pids == NULL) {
3735458Sbostic 		if ((fds = getdtablesize()) <= 0)
3840870Skarels 			return (NULL);
3936302Skarels 		if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
4040870Skarels 			return (NULL);
4136302Skarels 		bzero((char *)pids, fds * sizeof(pid_t));
4235458Sbostic 	}
4335451Sbostic 	if (pipe(pdes) < 0)
4440870Skarels 		return (NULL);
4536302Skarels 	switch (pid = vfork()) {
4635458Sbostic 	case -1:			/* error */
4740870Skarels 		(void) close(pdes[0]);
4840870Skarels 		(void) close(pdes[1]);
4940870Skarels 		return (NULL);
5035458Sbostic 		/* NOTREACHED */
5135458Sbostic 	case 0:				/* child */
5235451Sbostic 		if (*type == 'r') {
5339651Sbostic 			if (pdes[1] != STDOUT_FILENO) {
5440870Skarels 				(void) dup2(pdes[1], STDOUT_FILENO);
5540870Skarels 				(void) close(pdes[1]);
5635458Sbostic 			}
5740870Skarels 			(void) close(pdes[0]);
5835458Sbostic 		} else {
5939651Sbostic 			if (pdes[0] != STDIN_FILENO) {
6040870Skarels 				(void) dup2(pdes[0], STDIN_FILENO);
6140870Skarels 				(void) close(pdes[0]);
6235458Sbostic 			}
6340870Skarels 			(void) close(pdes[1]);
6414718Ssam 		}
6539261Sbostic 		execl(_PATH_BSHELL, "sh", "-c", program, NULL);
6635458Sbostic 		_exit(127);
6735451Sbostic 		/* NOTREACHED */
682024Swnj 	}
6935458Sbostic 	/* parent; assume fdopen can't fail...  */
7035458Sbostic 	if (*type == 'r') {
7135458Sbostic 		iop = fdopen(pdes[0], type);
7240870Skarels 		(void) close(pdes[1]);
7335458Sbostic 	} else {
7435458Sbostic 		iop = fdopen(pdes[1], type);
7540870Skarels 		(void) close(pdes[0]);
7615073Skarels 	}
7735458Sbostic 	pids[fileno(iop)] = pid;
7840870Skarels 	return (iop);
792024Swnj }
802024Swnj 
8135451Sbostic pclose(iop)
8235458Sbostic 	FILE *iop;
832024Swnj {
8440829Sbostic 	extern int errno;
8535458Sbostic 	register int fdes;
8636302Skarels 	int omask;
8736309Sbostic 	union wait pstat;
8836309Sbostic 	pid_t pid, waitpid();
892024Swnj 
9035458Sbostic 	/*
9135458Sbostic 	 * pclose returns -1 if stream is not associated with a
9236309Sbostic 	 * `popened' command, if already `pclosed', or waitpid
9336309Sbostic 	 * returns an error.
9435458Sbostic 	 */
9536302Skarels 	if (pids == NULL || pids[fdes = fileno(iop)] == 0)
9640870Skarels 		return (-1);
9740870Skarels 	(void) fclose(iop);
9835458Sbostic 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
9940829Sbostic 	do {
10040829Sbostic 		pid = waitpid(pids[fdes], &pstat, 0);
10140829Sbostic 	} while (pid == -1 && errno == EINTR);
10240870Skarels 	(void) sigsetmask(omask);
10335458Sbostic 	pids[fdes] = 0;
10440870Skarels 	return (pid == -1 ? -1 : pstat.w_status);
1052024Swnj }
106