xref: /plan9/sys/src/ape/lib/bsd/popen.c (revision f19e7b749ec99577072cd8e44030fe810f42c7ad)
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <sys/types.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 
7 #define MAXFORKS	20
8 #define NSYSFILE	3
9 #define	tst(a,b)	(*mode == 'r'? (b) : (a))
10 #define	RDR	0
11 #define	WTR	1
12 
13 struct a_fork {
14 	short	done;
15 	short	fd;
16 	int	pid;
17 	int	status;
18 };
19 static struct a_fork the_fork[MAXFORKS];
20 
21 FILE *
popen(char * cmd,char * mode)22 popen(char *cmd, char *mode)
23 {
24 	int p[2];
25 	int myside, hisside, pid;
26 	int i, ind;
27 
28 	for (ind = 0; ind < MAXFORKS; ind++)
29 		if (the_fork[ind].pid == 0)
30 			break;
31 	if (ind == MAXFORKS)
32 		return NULL;
33 	if(pipe(p) < 0)
34 		return NULL;
35 	myside = tst(p[WTR], p[RDR]);
36 	hisside = tst(p[RDR], p[WTR]);
37 	switch (pid = fork()) {
38 	case -1:
39 		return NULL;
40 	case 0:
41 		/* myside and hisside reverse roles in child */
42 		close(myside);
43 		dup2(hisside, tst(0, 1));
44 		for (i=NSYSFILE; i<FOPEN_MAX; i++)
45 			close(i);
46 		execl("/bin/ape/sh", "sh", "-c", cmd, NULL);
47 		_exit(1);
48 	default:
49 		the_fork[ind].pid = pid;
50 		the_fork[ind].fd = myside;
51 		the_fork[ind].done = 0;
52 		close(hisside);
53 		return(fdopen(myside, mode));
54 	}
55 }
56 
57 int
pclose(FILE * ptr)58 pclose(FILE *ptr)
59 {
60 	int f, r, ind;
61 	int status;
62 
63 	f = fileno(ptr);
64 	fclose(ptr);
65 	for (ind = 0; ind < MAXFORKS; ind++)
66 		if (the_fork[ind].fd == f && the_fork[ind].pid != 0)
67 			break;
68 	if (ind == MAXFORKS)
69 		return 0;
70 	if (!the_fork[ind].done) {
71 		do {
72 			r = wait(&status);
73 			for (f = 0; f < MAXFORKS; f++)
74 				if (the_fork[f].pid == r) {
75 					the_fork[f].done = 1;
76 					the_fork[f].status = status;
77 					break;
78 				}
79 		} while(r != the_fork[ind].pid && r != -1);
80 		the_fork[ind].status = r == -1 ? -1 : status;
81 	}
82 	the_fork[ind].pid = 0;
83 	return (the_fork[ind].status);
84 }
85