xref: /csrg-svn/lib/libc/gen/popen.c (revision 18246)
1 /* @(#)popen.c	4.7 (Berkeley) 03/04/85 */
2 
3 #include <stdio.h>
4 #include <signal.h>
5 #include <sys/param.h>
6 
7 #define	tst(a,b)	(*mode == 'r'? (b) : (a))
8 #define	RDR	0
9 #define	WTR	1
10 
11 extern	char *malloc();
12 
13 static	int *popen_pid;
14 static	int nfiles;
15 
16 FILE *
17 popen(cmd,mode)
18 	char *cmd;
19 	char *mode;
20 {
21 	int p[2];
22 	int myside, hisside, pid;
23 
24 	if (nfiles <= 0)
25 		nfiles = getdtablesize();
26 	if (popen_pid == NULL) {
27 		popen_pid = (int *)malloc(nfiles * sizeof *popen_pid);
28 		if (popen_pid == NULL)
29 			return (NULL);
30 		for (pid = 0; pid < nfiles; pid++)
31 			popen_pid[pid] = -1;
32 	}
33 	if (pipe(p) < 0)
34 		return (NULL);
35 	myside = tst(p[WTR], p[RDR]);
36 	hisside = tst(p[RDR], p[WTR]);
37 	if ((pid = vfork()) == 0) {
38 		/* myside and hisside reverse roles in child */
39 		close(myside);
40 		if (hisside != tst(0, 1)) {
41 			dup2(hisside, tst(0, 1));
42 			close(hisside);
43 		}
44 		execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
45 		_exit(127);
46 	}
47 	if (pid == -1) {
48 		close(myside);
49 		close(hisside);
50 		return (NULL);
51 	}
52 	popen_pid[myside] = pid;
53 	close(hisside);
54 	return (fdopen(myside, mode));
55 }
56 
57 pclose(ptr)
58 	FILE *ptr;
59 {
60 	int child, pid, status, omask;
61 
62 	child = popen_pid[fileno(ptr)];
63 	popen_pid[fileno(ptr)] = -1;
64 	fclose(ptr);
65 	if (child == -1)
66 		return (-1);
67 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
68 	while ((pid = wait(&status)) != child && pid != -1)
69 		;
70 	(void) sigsetmask(omask);
71 	return (pid == -1 ? -1 : status);
72 }
73