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