Annotation of src/usr.bin/mail/popen.c, Revision 1.14
1.14 ! millert 1: /* $OpenBSD: popen.c,v 1.13 1997/08/31 14:32:14 millert Exp $ */
1.6 millert 2: /* $NetBSD: popen.c,v 1.6 1997/05/13 06:48:42 mikel Exp $ */
1.2 deraadt 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.14 ! millert 41: static char rcsid[] = "$OpenBSD: popen.c,v 1.13 1997/08/31 14:32:14 millert 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>
1.12 deraadt 48: #include <errno.h>
1.1 deraadt 49: #include "extern.h"
50:
51: #define READ 0
52: #define WRITE 1
53:
54: struct fp {
55: FILE *fp;
56: int pipe;
57: int pid;
58: struct fp *link;
59: };
60: static struct fp *fp_head;
61:
62: struct child {
63: int pid;
64: char done;
65: char free;
1.13 millert 66: int status;
1.1 deraadt 67: struct child *link;
68: };
69: static struct child *child;
70: static struct child *findchild __P((int));
71: static void delchild __P((struct child *));
1.2 deraadt 72: static int file_pid __P((FILE *));
1.4 millert 73: static int handle_spool_locks __P((int));
1.1 deraadt 74:
75: FILE *
76: Fopen(file, mode)
77: char *file, *mode;
78: {
79: FILE *fp;
80:
81: if ((fp = fopen(file, mode)) != NULL) {
82: register_file(fp, 0, 0);
1.7 millert 83: (void)fcntl(fileno(fp), F_SETFD, 1);
1.1 deraadt 84: }
1.6 millert 85: return(fp);
1.1 deraadt 86: }
87:
88: FILE *
89: Fdopen(fd, mode)
90: int fd;
91: char *mode;
92: {
93: FILE *fp;
94:
95: if ((fp = fdopen(fd, mode)) != NULL) {
96: register_file(fp, 0, 0);
1.7 millert 97: (void)fcntl(fileno(fp), F_SETFD, 1);
1.1 deraadt 98: }
1.6 millert 99: return(fp);
1.1 deraadt 100: }
101:
102: int
103: Fclose(fp)
104: FILE *fp;
105: {
106: unregister_file(fp);
1.6 millert 107: return(fclose(fp));
1.1 deraadt 108: }
109:
110: FILE *
111: Popen(cmd, mode)
112: char *cmd;
113: char *mode;
114: {
115: int p[2];
116: int myside, hisside, fd0, fd1;
117: int pid;
1.2 deraadt 118: sigset_t nset;
1.1 deraadt 119: FILE *fp;
120:
121: if (pipe(p) < 0)
1.6 millert 122: return(NULL);
1.7 millert 123: (void)fcntl(p[READ], F_SETFD, 1);
124: (void)fcntl(p[WRITE], F_SETFD, 1);
1.1 deraadt 125: if (*mode == 'r') {
126: myside = p[READ];
127: fd0 = -1;
128: hisside = fd1 = p[WRITE];
129: } else {
130: myside = p[WRITE];
131: hisside = fd0 = p[READ];
132: fd1 = -1;
133: }
1.2 deraadt 134: sigemptyset(&nset);
1.8 millert 135: if ((pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL)) < 0) {
1.6 millert 136: (void)close(p[READ]);
137: (void)close(p[WRITE]);
138: return(NULL);
1.1 deraadt 139: }
1.6 millert 140: (void)close(hisside);
1.1 deraadt 141: if ((fp = fdopen(myside, mode)) != NULL)
142: register_file(fp, 1, pid);
1.6 millert 143: return(fp);
1.1 deraadt 144: }
145:
146: int
147: Pclose(ptr)
148: FILE *ptr;
149: {
150: int i;
1.2 deraadt 151: sigset_t nset, oset;
1.1 deraadt 152:
153: i = file_pid(ptr);
154: unregister_file(ptr);
1.6 millert 155: (void)fclose(ptr);
1.2 deraadt 156: sigemptyset(&nset);
157: sigaddset(&nset, SIGINT);
158: sigaddset(&nset, SIGHUP);
159: sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 160: i = wait_child(i);
1.2 deraadt 161: sigprocmask(SIG_SETMASK, &oset, NULL);
1.6 millert 162: return(i);
1.1 deraadt 163: }
164:
165: void
166: close_all_files()
167: {
168:
169: while (fp_head)
170: if (fp_head->pipe)
1.6 millert 171: (void)Pclose(fp_head->fp);
1.1 deraadt 172: else
1.6 millert 173: (void)Fclose(fp_head->fp);
1.1 deraadt 174: }
175:
176: void
177: register_file(fp, pipe, pid)
178: FILE *fp;
179: int pipe, pid;
180: {
181: struct fp *fpp;
182:
1.7 millert 183: if ((fpp = (struct fp *)malloc(sizeof(*fpp))) == NULL)
1.14 ! millert 184: errx(1, "Out of memory");
1.1 deraadt 185: fpp->fp = fp;
186: fpp->pipe = pipe;
187: fpp->pid = pid;
188: fpp->link = fp_head;
189: fp_head = fpp;
190: }
191:
192: void
193: unregister_file(fp)
194: FILE *fp;
195: {
196: struct fp **pp, *p;
197:
1.2 deraadt 198: for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
1.1 deraadt 199: if (p->fp == fp) {
200: *pp = p->link;
1.7 millert 201: (void)free(p);
1.1 deraadt 202: return;
203: }
1.14 ! millert 204: errx(1, "Invalid file pointer");
1.1 deraadt 205: }
206:
1.2 deraadt 207: static int
1.1 deraadt 208: file_pid(fp)
209: FILE *fp;
210: {
211: struct fp *p;
212:
213: for (p = fp_head; p; p = p->link)
214: if (p->fp == fp)
1.6 millert 215: return(p->pid);
1.14 ! millert 216: errx(1, "Invalid file pointer");
1.1 deraadt 217: /*NOTREACHED*/
218: }
219:
220: /*
221: * Run a command without a shell, with optional arguments and splicing
222: * of stdin and stdout. The command name can be a sequence of words.
223: * Signals must be handled by the caller.
224: * "Mask" contains the signals to ignore in the new process.
225: * SIGINT is enabled unless it's in the mask.
226: */
227: /*VARARGS4*/
228: int
1.10 millert 229: run_command(cmd, nset, infd, outfd, a0, a1, a2)
1.1 deraadt 230: char *cmd;
1.10 millert 231: sigset_t *nset;
1.2 deraadt 232: int infd, outfd;
1.1 deraadt 233: char *a0, *a1, *a2;
234: {
235: int pid;
236:
1.10 millert 237: if ((pid = start_command(cmd, nset, infd, outfd, a0, a1, a2)) < 0)
1.6 millert 238: return(-1);
239: return(wait_command(pid));
1.1 deraadt 240: }
241:
242: /*VARARGS4*/
243: int
1.10 millert 244: start_command(cmd, nset, infd, outfd, a0, a1, a2)
1.1 deraadt 245: char *cmd;
1.10 millert 246: sigset_t *nset;
1.2 deraadt 247: int infd, outfd;
1.1 deraadt 248: char *a0, *a1, *a2;
249: {
250: int pid;
251:
252: if ((pid = vfork()) < 0) {
1.6 millert 253: warn("fork");
254: return(-1);
1.1 deraadt 255: }
256: if (pid == 0) {
257: char *argv[100];
1.6 millert 258: int i = getrawlist(cmd, argv, sizeof(argv)/ sizeof(*argv));
1.1 deraadt 259:
1.8 millert 260: if ((argv[i++] = a0) != NULL &&
261: (argv[i++] = a1) != NULL &&
262: (argv[i++] = a2) != NULL)
263: argv[i] = NULL;
1.10 millert 264: prepare_child(nset, infd, outfd);
1.1 deraadt 265: execvp(argv[0], argv);
1.6 millert 266: warn(argv[0]);
1.1 deraadt 267: _exit(1);
268: }
1.6 millert 269: return(pid);
1.1 deraadt 270: }
271:
272: void
1.2 deraadt 273: prepare_child(nset, infd, outfd)
274: sigset_t *nset;
275: int infd, outfd;
1.1 deraadt 276: {
277: int i;
1.9 millert 278: sigset_t eset;
1.1 deraadt 279:
280: /*
281: * All file descriptors other than 0, 1, and 2 are supposed to be
282: * close-on-exec.
283: */
284: if (infd >= 0)
285: dup2(infd, 0);
286: if (outfd >= 0)
287: dup2(outfd, 1);
1.6 millert 288: if (nset == NULL)
289: return;
290: if (nset != NULL) {
1.5 deraadt 291: for (i = 1; i < NSIG; i++)
1.3 dm 292: if (sigismember(nset, i))
1.7 millert 293: (void)signal(i, SIG_IGN);
1.3 dm 294: }
1.6 millert 295: if (nset == NULL || !sigismember(nset, SIGINT))
1.7 millert 296: (void)signal(SIGINT, SIG_DFL);
1.9 millert 297: sigemptyset(&eset);
298: (void)sigprocmask(SIG_SETMASK, &eset, NULL);
1.1 deraadt 299: }
300:
301: int
302: wait_command(pid)
303: int pid;
304: {
305:
306: if (wait_child(pid) < 0) {
1.6 millert 307: puts("Fatal error in process.");
308: return(-1);
1.1 deraadt 309: }
1.6 millert 310: return(0);
1.1 deraadt 311: }
312:
313: static struct child *
314: findchild(pid)
315: int pid;
316: {
1.14 ! millert 317: struct child **cpp;
1.1 deraadt 318:
319: for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
320: cpp = &(*cpp)->link)
321: ;
322: if (*cpp == NULL) {
1.7 millert 323: *cpp = (struct child *)malloc(sizeof(struct child));
1.1 deraadt 324: (*cpp)->pid = pid;
325: (*cpp)->done = (*cpp)->free = 0;
326: (*cpp)->link = NULL;
327: }
1.6 millert 328: return(*cpp);
1.1 deraadt 329: }
330:
331: static void
332: delchild(cp)
1.14 ! millert 333: struct child *cp;
1.1 deraadt 334: {
1.14 ! millert 335: struct child **cpp;
1.1 deraadt 336:
337: for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
338: ;
339: *cpp = cp->link;
1.7 millert 340: (void)free(cp);
1.1 deraadt 341: }
342:
343: void
344: sigchild(signo)
345: int signo;
346: {
347: int pid;
1.13 millert 348: int status;
1.14 ! millert 349: struct child *cp;
1.11 deraadt 350: int save_errno = errno;
1.1 deraadt 351:
352: while ((pid =
1.13 millert 353: waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
1.1 deraadt 354: cp = findchild(pid);
355: if (cp->free)
356: delchild(cp);
357: else {
358: cp->done = 1;
359: cp->status = status;
360: }
361: }
1.11 deraadt 362: errno = save_errno;
1.1 deraadt 363: }
364:
1.13 millert 365: int wait_status;
1.1 deraadt 366:
367: /*
368: * Wait for a specific child to die.
369: */
370: int
371: wait_child(pid)
372: int pid;
373: {
1.14 ! millert 374: struct child *cp = findchild(pid);
1.2 deraadt 375: sigset_t nset, oset;
1.9 millert 376:
1.2 deraadt 377: sigemptyset(&nset);
378: sigaddset(&nset, SIGCHLD);
379: sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 380:
381: while (!cp->done)
1.2 deraadt 382: sigsuspend(&oset);
1.1 deraadt 383: wait_status = cp->status;
384: delchild(cp);
1.2 deraadt 385: sigprocmask(SIG_SETMASK, &oset, NULL);
1.13 millert 386: return((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0);
1.1 deraadt 387: }
388:
389: /*
390: * Mark a child as don't care.
391: */
392: void
393: free_child(pid)
394: int pid;
395: {
1.14 ! millert 396: struct child *cp = findchild(pid);
1.2 deraadt 397: sigset_t nset, oset;
1.9 millert 398:
1.2 deraadt 399: sigemptyset(&nset);
400: sigaddset(&nset, SIGCHLD);
401: sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 402:
403: if (cp->done)
404: delchild(cp);
405: else
406: cp->free = 1;
1.2 deraadt 407: sigprocmask(SIG_SETMASK, &oset, NULL);
1.4 millert 408: }
409:
410: /*
411: * Lock(1)/unlock(0) mail spool using mail.local's -H flag.
412: * Returns 1 for success, 0 for failure, -1 for bad usage.
413: */
414: static int
415: handle_spool_locks(action)
416: int action;
417: {
418: char *cmd;
419: static FILE *lockfp = NULL;
420: static int lock_pid;
421:
422: if (action == 0) {
423: /* Clear the lock */
424: if (lockfp == NULL) {
1.6 millert 425: fputs("handle_spool_locks: no spool lock to remove.\n",
426: stderr);
427: return(-1);
1.4 millert 428: }
429: (void)kill(lock_pid, SIGTERM);
1.6 millert 430: (void)Pclose(lockfp);
1.4 millert 431: lockfp = NULL;
432: } else if (action == 1) {
433: /* Create the lock */
1.7 millert 434: if ((cmd = (char *)malloc(sizeof(_PATH_MAIL_LOCAL) + 3)) == NULL)
1.14 ! millert 435: errx(1, "Out of memory");
1.4 millert 436: sprintf(cmd, "%s -H", _PATH_MAIL_LOCAL);
437: if ((lockfp = Popen(cmd, "r")) == NULL || getc(lockfp) != '1') {
438: lockfp = NULL;
1.7 millert 439: (void)free(cmd);
1.6 millert 440: return(0);
1.4 millert 441: }
442:
443: lock_pid = fp_head->pid; /* new entries added at head */
1.7 millert 444: (void)free(cmd);
1.4 millert 445: } else {
446: fprintf(stderr, "handle_spool_locks: unknown action %d\n",
447: action);
1.6 millert 448: return(-1);
1.4 millert 449: }
450:
1.6 millert 451: return(1);
1.4 millert 452: }
453:
454: int
455: spool_lock()
456: {
457: return(handle_spool_locks(1));
458: }
459:
460: int
461: spool_unlock()
462: {
463: return(handle_spool_locks(0));
1.1 deraadt 464: }