1 /* $NetBSD: popen.c,v 1.26 2010/01/12 14:43:31 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.26 2010/01/12 14:43:31 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 #include "sig.h" 50 51 #define READ 0 52 #define WRITE 1 53 54 struct fp { 55 FILE *fp; 56 int pipe; 57 pid_t pid; 58 struct fp *link; 59 }; 60 static struct fp *fp_head; 61 62 struct child { 63 pid_t pid; 64 char done; 65 char free; 66 int status; 67 struct child *link; 68 }; 69 static struct child *child, *child_freelist = NULL; 70 static struct child *findchild(pid_t, int); 71 72 73 #if 0 /* XXX - debugging stuff. This should go away eventually! */ 74 static void 75 show_one_file(FILE *fo, struct fp *fpp) 76 { 77 (void)fprintf(fo, ">>> fp: %p, pipe: %d, pid: %d, link: %p\n", 78 fpp->fp, fpp->pipe, fpp->pid, fpp->link); 79 } 80 81 void show_all_files(FILE *fo); 82 __unused 83 PUBLIC void 84 show_all_files(FILE *fo) 85 { 86 struct fp *fpp; 87 88 (void)fprintf(fo, ">> FILES\n"); 89 for (fpp = fp_head; fpp; fpp = fpp->link) 90 show_one_file(fo, fpp); 91 (void)fprintf(fo, ">> -------\n"); 92 (void)fflush(fo); 93 } 94 #endif /* end debugging stuff */ 95 96 97 static void 98 unregister_file(FILE *fp) 99 { 100 struct fp **pp, *p; 101 102 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 103 if (p->fp == fp) { 104 *pp = p->link; 105 (void)free(p); 106 return; 107 } 108 errx(EXIT_FAILURE, "Invalid file pointer"); 109 } 110 111 PUBLIC void 112 register_file(FILE *fp, int pipefd, pid_t pid) 113 { 114 struct fp *fpp; 115 116 fpp = emalloc(sizeof(*fpp)); 117 fpp->fp = fp; 118 fpp->pipe = pipefd; 119 fpp->pid = pid; 120 fpp->link = fp_head; 121 fp_head = fpp; 122 } 123 124 PUBLIC FILE * 125 Fopen(const char *fn, const char *mode) 126 { 127 FILE *fp; 128 129 if ((fp = fopen(fn, mode)) != NULL) { 130 register_file(fp, 0, 0); 131 (void)fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); 132 } 133 return fp; 134 } 135 136 PUBLIC FILE * 137 Fdopen(int fd, const char *mode) 138 { 139 FILE *fp; 140 141 if ((fp = fdopen(fd, mode)) != NULL) { 142 register_file(fp, 0, 0); 143 (void)fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); 144 } 145 return fp; 146 } 147 148 PUBLIC int 149 Fclose(FILE *fp) 150 { 151 152 if (fp == NULL) 153 return 0; 154 155 unregister_file(fp); 156 return fclose(fp); 157 } 158 159 PUBLIC void 160 prepare_child(sigset_t *nset, int infd, int outfd) 161 { 162 int i; 163 sigset_t eset; 164 165 /* 166 * All file descriptors other than 0, 1, and 2 are supposed to be 167 * close-on-exec. 168 */ 169 if (infd > 0) { 170 (void)dup2(infd, 0); 171 } else if (infd != 0) { 172 /* we don't want the child stealing my stdin input */ 173 (void)close(0); 174 (void)open(_PATH_DEVNULL, O_RDONLY, 0); 175 } 176 if (outfd >= 0 && outfd != 1) 177 (void)dup2(outfd, 1); 178 179 if (nset != NULL) { 180 for (i = 1; i < NSIG; i++) { 181 if (sigismember(nset, i)) 182 (void)signal(i, SIG_IGN); 183 } 184 if (!sigismember(nset, SIGINT)) 185 (void)signal(SIGINT, SIG_DFL); 186 (void)sigemptyset(&eset); 187 (void)sigprocmask(SIG_SETMASK, &eset, NULL); 188 } 189 } 190 191 /* 192 * Run a command without a shell, with optional arguments and splicing 193 * of stdin (-1 means none) and stdout. The command name can be a sequence 194 * of words. 195 * Signals must be handled by the caller. 196 * "nset" contains the signals to ignore in the new process. 197 * SIGINT is enabled unless it's in "nset". 198 */ 199 static pid_t 200 start_commandv(const char *cmd, sigset_t *nset, int infd, int outfd, 201 va_list args) 202 { 203 pid_t pid; 204 205 sig_check(); 206 if ((pid = fork()) < 0) { 207 warn("fork"); 208 return -1; 209 } 210 if (pid == 0) { 211 char *argv[100]; 212 size_t i; 213 214 i = getrawlist(cmd, argv, (int)__arraycount(argv)); 215 while (i < __arraycount(argv) - 1 && 216 (argv[i++] = va_arg(args, char *)) != NULL) 217 continue; 218 argv[i] = NULL; 219 prepare_child(nset, infd, outfd); 220 (void)execvp(argv[0], argv); 221 warn("%s", argv[0]); 222 _exit(1); 223 } 224 (void)findchild(pid, 0); 225 return pid; 226 } 227 228 PUBLIC int 229 start_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...) 230 { 231 va_list args; 232 int r; 233 234 va_start(args, outfd); 235 r = start_commandv(cmd, nset, infd, outfd, args); 236 va_end(args); 237 return r; 238 } 239 240 PUBLIC FILE * 241 Popen(const char *cmd, const char *mode) 242 { 243 int p[2]; 244 int myside, hisside, fd0, fd1; 245 pid_t pid; 246 sigset_t nset; 247 FILE *fp; 248 char *shellcmd; 249 250 if (pipe(p) < 0) 251 return NULL; 252 (void)fcntl(p[READ], F_SETFD, FD_CLOEXEC); 253 (void)fcntl(p[WRITE], F_SETFD, FD_CLOEXEC); 254 if (*mode == 'r') { 255 myside = p[READ]; 256 hisside = fd0 = fd1 = p[WRITE]; 257 } else { 258 myside = p[WRITE]; 259 hisside = fd0 = p[READ]; 260 fd1 = -1; 261 } 262 (void)sigemptyset(&nset); 263 if ((shellcmd = value(ENAME_SHELL)) == NULL) 264 shellcmd = __UNCONST(_PATH_CSHELL); 265 pid = start_command(shellcmd, &nset, fd0, fd1, "-c", cmd, NULL); 266 if (pid < 0) { 267 (void)close(p[READ]); 268 (void)close(p[WRITE]); 269 return NULL; 270 } 271 (void)close(hisside); 272 if ((fp = fdopen(myside, mode)) != NULL) 273 register_file(fp, 1, pid); 274 return fp; 275 } 276 277 static struct child * 278 findchild(pid_t pid, int dont_alloc) 279 { 280 struct child **cpp; 281 282 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 283 cpp = &(*cpp)->link) 284 continue; 285 if (*cpp == NULL) { 286 if (dont_alloc) 287 return NULL; 288 if (child_freelist) { 289 *cpp = child_freelist; 290 child_freelist = (*cpp)->link; 291 } else 292 *cpp = emalloc(sizeof(**cpp)); 293 294 (*cpp)->pid = pid; 295 (*cpp)->done = (*cpp)->free = 0; 296 (*cpp)->link = NULL; 297 } 298 return *cpp; 299 } 300 301 static void 302 delchild(struct child *cp) 303 { 304 struct child **cpp; 305 306 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 307 continue; 308 *cpp = cp->link; 309 cp->link = child_freelist; 310 child_freelist = cp; 311 } 312 313 /* 314 * Wait for a specific child to die. 315 */ 316 PUBLIC int 317 wait_child(pid_t pid) 318 { 319 struct child *cp; 320 sigset_t nset, oset; 321 pid_t rv = 0; 322 323 (void)sigemptyset(&nset); 324 (void)sigaddset(&nset, SIGCHLD); 325 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 326 /* 327 * If we have not already waited on the pid (via sigchild) 328 * wait on it now. Otherwise, use the wait status stashed 329 * by sigchild. 330 */ 331 cp = findchild(pid, 1); 332 if (cp == NULL || !cp->done) 333 rv = waitpid(pid, &wait_status, 0); 334 else 335 wait_status = cp->status; 336 if (cp != NULL) 337 delchild(cp); 338 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 339 if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status))) 340 return -1; 341 else 342 return 0; 343 } 344 345 static pid_t 346 file_pid(FILE *fp) 347 { 348 struct fp *p; 349 350 for (p = fp_head; p; p = p->link) 351 if (p->fp == fp) 352 return p->pid; 353 errx(EXIT_FAILURE, "Invalid file pointer"); 354 /*NOTREACHED*/ 355 } 356 357 PUBLIC int 358 Pclose(FILE *ptr) 359 { 360 int i; 361 sigset_t nset, oset; 362 363 if (ptr == NULL) 364 return 0; 365 366 i = file_pid(ptr); 367 unregister_file(ptr); 368 (void)fclose(ptr); 369 (void)sigemptyset(&nset); 370 (void)sigaddset(&nset, SIGINT); 371 (void)sigaddset(&nset, SIGHUP); 372 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 373 i = wait_child(i); 374 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 375 return i; 376 } 377 378 PUBLIC void 379 close_all_files(void) 380 { 381 while (fp_head) 382 if (fp_head->pipe) 383 (void)Pclose(fp_head->fp); 384 else 385 (void)Fclose(fp_head->fp); 386 } 387 388 PUBLIC FILE * 389 last_registered_file(int last_pipe) 390 { 391 struct fp *fpp; 392 393 if (last_pipe == 0) 394 return fp_head ? fp_head->fp : NULL; 395 396 for (fpp = fp_head; fpp; fpp = fpp->link) 397 if (fpp->pipe) 398 return fpp->fp; 399 return NULL; 400 } 401 402 PUBLIC void 403 close_top_files(FILE *fp_stop) 404 { 405 while (fp_head && fp_head->fp != fp_stop) 406 if (fp_head->pipe) 407 (void)Pclose(fp_head->fp); 408 else 409 (void)Fclose(fp_head->fp); 410 } 411 412 #ifdef MIME_SUPPORT 413 PUBLIC void 414 flush_files(FILE *fo, int only_pipes) 415 { 416 struct fp *fpp; 417 418 if (fo) 419 (void)fflush(fo); 420 421 for (fpp = fp_head; fpp; fpp = fpp->link) 422 if (!only_pipes || fpp->pipe) 423 (void)fflush(fpp->fp); 424 425 (void)fflush(stdout); 426 } 427 #endif /* MIME_SUPPORT */ 428 429 static int 430 wait_command(pid_t pid) 431 { 432 433 if (wait_child(pid) < 0) { 434 (void)puts("Fatal error in process."); 435 return -1; 436 } 437 return 0; 438 } 439 440 PUBLIC int 441 run_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...) 442 { 443 pid_t pid; 444 va_list args; 445 int rval; 446 447 #ifdef BROKEN_EXEC_TTY_RESTORE 448 struct termios ttybuf; 449 int tcrval; 450 /* 451 * XXX - grab the tty settings as currently they can get 452 * trashed by emacs-21 when suspending with bash-3.2.25 as the 453 * shell. 454 * 455 * 1) from the mail editor, start "emacs -nw" (21.4) 456 * 2) suspend emacs to the shell (bash 3.2.25) 457 * 3) resume emacs 458 * 4) exit emacs back to the mail editor 459 * 5) discover the tty is screwed: the mail editor is no 460 * longer receiving characters 461 * 462 * - This occurs on both i386 and amd64. 463 * - This did _NOT_ occur before 4.99.10. 464 * - This does _NOT_ occur if the editor is vi(1) or if the shell 465 * is /bin/sh. 466 * - This _DOES_ happen with the old mail(1) from 2006-01-01 (long 467 * before my changes). 468 * 469 * This is the commit that introduced this "feature": 470 * http://mail-index.netbsd.org/source-changes/2007/02/09/0020.html 471 */ 472 if ((tcrval = tcgetattr(fileno(stdin), &ttybuf)) == -1) 473 warn("tcgetattr"); 474 #endif 475 va_start(args, outfd); 476 pid = start_commandv(cmd, nset, infd, outfd, args); 477 va_end(args); 478 if (pid < 0) 479 return -1; 480 rval = wait_command(pid); 481 #ifdef BROKEN_EXEC_TTY_RESTORE 482 if (tcrval != -1 && tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf) == -1) 483 warn("tcsetattr"); 484 #endif 485 return rval; 486 487 } 488 489 /*ARGSUSED*/ 490 PUBLIC void 491 sigchild(int signo __unused) 492 { 493 pid_t pid; 494 int status; 495 struct child *cp; 496 int save_errno; 497 498 save_errno = errno; 499 while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) { 500 cp = findchild(pid, 1); /* async-signal-safe: we don't alloc */ 501 if (!cp) 502 continue; 503 if (cp->free) 504 delchild(cp); /* async-signal-safe: list changes */ 505 else { 506 cp->done = 1; 507 cp->status = status; 508 } 509 } 510 errno = save_errno; 511 } 512 513 /* 514 * Mark a child as don't care. 515 */ 516 PUBLIC void 517 free_child(pid_t pid) 518 { 519 struct child *cp; 520 sigset_t nset, oset; 521 522 (void)sigemptyset(&nset); 523 (void)sigaddset(&nset, SIGCHLD); 524 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 525 if ((cp = findchild(pid, 0)) != NULL) { 526 if (cp->done) 527 delchild(cp); 528 else 529 cp->free = 1; 530 } 531 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 532 } 533