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