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