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