1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 36 #endif /* not lint */ 37 38 #include "rcv.h" 39 #include <sys/wait.h> 40 #include <fcntl.h> 41 #include "extern.h" 42 43 #define READ 0 44 #define WRITE 1 45 46 struct fp { 47 FILE *fp; 48 int pipe; 49 int pid; 50 struct fp *link; 51 }; 52 static struct fp *fp_head; 53 54 struct child { 55 int pid; 56 char done; 57 char free; 58 union wait status; 59 struct child *link; 60 }; 61 static struct child *child; 62 static struct child *findchild __P((int)); 63 static void delchild __P((struct child *)); 64 65 FILE * 66 Fopen(file, mode) 67 char *file, *mode; 68 { 69 FILE *fp; 70 71 if ((fp = fopen(file, mode)) != NULL) { 72 register_file(fp, 0, 0); 73 (void) fcntl(fileno(fp), F_SETFD, 1); 74 } 75 return fp; 76 } 77 78 FILE * 79 Fdopen(fd, mode) 80 int fd; 81 char *mode; 82 { 83 FILE *fp; 84 85 if ((fp = fdopen(fd, mode)) != NULL) { 86 register_file(fp, 0, 0); 87 (void) fcntl(fileno(fp), F_SETFD, 1); 88 } 89 return fp; 90 } 91 92 int 93 Fclose(fp) 94 FILE *fp; 95 { 96 unregister_file(fp); 97 return fclose(fp); 98 } 99 100 FILE * 101 Popen(cmd, mode) 102 char *cmd; 103 char *mode; 104 { 105 int p[2]; 106 int myside, hisside, fd0, fd1; 107 int pid; 108 FILE *fp; 109 110 if (pipe(p) < 0) 111 return NULL; 112 (void) fcntl(p[READ], F_SETFD, 1); 113 (void) fcntl(p[WRITE], F_SETFD, 1); 114 if (*mode == 'r') { 115 myside = p[READ]; 116 fd0 = -1; 117 hisside = fd1 = p[WRITE]; 118 } else { 119 myside = p[WRITE]; 120 hisside = fd0 = p[READ]; 121 fd1 = -1; 122 } 123 if ((pid = start_command(cmd, 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) { 124 close(p[READ]); 125 close(p[WRITE]); 126 return NULL; 127 } 128 (void) close(hisside); 129 if ((fp = fdopen(myside, mode)) != NULL) 130 register_file(fp, 1, pid); 131 return fp; 132 } 133 134 int 135 Pclose(ptr) 136 FILE *ptr; 137 { 138 int i; 139 int omask; 140 141 i = file_pid(ptr); 142 unregister_file(ptr); 143 (void) fclose(ptr); 144 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); 145 i = wait_child(i); 146 sigsetmask(omask); 147 return i; 148 } 149 150 void 151 close_all_files() 152 { 153 154 while (fp_head) 155 if (fp_head->pipe) 156 (void) Pclose(fp_head->fp); 157 else 158 (void) Fclose(fp_head->fp); 159 } 160 161 void 162 register_file(fp, pipe, pid) 163 FILE *fp; 164 int pipe, pid; 165 { 166 struct fp *fpp; 167 168 if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) 169 panic("Out of memory"); 170 fpp->fp = fp; 171 fpp->pipe = pipe; 172 fpp->pid = pid; 173 fpp->link = fp_head; 174 fp_head = fpp; 175 } 176 177 void 178 unregister_file(fp) 179 FILE *fp; 180 { 181 struct fp **pp, *p; 182 183 for (pp = &fp_head; p = *pp; pp = &p->link) 184 if (p->fp == fp) { 185 *pp = p->link; 186 free((char *) p); 187 return; 188 } 189 panic("Invalid file pointer"); 190 } 191 192 file_pid(fp) 193 FILE *fp; 194 { 195 struct fp *p; 196 197 for (p = fp_head; p; p = p->link) 198 if (p->fp == fp) 199 return (p->pid); 200 panic("Invalid file pointer"); 201 /*NOTREACHED*/ 202 } 203 204 /* 205 * Run a command without a shell, with optional arguments and splicing 206 * of stdin and stdout. The command name can be a sequence of words. 207 * Signals must be handled by the caller. 208 * "Mask" contains the signals to ignore in the new process. 209 * SIGINT is enabled unless it's in the mask. 210 */ 211 /*VARARGS4*/ 212 int 213 run_command(cmd, mask, infd, outfd, a0, a1, a2) 214 char *cmd; 215 int mask, infd, outfd; 216 char *a0, *a1, *a2; 217 { 218 int pid; 219 220 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 221 return -1; 222 return wait_command(pid); 223 } 224 225 /*VARARGS4*/ 226 int 227 start_command(cmd, mask, infd, outfd, a0, a1, a2) 228 char *cmd; 229 int mask, infd, outfd; 230 char *a0, *a1, *a2; 231 { 232 int pid; 233 234 if ((pid = vfork()) < 0) { 235 perror("fork"); 236 return -1; 237 } 238 if (pid == 0) { 239 char *argv[100]; 240 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); 241 242 if ((argv[i++] = a0) != NOSTR && 243 (argv[i++] = a1) != NOSTR && 244 (argv[i++] = a2) != NOSTR) 245 argv[i] = NOSTR; 246 prepare_child(mask, infd, outfd); 247 execvp(argv[0], argv); 248 perror(argv[0]); 249 _exit(1); 250 } 251 return pid; 252 } 253 254 void 255 prepare_child(mask, infd, outfd) 256 int mask, infd, outfd; 257 { 258 int i; 259 260 /* 261 * All file descriptors other than 0, 1, and 2 are supposed to be 262 * close-on-exec. 263 */ 264 if (infd >= 0) 265 dup2(infd, 0); 266 if (outfd >= 0) 267 dup2(outfd, 1); 268 for (i = 1; i <= NSIG; i++) 269 if (mask & sigmask(i)) 270 (void) signal(i, SIG_IGN); 271 if ((mask & sigmask(SIGINT)) == 0) 272 (void) signal(SIGINT, SIG_DFL); 273 (void) sigsetmask(0); 274 } 275 276 int 277 wait_command(pid) 278 int pid; 279 { 280 281 if (wait_child(pid) < 0) { 282 printf("Fatal error in process.\n"); 283 return -1; 284 } 285 return 0; 286 } 287 288 static struct child * 289 findchild(pid) 290 int pid; 291 { 292 register struct child **cpp; 293 294 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 295 cpp = &(*cpp)->link) 296 ; 297 if (*cpp == NULL) { 298 *cpp = (struct child *) malloc(sizeof (struct child)); 299 (*cpp)->pid = pid; 300 (*cpp)->done = (*cpp)->free = 0; 301 (*cpp)->link = NULL; 302 } 303 return *cpp; 304 } 305 306 static void 307 delchild(cp) 308 register struct child *cp; 309 { 310 register struct child **cpp; 311 312 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 313 ; 314 *cpp = cp->link; 315 free((char *) cp); 316 } 317 318 void 319 sigchild(signo) 320 int signo; 321 { 322 int pid; 323 union wait status; 324 register struct child *cp; 325 326 while ((pid = 327 wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { 328 cp = findchild(pid); 329 if (cp->free) 330 delchild(cp); 331 else { 332 cp->done = 1; 333 cp->status = status; 334 } 335 } 336 } 337 338 union wait wait_status; 339 340 /* 341 * Wait for a specific child to die. 342 */ 343 int 344 wait_child(pid) 345 int pid; 346 { 347 int mask = sigblock(sigmask(SIGCHLD)); 348 register struct child *cp = findchild(pid); 349 350 while (!cp->done) 351 sigpause(mask); 352 wait_status = cp->status; 353 delchild(cp); 354 sigsetmask(mask); 355 return wait_status.w_status ? -1 : 0; 356 } 357 358 /* 359 * Mark a child as don't care. 360 */ 361 void 362 free_child(pid) 363 int pid; 364 { 365 int mask = sigblock(sigmask(SIGCHLD)); 366 register struct child *cp = findchild(pid); 367 368 if (cp->done) 369 delchild(cp); 370 else 371 cp->free = 1; 372 sigsetmask(mask); 373 } 374