xref: /original-bsd/lib/libc/gen/popen.c (revision e2944021)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #if defined(LIBC_SCCS) && !defined(lint)
8 static char sccsid[] = "@(#)popen.c	5.4 (Berkeley) 03/26/86";
9 #endif LIBC_SCCS and not lint
10 
11 #include <stdio.h>
12 #include <signal.h>
13 
14 #define	tst(a,b)	(*mode == 'r'? (b) : (a))
15 #define	RDR	0
16 #define	WTR	1
17 
18 extern	char *malloc();
19 
20 static	int *popen_pid;
21 static	int nfiles;
22 
23 FILE *
24 popen(cmd,mode)
25 	char *cmd;
26 	char *mode;
27 {
28 	int p[2];
29 	int myside, hisside, pid;
30 
31 	if (nfiles <= 0)
32 		nfiles = getdtablesize();
33 	if (popen_pid == NULL) {
34 		popen_pid = (int *)malloc(nfiles * sizeof *popen_pid);
35 		if (popen_pid == NULL)
36 			return (NULL);
37 		for (pid = 0; pid < nfiles; pid++)
38 			popen_pid[pid] = -1;
39 	}
40 	if (pipe(p) < 0)
41 		return (NULL);
42 	myside = tst(p[WTR], p[RDR]);
43 	hisside = tst(p[RDR], p[WTR]);
44 	if ((pid = vfork()) == 0) {
45 		/* myside and hisside reverse roles in child */
46 		close(myside);
47 		if (hisside != tst(0, 1)) {
48 			dup2(hisside, tst(0, 1));
49 			close(hisside);
50 		}
51 		execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
52 		_exit(127);
53 	}
54 	if (pid == -1) {
55 		close(myside);
56 		close(hisside);
57 		return (NULL);
58 	}
59 	popen_pid[myside] = pid;
60 	close(hisside);
61 	return (fdopen(myside, mode));
62 }
63 
64 pclose(ptr)
65 	FILE *ptr;
66 {
67 	int child, pid, status, omask;
68 
69 	child = popen_pid[fileno(ptr)];
70 	popen_pid[fileno(ptr)] = -1;
71 	fclose(ptr);
72 	if (child == -1)
73 		return (-1);
74 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
75 	while ((pid = wait(&status)) != child && pid != -1)
76 		;
77 	(void) sigsetmask(omask);
78 	return (pid == -1 ? -1 : status);
79 }
80