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