xref: /csrg-svn/lib/libc/gen/popen.c (revision 39261)
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  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #if defined(LIBC_SCCS) && !defined(lint)
22 static char sccsid[] = "@(#)popen.c	5.10 (Berkeley) 10/09/89";
23 #endif /* LIBC_SCCS and not lint */
24 
25 #include <sys/param.h>
26 #include <sys/signal.h>
27 #include <sys/wait.h>
28 #include <stdio.h>
29 #include <paths.h>
30 
31 static pid_t *pids;
32 static int fds;
33 
34 FILE *
35 popen(program, type)
36 	char *program, *type;
37 {
38 	FILE *iop;
39 	int pdes[2], pid;
40 	char *malloc();
41 
42 	if (*type != 'r' && *type != 'w' || type[1])
43 		return(NULL);
44 
45 	if (pids == NULL) {
46 		if ((fds = getdtablesize()) <= 0)
47 			return(NULL);
48 		if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
49 			return(NULL);
50 		bzero((char *)pids, fds * sizeof(pid_t));
51 	}
52 	if (pipe(pdes) < 0)
53 		return(NULL);
54 	switch (pid = vfork()) {
55 	case -1:			/* error */
56 		(void)close(pdes[0]);
57 		(void)close(pdes[1]);
58 		return(NULL);
59 		/* NOTREACHED */
60 	case 0:				/* child */
61 		if (*type == 'r') {
62 			if (pdes[1] != 1) {
63 				dup2(pdes[1], 1);
64 				(void)close(pdes[1]);
65 			}
66 			(void)close(pdes[0]);
67 		} else {
68 			if (pdes[0] != 0) {
69 				dup2(pdes[0], 0);
70 				(void)close(pdes[0]);
71 			}
72 			(void)close(pdes[1]);
73 		}
74 		execl(_PATH_BSHELL, "sh", "-c", program, NULL);
75 		_exit(127);
76 		/* NOTREACHED */
77 	}
78 	/* parent; assume fdopen can't fail...  */
79 	if (*type == 'r') {
80 		iop = fdopen(pdes[0], type);
81 		(void)close(pdes[1]);
82 	} else {
83 		iop = fdopen(pdes[1], type);
84 		(void)close(pdes[0]);
85 	}
86 	pids[fileno(iop)] = pid;
87 	return(iop);
88 }
89 
90 pclose(iop)
91 	FILE *iop;
92 {
93 	register int fdes;
94 	int omask;
95 	union wait pstat;
96 	pid_t pid, waitpid();
97 
98 	/*
99 	 * pclose returns -1 if stream is not associated with a
100 	 * `popened' command, if already `pclosed', or waitpid
101 	 * returns an error.
102 	 */
103 	if (pids == NULL || pids[fdes = fileno(iop)] == 0)
104 		return(-1);
105 	(void)fclose(iop);
106 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
107 	pid = waitpid(pids[fdes], &pstat, 0);
108 	(void)sigsetmask(omask);
109 	pids[fdes] = 0;
110 	return(pid == -1 ? -1 : pstat.w_status);
111 }
112