kludge to make undeleting an undeleted message work
[unix-history] / usr / src / usr.bin / mail / popen.c
CommitLineData
761330fe
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
0c5f72fb
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
acfc7e9b
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
761330fe
DF
16 */
17
acfc7e9b 18#ifndef lint
470c33f3 19static char sccsid[] = "@(#)popen.c 5.13 (Berkeley) %G%";
acfc7e9b 20#endif /* not lint */
bbbe213d 21
9650997e 22#include "rcv.h"
828615a1 23#include <sys/signal.h>
828615a1 24#include <sys/wait.h>
828615a1 25
d33aa50d
EW
26#define READ 0
27#define WRITE 1
e4920814 28static int *pid;
ea394d88 29
e343f97a 30FILE *
d33aa50d
EW
31Popen(cmd, mode)
32 char *cmd;
33 char *mode;
e343f97a
KS
34{
35 int p[2];
d33aa50d 36 int myside, hisside, fd0, fd1;
e343f97a 37
e4920814 38 if (pid == 0)
d33aa50d 39 pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize());
9650997e 40 if (pipe(p) < 0)
e343f97a 41 return NULL;
d33aa50d
EW
42 if (*mode == 'r') {
43 myside = p[READ];
44 fd0 = -1;
45 hisside = fd1 = p[WRITE];
46 } else {
47 myside = p[WRITE];
48 hisside = fd0 = p[READ];
49 fd1 = -1;
e343f97a 50 }
d33aa50d
EW
51 if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) {
52 close(p[READ]);
53 close(p[WRITE]);
e343f97a 54 return NULL;
d33aa50d 55 }
e343f97a 56 close(hisside);
9650997e 57 return fdopen(myside, mode);
e343f97a
KS
58}
59
d96977db 60Pclose(ptr)
d33aa50d 61 FILE *ptr;
e343f97a 62{
d33aa50d 63 int i;
828615a1 64 int omask;
e343f97a 65
d33aa50d 66 i = fileno(ptr);
e343f97a 67 fclose(ptr);
d33aa50d 68 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
322c8626 69 i = wait_child(pid[i]);
4bc721c3 70 sigsetmask(omask);
d33aa50d
EW
71 return i;
72}
73
74/*
75 * Run a command without a shell, with optional arguments and splicing
76 * of stdin and stdout. The command name can be a sequence of words.
77 * Signals must be handled by the caller.
78 * "Mask" contains the signals to ignore in the new process.
79 * SIGINT is enabled unless it's in the mask.
80 */
81/*VARARGS4*/
82run_command(cmd, mask, infd, outfd, a0, a1, a2)
83 char *cmd;
322c8626 84 int mask, infd, outfd;
d33aa50d
EW
85 char *a0, *a1, *a2;
86{
87 int pid;
88
89 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
90 return -1;
91 return wait_command(pid);
92}
93
94/*VARARGS4*/
95start_command(cmd, mask, infd, outfd, a0, a1, a2)
96 char *cmd;
322c8626 97 int mask, infd, outfd;
d33aa50d
EW
98 char *a0, *a1, *a2;
99{
100 int pid;
101
102 if ((pid = vfork()) < 0) {
103 perror("fork");
104 return -1;
105 }
106 if (pid == 0) {
107 char *argv[100];
108 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv);
109
110 if ((argv[i++] = a0) != NOSTR &&
111 (argv[i++] = a1) != NOSTR &&
112 (argv[i++] = a2) != NOSTR)
113 argv[i] = NOSTR;
322c8626 114 prepare_child(mask, infd, outfd);
d33aa50d
EW
115 execvp(argv[0], argv);
116 perror(argv[0]);
117 _exit(1);
118 }
119 return pid;
120}
121
322c8626
EW
122prepare_child(mask, infd, outfd)
123 int mask, infd, outfd;
124{
125 int i;
126
127 if (infd >= 0)
128 dup2(infd, 0);
129 if (outfd >= 0)
130 dup2(outfd, 1);
131 for (i = getdtablesize(); --i > 2;)
132 close(i);
133 for (i = 1; i <= NSIG; i++)
134 if (mask & sigmask(i))
135 (void) signal(i, SIG_IGN);
136 if ((mask & sigmask(SIGINT)) == 0)
137 (void) signal(SIGINT, SIG_DFL);
138 (void) sigsetmask(0);
139}
140
d33aa50d
EW
141wait_command(pid)
142 int pid;
143{
d33aa50d 144
322c8626 145 if (wait_child(pid) < 0) {
d33aa50d
EW
146 printf("Fatal error in process.\n");
147 return -1;
148 }
149 return 0;
e343f97a 150}
322c8626
EW
151
152struct child {
153 int pid;
154 char done;
155 char free;
156 union wait status;
157 struct child *link;
158};
159static struct child *child;
160
161struct child *
162findchild(pid)
163 int pid;
164{
165 register struct child **cpp;
166
167 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
168 cpp = &(*cpp)->link)
169 ;
170 if (*cpp == NULL) {
171 *cpp = (struct child *) malloc(sizeof (struct child));
172 (*cpp)->pid = pid;
173 (*cpp)->done = (*cpp)->free = 0;
174 (*cpp)->link = NULL;
175 }
176 return *cpp;
177}
178
179delchild(cp)
180 register struct child *cp;
181{
182 register struct child **cpp;
183
184 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
185 ;
186 *cpp = cp->link;
187 free((char *) cp);
188}
189
190sigchild()
191{
192 int pid;
193 union wait status;
194 register struct child *cp;
195
196 while ((pid = wait3(&status, WNOHANG, (struct timeval *)0)) > 0) {
197 cp = findchild(pid);
198 if (cp->free)
199 delchild(cp);
200 else {
201 cp->done = 1;
202 cp->status = status;
203 }
204 }
205}
206
207union wait wait_status;
208
209/*
210 * Wait for a specific child to die.
211 */
212wait_child(pid)
213 int pid;
214{
215 int mask = sigblock(sigmask(SIGCHLD));
216 register struct child *cp = findchild(pid);
217
218 while (!cp->done)
219 sigpause(mask);
220 wait_status = cp->status;
221 delchild(cp);
222 sigsetmask(mask);
223 return wait_status.w_status ? -1 : 0;
224}
225
226/*
227 * Mark a child as don't care.
228 */
229free_child(pid)
230 int pid;
231{
232 int mask = sigblock(sigmask(SIGCHLD));
233 register struct child *cp = findchild(pid);
234
235 if (cp->done)
236 delchild(cp);
237 else
238 cp->free = 1;
239 sigsetmask(mask);
240}