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