xref: /original-bsd/lib/libc/gen/popen.c (revision 540a81df)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software written by Ken Arnold and
6  * published in UNIX Review, Vol. 6, No. 8.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)popen.c	5.14 (Berkeley) 06/01/90";
13 #endif /* LIBC_SCCS and not lint */
14 
15 #include <sys/param.h>
16 #include <sys/signal.h>
17 #include <sys/wait.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <paths.h>
22 
23 static pid_t *pids;
24 
25 FILE *
26 popen(program, type)
27 	char *program, *type;
28 {
29 	FILE *iop;
30 	int pdes[2], fds, pid;
31 	char *malloc();
32 
33 	if (*type != 'r' && *type != 'w' || type[1])
34 		return (NULL);
35 
36 	if (pids == NULL) {
37 		if ((fds = getdtablesize()) <= 0)
38 			return (NULL);
39 		if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
40 			return (NULL);
41 		bzero((char *)pids, fds * sizeof(pid_t));
42 	}
43 	if (pipe(pdes) < 0)
44 		return (NULL);
45 	switch (pid = vfork()) {
46 	case -1:			/* error */
47 		(void) close(pdes[0]);
48 		(void) close(pdes[1]);
49 		return (NULL);
50 		/* NOTREACHED */
51 	case 0:				/* child */
52 		if (*type == 'r') {
53 			if (pdes[1] != STDOUT_FILENO) {
54 				(void) dup2(pdes[1], STDOUT_FILENO);
55 				(void) close(pdes[1]);
56 			}
57 			(void) close(pdes[0]);
58 		} else {
59 			if (pdes[0] != STDIN_FILENO) {
60 				(void) dup2(pdes[0], STDIN_FILENO);
61 				(void) close(pdes[0]);
62 			}
63 			(void) close(pdes[1]);
64 		}
65 		execl(_PATH_BSHELL, "sh", "-c", program, NULL);
66 		_exit(127);
67 		/* NOTREACHED */
68 	}
69 	/* parent; assume fdopen can't fail...  */
70 	if (*type == 'r') {
71 		iop = fdopen(pdes[0], type);
72 		(void) close(pdes[1]);
73 	} else {
74 		iop = fdopen(pdes[1], type);
75 		(void) close(pdes[0]);
76 	}
77 	pids[fileno(iop)] = pid;
78 	return (iop);
79 }
80 
81 pclose(iop)
82 	FILE *iop;
83 {
84 	extern int errno;
85 	register int fdes;
86 	int omask;
87 	union wait pstat;
88 	pid_t pid, waitpid();
89 
90 	/*
91 	 * pclose returns -1 if stream is not associated with a
92 	 * `popened' command, if already `pclosed', or waitpid
93 	 * returns an error.
94 	 */
95 	if (pids == NULL || pids[fdes = fileno(iop)] == 0)
96 		return (-1);
97 	(void) fclose(iop);
98 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
99 	do {
100 		pid = waitpid(pids[fdes], &pstat, 0);
101 	} while (pid == -1 && errno == EINTR);
102 	(void) sigsetmask(omask);
103 	pids[fdes] = 0;
104 	return (pid == -1 ? -1 : pstat.w_status);
105 }
106