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