xref: /original-bsd/usr.bin/mail/popen.c (revision 6f815012)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)popen.c	5.16 (Berkeley) 04/01/91";
10 #endif /* not lint */
11 
12 #include "rcv.h"
13 #include <sys/signal.h>
14 #include <sys/wait.h>
15 
16 #define READ 0
17 #define WRITE 1
18 static int *pid;
19 
20 struct fp {
21 	FILE *fp;
22 	int pipe;
23 	struct fp *link;
24 };
25 static struct fp *fp_head;
26 
27 FILE *
28 Fopen(file, mode)
29 	char *file, *mode;
30 {
31 	FILE *fp;
32 
33 	if ((fp = fopen(file, mode)) != NULL)
34 		register_file(fp, 0);
35 	return fp;
36 }
37 
38 FILE *
39 Fdopen(fd, mode)
40 	char *mode;
41 {
42 	FILE *fp;
43 
44 	if ((fp = fdopen(fd, mode)) != NULL)
45 		register_file(fp, 0);
46 	return fp;
47 }
48 
49 Fclose(fp)
50 	FILE *fp;
51 {
52 	unregister_file(fp);
53 	return fclose(fp);
54 }
55 
56 FILE *
57 Popen(cmd, mode)
58 	char *cmd;
59 	char *mode;
60 {
61 	int p[2];
62 	int myside, hisside, fd0, fd1;
63 	FILE *fp;
64 
65 	if (pid == 0)
66 		pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize());
67 	if (pipe(p) < 0)
68 		return NULL;
69 	if (*mode == 'r') {
70 		myside = p[READ];
71 		fd0 = -1;
72 		hisside = fd1 = p[WRITE];
73 	} else {
74 		myside = p[WRITE];
75 		hisside = fd0 = p[READ];
76 		fd1 = -1;
77 	}
78 	if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) {
79 		close(p[READ]);
80 		close(p[WRITE]);
81 		return NULL;
82 	}
83 	(void) close(hisside);
84 	if ((fp = fdopen(myside, mode)) != NULL)
85 		register_file(fp, 1);
86 	return fp;
87 }
88 
89 Pclose(ptr)
90 	FILE *ptr;
91 {
92 	int i;
93 	int omask;
94 
95 	i = fileno(ptr);
96 	unregister_file(ptr);
97 	(void) fclose(ptr);
98 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
99 	i = wait_child(pid[i]);
100 	sigsetmask(omask);
101 	return i;
102 }
103 
104 close_all_files()
105 {
106 
107 	while (fp_head)
108 		if (fp_head->pipe)
109 			(void) Pclose(fp_head->fp);
110 		else
111 			(void) Fclose(fp_head->fp);
112 }
113 
114 register_file(fp, pipe)
115 	FILE *fp;
116 {
117 	struct fp *fpp;
118 
119 	if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL)
120 		panic("Out of memory");
121 	fpp->fp = fp;
122 	fpp->pipe = pipe;
123 	fpp->link = fp_head;
124 	fp_head = fpp;
125 }
126 
127 unregister_file(fp)
128 	FILE *fp;
129 {
130 	struct fp **pp, *p;
131 
132 	for (pp = &fp_head; p = *pp; pp = &p->link)
133 		if (p->fp == fp) {
134 			*pp = p->link;
135 			free((char *) p);
136 			return;
137 		}
138 	/* XXX
139 	 * Ignore this for now; there may still be uncaught
140 	 * duplicate closes.
141 	panic("Invalid file pointer");
142 	*/
143 }
144 
145 /*
146  * Run a command without a shell, with optional arguments and splicing
147  * of stdin and stdout.  The command name can be a sequence of words.
148  * Signals must be handled by the caller.
149  * "Mask" contains the signals to ignore in the new process.
150  * SIGINT is enabled unless it's in the mask.
151  */
152 /*VARARGS4*/
153 run_command(cmd, mask, infd, outfd, a0, a1, a2)
154 	char *cmd;
155 	int mask, infd, outfd;
156 	char *a0, *a1, *a2;
157 {
158 	int pid;
159 
160 	if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
161 		return -1;
162 	return wait_command(pid);
163 }
164 
165 /*VARARGS4*/
166 start_command(cmd, mask, infd, outfd, a0, a1, a2)
167 	char *cmd;
168 	int mask, infd, outfd;
169 	char *a0, *a1, *a2;
170 {
171 	int pid;
172 
173 	if ((pid = vfork()) < 0) {
174 		perror("fork");
175 		return -1;
176 	}
177 	if (pid == 0) {
178 		char *argv[100];
179 		int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv);
180 
181 		if ((argv[i++] = a0) != NOSTR &&
182 		    (argv[i++] = a1) != NOSTR &&
183 		    (argv[i++] = a2) != NOSTR)
184 			argv[i] = NOSTR;
185 		prepare_child(mask, infd, outfd);
186 		execvp(argv[0], argv);
187 		perror(argv[0]);
188 		_exit(1);
189 	}
190 	return pid;
191 }
192 
193 prepare_child(mask, infd, outfd)
194 	int mask, infd, outfd;
195 {
196 	int i;
197 
198 	if (infd >= 0)
199 		dup2(infd, 0);
200 	if (outfd >= 0)
201 		dup2(outfd, 1);
202 	for (i = getdtablesize(); --i > 2;)
203 		close(i);
204 	for (i = 1; i <= NSIG; i++)
205 		if (mask & sigmask(i))
206 			(void) signal(i, SIG_IGN);
207 	if ((mask & sigmask(SIGINT)) == 0)
208 		(void) signal(SIGINT, SIG_DFL);
209 	(void) sigsetmask(0);
210 }
211 
212 wait_command(pid)
213 	int pid;
214 {
215 
216 	if (wait_child(pid) < 0) {
217 		printf("Fatal error in process.\n");
218 		return -1;
219 	}
220 	return 0;
221 }
222 
223 struct child {
224 	int pid;
225 	char done;
226 	char free;
227 	union wait status;
228 	struct child *link;
229 };
230 static struct child *child;
231 
232 struct child *
233 findchild(pid)
234 	int pid;
235 {
236 	register struct child **cpp;
237 
238 	for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
239 	     cpp = &(*cpp)->link)
240 			;
241 	if (*cpp == NULL) {
242 		*cpp = (struct child *) malloc(sizeof (struct child));
243 		(*cpp)->pid = pid;
244 		(*cpp)->done = (*cpp)->free = 0;
245 		(*cpp)->link = NULL;
246 	}
247 	return *cpp;
248 }
249 
250 delchild(cp)
251 	register struct child *cp;
252 {
253 	register struct child **cpp;
254 
255 	for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
256 		;
257 	*cpp = cp->link;
258 	free((char *) cp);
259 }
260 
261 void
262 sigchild()
263 {
264 	int pid;
265 	union wait status;
266 	register struct child *cp;
267 
268 	while ((pid =
269 	    wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) {
270 		cp = findchild(pid);
271 		if (cp->free)
272 			delchild(cp);
273 		else {
274 			cp->done = 1;
275 			cp->status = status;
276 		}
277 	}
278 }
279 
280 union wait wait_status;
281 
282 /*
283  * Wait for a specific child to die.
284  */
285 wait_child(pid)
286 	int pid;
287 {
288 	int mask = sigblock(sigmask(SIGCHLD));
289 	register struct child *cp = findchild(pid);
290 
291 	while (!cp->done)
292 		sigpause(mask);
293 	wait_status = cp->status;
294 	delchild(cp);
295 	sigsetmask(mask);
296 	return wait_status.w_status ? -1 : 0;
297 }
298 
299 /*
300  * Mark a child as don't care.
301  */
302 free_child(pid)
303 	int pid;
304 {
305 	int mask = sigblock(sigmask(SIGCHLD));
306 	register struct child *cp = findchild(pid);
307 
308 	if (cp->done)
309 		delchild(cp);
310 	else
311 		cp->free = 1;
312 	sigsetmask(mask);
313 }
314