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