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.18 (Berkeley) 08/23/92"; 10 #endif /* not lint */ 11 12 #include "rcv.h" 13 #include <sys/wait.h> 14 #include "extern.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 struct child { 28 int pid; 29 char done; 30 char free; 31 union wait status; 32 struct child *link; 33 }; 34 static struct child *child; 35 static struct child *findchild __P((int)); 36 static void delchild __P((struct child *)); 37 38 FILE * 39 Fopen(file, mode) 40 char *file, *mode; 41 { 42 FILE *fp; 43 44 if ((fp = fopen(file, mode)) != NULL) 45 register_file(fp, 0); 46 return fp; 47 } 48 49 FILE * 50 Fdopen(fd, mode) 51 int fd; 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 int 62 Fclose(fp) 63 FILE *fp; 64 { 65 unregister_file(fp); 66 return fclose(fp); 67 } 68 69 /* 70 * XXX 71 * The old mail code used getdtablesize() to return the max number of 72 * file descriptors. That's a *real* big number now. Fake it. 73 */ 74 #define MAX_FILE_DESCRIPTORS 64 75 #define MAX_FILE_DESCRIPTORS_TO_CLOSE 20 76 FILE * 77 Popen(cmd, mode) 78 char *cmd; 79 char *mode; 80 { 81 int p[2]; 82 int myside, hisside, fd0, fd1; 83 FILE *fp; 84 85 if (pid == 0) 86 pid = malloc((u_int)sizeof (int) * MAX_FILE_DESCRIPTORS); 87 if (pipe(p) < 0) 88 return NULL; 89 if (*mode == 'r') { 90 myside = p[READ]; 91 fd0 = -1; 92 hisside = fd1 = p[WRITE]; 93 } else { 94 myside = p[WRITE]; 95 hisside = fd0 = p[READ]; 96 fd1 = -1; 97 } 98 if ((pid[myside] = start_command(cmd, 99 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) { 100 close(p[READ]); 101 close(p[WRITE]); 102 return NULL; 103 } 104 (void) close(hisside); 105 if ((fp = fdopen(myside, mode)) != NULL) 106 register_file(fp, 1); 107 return fp; 108 } 109 110 int 111 Pclose(ptr) 112 FILE *ptr; 113 { 114 int i; 115 int omask; 116 117 i = fileno(ptr); 118 unregister_file(ptr); 119 (void) fclose(ptr); 120 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); 121 i = wait_child(pid[i]); 122 sigsetmask(omask); 123 return i; 124 } 125 126 void 127 close_all_files() 128 { 129 130 while (fp_head) 131 if (fp_head->pipe) 132 (void) Pclose(fp_head->fp); 133 else 134 (void) Fclose(fp_head->fp); 135 } 136 137 void 138 register_file(fp, pipe) 139 FILE *fp; 140 int pipe; 141 { 142 struct fp *fpp; 143 144 if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) 145 panic("Out of memory"); 146 fpp->fp = fp; 147 fpp->pipe = pipe; 148 fpp->link = fp_head; 149 fp_head = fpp; 150 } 151 152 void 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 int 180 run_command(cmd, mask, infd, outfd, a0, a1, a2) 181 char *cmd; 182 int mask, 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 int 194 start_command(cmd, mask, infd, outfd, a0, a1, a2) 195 char *cmd; 196 int mask, 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 void 222 prepare_child(mask, infd, outfd) 223 int mask, 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 = MAX_FILE_DESCRIPTORS_TO_CLOSE; --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(0); 239 } 240 241 int 242 wait_command(pid) 243 int pid; 244 { 245 246 if (wait_child(pid) < 0) { 247 printf("Fatal error in process.\n"); 248 return -1; 249 } 250 return 0; 251 } 252 253 static struct child * 254 findchild(pid) 255 int pid; 256 { 257 register struct child **cpp; 258 259 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 260 cpp = &(*cpp)->link) 261 ; 262 if (*cpp == NULL) { 263 *cpp = (struct child *) malloc(sizeof (struct child)); 264 (*cpp)->pid = pid; 265 (*cpp)->done = (*cpp)->free = 0; 266 (*cpp)->link = NULL; 267 } 268 return *cpp; 269 } 270 271 static void 272 delchild(cp) 273 register struct child *cp; 274 { 275 register struct child **cpp; 276 277 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 278 ; 279 *cpp = cp->link; 280 free((char *) cp); 281 } 282 283 void 284 sigchild(signo) 285 int signo; 286 { 287 int pid; 288 union wait status; 289 register struct child *cp; 290 291 while ((pid = 292 wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { 293 cp = findchild(pid); 294 if (cp->free) 295 delchild(cp); 296 else { 297 cp->done = 1; 298 cp->status = status; 299 } 300 } 301 } 302 303 union wait wait_status; 304 305 /* 306 * Wait for a specific child to die. 307 */ 308 int 309 wait_child(pid) 310 int pid; 311 { 312 int mask = sigblock(sigmask(SIGCHLD)); 313 register struct child *cp = findchild(pid); 314 315 while (!cp->done) 316 sigpause(mask); 317 wait_status = cp->status; 318 delchild(cp); 319 sigsetmask(mask); 320 return wait_status.w_status ? -1 : 0; 321 } 322 323 /* 324 * Mark a child as don't care. 325 */ 326 void 327 free_child(pid) 328 int pid; 329 { 330 int mask = sigblock(sigmask(SIGCHLD)); 331 register struct child *cp = findchild(pid); 332 333 if (cp->done) 334 delchild(cp); 335 else 336 cp->free = 1; 337 sigsetmask(mask); 338 } 339