xref: /titanic_51/usr/src/lib/libbc/libc/gen/common/popen.c (revision 0cd13cbfb4270b840b4bd22ec5f673b2b6a2c02b)
1 /*
2  * Copyright (c) 1995, by Sun Microsystems, Inc.
3  * All rights reserved.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 	  /* from UCB 5.2 85/06/05 */
8 
9 /*
10  * Copyright (c) 1980 Regents of the University of California.
11  * All rights reserved.  The Berkeley software License Agreement
12  * specifies the terms and conditions for redistribution.
13  */
14 
15 #include <stdio.h>
16 #include <signal.h>
17 #include <vfork.h>
18 
19 #define	tst(a,b)	(*mode == 'r'? (b) : (a))
20 #define	RDR	0
21 #define	WTR	1
22 
23 extern	char *malloc();
24 extern	int execl(), vfork(), pipe(), close(), fcntl();
25 
26 static	int *popen_pid;
27 static	int nfiles;
28 
29 FILE *
30 popen(cmd,mode)
31 	char *cmd;
32 	char *mode;
33 {
34 	int p[2];
35 	register int *poptr;
36 	register int myside, hisside, pid;
37 
38 	if (nfiles <= 0)
39 		nfiles = getdtablesize();
40 	if (popen_pid == NULL) {
41 		popen_pid = (int *)malloc(nfiles * sizeof *popen_pid);
42 		if (popen_pid == NULL)
43 			return (NULL);
44 		for (pid = 0; pid < nfiles; pid++)
45 			popen_pid[pid] = -1;
46 	}
47 	if (pipe(p) < 0)
48 		return (NULL);
49 	myside = tst(p[WTR], p[RDR]);
50 	hisside = tst(p[RDR], p[WTR]);
51 	if ((pid = vfork()) == 0) {
52 		/* myside and hisside reverse roles in child */
53 		int	stdio;
54 
55 		/* close all pipes from other popen's */
56 		for (poptr = popen_pid; poptr < popen_pid+nfiles; poptr++) {
57 			if(*poptr >= 0)
58 				close(poptr - popen_pid);
59 		}
60 		stdio = tst(0, 1);
61 		(void) close(myside);
62 		if (hisside != stdio) {
63 			(void) dup2(hisside, stdio);
64 			(void) close(hisside);
65 		}
66 		(void) execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
67 		_exit(127);
68 	}
69 	if (pid == -1) {
70 		close(myside);
71 		close(hisside);
72 		return (NULL);
73 	}
74 	popen_pid[myside] = pid;
75 	close(hisside);
76 	return (fdopen(myside, mode));
77 }
78 
79 int
80 pclose(ptr)
81 	FILE *ptr;
82 {
83 	int child = -1;
84 	int pid, status, omask;
85 
86 	if (popen_pid != NULL) {
87 		child = popen_pid[fileno(ptr)];
88 		popen_pid[fileno(ptr)] = -1;
89 	}
90 	fclose(ptr);
91 	if (child == -1)
92 		return (-1);
93 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
94 	while ((pid = waitpid(child, &status, 0)) != child && pid != -1)
95 		;
96 	(void) sigsetmask(omask);
97 	return (pid == -1 ? -1 : status);
98 }
99