Annotation of src/usr.bin/mail/popen.c, Revision 1.3
1.3 ! dm 1: /* $OpenBSD: popen.c,v 1.2 1996/06/11 12:53:47 deraadt Exp $ */
1.2 deraadt 2: /* $NetBSD: popen.c,v 1.4 1996/06/08 19:48:35 christos Exp $ */
3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.2 deraadt 38: #if 0
39: static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93";
40: #else
1.3 ! dm 41: static char rcsid[] = "$OpenBSD: popen.c,v 1.2 1996/06/11 12:53:47 deraadt Exp $";
1.2 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: #include "rcv.h"
46: #include <sys/wait.h>
47: #include <fcntl.h>
48: #include "extern.h"
49:
50: #define READ 0
51: #define WRITE 1
52:
53: struct fp {
54: FILE *fp;
55: int pipe;
56: int pid;
57: struct fp *link;
58: };
59: static struct fp *fp_head;
60:
61: struct child {
62: int pid;
63: char done;
64: char free;
65: union wait status;
66: struct child *link;
67: };
68: static struct child *child;
69: static struct child *findchild __P((int));
70: static void delchild __P((struct child *));
1.2 deraadt 71: static int file_pid __P((FILE *));
1.1 deraadt 72:
73: FILE *
74: Fopen(file, mode)
75: char *file, *mode;
76: {
77: FILE *fp;
78:
79: if ((fp = fopen(file, mode)) != NULL) {
80: register_file(fp, 0, 0);
81: (void) fcntl(fileno(fp), F_SETFD, 1);
82: }
83: return fp;
84: }
85:
86: FILE *
87: Fdopen(fd, mode)
88: int fd;
89: char *mode;
90: {
91: FILE *fp;
92:
93: if ((fp = fdopen(fd, mode)) != NULL) {
94: register_file(fp, 0, 0);
95: (void) fcntl(fileno(fp), F_SETFD, 1);
96: }
97: return fp;
98: }
99:
100: int
101: Fclose(fp)
102: FILE *fp;
103: {
104: unregister_file(fp);
105: return fclose(fp);
106: }
107:
108: FILE *
109: Popen(cmd, mode)
110: char *cmd;
111: char *mode;
112: {
113: int p[2];
114: int myside, hisside, fd0, fd1;
115: int pid;
1.2 deraadt 116: sigset_t nset;
1.1 deraadt 117: FILE *fp;
118:
119: if (pipe(p) < 0)
120: return NULL;
121: (void) fcntl(p[READ], F_SETFD, 1);
122: (void) fcntl(p[WRITE], F_SETFD, 1);
123: if (*mode == 'r') {
124: myside = p[READ];
125: fd0 = -1;
126: hisside = fd1 = p[WRITE];
127: } else {
128: myside = p[WRITE];
129: hisside = fd0 = p[READ];
130: fd1 = -1;
131: }
1.2 deraadt 132: sigemptyset(&nset);
133: if ((pid = start_command(cmd, &nset, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) {
1.1 deraadt 134: close(p[READ]);
135: close(p[WRITE]);
136: return NULL;
137: }
138: (void) close(hisside);
139: if ((fp = fdopen(myside, mode)) != NULL)
140: register_file(fp, 1, pid);
141: return fp;
142: }
143:
144: int
145: Pclose(ptr)
146: FILE *ptr;
147: {
148: int i;
1.2 deraadt 149: sigset_t nset, oset;
1.1 deraadt 150:
151: i = file_pid(ptr);
152: unregister_file(ptr);
153: (void) fclose(ptr);
1.2 deraadt 154: sigemptyset(&nset);
155: sigaddset(&nset, SIGINT);
156: sigaddset(&nset, SIGHUP);
157: sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 158: i = wait_child(i);
1.2 deraadt 159: sigprocmask(SIG_SETMASK, &oset, NULL);
1.1 deraadt 160: return i;
161: }
162:
163: void
164: close_all_files()
165: {
166:
167: while (fp_head)
168: if (fp_head->pipe)
169: (void) Pclose(fp_head->fp);
170: else
171: (void) Fclose(fp_head->fp);
172: }
173:
174: void
175: register_file(fp, pipe, pid)
176: FILE *fp;
177: int pipe, pid;
178: {
179: struct fp *fpp;
180:
181: if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL)
182: panic("Out of memory");
183: fpp->fp = fp;
184: fpp->pipe = pipe;
185: fpp->pid = pid;
186: fpp->link = fp_head;
187: fp_head = fpp;
188: }
189:
190: void
191: unregister_file(fp)
192: FILE *fp;
193: {
194: struct fp **pp, *p;
195:
1.2 deraadt 196: for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
1.1 deraadt 197: if (p->fp == fp) {
198: *pp = p->link;
199: free((char *) p);
200: return;
201: }
202: panic("Invalid file pointer");
203: }
204:
1.2 deraadt 205: static int
1.1 deraadt 206: file_pid(fp)
207: FILE *fp;
208: {
209: struct fp *p;
210:
211: for (p = fp_head; p; p = p->link)
212: if (p->fp == fp)
213: return (p->pid);
214: panic("Invalid file pointer");
215: /*NOTREACHED*/
216: }
217:
218: /*
219: * Run a command without a shell, with optional arguments and splicing
220: * of stdin and stdout. The command name can be a sequence of words.
221: * Signals must be handled by the caller.
222: * "Mask" contains the signals to ignore in the new process.
223: * SIGINT is enabled unless it's in the mask.
224: */
225: /*VARARGS4*/
226: int
227: run_command(cmd, mask, infd, outfd, a0, a1, a2)
228: char *cmd;
1.2 deraadt 229: sigset_t *mask;
230: int infd, outfd;
1.1 deraadt 231: char *a0, *a1, *a2;
232: {
233: int pid;
234:
235: if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
236: return -1;
237: return wait_command(pid);
238: }
239:
240: /*VARARGS4*/
241: int
242: start_command(cmd, mask, infd, outfd, a0, a1, a2)
243: char *cmd;
1.2 deraadt 244: sigset_t *mask;
245: int infd, outfd;
1.1 deraadt 246: char *a0, *a1, *a2;
247: {
248: int pid;
249:
250: if ((pid = vfork()) < 0) {
251: perror("fork");
252: return -1;
253: }
254: if (pid == 0) {
255: char *argv[100];
256: int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv);
257:
258: if ((argv[i++] = a0) != NOSTR &&
259: (argv[i++] = a1) != NOSTR &&
260: (argv[i++] = a2) != NOSTR)
261: argv[i] = NOSTR;
262: prepare_child(mask, infd, outfd);
263: execvp(argv[0], argv);
264: perror(argv[0]);
265: _exit(1);
266: }
267: return pid;
268: }
269:
270: void
1.2 deraadt 271: prepare_child(nset, infd, outfd)
272: sigset_t *nset;
273: int infd, outfd;
1.1 deraadt 274: {
275: int i;
1.2 deraadt 276: sigset_t fset;
1.1 deraadt 277:
278: /*
279: * All file descriptors other than 0, 1, and 2 are supposed to be
280: * close-on-exec.
281: */
282: if (infd >= 0)
283: dup2(infd, 0);
284: if (outfd >= 0)
285: dup2(outfd, 1);
1.3 ! dm 286: if (nset) {
! 287: for (i = 1; i <= NSIG; i++)
! 288: if (sigismember(nset, i))
! 289: (void) signal(i, SIG_IGN);
! 290: if (!sigismember(nset, SIGINT))
! 291: (void) signal(SIGINT, SIG_DFL);
! 292: }
1.2 deraadt 293: sigfillset(&fset);
294: (void) sigprocmask(SIG_UNBLOCK, &fset, NULL);
1.1 deraadt 295: }
296:
297: int
298: wait_command(pid)
299: int pid;
300: {
301:
302: if (wait_child(pid) < 0) {
303: printf("Fatal error in process.\n");
304: return -1;
305: }
306: return 0;
307: }
308:
309: static struct child *
310: findchild(pid)
311: int pid;
312: {
313: register struct child **cpp;
314:
315: for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
316: cpp = &(*cpp)->link)
317: ;
318: if (*cpp == NULL) {
319: *cpp = (struct child *) malloc(sizeof (struct child));
320: (*cpp)->pid = pid;
321: (*cpp)->done = (*cpp)->free = 0;
322: (*cpp)->link = NULL;
323: }
324: return *cpp;
325: }
326:
327: static void
328: delchild(cp)
329: register struct child *cp;
330: {
331: register struct child **cpp;
332:
333: for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
334: ;
335: *cpp = cp->link;
336: free((char *) cp);
337: }
338:
339: void
340: sigchild(signo)
341: int signo;
342: {
343: int pid;
344: union wait status;
345: register struct child *cp;
346:
347: while ((pid =
348: wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) {
349: cp = findchild(pid);
350: if (cp->free)
351: delchild(cp);
352: else {
353: cp->done = 1;
354: cp->status = status;
355: }
356: }
357: }
358:
359: union wait wait_status;
360:
361: /*
362: * Wait for a specific child to die.
363: */
364: int
365: wait_child(pid)
366: int pid;
367: {
1.2 deraadt 368: sigset_t nset, oset;
1.1 deraadt 369: register struct child *cp = findchild(pid);
1.2 deraadt 370: sigemptyset(&nset);
371: sigaddset(&nset, SIGCHLD);
372: sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 373:
374: while (!cp->done)
1.2 deraadt 375: sigsuspend(&oset);
1.1 deraadt 376: wait_status = cp->status;
377: delchild(cp);
1.2 deraadt 378: sigprocmask(SIG_SETMASK, &oset, NULL);
1.1 deraadt 379: return wait_status.w_status ? -1 : 0;
380: }
381:
382: /*
383: * Mark a child as don't care.
384: */
385: void
386: free_child(pid)
387: int pid;
388: {
1.2 deraadt 389: sigset_t nset, oset;
1.1 deraadt 390: register struct child *cp = findchild(pid);
1.2 deraadt 391: sigemptyset(&nset);
392: sigaddset(&nset, SIGCHLD);
393: sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 394:
395: if (cp->done)
396: delchild(cp);
397: else
398: cp->free = 1;
1.2 deraadt 399: sigprocmask(SIG_SETMASK, &oset, NULL);
1.1 deraadt 400: }