xref: /csrg-svn/usr.bin/mail/popen.c (revision 62083)
122463Sdist /*
2*62083Sbostic  * Copyright (c) 1980, 1993
3*62083Sbostic  *	The Regents of the University of California.  All rights reserved.
433499Sbostic  *
542741Sbostic  * %sccs.include.redist.c%
622463Sdist  */
722463Sdist 
834905Sbostic #ifndef lint
9*62083Sbostic static char sccsid[] = "@(#)popen.c	8.1 (Berkeley) 06/06/93";
1034905Sbostic #endif /* not lint */
1114594Ssam 
1234699Sedward #include "rcv.h"
1331142Sedward #include <sys/wait.h>
1456291Sedward #include <fcntl.h>
1554505Sbostic #include "extern.h"
1631142Sedward 
1734963Sedward #define READ 0
1834963Sedward #define WRITE 1
194363Skurt 
2043865Sedward struct fp {
2143865Sedward 	FILE *fp;
2243865Sedward 	int pipe;
2356291Sedward 	int pid;
2443865Sedward 	struct fp *link;
2543865Sedward };
2643865Sedward static struct fp *fp_head;
2743865Sedward 
2854505Sbostic struct child {
2954505Sbostic 	int pid;
3054505Sbostic 	char done;
3154505Sbostic 	char free;
3254505Sbostic 	union wait status;
3354505Sbostic 	struct child *link;
3454505Sbostic };
3554505Sbostic static struct child *child;
3654505Sbostic static struct child *findchild __P((int));
3754505Sbostic static void delchild __P((struct child *));
3854505Sbostic 
394363Skurt FILE *
Fopen(file,mode)4043865Sedward Fopen(file, mode)
4143865Sedward 	char *file, *mode;
4243865Sedward {
4343865Sedward 	FILE *fp;
4443865Sedward 
4556291Sedward 	if ((fp = fopen(file, mode)) != NULL) {
4656291Sedward 		register_file(fp, 0, 0);
4756291Sedward 		(void) fcntl(fileno(fp), F_SETFD, 1);
4856291Sedward 	}
4943865Sedward 	return fp;
5043865Sedward }
5143865Sedward 
5243865Sedward FILE *
Fdopen(fd,mode)5343865Sedward Fdopen(fd, mode)
5454505Sbostic 	int fd;
5543865Sedward 	char *mode;
5643865Sedward {
5743865Sedward 	FILE *fp;
5843865Sedward 
5956291Sedward 	if ((fp = fdopen(fd, mode)) != NULL) {
6056291Sedward 		register_file(fp, 0, 0);
6156291Sedward 		(void) fcntl(fileno(fp), F_SETFD, 1);
6256291Sedward 	}
6343865Sedward 	return fp;
6443865Sedward }
6543865Sedward 
6654505Sbostic int
Fclose(fp)6743865Sedward Fclose(fp)
6843865Sedward 	FILE *fp;
6943865Sedward {
7043865Sedward 	unregister_file(fp);
7143865Sedward 	return fclose(fp);
7243865Sedward }
7343865Sedward 
7443865Sedward FILE *
Popen(cmd,mode)7534963Sedward Popen(cmd, mode)
7634963Sedward 	char *cmd;
7734963Sedward 	char *mode;
784363Skurt {
794363Skurt 	int p[2];
8034963Sedward 	int myside, hisside, fd0, fd1;
8156291Sedward 	int pid;
8243865Sedward 	FILE *fp;
834363Skurt 
8434699Sedward 	if (pipe(p) < 0)
854363Skurt 		return NULL;
8656291Sedward 	(void) fcntl(p[READ], F_SETFD, 1);
8756291Sedward 	(void) fcntl(p[WRITE], F_SETFD, 1);
8834963Sedward 	if (*mode == 'r') {
8934963Sedward 		myside = p[READ];
9034963Sedward 		fd0 = -1;
9134963Sedward 		hisside = fd1 = p[WRITE];
9234963Sedward 	} else {
9334963Sedward 		myside = p[WRITE];
9434963Sedward 		hisside = fd0 = p[READ];
9534963Sedward 		fd1 = -1;
964363Skurt 	}
9756291Sedward 	if ((pid = start_command(cmd, 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) {
9834963Sedward 		close(p[READ]);
9934963Sedward 		close(p[WRITE]);
1004363Skurt 		return NULL;
10134963Sedward 	}
10243865Sedward 	(void) close(hisside);
10343865Sedward 	if ((fp = fdopen(myside, mode)) != NULL)
10456291Sedward 		register_file(fp, 1, pid);
10543865Sedward 	return fp;
1064363Skurt }
1074363Skurt 
10854505Sbostic int
Pclose(ptr)10934877Sedward Pclose(ptr)
11034963Sedward 	FILE *ptr;
1114363Skurt {
11234963Sedward 	int i;
11331142Sedward 	int omask;
1144363Skurt 
11556291Sedward 	i = file_pid(ptr);
11643865Sedward 	unregister_file(ptr);
11743865Sedward 	(void) fclose(ptr);
11834963Sedward 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
11956291Sedward 	i = wait_child(i);
12013040Ssam 	sigsetmask(omask);
12134963Sedward 	return i;
1224363Skurt }
12334963Sedward 
12454505Sbostic void
close_all_files()12543865Sedward close_all_files()
12643865Sedward {
12743865Sedward 
12843865Sedward 	while (fp_head)
12943865Sedward 		if (fp_head->pipe)
13043865Sedward 			(void) Pclose(fp_head->fp);
13143865Sedward 		else
13243865Sedward 			(void) Fclose(fp_head->fp);
13343865Sedward }
13443865Sedward 
13554505Sbostic void
register_file(fp,pipe,pid)13656291Sedward register_file(fp, pipe, pid)
13743865Sedward 	FILE *fp;
13856291Sedward 	int pipe, pid;
13943865Sedward {
14043865Sedward 	struct fp *fpp;
14143865Sedward 
14243865Sedward 	if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL)
14343865Sedward 		panic("Out of memory");
14443865Sedward 	fpp->fp = fp;
14543865Sedward 	fpp->pipe = pipe;
14656291Sedward 	fpp->pid = pid;
14743865Sedward 	fpp->link = fp_head;
14843865Sedward 	fp_head = fpp;
14943865Sedward }
15043865Sedward 
15154505Sbostic void
unregister_file(fp)15243865Sedward unregister_file(fp)
15343865Sedward 	FILE *fp;
15443865Sedward {
15543865Sedward 	struct fp **pp, *p;
15643865Sedward 
15743865Sedward 	for (pp = &fp_head; p = *pp; pp = &p->link)
15843865Sedward 		if (p->fp == fp) {
15943865Sedward 			*pp = p->link;
16043865Sedward 			free((char *) p);
16143865Sedward 			return;
16243865Sedward 		}
16343865Sedward 	panic("Invalid file pointer");
16443865Sedward }
16543865Sedward 
file_pid(fp)16656291Sedward file_pid(fp)
16756291Sedward 	FILE *fp;
16856291Sedward {
16956291Sedward 	struct fp *p;
17056291Sedward 
17156291Sedward 	for (p = fp_head; p; p = p->link)
17256291Sedward 		if (p->fp == fp)
17356291Sedward 			return (p->pid);
17456291Sedward 	panic("Invalid file pointer");
17556291Sedward 	/*NOTREACHED*/
17656291Sedward }
17756291Sedward 
17834963Sedward /*
17934963Sedward  * Run a command without a shell, with optional arguments and splicing
18034963Sedward  * of stdin and stdout.  The command name can be a sequence of words.
18134963Sedward  * Signals must be handled by the caller.
18234963Sedward  * "Mask" contains the signals to ignore in the new process.
18334963Sedward  * SIGINT is enabled unless it's in the mask.
18434963Sedward  */
18534963Sedward /*VARARGS4*/
18654505Sbostic int
run_command(cmd,mask,infd,outfd,a0,a1,a2)18734963Sedward run_command(cmd, mask, infd, outfd, a0, a1, a2)
18834963Sedward 	char *cmd;
18934976Sedward 	int mask, infd, outfd;
19034963Sedward 	char *a0, *a1, *a2;
19134963Sedward {
19234963Sedward 	int pid;
19334963Sedward 
19434963Sedward 	if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
19534963Sedward 		return -1;
19634963Sedward 	return wait_command(pid);
19734963Sedward }
19834963Sedward 
19934963Sedward /*VARARGS4*/
20054505Sbostic int
start_command(cmd,mask,infd,outfd,a0,a1,a2)20134963Sedward start_command(cmd, mask, infd, outfd, a0, a1, a2)
20234963Sedward 	char *cmd;
20334976Sedward 	int mask, infd, outfd;
20434963Sedward 	char *a0, *a1, *a2;
20534963Sedward {
20634963Sedward 	int pid;
20734963Sedward 
20834963Sedward 	if ((pid = vfork()) < 0) {
20934963Sedward 		perror("fork");
21034963Sedward 		return -1;
21134963Sedward 	}
21234963Sedward 	if (pid == 0) {
21334963Sedward 		char *argv[100];
21434963Sedward 		int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv);
21534963Sedward 
21634963Sedward 		if ((argv[i++] = a0) != NOSTR &&
21734963Sedward 		    (argv[i++] = a1) != NOSTR &&
21834963Sedward 		    (argv[i++] = a2) != NOSTR)
21934963Sedward 			argv[i] = NOSTR;
22034976Sedward 		prepare_child(mask, infd, outfd);
22134963Sedward 		execvp(argv[0], argv);
22234963Sedward 		perror(argv[0]);
22334963Sedward 		_exit(1);
22434963Sedward 	}
22534963Sedward 	return pid;
22634963Sedward }
22734963Sedward 
22854505Sbostic void
prepare_child(mask,infd,outfd)22934976Sedward prepare_child(mask, infd, outfd)
23034976Sedward 	int mask, infd, outfd;
23134976Sedward {
23234976Sedward 	int i;
23334976Sedward 
23456291Sedward 	/*
23556291Sedward 	 * All file descriptors other than 0, 1, and 2 are supposed to be
23656291Sedward 	 * close-on-exec.
23756291Sedward 	 */
23834976Sedward 	if (infd >= 0)
23934976Sedward 		dup2(infd, 0);
24034976Sedward 	if (outfd >= 0)
24134976Sedward 		dup2(outfd, 1);
24234976Sedward 	for (i = 1; i <= NSIG; i++)
24334976Sedward 		if (mask & sigmask(i))
24434976Sedward 			(void) signal(i, SIG_IGN);
24534976Sedward 	if ((mask & sigmask(SIGINT)) == 0)
24634976Sedward 		(void) signal(SIGINT, SIG_DFL);
24734976Sedward 	(void) sigsetmask(0);
24834976Sedward }
24934976Sedward 
25054505Sbostic int
wait_command(pid)25134963Sedward wait_command(pid)
25234963Sedward 	int pid;
25334963Sedward {
25434963Sedward 
25534976Sedward 	if (wait_child(pid) < 0) {
25634963Sedward 		printf("Fatal error in process.\n");
25734963Sedward 		return -1;
25834963Sedward 	}
25934963Sedward 	return 0;
26034963Sedward }
26134976Sedward 
26254505Sbostic static struct child *
findchild(pid)26334976Sedward findchild(pid)
26434976Sedward 	int pid;
26534976Sedward {
26634976Sedward 	register struct child **cpp;
26734976Sedward 
26834976Sedward 	for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
26934976Sedward 	     cpp = &(*cpp)->link)
27034976Sedward 			;
27134976Sedward 	if (*cpp == NULL) {
27234976Sedward 		*cpp = (struct child *) malloc(sizeof (struct child));
27334976Sedward 		(*cpp)->pid = pid;
27434976Sedward 		(*cpp)->done = (*cpp)->free = 0;
27534976Sedward 		(*cpp)->link = NULL;
27634976Sedward 	}
27734976Sedward 	return *cpp;
27834976Sedward }
27934976Sedward 
28054505Sbostic static void
delchild(cp)28134976Sedward delchild(cp)
28234976Sedward 	register struct child *cp;
28334976Sedward {
28434976Sedward 	register struct child **cpp;
28534976Sedward 
28634976Sedward 	for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
28734976Sedward 		;
28834976Sedward 	*cpp = cp->link;
28934976Sedward 	free((char *) cp);
29034976Sedward }
29134976Sedward 
29247708Sbostic void
sigchild(signo)29354505Sbostic sigchild(signo)
29454505Sbostic 	int signo;
29534976Sedward {
29634976Sedward 	int pid;
29734976Sedward 	union wait status;
29834976Sedward 	register struct child *cp;
29934976Sedward 
30047708Sbostic 	while ((pid =
30147708Sbostic 	    wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) {
30234976Sedward 		cp = findchild(pid);
30334976Sedward 		if (cp->free)
30434976Sedward 			delchild(cp);
30534976Sedward 		else {
30634976Sedward 			cp->done = 1;
30734976Sedward 			cp->status = status;
30834976Sedward 		}
30934976Sedward 	}
31034976Sedward }
31134976Sedward 
31234976Sedward union wait wait_status;
31334976Sedward 
31434976Sedward /*
31534976Sedward  * Wait for a specific child to die.
31634976Sedward  */
31754505Sbostic int
wait_child(pid)31834976Sedward wait_child(pid)
31934976Sedward 	int pid;
32034976Sedward {
32134976Sedward 	int mask = sigblock(sigmask(SIGCHLD));
32234976Sedward 	register struct child *cp = findchild(pid);
32334976Sedward 
32434976Sedward 	while (!cp->done)
32534976Sedward 		sigpause(mask);
32634976Sedward 	wait_status = cp->status;
32734976Sedward 	delchild(cp);
32834976Sedward 	sigsetmask(mask);
32934976Sedward 	return wait_status.w_status ? -1 : 0;
33034976Sedward }
33134976Sedward 
33234976Sedward /*
33334976Sedward  * Mark a child as don't care.
33434976Sedward  */
33554505Sbostic void
free_child(pid)33634976Sedward free_child(pid)
33734976Sedward 	int pid;
33834976Sedward {
33934976Sedward 	int mask = sigblock(sigmask(SIGCHLD));
34034976Sedward 	register struct child *cp = findchild(pid);
34134976Sedward 
34234976Sedward 	if (cp->done)
34334976Sedward 		delchild(cp);
34434976Sedward 	else
34534976Sedward 		cp->free = 1;
34634976Sedward 	sigsetmask(mask);
34734976Sedward }
348