|
|
1.1 ! root 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 are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)popen.c 5.15 (Berkeley) 6/25/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include "rcv.h" ! 25: #include <sys/signal.h> ! 26: #include <sys/wait.h> ! 27: ! 28: #define READ 0 ! 29: #define WRITE 1 ! 30: static int *pid; ! 31: ! 32: struct fp { ! 33: FILE *fp; ! 34: int pipe; ! 35: struct fp *link; ! 36: }; ! 37: static struct fp *fp_head; ! 38: ! 39: FILE * ! 40: Fopen(file, mode) ! 41: char *file, *mode; ! 42: { ! 43: FILE *fp; ! 44: ! 45: if ((fp = fopen(file, mode)) != NULL) ! 46: register_file(fp, 0); ! 47: return fp; ! 48: } ! 49: ! 50: FILE * ! 51: Fdopen(fd, mode) ! 52: char *mode; ! 53: { ! 54: FILE *fp; ! 55: ! 56: if ((fp = fdopen(fd, mode)) != NULL) ! 57: register_file(fp, 0); ! 58: return fp; ! 59: } ! 60: ! 61: Fclose(fp) ! 62: FILE *fp; ! 63: { ! 64: unregister_file(fp); ! 65: return fclose(fp); ! 66: } ! 67: ! 68: FILE * ! 69: Popen(cmd, mode) ! 70: char *cmd; ! 71: char *mode; ! 72: { ! 73: int p[2]; ! 74: int myside, hisside, fd0, fd1; ! 75: FILE *fp; ! 76: ! 77: if (pid == 0) ! 78: pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize()); ! 79: if (pipe(p) < 0) ! 80: return NULL; ! 81: if (*mode == 'r') { ! 82: myside = p[READ]; ! 83: fd0 = -1; ! 84: hisside = fd1 = p[WRITE]; ! 85: } else { ! 86: myside = p[WRITE]; ! 87: hisside = fd0 = p[READ]; ! 88: fd1 = -1; ! 89: } ! 90: if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) { ! 91: close(p[READ]); ! 92: close(p[WRITE]); ! 93: return NULL; ! 94: } ! 95: (void) close(hisside); ! 96: if ((fp = fdopen(myside, mode)) != NULL) ! 97: register_file(fp, 1); ! 98: return fp; ! 99: } ! 100: ! 101: Pclose(ptr) ! 102: FILE *ptr; ! 103: { ! 104: int i; ! 105: int omask; ! 106: ! 107: i = fileno(ptr); ! 108: unregister_file(ptr); ! 109: (void) fclose(ptr); ! 110: omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); ! 111: i = wait_child(pid[i]); ! 112: sigsetmask(omask); ! 113: return i; ! 114: } ! 115: ! 116: close_all_files() ! 117: { ! 118: ! 119: while (fp_head) ! 120: if (fp_head->pipe) ! 121: (void) Pclose(fp_head->fp); ! 122: else ! 123: (void) Fclose(fp_head->fp); ! 124: } ! 125: ! 126: register_file(fp, pipe) ! 127: FILE *fp; ! 128: { ! 129: struct fp *fpp; ! 130: ! 131: if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) ! 132: panic("Out of memory"); ! 133: fpp->fp = fp; ! 134: fpp->pipe = pipe; ! 135: fpp->link = fp_head; ! 136: fp_head = fpp; ! 137: } ! 138: ! 139: unregister_file(fp) ! 140: FILE *fp; ! 141: { ! 142: struct fp **pp, *p; ! 143: ! 144: for (pp = &fp_head; p = *pp; pp = &p->link) ! 145: if (p->fp == fp) { ! 146: *pp = p->link; ! 147: free((char *) p); ! 148: return; ! 149: } ! 150: /* XXX ! 151: * Ignore this for now; there may still be uncaught ! 152: * duplicate closes. ! 153: panic("Invalid file pointer"); ! 154: */ ! 155: } ! 156: ! 157: /* ! 158: * Run a command without a shell, with optional arguments and splicing ! 159: * of stdin and stdout. The command name can be a sequence of words. ! 160: * Signals must be handled by the caller. ! 161: * "Mask" contains the signals to ignore in the new process. ! 162: * SIGINT is enabled unless it's in the mask. ! 163: */ ! 164: /*VARARGS4*/ ! 165: run_command(cmd, mask, infd, outfd, a0, a1, a2) ! 166: char *cmd; ! 167: int mask, infd, outfd; ! 168: char *a0, *a1, *a2; ! 169: { ! 170: int pid; ! 171: ! 172: if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) ! 173: return -1; ! 174: return wait_command(pid); ! 175: } ! 176: ! 177: /*VARARGS4*/ ! 178: start_command(cmd, mask, infd, outfd, a0, a1, a2) ! 179: char *cmd; ! 180: int mask, infd, outfd; ! 181: char *a0, *a1, *a2; ! 182: { ! 183: int pid; ! 184: ! 185: if ((pid = vfork()) < 0) { ! 186: perror("fork"); ! 187: return -1; ! 188: } ! 189: if (pid == 0) { ! 190: char *argv[100]; ! 191: int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); ! 192: ! 193: if ((argv[i++] = a0) != NOSTR && ! 194: (argv[i++] = a1) != NOSTR && ! 195: (argv[i++] = a2) != NOSTR) ! 196: argv[i] = NOSTR; ! 197: prepare_child(mask, infd, outfd); ! 198: execvp(argv[0], argv); ! 199: perror(argv[0]); ! 200: _exit(1); ! 201: } ! 202: return pid; ! 203: } ! 204: ! 205: prepare_child(mask, infd, outfd) ! 206: int mask, infd, outfd; ! 207: { ! 208: int i; ! 209: ! 210: if (infd >= 0) ! 211: dup2(infd, 0); ! 212: if (outfd >= 0) ! 213: dup2(outfd, 1); ! 214: for (i = getdtablesize(); --i > 2;) ! 215: close(i); ! 216: for (i = 1; i <= NSIG; i++) ! 217: if (mask & sigmask(i)) ! 218: (void) signal(i, SIG_IGN); ! 219: if ((mask & sigmask(SIGINT)) == 0) ! 220: (void) signal(SIGINT, SIG_DFL); ! 221: (void) sigsetmask(0); ! 222: } ! 223: ! 224: wait_command(pid) ! 225: int pid; ! 226: { ! 227: ! 228: if (wait_child(pid) < 0) { ! 229: printf("Fatal error in process.\n"); ! 230: return -1; ! 231: } ! 232: return 0; ! 233: } ! 234: ! 235: struct child { ! 236: int pid; ! 237: char done; ! 238: char free; ! 239: union wait status; ! 240: struct child *link; ! 241: }; ! 242: static struct child *child; ! 243: ! 244: struct child * ! 245: findchild(pid) ! 246: int pid; ! 247: { ! 248: register struct child **cpp; ! 249: ! 250: for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; ! 251: cpp = &(*cpp)->link) ! 252: ; ! 253: if (*cpp == NULL) { ! 254: *cpp = (struct child *) malloc(sizeof (struct child)); ! 255: (*cpp)->pid = pid; ! 256: (*cpp)->done = (*cpp)->free = 0; ! 257: (*cpp)->link = NULL; ! 258: } ! 259: return *cpp; ! 260: } ! 261: ! 262: delchild(cp) ! 263: register struct child *cp; ! 264: { ! 265: register struct child **cpp; ! 266: ! 267: for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) ! 268: ; ! 269: *cpp = cp->link; ! 270: free((char *) cp); ! 271: } ! 272: ! 273: sigchild() ! 274: { ! 275: int pid; ! 276: union wait status; ! 277: register struct child *cp; ! 278: ! 279: while ((pid = wait3(&status, WNOHANG, (struct timeval *)0)) > 0) { ! 280: cp = findchild(pid); ! 281: if (cp->free) ! 282: delchild(cp); ! 283: else { ! 284: cp->done = 1; ! 285: cp->status = status; ! 286: } ! 287: } ! 288: } ! 289: ! 290: union wait wait_status; ! 291: ! 292: /* ! 293: * Wait for a specific child to die. ! 294: */ ! 295: wait_child(pid) ! 296: int pid; ! 297: { ! 298: int mask = sigblock(sigmask(SIGCHLD)); ! 299: register struct child *cp = findchild(pid); ! 300: ! 301: while (!cp->done) ! 302: sigpause(mask); ! 303: wait_status = cp->status; ! 304: delchild(cp); ! 305: sigsetmask(mask); ! 306: return wait_status.w_status ? -1 : 0; ! 307: } ! 308: ! 309: /* ! 310: * Mark a child as don't care. ! 311: */ ! 312: free_child(pid) ! 313: int pid; ! 314: { ! 315: int mask = sigblock(sigmask(SIGCHLD)); ! 316: register struct child *cp = findchild(pid); ! 317: ! 318: if (cp->done) ! 319: delchild(cp); ! 320: else ! 321: cp->free = 1; ! 322: sigsetmask(mask); ! 323: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.