1 /* $NetBSD: redir.c,v 1.72 2021/11/22 05:17:43 kre Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; 39 #else 40 __RCSID("$NetBSD: redir.c,v 1.72 2021/11/22 05:17:43 kre Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/types.h> 45 #include <sys/param.h> /* PIPE_BUF */ 46 #include <sys/stat.h> 47 #include <signal.h> 48 #include <string.h> 49 #include <fcntl.h> 50 #include <errno.h> 51 #include <unistd.h> 52 #include <stdlib.h> 53 54 /* 55 * Code for dealing with input/output redirection. 56 */ 57 58 #include "main.h" 59 #include "builtins.h" 60 #include "shell.h" 61 #include "nodes.h" 62 #include "jobs.h" 63 #include "options.h" 64 #include "expand.h" 65 #include "redir.h" 66 #include "output.h" 67 #include "memalloc.h" 68 #include "mystring.h" 69 #include "error.h" 70 #include "show.h" 71 72 73 #define EMPTY -2 /* marks an unused slot in redirtab */ 74 #define CLOSED -1 /* fd was not open before redir */ 75 #ifndef PIPE_BUF 76 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 77 #else 78 # define PIPESIZE PIPE_BUF 79 #endif 80 81 #ifndef FD_CLOEXEC 82 # define FD_CLOEXEC 1 /* well known from before there was a name */ 83 #endif 84 85 #ifndef F_DUPFD_CLOEXEC 86 #define F_DUPFD_CLOEXEC F_DUPFD 87 #define CLOEXEC(fd) (fcntl((fd), F_SETFD, fcntl((fd),F_GETFD) | FD_CLOEXEC)) 88 #else 89 #define CLOEXEC(fd) 90 #endif 91 92 93 MKINIT 94 struct renamelist { 95 struct renamelist *next; 96 int orig; 97 int into; 98 }; 99 100 MKINIT 101 struct redirtab { 102 struct redirtab *next; 103 struct renamelist *renamed; 104 }; 105 106 107 MKINIT struct redirtab *redirlist; 108 109 /* 110 * We keep track of whether or not fd0 has been redirected. This is for 111 * background commands, where we want to redirect fd0 to /dev/null only 112 * if it hasn't already been redirected. 113 */ 114 STATIC int fd0_redirected = 0; 115 116 /* 117 * And also where to put internal use fds that should be out of the 118 * way of user defined fds (normally) 119 */ 120 STATIC int big_sh_fd = 0; 121 122 STATIC const struct renamelist *is_renamed(const struct renamelist *, int); 123 STATIC void fd_rename(struct redirtab *, int, int); 124 STATIC int * saved_redirected_fd(int); 125 STATIC void free_rl(struct redirtab *, int); 126 STATIC void openredirect(union node *, char[10], int); 127 STATIC int openhere(const union node *); 128 STATIC int copyfd(int, int, int); 129 STATIC void find_big_fd(void); 130 131 132 struct shell_fds { /* keep track of internal shell fds */ 133 struct shell_fds *nxt; 134 void (*cb)(int, int); 135 int fd; 136 }; 137 138 STATIC struct shell_fds *sh_fd_list; 139 140 STATIC int pick_new_fd(int); 141 STATIC void renumber_sh_fd(struct shell_fds *); 142 STATIC struct shell_fds *sh_fd(int); 143 144 STATIC const struct renamelist * 145 is_renamed(const struct renamelist *rl, int fd) 146 { 147 while (rl != NULL) { 148 if (rl->orig == fd) 149 return rl; 150 rl = rl->next; 151 } 152 return NULL; 153 } 154 155 STATIC int * 156 saved_redirected_fd(int fd) 157 { 158 struct redirtab *rt; 159 struct renamelist *rl; 160 161 for (rt = redirlist; rt != NULL; rt = rt->next) { 162 for (rl = rt->renamed; rl != NULL; rl = rl->next) { 163 if (rl->into == fd) 164 return &rl->into; 165 } 166 } 167 return NULL; 168 } 169 170 STATIC void 171 free_rl(struct redirtab *rt, int reset) 172 { 173 struct renamelist *rl, *rn = rt->renamed; 174 175 while ((rl = rn) != NULL) { 176 rn = rl->next; 177 if (rl->orig == 0) 178 fd0_redirected--; 179 VTRACE(DBG_REDIR, ("popredir %d%s: %s", 180 rl->orig, rl->orig==0 ? " (STDIN)" : "", 181 reset ? "" : "no reset\n")); 182 if (reset) { 183 if (rl->into < 0) { 184 VTRACE(DBG_REDIR, ("closed\n")); 185 close(rl->orig); 186 } else { 187 VTRACE(DBG_REDIR, ("from %d\n", rl->into)); 188 movefd(rl->into, rl->orig); 189 } 190 } 191 ckfree(rl); 192 } 193 rt->renamed = NULL; 194 } 195 196 STATIC void 197 fd_rename(struct redirtab *rt, int from, int to) 198 { 199 /* XXX someday keep a short list (8..10) of freed renamelists XXX */ 200 struct renamelist *rl = ckmalloc(sizeof(struct renamelist)); 201 202 rl->next = rt->renamed; 203 rt->renamed = rl; 204 205 rl->orig = from; 206 rl->into = to; 207 } 208 209 /* 210 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 211 * old file descriptors are stashed away so that the redirection can be 212 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 213 * standard output, and the standard error if it becomes a duplicate of 214 * stdout, is saved in memory. 215 */ 216 217 void 218 redirect(union node *redir, int flags) 219 { 220 union node *n; 221 struct redirtab *sv = NULL; 222 int i; 223 int fd; 224 char memory[10]; /* file descriptors to write to memory */ 225 226 CTRACE(DBG_REDIR, ("redirect(F=0x%x):%s\n", flags, redir?"":" NONE")); 227 for (i = 10 ; --i >= 0 ; ) 228 memory[i] = 0; 229 memory[1] = flags & REDIR_BACKQ; 230 if (flags & REDIR_PUSH) { 231 /* 232 * We don't have to worry about REDIR_VFORK here, as 233 * flags & REDIR_PUSH is never true if REDIR_VFORK is set. 234 */ 235 sv = ckmalloc(sizeof (struct redirtab)); 236 sv->renamed = NULL; 237 sv->next = redirlist; 238 redirlist = sv; 239 } 240 for (n = redir ; n ; n = n->nfile.next) { 241 int *renamed; 242 243 fd = n->nfile.fd; 244 VTRACE(DBG_REDIR, ("redir %d (max=%d limit=%ld) ", 245 fd, max_user_fd, user_fd_limit)); 246 if (fd < user_fd_limit && fd > max_user_fd) 247 max_user_fd = fd; 248 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && 249 n->ndup.dupfd == fd) { 250 VTRACE(DBG_REDIR, ("!cloexec\n")); 251 if (sh_fd(fd) != NULL || 252 saved_redirected_fd(fd) != NULL) 253 error("fd %d: %s", fd, strerror(EBADF)); 254 /* redirect from/to same file descriptor */ 255 /* make sure it stays open */ 256 if (fcntl(fd, F_SETFD, 0) < 0) 257 error("fd %d: %s", fd, strerror(errno)); 258 continue; 259 } 260 if ((renamed = saved_redirected_fd(fd)) != NULL) { 261 int to = pick_new_fd(fd); 262 263 VTRACE(DBG_REDIR, 264 ("redirect: moved holding fd %d to %d\n", fd, to)); 265 *renamed = to; 266 if (to != fd) /* always... */ 267 (void)close(fd); 268 } 269 renumber_sh_fd(sh_fd(fd)); 270 271 if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) { 272 int bigfd; 273 274 INTOFF; 275 if (big_sh_fd < 10) 276 find_big_fd(); 277 if ((bigfd = big_sh_fd) < max_user_fd) 278 bigfd = max_user_fd; 279 if ((i = fcntl(fd, F_DUPFD, bigfd + 1)) == -1) { 280 switch (errno) { 281 case EBADF: 282 i = CLOSED; 283 break; 284 case EMFILE: 285 case EINVAL: 286 find_big_fd(); 287 i = fcntl(fd, F_DUPFD, big_sh_fd); 288 if (i >= 0) 289 break; 290 if (errno == EMFILE || errno == EINVAL) 291 i = fcntl(fd, F_DUPFD, 3); 292 if (i >= 0) 293 break; 294 /* FALLTHRU */ 295 default: 296 error("%d: %s", fd, strerror(errno)); 297 /* NOTREACHED */ 298 } 299 } 300 if (i >= 0) 301 (void)fcntl(i, F_SETFD, FD_CLOEXEC); 302 fd_rename(sv, fd, i); 303 VTRACE(DBG_REDIR, ("fd %d saved as %d ", fd, i)); 304 INTON; 305 } 306 VTRACE(DBG_REDIR, ("%s\n", fd == 0 ? "STDIN" : "")); 307 if (fd == 0) 308 fd0_redirected++; 309 openredirect(n, memory, flags); 310 } 311 if (memory[1]) 312 out1 = &memout; 313 if (memory[2]) 314 out2 = &memout; 315 } 316 317 318 STATIC void 319 openredirect(union node *redir, char memory[10], int flags) 320 { 321 struct stat sb; 322 int fd = redir->nfile.fd; 323 char *fname; 324 int f; 325 int eflags, cloexec; 326 327 /* 328 * We suppress interrupts so that we won't leave open file 329 * descriptors around. This may not be such a good idea because 330 * an open of a device or a fifo can block indefinitely. 331 */ 332 INTOFF; 333 if (fd < 10) 334 memory[fd] = 0; 335 switch (redir->nfile.type) { 336 case NFROM: 337 fname = redir->nfile.expfname; 338 if (flags & REDIR_VFORK) 339 eflags = O_NONBLOCK; 340 else 341 eflags = 0; 342 if ((f = open(fname, O_RDONLY|eflags)) < 0) 343 goto eopen; 344 VTRACE(DBG_REDIR, ("openredirect(< '%s') -> %d [%#x]", 345 fname, f, eflags)); 346 if (eflags) 347 (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags); 348 break; 349 case NFROMTO: 350 fname = redir->nfile.expfname; 351 if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0) 352 goto ecreate; 353 VTRACE(DBG_REDIR, ("openredirect(<> '%s') -> %d", fname, f)); 354 break; 355 case NTO: 356 if (Cflag) { 357 fname = redir->nfile.expfname; 358 if ((f = open(fname, O_WRONLY)) == -1) { 359 if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 360 0666)) < 0) 361 goto ecreate; 362 } else if (fstat(f, &sb) == -1) { 363 int serrno = errno; 364 close(f); 365 errno = serrno; 366 goto ecreate; 367 } else if (S_ISREG(sb.st_mode)) { 368 close(f); 369 errno = EEXIST; 370 goto ecreate; 371 } 372 VTRACE(DBG_REDIR, ("openredirect(>| '%s') -> %d", 373 fname, f)); 374 break; 375 } 376 /* FALLTHROUGH */ 377 case NCLOBBER: 378 fname = redir->nfile.expfname; 379 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 380 goto ecreate; 381 VTRACE(DBG_REDIR, ("openredirect(> '%s') -> %d", fname, f)); 382 break; 383 case NAPPEND: 384 fname = redir->nfile.expfname; 385 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) 386 goto ecreate; 387 VTRACE(DBG_REDIR, ("openredirect(>> '%s') -> %d", fname, f)); 388 break; 389 case NTOFD: 390 case NFROMFD: 391 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 392 if (sh_fd(redir->ndup.dupfd) != NULL || 393 saved_redirected_fd(redir->ndup.dupfd) != NULL) 394 error("Redirect (from %d to %d) failed: %s", 395 redir->ndup.dupfd, fd, strerror(EBADF)); 396 if (fd < 10 && redir->ndup.dupfd < 10 && 397 memory[redir->ndup.dupfd]) 398 memory[fd] = 1; 399 else if (copyfd(redir->ndup.dupfd, fd, 400 (flags & REDIR_KEEP) == 0) < 0) 401 error("Redirect (from %d to %d) failed: %s", 402 redir->ndup.dupfd, fd, strerror(errno)); 403 VTRACE(DBG_REDIR, ("openredirect: %d%c&%d\n", fd, 404 "<>"[redir->nfile.type==NTOFD], redir->ndup.dupfd)); 405 } else { 406 (void) close(fd); 407 VTRACE(DBG_REDIR, ("openredirect: %d%c&-\n", fd, 408 "<>"[redir->nfile.type==NTOFD])); 409 } 410 INTON; 411 return; 412 case NHERE: 413 case NXHERE: 414 VTRACE(DBG_REDIR, ("openredirect: %d<<...", fd)); 415 f = openhere(redir); 416 break; 417 default: 418 abort(); 419 } 420 421 cloexec = fd > 2 && (flags & REDIR_KEEP) == 0 && !posix; 422 if (f != fd) { 423 VTRACE(DBG_REDIR, (" -> %d", fd)); 424 if (copyfd(f, fd, cloexec) < 0) { 425 int e = errno; 426 427 VTRACE(DBG_REDIR, (" failed: %s\n", strerror(e))); 428 close(f); 429 error("redirect reassignment (fd %d) failed: %s", fd, 430 strerror(e)); 431 } 432 close(f); 433 } else if (cloexec) 434 (void)fcntl(f, F_SETFD, FD_CLOEXEC); 435 VTRACE(DBG_REDIR, ("%s\n", cloexec ? " cloexec" : "")); 436 437 INTON; 438 return; 439 ecreate: 440 exerrno = 1; 441 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 442 eopen: 443 exerrno = 1; 444 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 445 } 446 447 448 /* 449 * Handle here documents. Normally we fork off a process to write the 450 * data to a pipe. If the document is short, we can stuff the data in 451 * the pipe without forking. 452 */ 453 454 STATIC int 455 openhere(const union node *redir) 456 { 457 int pip[2]; 458 int len = 0; 459 460 if (pipe(pip) < 0) 461 error("Pipe call failed"); 462 len = strlen(redir->nhere.text); 463 VTRACE(DBG_REDIR, ("openhere(%p) [%d] \"%.*s\"%s\n", redir, len, 464 (len < 40 ? len : 40), redir->nhere.text, (len < 40 ? "" : "..."))); 465 if (len <= PIPESIZE) { /* XXX eventually copy FreeBSD method */ 466 xwrite(pip[1], redir->nhere.text, len); 467 goto out; 468 } 469 VTRACE(DBG_REDIR, (" forking [%d,%d]\n", pip[0], pip[1])); 470 if (forkshell(NULL, NULL, FORK_NOJOB) == 0) { 471 close(pip[0]); 472 signal(SIGINT, SIG_IGN); 473 signal(SIGQUIT, SIG_IGN); 474 signal(SIGHUP, SIG_IGN); 475 #ifdef SIGTSTP 476 signal(SIGTSTP, SIG_IGN); 477 #endif 478 signal(SIGPIPE, SIG_DFL); 479 xwrite(pip[1], redir->nhere.text, len); 480 VTRACE(DBG_PROCS|DBG_REDIR, ("wrote here doc. exiting(0)\n")); 481 _exit(0); 482 } 483 VTRACE(DBG_REDIR, ("openhere (closing %d)", pip[1])); 484 out: 485 close(pip[1]); 486 VTRACE(DBG_REDIR, (" (pipe fd=%d)", pip[0])); 487 return pip[0]; 488 } 489 490 491 492 /* 493 * Undo the effects of the last redirection. 494 */ 495 496 void 497 popredir(void) 498 { 499 struct redirtab *rp = redirlist; 500 501 INTOFF; 502 free_rl(rp, 1); 503 redirlist = rp->next; 504 ckfree(rp); 505 INTON; 506 } 507 508 /* 509 * Undo all redirections. Called on error or interrupt. 510 */ 511 512 #ifdef mkinit 513 514 INCLUDE "redir.h" 515 516 RESET { 517 while (redirlist) 518 popredir(); 519 } 520 521 SHELLPROC { 522 clearredir(0); 523 } 524 525 #endif 526 527 /* Return true if fd 0 has already been redirected at least once. */ 528 int 529 fd0_redirected_p(void) 530 { 531 return fd0_redirected != 0; 532 } 533 534 /* 535 * Discard all saved file descriptors. 536 */ 537 538 void 539 clearredir(int vforked) 540 { 541 struct redirtab *rp; 542 struct renamelist *rl; 543 544 for (rp = redirlist ; rp ; rp = rp->next) { 545 if (!vforked) 546 free_rl(rp, 0); 547 else for (rl = rp->renamed; rl; rl = rl->next) 548 if (rl->into >= 0) 549 close(rl->into); 550 } 551 } 552 553 554 555 /* 556 * Copy a file descriptor to be == to. 557 * cloexec indicates if we want close-on-exec or not. 558 * Returns -1 if any error occurs. 559 */ 560 561 STATIC int 562 copyfd(int from, int to, int cloexec) 563 { 564 int newfd; 565 566 if (cloexec && to > 2) { 567 #ifdef O_CLOEXEC 568 newfd = dup3(from, to, O_CLOEXEC); 569 #else 570 newfd = dup2(from, to); 571 fcntl(newfd, F_SETFD, fcntl(newfd,F_GETFD) | FD_CLOEXEC); 572 #endif 573 } else 574 newfd = dup2(from, to); 575 576 return newfd; 577 } 578 579 /* 580 * rename fd from to be fd to (closing from). 581 * close-on-exec is never set on 'to' (unless 582 * from==to and it was set on from) - ie: a no-op 583 * returns to (or errors() if an error occurs). 584 * 585 * This is mostly used for rearranging the 586 * results from pipe(). 587 */ 588 int 589 movefd(int from, int to) 590 { 591 if (from == to) 592 return to; 593 594 (void) close(to); 595 if (copyfd(from, to, 0) != to) { 596 int e = errno; 597 598 (void) close(from); 599 error("Unable to make fd %d: %s", to, strerror(e)); 600 } 601 (void) close(from); 602 603 return to; 604 } 605 606 STATIC void 607 find_big_fd(void) 608 { 609 int i, fd; 610 static int last_start = 3; /* aim to keep sh fd's under 20 */ 611 612 if (last_start < 10) 613 last_start++; 614 615 for (i = (1 << last_start); i >= 10; i >>= 1) { 616 if ((fd = fcntl(0, F_DUPFD, i - 1)) >= 0) { 617 close(fd); 618 break; 619 } 620 } 621 622 fd = (i / 5) * 4; 623 if (fd < 10) 624 fd = 10; 625 626 big_sh_fd = fd; 627 } 628 629 /* 630 * If possible, move file descriptor fd out of the way 631 * of expected user fd values. Returns the new fd 632 * (which may be the input fd if things do not go well.) 633 * Always set close-on-exec on the result, and close 634 * the input fd unless it is to be our result. 635 */ 636 int 637 to_upper_fd(int fd) 638 { 639 int i; 640 641 VTRACE(DBG_REDIR|DBG_OUTPUT, ("to_upper_fd(%d)", fd)); 642 if (big_sh_fd < 10 || big_sh_fd >= user_fd_limit) 643 find_big_fd(); 644 do { 645 i = fcntl(fd, F_DUPFD_CLOEXEC, big_sh_fd); 646 if (i >= 0) { 647 if (fd != i) 648 close(fd); 649 VTRACE(DBG_REDIR|DBG_OUTPUT, ("-> %d\n", i)); 650 return i; 651 } 652 if (errno != EMFILE && errno != EINVAL) 653 break; 654 find_big_fd(); 655 } while (big_sh_fd > 10); 656 657 /* 658 * If we wanted to move this fd to some random high number 659 * we certainly do not intend to pass it through exec, even 660 * if the reassignment failed. 661 */ 662 (void)fcntl(fd, F_SETFD, FD_CLOEXEC); 663 VTRACE(DBG_REDIR|DBG_OUTPUT, (" fails ->%d\n", fd)); 664 return fd; 665 } 666 667 void 668 register_sh_fd(int fd, void (*cb)(int, int)) 669 { 670 struct shell_fds *fp; 671 672 fp = ckmalloc(sizeof (struct shell_fds)); 673 if (fp != NULL) { 674 fp->nxt = sh_fd_list; 675 sh_fd_list = fp; 676 677 fp->fd = fd; 678 fp->cb = cb; 679 } 680 } 681 682 void 683 sh_close(int fd) 684 { 685 struct shell_fds **fpp, *fp; 686 687 fpp = &sh_fd_list; 688 while ((fp = *fpp) != NULL) { 689 if (fp->fd == fd) { 690 *fpp = fp->nxt; 691 ckfree(fp); 692 break; 693 } 694 fpp = &fp->nxt; 695 } 696 (void)close(fd); 697 } 698 699 STATIC struct shell_fds * 700 sh_fd(int fd) 701 { 702 struct shell_fds *fp; 703 704 for (fp = sh_fd_list; fp != NULL; fp = fp->nxt) 705 if (fp->fd == fd) 706 return fp; 707 return NULL; 708 } 709 710 STATIC int 711 pick_new_fd(int fd) 712 { 713 int to; 714 715 to = fcntl(fd, F_DUPFD_CLOEXEC, big_sh_fd); 716 if (to == -1 && big_sh_fd >= 22) 717 to = fcntl(fd, F_DUPFD_CLOEXEC, big_sh_fd/2); 718 if (to == -1) 719 to = fcntl(fd, F_DUPFD_CLOEXEC, fd + 1); 720 if (to == -1) 721 to = fcntl(fd, F_DUPFD_CLOEXEC, 10); 722 if (to == -1) 723 to = fcntl(fd, F_DUPFD_CLOEXEC, 3); 724 if (to == -1) 725 error("insufficient file descriptors available"); 726 CLOEXEC(to); 727 return to; 728 } 729 730 STATIC void 731 renumber_sh_fd(struct shell_fds *fp) 732 { 733 int to; 734 735 if (fp == NULL) 736 return; 737 738 /* 739 * if we have had a collision, and the sh fd was a "big" one 740 * try moving the sh fd base to a higher number (if possible) 741 * so future sh fds are less likely to be in the user's sights 742 * (incl this one when moved) 743 */ 744 if (fp->fd >= big_sh_fd) 745 find_big_fd(); 746 747 to = pick_new_fd(fp->fd); 748 749 if (fp->fd == to) /* impossible? */ 750 return; 751 752 VTRACE(DBG_REDIR, ("renumber_sh_fd: moved shell fd %d to %d\n", 753 fp->fd, to)); 754 755 (*fp->cb)(fp->fd, to); 756 (void)close(fp->fd); 757 fp->fd = to; 758 } 759 760 static const struct flgnames { 761 const char *name; 762 uint16_t minch; 763 uint32_t value; 764 } nv[] = { 765 #ifdef O_APPEND 766 { "append", 2, O_APPEND }, 767 #else 768 # define O_APPEND 0 769 #endif 770 #ifdef O_ASYNC 771 { "async", 2, O_ASYNC }, 772 #else 773 # define O_ASYNC 0 774 #endif 775 #ifdef O_SYNC 776 { "sync", 2, O_SYNC }, 777 #else 778 # define O_SYNC 0 779 #endif 780 #ifdef O_NONBLOCK 781 { "nonblock", 3, O_NONBLOCK }, 782 #else 783 # define O_NONBLOCK 0 784 #endif 785 #ifdef O_FSYNC 786 { "fsync", 2, O_FSYNC }, 787 #else 788 # define O_FSYNC 0 789 #endif 790 #ifdef O_DSYNC 791 { "dsync", 2, O_DSYNC }, 792 #else 793 # define O_DSYNC 0 794 #endif 795 #ifdef O_RSYNC 796 { "rsync", 2, O_RSYNC }, 797 #else 798 # define O_RSYNC 0 799 #endif 800 #ifdef O_ALT_IO 801 { "altio", 2, O_ALT_IO }, 802 #else 803 # define O_ALT_IO 0 804 #endif 805 #ifdef O_DIRECT 806 { "direct", 2, O_DIRECT }, 807 #else 808 # define O_DIRECT 0 809 #endif 810 #ifdef O_NOSIGPIPE 811 { "nosigpipe", 3, O_NOSIGPIPE }, 812 #else 813 # define O_NOSIGPIPE 0 814 #endif 815 816 #define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_DSYNC|O_RSYNC|\ 817 O_ALT_IO|O_DIRECT|O_NOSIGPIPE) 818 819 #ifndef O_CLOEXEC 820 # define O_CLOEXEC ((~ALLFLAGS) ^ ((~ALLFLAGS) & ((~ALLFLAGS) - 1))) 821 #endif 822 823 /* for any system we support, close on exec is always defined */ 824 { "cloexec", 2, O_CLOEXEC }, 825 { 0, 0, 0 } 826 }; 827 828 #ifndef O_ACCMODE 829 # define O_ACCMODE 0 830 #endif 831 #ifndef O_RDONLY 832 # define O_RDONLY 0 833 #endif 834 #ifndef O_WRONLY 835 # define O_WRONLY 0 836 #endif 837 #ifndef O_RWDR 838 # define O_RWDR 0 839 #endif 840 #ifndef O_SHLOCK 841 # define O_SHLOCK 0 842 #endif 843 #ifndef O_EXLOCK 844 # define O_EXLOCK 0 845 #endif 846 #ifndef O_NOFOLLOW 847 # define O_NOFOLLOW 0 848 #endif 849 #ifndef O_CREAT 850 # define O_CREAT 0 851 #endif 852 #ifndef O_TRUNC 853 # define O_TRUNC 0 854 #endif 855 #ifndef O_EXCL 856 # define O_EXCL 0 857 #endif 858 #ifndef O_NOCTTY 859 # define O_NOCTTY 0 860 #endif 861 #ifndef O_DIRECTORY 862 # define O_DIRECTORY 0 863 #endif 864 #ifndef O_REGULAR 865 # define O_REGULAR 0 866 #endif 867 /* 868 * flags that F_GETFL might return that we want to ignore 869 * 870 * F_GETFL should not actually return these, they're all just open() 871 * modifiers, rather than state, but just in case... 872 */ 873 #define IGNFLAGS (O_ACCMODE|O_RDONLY|O_WRONLY|O_RDWR|O_SHLOCK|O_EXLOCK| \ 874 O_NOFOLLOW|O_CREAT|O_TRUNC|O_EXCL|O_NOCTTY|O_DIRECTORY|O_REGULAR) 875 876 static int 877 getflags(int fd, int p) 878 { 879 int c, f; 880 881 if (sh_fd(fd) != NULL || saved_redirected_fd(fd) != NULL) { 882 if (!p) 883 return -1; 884 error("Can't get status for fd=%d (%s)", fd, strerror(EBADF)); 885 } 886 887 if ((c = fcntl(fd, F_GETFD)) == -1) { 888 if (!p) 889 return -1; 890 error("Can't get status for fd=%d (%s)", fd, strerror(errno)); 891 } 892 if ((f = fcntl(fd, F_GETFL)) == -1) { 893 if (!p) 894 return -1; 895 error("Can't get flags for fd=%d (%s)", fd, strerror(errno)); 896 } 897 f &= ~IGNFLAGS; /* clear anything we know about, but ignore */ 898 if (c & FD_CLOEXEC) 899 f |= O_CLOEXEC; 900 return f; 901 } 902 903 static void 904 printone(int fd, int p, int verbose, int pfd) 905 { 906 int f = getflags(fd, p); 907 const struct flgnames *fn; 908 909 if (f == -1) 910 return; 911 912 if (pfd) 913 outfmt(out1, "%d: ", fd); 914 for (fn = nv; fn->name; fn++) { 915 if (f & fn->value) { 916 outfmt(out1, "%s%s", verbose ? "+" : "", fn->name); 917 f &= ~fn->value; 918 } else if (verbose) 919 outfmt(out1, "-%s", fn->name); 920 else 921 continue; 922 if (f || (verbose && fn[1].name)) 923 outfmt(out1, ","); 924 } 925 if (verbose && f) /* f should be normally be 0 */ 926 outfmt(out1, " +%#x", f); 927 outfmt(out1, "\n"); 928 } 929 930 static void 931 parseflags(char *s, int *p, int *n) 932 { 933 int *v, *w; 934 const struct flgnames *fn; 935 size_t len; 936 937 *p = 0; 938 *n = 0; 939 for (s = strtok(s, ","); s; s = strtok(NULL, ",")) { 940 switch (*s++) { 941 case '+': 942 v = p; 943 w = n; 944 break; 945 case '-': 946 v = n; 947 w = p; 948 break; 949 default: 950 error("Missing +/- indicator before flag %s", s-1); 951 } 952 953 len = strlen(s); 954 for (fn = nv; fn->name; fn++) 955 if (len >= fn->minch && strncmp(s,fn->name,len) == 0) { 956 *v |= fn->value; 957 *w &=~ fn->value; 958 break; 959 } 960 if (fn->name == 0) 961 error("Bad flag `%s'", s); 962 } 963 } 964 965 static void 966 setone(int fd, int pos, int neg, int verbose) 967 { 968 int f = getflags(fd, 1); 969 int n, cloexec; 970 971 if (f == -1) 972 return; 973 974 cloexec = -1; 975 if ((pos & O_CLOEXEC) && !(f & O_CLOEXEC)) 976 cloexec = FD_CLOEXEC; 977 if ((neg & O_CLOEXEC) && (f & O_CLOEXEC)) 978 cloexec = 0; 979 980 if (cloexec != -1 && fcntl(fd, F_SETFD, cloexec) == -1) 981 error("Can't set status for fd=%d (%s)", fd, strerror(errno)); 982 983 pos &= ~O_CLOEXEC; 984 neg &= ~O_CLOEXEC; 985 f &= ~O_CLOEXEC; 986 n = f; 987 n |= pos; 988 n &= ~neg; 989 if (n != f && fcntl(fd, F_SETFL, n) == -1) 990 error("Can't set flags for fd=%d (%s)", fd, strerror(errno)); 991 if (verbose) 992 printone(fd, 1, verbose, 1); 993 } 994 995 int 996 fdflagscmd(int argc, char *argv[]) 997 { 998 char *num; 999 int verbose = 0, ch, pos = 0, neg = 0; 1000 char *setflags = NULL; 1001 1002 optreset = 1; optind = 1; /* initialize getopt */ 1003 while ((ch = getopt(argc, argv, ":vs:")) != -1) 1004 switch ((char)ch) { 1005 case 'v': 1006 verbose = 1; 1007 break; 1008 case 's': 1009 if (setflags) 1010 goto msg; 1011 setflags = optarg; 1012 break; 1013 case '?': 1014 default: 1015 msg: 1016 error("Usage: fdflags [-v] [-s <flags> fd] [fd...]"); 1017 /* NOTREACHED */ 1018 } 1019 1020 argc -= optind, argv += optind; 1021 1022 if (setflags) 1023 parseflags(setflags, &pos, &neg); 1024 1025 if (argc == 0) { 1026 int i; 1027 1028 if (setflags) 1029 goto msg; 1030 1031 for (i = 0; i <= max_user_fd; i++) 1032 printone(i, 0, verbose, 1); 1033 1034 } else while ((num = *argv++) != NULL) { 1035 int fd = number(num); 1036 1037 while (num[0] == '0' && num[1] != '\0') /* skip 0's */ 1038 num++; 1039 if (strlen(num) > 5 || 1040 (fd >= user_fd_limit && fd > max_user_fd)) 1041 error("%s: too big to be a file descriptor", num); 1042 1043 if (setflags) 1044 setone(fd, pos, neg, verbose); 1045 else 1046 printone(fd, 1, verbose, argc > 1); 1047 } 1048 flushout(out1); 1049 if (io_err(out1)) { 1050 out2str("fdflags: I/O error\n"); 1051 return 1; 1052 } 1053 return 0; 1054 } 1055 1056 #undef MAX /* in case we inherited them from somewhere */ 1057 #undef MIN 1058 1059 #define MIN(a,b) (/*CONSTCOND*/((a)<=(b)) ? (a) : (b)) 1060 #define MAX(a,b) (/*CONSTCOND*/((a)>=(b)) ? (a) : (b)) 1061 1062 /* now make the compiler work for us... */ 1063 #define MIN_REDIR MIN(MIN(MIN(MIN(NTO,NFROM), MIN(NTOFD,NFROMFD)), \ 1064 MIN(MIN(NCLOBBER,NAPPEND), MIN(NHERE,NXHERE))), NFROMTO) 1065 #define MAX_REDIR MAX(MAX(MAX(MAX(NTO,NFROM), MAX(NTOFD,NFROMFD)), \ 1066 MAX(MAX(NCLOBBER,NAPPEND), MAX(NHERE,NXHERE))), NFROMTO) 1067 1068 static const char *redir_sym[MAX_REDIR - MIN_REDIR + 1] = { 1069 [NTO - MIN_REDIR]= ">", 1070 [NFROM - MIN_REDIR]= "<", 1071 [NTOFD - MIN_REDIR]= ">&", 1072 [NFROMFD - MIN_REDIR]= "<&", 1073 [NCLOBBER - MIN_REDIR]= ">|", 1074 [NAPPEND - MIN_REDIR]= ">>", 1075 [NHERE - MIN_REDIR]= "<<", 1076 [NXHERE - MIN_REDIR]= "<<", 1077 [NFROMTO - MIN_REDIR]= "<>", 1078 }; 1079 1080 int 1081 outredir(struct output *out, union node *n, int sep) 1082 { 1083 if (n == NULL) 1084 return 0; 1085 if (n->type < MIN_REDIR || n->type > MAX_REDIR || 1086 redir_sym[n->type - MIN_REDIR] == NULL) 1087 return 0; 1088 1089 if (sep) 1090 outc(sep, out); 1091 1092 /* 1093 * ugly, but all redir node types have "fd" in same slot... 1094 * (and code other places assumes it as well) 1095 */ 1096 if ((redir_sym[n->type - MIN_REDIR][0] == '<' && n->nfile.fd != 0) || 1097 (redir_sym[n->type - MIN_REDIR][0] == '>' && n->nfile.fd != 1)) 1098 outfmt(out, "%d", n->nfile.fd); 1099 1100 outstr(redir_sym[n->type - MIN_REDIR], out); 1101 1102 switch (n->type) { 1103 case NHERE: 1104 outstr("'...'", out); 1105 break; 1106 case NXHERE: 1107 outstr("...", out); 1108 break; 1109 case NTOFD: 1110 case NFROMFD: 1111 if (n->ndup.dupfd < 0) 1112 outc('-', out); 1113 else 1114 outfmt(out, "%d", n->ndup.dupfd); 1115 break; 1116 default: 1117 outstr(n->nfile.expfname, out); 1118 break; 1119 } 1120 return 1; 1121 } 1122