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