1 /* $NetBSD: popen.c,v 1.21 2006/10/31 20:07:32 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 36 #else 37 __RCSID("$NetBSD: popen.c,v 1.21 2006/10/31 20:07:32 christos Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <stdarg.h> 44 #include <util.h> 45 #include <sys/wait.h> 46 47 #include "rcv.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 pid_t pid; 57 struct fp *link; 58 }; 59 static struct fp *fp_head; 60 61 struct child { 62 pid_t pid; 63 char done; 64 char free; 65 int status; 66 struct child *link; 67 }; 68 static struct child *child, *child_freelist = NULL; 69 70 static struct child *findchild(pid_t, int); 71 static void delchild(struct child *); 72 static pid_t file_pid(FILE *); 73 static pid_t start_commandv(const char *, sigset_t *, int, int, va_list); 74 75 FILE * 76 Fopen(const char *fn, const char *mode) 77 { 78 FILE *fp; 79 80 if ((fp = fopen(fn, mode)) != NULL) { 81 register_file(fp, 0, 0); 82 (void)fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); 83 } 84 return fp; 85 } 86 87 FILE * 88 Fdopen(int fd, const char *mode) 89 { 90 FILE *fp; 91 92 if ((fp = fdopen(fd, mode)) != NULL) { 93 register_file(fp, 0, 0); 94 (void)fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); 95 } 96 return fp; 97 } 98 99 int 100 Fclose(FILE *fp) 101 { 102 103 unregister_file(fp); 104 return fclose(fp); 105 } 106 107 FILE * 108 Popen(const char *cmd, const char *mode) 109 { 110 int p[2]; 111 int myside, hisside, fd0, fd1; 112 pid_t pid; 113 sigset_t nset; 114 FILE *fp; 115 char *shellcmd; 116 117 if (pipe(p) < 0) 118 return NULL; 119 (void)fcntl(p[READ], F_SETFD, FD_CLOEXEC); 120 (void)fcntl(p[WRITE], F_SETFD, FD_CLOEXEC); 121 if (*mode == 'r') { 122 myside = p[READ]; 123 hisside = fd0 = fd1 = p[WRITE]; 124 } else { 125 myside = p[WRITE]; 126 hisside = fd0 = p[READ]; 127 fd1 = -1; 128 } 129 (void)sigemptyset(&nset); 130 if ((shellcmd = value("SHELL")) == NULL) 131 shellcmd = __UNCONST(_PATH_CSHELL); 132 pid = start_command(shellcmd, &nset, fd0, fd1, "-c", cmd, NULL); 133 if (pid < 0) { 134 (void)close(p[READ]); 135 (void)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(FILE *ptr) 146 { 147 int i; 148 sigset_t nset, oset; 149 150 i = file_pid(ptr); 151 unregister_file(ptr); 152 (void)fclose(ptr); 153 (void)sigemptyset(&nset); 154 (void)sigaddset(&nset, SIGINT); 155 (void)sigaddset(&nset, SIGHUP); 156 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 157 i = wait_child(i); 158 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 159 return i; 160 } 161 162 void 163 close_all_files(void) 164 { 165 while (fp_head) 166 if (fp_head->pipe) 167 (void)Pclose(fp_head->fp); 168 else 169 (void)Fclose(fp_head->fp); 170 } 171 172 #ifdef MIME_SUPPORT 173 #if 0 /* XXX - debugging stuff. This should go away eventually! */ 174 static void 175 show_one_file(FILE *fo, struct fp *fpp) 176 { 177 (void)fprintf(fo, ">>> fp: %p, pipe: %d, pid: %d, link: %p\n", 178 fpp->fp, fpp->pipe, fpp->pid, fpp->link); 179 } 180 181 void show_all_files(FILE *fo); 182 __unused 183 void 184 show_all_files(FILE *fo) 185 { 186 struct fp *fpp; 187 188 (void)fprintf(fo, ">> FILES\n"); 189 for (fpp = fp_head; fpp; fpp = fpp->link) 190 show_one_file(fo, fpp); 191 (void)fprintf(fo, ">> -------\n"); 192 (void)fflush(fo); 193 } 194 #endif 195 196 FILE * 197 last_registered_file(int last_pipe) 198 { 199 struct fp *fpp; 200 201 if (last_pipe == 0) 202 return fp_head ? fp_head->fp : NULL; 203 204 for (fpp = fp_head; fpp; fpp = fpp->link) 205 if (fpp->pipe) 206 return fpp->fp; 207 return NULL; 208 } 209 210 void 211 close_top_files(FILE *fp_stop) 212 { 213 while (fp_head && fp_head->fp != fp_stop) 214 if (fp_head->pipe) 215 (void)Pclose(fp_head->fp); 216 else 217 (void)Fclose(fp_head->fp); 218 } 219 220 void 221 flush_files(FILE *fo, int only_pipes) 222 { 223 struct fp *fpp; 224 225 if (fo) 226 (void)fflush(fo); 227 228 for (fpp = fp_head; fpp; fpp = fpp->link) 229 if (!only_pipes || fpp->pipe) 230 (void)fflush(fpp->fp); 231 232 (void)fflush(stdout); 233 } 234 #endif /* ENABLE_MIME */ 235 236 void 237 register_file(FILE *fp, int pipefd, pid_t pid) 238 { 239 struct fp *fpp; 240 241 fpp = (struct fp *)emalloc(sizeof(*fpp)); 242 fpp->fp = fp; 243 fpp->pipe = pipefd; 244 fpp->pid = pid; 245 fpp->link = fp_head; 246 fp_head = fpp; 247 } 248 249 void 250 unregister_file(FILE *fp) 251 { 252 struct fp **pp, *p; 253 254 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 255 if (p->fp == fp) { 256 *pp = p->link; 257 (void)free(p); 258 return; 259 } 260 errx(1, "Invalid file pointer"); 261 } 262 263 static pid_t 264 file_pid(FILE *fp) 265 { 266 struct fp *p; 267 268 for (p = fp_head; p; p = p->link) 269 if (p->fp == fp) 270 return p->pid; 271 errx(1, "Invalid file pointer"); 272 /*NOTREACHED*/ 273 } 274 275 /* 276 * Run a command without a shell, with optional arguments and splicing 277 * of stdin (-1 means none) and stdout. The command name can be a sequence 278 * of words. 279 * Signals must be handled by the caller. 280 * "nset" contains the signals to ignore in the new process. 281 * SIGINT is enabled unless it's in "nset". 282 */ 283 static pid_t 284 start_commandv(const char *cmd, sigset_t *nset, int infd, int outfd, 285 va_list args) 286 { 287 pid_t pid; 288 289 if ((pid = fork()) < 0) { 290 warn("fork"); 291 return -1; 292 } 293 if (pid == 0) { 294 char *argv[100]; 295 int i = getrawlist(cmd, argv, sizeof(argv)/ sizeof(*argv)); 296 297 while ((argv[i++] = va_arg(args, char *)) != NULL) 298 continue; 299 argv[i] = NULL; 300 prepare_child(nset, infd, outfd); 301 (void)execvp(argv[0], argv); 302 warn("%s", argv[0]); 303 _exit(1); 304 } 305 return pid; 306 } 307 308 int 309 run_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...) 310 { 311 pid_t pid; 312 va_list args; 313 314 va_start(args, outfd); 315 pid = start_commandv(cmd, nset, infd, outfd, args); 316 va_end(args); 317 if (pid < 0) 318 return -1; 319 return wait_command(pid); 320 } 321 322 int 323 start_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...) 324 { 325 va_list args; 326 int r; 327 328 va_start(args, outfd); 329 r = start_commandv(cmd, nset, infd, outfd, args); 330 va_end(args); 331 return r; 332 } 333 334 void 335 prepare_child(sigset_t *nset, int infd, int outfd) 336 { 337 int i; 338 sigset_t eset; 339 340 /* 341 * All file descriptors other than 0, 1, and 2 are supposed to be 342 * close-on-exec. 343 */ 344 if (infd > 0) { 345 (void)dup2(infd, 0); 346 } else if (infd != 0) { 347 /* we don't want the child stealing my stdin input */ 348 (void)close(0); 349 (void)open(_PATH_DEVNULL, O_RDONLY, 0); 350 } 351 if (outfd >= 0 && outfd != 1) 352 (void)dup2(outfd, 1); 353 if (nset == NULL) 354 return; 355 if (nset != NULL) { 356 for (i = 1; i < NSIG; i++) 357 if (sigismember(nset, i)) 358 (void)signal(i, SIG_IGN); 359 } 360 if (nset == NULL || !sigismember(nset, SIGINT)) 361 (void)signal(SIGINT, SIG_DFL); 362 (void)sigemptyset(&eset); 363 (void)sigprocmask(SIG_SETMASK, &eset, NULL); 364 } 365 366 int 367 wait_command(pid_t pid) 368 { 369 370 if (wait_child(pid) < 0) { 371 (void)puts("Fatal error in process."); 372 return -1; 373 } 374 return 0; 375 } 376 377 static struct child * 378 findchild(pid_t pid, int dont_alloc) 379 { 380 struct child **cpp; 381 382 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 383 cpp = &(*cpp)->link) 384 continue; 385 if (*cpp == NULL) { 386 if (dont_alloc) 387 return NULL; 388 if (child_freelist) { 389 *cpp = child_freelist; 390 child_freelist = (*cpp)->link; 391 } else 392 *cpp = (struct child *)emalloc(sizeof(struct child)); 393 394 (*cpp)->pid = pid; 395 (*cpp)->done = (*cpp)->free = 0; 396 (*cpp)->link = NULL; 397 } 398 return *cpp; 399 } 400 401 static void 402 delchild(struct child *cp) 403 { 404 struct child **cpp; 405 406 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 407 continue; 408 *cpp = cp->link; 409 cp->link = child_freelist; 410 child_freelist = cp; 411 } 412 413 void 414 /*ARGSUSED*/ 415 sigchild(int signo __unused) 416 { 417 pid_t pid; 418 int status; 419 struct child *cp; 420 int save_errno = errno; 421 422 while ((pid = 423 waitpid((pid_t)-1, &status, WNOHANG)) > 0) { 424 cp = findchild(pid, 1); 425 if (!cp) 426 continue; 427 if (cp->free) 428 delchild(cp); 429 else { 430 cp->done = 1; 431 cp->status = status; 432 } 433 } 434 errno = save_errno; 435 } 436 437 int wait_status; 438 439 /* 440 * Wait for a specific child to die. 441 */ 442 int 443 wait_child(pid_t pid) 444 { 445 struct child *cp; 446 sigset_t nset, oset; 447 pid_t rv = 0; 448 449 (void)sigemptyset(&nset); 450 (void)sigaddset(&nset, SIGCHLD); 451 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 452 /* 453 * If we have not already waited on the pid (via sigchild) 454 * wait on it now. Otherwise, use the wait status stashed 455 * by sigchild. 456 */ 457 cp = findchild(pid, 1); 458 if (cp == NULL || !cp->done) 459 rv = waitpid(pid, &wait_status, 0); 460 else 461 wait_status = cp->status; 462 if (cp != NULL) 463 delchild(cp); 464 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 465 if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status))) 466 return -1; 467 else 468 return 0; 469 } 470 471 /* 472 * Mark a child as don't care. 473 */ 474 void 475 free_child(pid_t pid) 476 { 477 struct child *cp; 478 sigset_t nset, oset; 479 480 (void)sigemptyset(&nset); 481 (void)sigaddset(&nset, SIGCHLD); 482 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 483 if ((cp = findchild(pid, 0)) != NULL) { 484 if (cp->done) 485 delchild(cp); 486 else 487 cp->free = 1; 488 } 489 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 490 } 491