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