xref: /original-bsd/lib/libc/gen/popen.c (revision f71c8376)
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.15 (Berkeley) 02/23/91";
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 <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <paths.h>
24 
25 static pid_t *pids;
26 
27 FILE *
28 popen(program, type)
29 	const char *program;
30 	const char *type;
31 {
32 	FILE *iop;
33 	int pdes[2], fds, pid;
34 
35 	if (*type != 'r' && *type != 'w' || type[1])
36 		return (NULL);
37 
38 	if (pids == NULL) {
39 		if ((fds = getdtablesize()) <= 0)
40 			return (NULL);
41 		if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
42 			return (NULL);
43 		bzero((char *)pids, fds * sizeof(pid_t));
44 	}
45 	if (pipe(pdes) < 0)
46 		return (NULL);
47 	switch (pid = vfork()) {
48 	case -1:			/* error */
49 		(void) close(pdes[0]);
50 		(void) close(pdes[1]);
51 		return (NULL);
52 		/* NOTREACHED */
53 	case 0:				/* child */
54 		if (*type == 'r') {
55 			if (pdes[1] != STDOUT_FILENO) {
56 				(void) dup2(pdes[1], STDOUT_FILENO);
57 				(void) close(pdes[1]);
58 			}
59 			(void) close(pdes[0]);
60 		} else {
61 			if (pdes[0] != STDIN_FILENO) {
62 				(void) dup2(pdes[0], STDIN_FILENO);
63 				(void) close(pdes[0]);
64 			}
65 			(void) close(pdes[1]);
66 		}
67 		execl(_PATH_BSHELL, "sh", "-c", program, NULL);
68 		_exit(127);
69 		/* NOTREACHED */
70 	}
71 	/* parent; assume fdopen can't fail...  */
72 	if (*type == 'r') {
73 		iop = fdopen(pdes[0], type);
74 		(void) close(pdes[1]);
75 	} else {
76 		iop = fdopen(pdes[1], type);
77 		(void) close(pdes[0]);
78 	}
79 	pids[fileno(iop)] = pid;
80 	return (iop);
81 }
82 
83 int
84 pclose(iop)
85 	FILE *iop;
86 {
87 	register int fdes;
88 	int omask;
89 	union wait pstat;
90 	pid_t pid;
91 
92 	/*
93 	 * pclose returns -1 if stream is not associated with a
94 	 * `popened' command, if already `pclosed', or waitpid
95 	 * returns an error.
96 	 */
97 	if (pids == NULL || pids[fdes = fileno(iop)] == 0)
98 		return (-1);
99 	(void) fclose(iop);
100 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
101 	do {
102 		pid = waitpid(pids[fdes], (int *) &pstat, 0);
103 	} while (pid == -1 && errno == EINTR);
104 	(void) sigsetmask(omask);
105 	pids[fdes] = 0;
106 	return (pid == -1 ? -1 : pstat.w_status);
107 }
108