popen.c revision 1590
1153151Sjkim/*
2153151Sjkim * Copyright (c) 1980, 1993
3153151Sjkim *	The Regents of the University of California.  All rights reserved.
4153151Sjkim *
5153151Sjkim * Redistribution and use in source and binary forms, with or without
6153151Sjkim * modification, are permitted provided that the following conditions
7153151Sjkim * are met:
8153151Sjkim * 1. Redistributions of source code must retain the above copyright
9153151Sjkim *    notice, this list of conditions and the following disclaimer.
10153151Sjkim * 2. Redistributions in binary form must reproduce the above copyright
11153151Sjkim *    notice, this list of conditions and the following disclaimer in the
12153151Sjkim *    documentation and/or other materials provided with the distribution.
13153151Sjkim * 3. All advertising materials mentioning features or use of this software
14153151Sjkim *    must display the following acknowledgement:
15153151Sjkim *	This product includes software developed by the University of
16153151Sjkim *	California, Berkeley and its contributors.
17153151Sjkim * 4. Neither the name of the University nor the names of its contributors
18153151Sjkim *    may be used to endorse or promote products derived from this software
19153151Sjkim *    without specific prior written permission.
20153151Sjkim *
21153151Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22153151Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23153151Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24153151Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25153151Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26153151Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27153151Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28153151Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29153151Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30153151Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31153151Sjkim * SUCH DAMAGE.
32153151Sjkim */
33153151Sjkim
34153151Sjkim#ifndef lint
35153151Sjkimstatic char sccsid[] = "@(#)popen.c	8.1 (Berkeley) 6/6/93";
36153151Sjkim#endif /* not lint */
37153151Sjkim
38153151Sjkim#include "rcv.h"
39153151Sjkim#include <sys/wait.h>
40153151Sjkim#include <fcntl.h>
41153151Sjkim#include "extern.h"
42153151Sjkim
43153151Sjkim#define READ 0
44153151Sjkim#define WRITE 1
45153151Sjkim
46153151Sjkimstruct fp {
47153151Sjkim	FILE *fp;
48153151Sjkim	int pipe;
49153151Sjkim	int pid;
50153151Sjkim	struct fp *link;
51153151Sjkim};
52153151Sjkimstatic struct fp *fp_head;
53153151Sjkim
54153151Sjkimstruct child {
55153151Sjkim	int pid;
56153151Sjkim	char done;
57153151Sjkim	char free;
58153151Sjkim	union wait status;
59153151Sjkim	struct child *link;
60153151Sjkim};
61153151Sjkimstatic struct child *child;
62153151Sjkimstatic struct child *findchild __P((int));
63153151Sjkimstatic void delchild __P((struct child *));
64153151Sjkim
65153151SjkimFILE *
66153151SjkimFopen(file, mode)
67153151Sjkim	char *file, *mode;
68153151Sjkim{
69153151Sjkim	FILE *fp;
70153151Sjkim
71153151Sjkim	if ((fp = fopen(file, mode)) != NULL) {
72153151Sjkim		register_file(fp, 0, 0);
73153151Sjkim		(void) fcntl(fileno(fp), F_SETFD, 1);
74153151Sjkim	}
75153151Sjkim	return fp;
76153151Sjkim}
77153151Sjkim
78153151SjkimFILE *
79153151SjkimFdopen(fd, mode)
80153151Sjkim	int fd;
81153151Sjkim	char *mode;
82153151Sjkim{
83153151Sjkim	FILE *fp;
84153151Sjkim
85153151Sjkim	if ((fp = fdopen(fd, mode)) != NULL) {
86153151Sjkim		register_file(fp, 0, 0);
87153151Sjkim		(void) fcntl(fileno(fp), F_SETFD, 1);
88153151Sjkim	}
89153151Sjkim	return fp;
90153151Sjkim}
91153151Sjkim
92153151Sjkimint
93153151SjkimFclose(fp)
94153151Sjkim	FILE *fp;
95153151Sjkim{
96153151Sjkim	unregister_file(fp);
97153151Sjkim	return fclose(fp);
98153151Sjkim}
99153151Sjkim
100153151SjkimFILE *
101153151SjkimPopen(cmd, mode)
102153151Sjkim	char *cmd;
103153151Sjkim	char *mode;
104153151Sjkim{
105153151Sjkim	int p[2];
106153995Sjkim	int myside, hisside, fd0, fd1;
107153995Sjkim	int pid;
108153995Sjkim	FILE *fp;
109153995Sjkim
110153151Sjkim	if (pipe(p) < 0)
111153151Sjkim		return NULL;
112153157Sjkim	(void) fcntl(p[READ], F_SETFD, 1);
113153151Sjkim	(void) fcntl(p[WRITE], F_SETFD, 1);
114153151Sjkim	if (*mode == 'r') {
115153151Sjkim		myside = p[READ];
116153151Sjkim		fd0 = -1;
117153151Sjkim		hisside = fd1 = p[WRITE];
118153151Sjkim	} else {
119153151Sjkim		myside = p[WRITE];
120153151Sjkim		hisside = fd0 = p[READ];
121153151Sjkim		fd1 = -1;
122153151Sjkim	}
123153151Sjkim	if ((pid = start_command(cmd, 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) {
124153151Sjkim		close(p[READ]);
125153151Sjkim		close(p[WRITE]);
126153151Sjkim		return NULL;
127153151Sjkim	}
128153151Sjkim	(void) close(hisside);
129153151Sjkim	if ((fp = fdopen(myside, mode)) != NULL)
130153151Sjkim		register_file(fp, 1, pid);
131153151Sjkim	return fp;
132153151Sjkim}
133153151Sjkim
134181644Sjkimint
135179967SjkimPclose(ptr)
136181644Sjkim	FILE *ptr;
137181644Sjkim{
138153151Sjkim	int i;
139153151Sjkim	int omask;
140153151Sjkim
141153151Sjkim	i = file_pid(ptr);
142153151Sjkim	unregister_file(ptr);
143153151Sjkim	(void) fclose(ptr);
144153151Sjkim	omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
145153151Sjkim	i = wait_child(i);
146153151Sjkim	sigsetmask(omask);
147179967Sjkim	return i;
148181644Sjkim}
149181644Sjkim
150153151Sjkimvoid
151153151Sjkimclose_all_files()
152153151Sjkim{
153181644Sjkim
154181644Sjkim	while (fp_head)
155153151Sjkim		if (fp_head->pipe)
156153151Sjkim			(void) Pclose(fp_head->fp);
157153151Sjkim		else
158179967Sjkim			(void) Fclose(fp_head->fp);
159179967Sjkim}
160179967Sjkim
161181644Sjkimvoid
162181644Sjkimregister_file(fp, pipe, pid)
163179977Sjkim	FILE *fp;
164181644Sjkim	int pipe, pid;
165181644Sjkim{
166179967Sjkim	struct fp *fpp;
167153151Sjkim
168153151Sjkim	if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL)
169153151Sjkim		panic("Out of memory");
170153151Sjkim	fpp->fp = fp;
171179977Sjkim	fpp->pipe = pipe;
172179967Sjkim	fpp->pid = pid;
173179967Sjkim	fpp->link = fp_head;
174179967Sjkim	fp_head = fpp;
175181644Sjkim}
176181644Sjkim
177181644Sjkimvoid
178181644Sjkimunregister_file(fp)
179179967Sjkim	FILE *fp;
180153151Sjkim{
181153151Sjkim	struct fp **pp, *p;
182153151Sjkim
183153151Sjkim	for (pp = &fp_head; p = *pp; pp = &p->link)
184179977Sjkim		if (p->fp == fp) {
185179967Sjkim			*pp = p->link;
186181644Sjkim			free((char *) p);
187181644Sjkim			return;
188181644Sjkim		}
189181644Sjkim	panic("Invalid file pointer");
190179967Sjkim}
191153151Sjkim
192153151Sjkimfile_pid(fp)
193153151Sjkim	FILE *fp;
194181644Sjkim{
195153151Sjkim	struct fp *p;
196153151Sjkim
197153151Sjkim	for (p = fp_head; p; p = p->link)
198181644Sjkim		if (p->fp == fp)
199153151Sjkim			return (p->pid);
200153151Sjkim	panic("Invalid file pointer");
201153151Sjkim	/*NOTREACHED*/
202179967Sjkim}
203179967Sjkim
204179967Sjkim/*
205179967Sjkim * Run a command without a shell, with optional arguments and splicing
206181644Sjkim * of stdin and stdout.  The command name can be a sequence of words.
207181644Sjkim * Signals must be handled by the caller.
208179977Sjkim * "Mask" contains the signals to ignore in the new process.
209181644Sjkim * SIGINT is enabled unless it's in the mask.
210181644Sjkim */
211179967Sjkim/*VARARGS4*/
212153151Sjkimint
213153151Sjkimrun_command(cmd, mask, infd, outfd, a0, a1, a2)
214153151Sjkim	char *cmd;
215153151Sjkim	int mask, infd, outfd;
216179977Sjkim	char *a0, *a1, *a2;
217179967Sjkim{
218179967Sjkim	int pid;
219179967Sjkim
220179967Sjkim	if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
221181644Sjkim		return -1;
222181644Sjkim	return wait_command(pid);
223181644Sjkim}
224181644Sjkim
225179967Sjkim/*VARARGS4*/
226153151Sjkimint
227153151Sjkimstart_command(cmd, mask, infd, outfd, a0, a1, a2)
228153151Sjkim	char *cmd;
229153151Sjkim	int mask, infd, outfd;
230179977Sjkim	char *a0, *a1, *a2;
231179967Sjkim{
232179967Sjkim	int pid;
233181644Sjkim
234181644Sjkim	if ((pid = vfork()) < 0) {
235181644Sjkim		perror("fork");
236181644Sjkim		return -1;
237179967Sjkim	}
238153151Sjkim	if (pid == 0) {
239153151Sjkim		char *argv[100];
240153151Sjkim		int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv);
241179967Sjkim
242181644Sjkim		if ((argv[i++] = a0) != NOSTR &&
243181644Sjkim		    (argv[i++] = a1) != NOSTR &&
244179977Sjkim		    (argv[i++] = a2) != NOSTR)
245181644Sjkim			argv[i] = NOSTR;
246181644Sjkim		prepare_child(mask, infd, outfd);
247179977Sjkim		execvp(argv[0], argv);
248179967Sjkim		perror(argv[0]);
249179967Sjkim		_exit(1);
250179967Sjkim	}
251153151Sjkim	return pid;
252153151Sjkim}
253153151Sjkim
254179967Sjkimvoid
255153151Sjkimprepare_child(mask, infd, outfd)
256153151Sjkim	int mask, infd, outfd;
257153151Sjkim{
258179967Sjkim	int i;
259153151Sjkim
260153151Sjkim	/*
261153151Sjkim	 * All file descriptors other than 0, 1, and 2 are supposed to be
262179967Sjkim	 * close-on-exec.
263179967Sjkim	 */
264179967Sjkim	if (infd >= 0)
265153151Sjkim		dup2(infd, 0);
266153151Sjkim	if (outfd >= 0)
267153151Sjkim		dup2(outfd, 1);
268179967Sjkim	for (i = 1; i <= NSIG; i++)
269179967Sjkim		if (mask & sigmask(i))
270179967Sjkim			(void) signal(i, SIG_IGN);
271153151Sjkim	if ((mask & sigmask(SIGINT)) == 0)
272153151Sjkim		(void) signal(SIGINT, SIG_DFL);
273153151Sjkim	(void) sigsetmask(0);
274153151Sjkim}
275153151Sjkim
276153151Sjkimint
277153151Sjkimwait_command(pid)
278153151Sjkim	int pid;
279179967Sjkim{
280179967Sjkim
281179967Sjkim	if (wait_child(pid) < 0) {
282153151Sjkim		printf("Fatal error in process.\n");
283153151Sjkim		return -1;
284153151Sjkim	}
285179967Sjkim	return 0;
286179967Sjkim}
287179967Sjkim
288153151Sjkimstatic struct child *
289153151Sjkimfindchild(pid)
290153151Sjkim	int pid;
291153151Sjkim{
292153151Sjkim	register struct child **cpp;
293153151Sjkim
294153151Sjkim	for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
295153151Sjkim	     cpp = &(*cpp)->link)
296179967Sjkim			;
297153151Sjkim	if (*cpp == NULL) {
298153151Sjkim		*cpp = (struct child *) malloc(sizeof (struct child));
299153151Sjkim		(*cpp)->pid = pid;
300153151Sjkim		(*cpp)->done = (*cpp)->free = 0;
301153151Sjkim		(*cpp)->link = NULL;
302153151Sjkim	}
303153151Sjkim	return *cpp;
304153151Sjkim}
305179967Sjkim
306153151Sjkimstatic void
307153151Sjkimdelchild(cp)
308153151Sjkim	register struct child *cp;
309153151Sjkim{
310153151Sjkim	register struct child **cpp;
311153151Sjkim
312153151Sjkim	for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
313179967Sjkim		;
314153151Sjkim	*cpp = cp->link;
315153151Sjkim	free((char *) cp);
316153151Sjkim}
317153151Sjkim
318153151Sjkimvoid
319153151Sjkimsigchild(signo)
320153151Sjkim	int signo;
321179967Sjkim{
322179967Sjkim	int pid;
323153151Sjkim	union wait status;
324153151Sjkim	register struct child *cp;
325153151Sjkim
326153151Sjkim	while ((pid =
327153151Sjkim	    wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) {
328153151Sjkim		cp = findchild(pid);
329153151Sjkim		if (cp->free)
330179967Sjkim			delchild(cp);
331153151Sjkim		else {
332153151Sjkim			cp->done = 1;
333153151Sjkim			cp->status = status;
334153151Sjkim		}
335153151Sjkim	}
336153151Sjkim}
337153151Sjkim
338179967Sjkimunion wait wait_status;
339153151Sjkim
340153151Sjkim/*
341153151Sjkim * Wait for a specific child to die.
342153151Sjkim */
343153151Sjkimint
344153151Sjkimwait_child(pid)
345153151Sjkim	int pid;
346179967Sjkim{
347153151Sjkim	int mask = sigblock(sigmask(SIGCHLD));
348153151Sjkim	register struct child *cp = findchild(pid);
349153151Sjkim
350153151Sjkim	while (!cp->done)
351153151Sjkim		sigpause(mask);
352153151Sjkim	wait_status = cp->status;
353153151Sjkim	delchild(cp);
354179967Sjkim	sigsetmask(mask);
355179967Sjkim	return wait_status.w_status ? -1 : 0;
356153151Sjkim}
357153151Sjkim
358153151Sjkim/*
359153151Sjkim * Mark a child as don't care.
360153151Sjkim */
361153151Sjkimvoid
362153151Sjkimfree_child(pid)
363179967Sjkim	int pid;
364153151Sjkim{
365153151Sjkim	int mask = sigblock(sigmask(SIGCHLD));
366153151Sjkim	register struct child *cp = findchild(pid);
367179967Sjkim
368153151Sjkim	if (cp->done)
369153151Sjkim		delchild(cp);
370153151Sjkim	else
371179967Sjkim		cp->free = 1;
372179967Sjkim	sigsetmask(mask);
373153151Sjkim}
374153151Sjkim