1 /* $NetBSD: redir.c,v 1.59 2017/11/15 09:21:48 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.59 2017/11/15 09:21:48 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 82 MKINIT 83 struct renamelist { 84 struct renamelist *next; 85 int orig; 86 int into; 87 }; 88 89 MKINIT 90 struct redirtab { 91 struct redirtab *next; 92 struct renamelist *renamed; 93 }; 94 95 96 MKINIT struct redirtab *redirlist; 97 98 /* 99 * We keep track of whether or not fd0 has been redirected. This is for 100 * background commands, where we want to redirect fd0 to /dev/null only 101 * if it hasn't already been redirected. 102 */ 103 STATIC int fd0_redirected = 0; 104 105 /* 106 * And also where to put internal use fds that should be out of the 107 * way of user defined fds (normally) 108 */ 109 STATIC int big_sh_fd = 0; 110 111 STATIC const struct renamelist *is_renamed(const struct renamelist *, int); 112 STATIC void fd_rename(struct redirtab *, int, int); 113 STATIC void free_rl(struct redirtab *, int); 114 STATIC void openredirect(union node *, char[10], int); 115 STATIC int openhere(const union node *); 116 STATIC int copyfd(int, int, int); 117 STATIC void find_big_fd(void); 118 119 120 struct shell_fds { /* keep track of internal shell fds */ 121 struct shell_fds *nxt; 122 void (*cb)(int, int); 123 int fd; 124 }; 125 126 STATIC struct shell_fds *sh_fd_list; 127 128 STATIC void renumber_sh_fd(struct shell_fds *); 129 STATIC struct shell_fds *sh_fd(int); 130 131 STATIC const struct renamelist * 132 is_renamed(const struct renamelist *rl, int fd) 133 { 134 while (rl != NULL) { 135 if (rl->orig == fd) 136 return rl; 137 rl = rl->next; 138 } 139 return NULL; 140 } 141 142 STATIC void 143 free_rl(struct redirtab *rt, int reset) 144 { 145 struct renamelist *rl, *rn = rt->renamed; 146 147 while ((rl = rn) != NULL) { 148 rn = rl->next; 149 if (rl->orig == 0) 150 fd0_redirected--; 151 if (reset) { 152 if (rl->into < 0) 153 close(rl->orig); 154 else 155 movefd(rl->into, rl->orig); 156 } 157 ckfree(rl); 158 } 159 rt->renamed = NULL; 160 } 161 162 STATIC void 163 fd_rename(struct redirtab *rt, int from, int to) 164 { 165 struct renamelist *rl = ckmalloc(sizeof(struct renamelist)); 166 167 rl->next = rt->renamed; 168 rt->renamed = rl; 169 170 rl->orig = from; 171 rl->into = to; 172 } 173 174 /* 175 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 176 * old file descriptors are stashed away so that the redirection can be 177 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 178 * standard output, and the standard error if it becomes a duplicate of 179 * stdout, is saved in memory. 180 */ 181 182 void 183 redirect(union node *redir, int flags) 184 { 185 union node *n; 186 struct redirtab *sv = NULL; 187 int i; 188 int fd; 189 char memory[10]; /* file descriptors to write to memory */ 190 191 for (i = 10 ; --i >= 0 ; ) 192 memory[i] = 0; 193 memory[1] = flags & REDIR_BACKQ; 194 if (flags & REDIR_PUSH) { 195 /* We don't have to worry about REDIR_VFORK here, as 196 * flags & REDIR_PUSH is never true if REDIR_VFORK is set. 197 */ 198 sv = ckmalloc(sizeof (struct redirtab)); 199 sv->renamed = NULL; 200 sv->next = redirlist; 201 redirlist = sv; 202 } 203 for (n = redir ; n ; n = n->nfile.next) { 204 fd = n->nfile.fd; 205 if (fd > max_user_fd) 206 max_user_fd = fd; 207 renumber_sh_fd(sh_fd(fd)); 208 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && 209 n->ndup.dupfd == fd) { 210 /* redirect from/to same file descriptor */ 211 /* make sure it stays open */ 212 if (fcntl(fd, F_SETFD, 0) < 0) 213 error("fd %d: %s", fd, strerror(errno)); 214 continue; 215 } 216 217 if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) { 218 INTOFF; 219 if (big_sh_fd < 10) 220 find_big_fd(); 221 if ((i = fcntl(fd, F_DUPFD, big_sh_fd)) == -1) { 222 switch (errno) { 223 case EBADF: 224 i = CLOSED; 225 break; 226 case EMFILE: 227 case EINVAL: 228 find_big_fd(); 229 i = fcntl(fd, F_DUPFD, big_sh_fd); 230 if (i >= 0) 231 break; 232 /* FALLTHRU */ 233 default: 234 i = errno; 235 INTON; /* XXX not needed here ? */ 236 error("%d: %s", fd, strerror(i)); 237 /* NOTREACHED */ 238 } 239 } 240 if (i >= 0) 241 (void)fcntl(i, F_SETFD, FD_CLOEXEC); 242 fd_rename(sv, fd, i); 243 INTON; 244 } 245 if (fd == 0) 246 fd0_redirected++; 247 openredirect(n, memory, flags); 248 } 249 if (memory[1]) 250 out1 = &memout; 251 if (memory[2]) 252 out2 = &memout; 253 } 254 255 256 STATIC void 257 openredirect(union node *redir, char memory[10], int flags) 258 { 259 struct stat sb; 260 int fd = redir->nfile.fd; 261 char *fname; 262 int f; 263 int eflags, cloexec; 264 265 /* 266 * We suppress interrupts so that we won't leave open file 267 * descriptors around. This may not be such a good idea because 268 * an open of a device or a fifo can block indefinitely. 269 */ 270 INTOFF; 271 if (fd < 10) 272 memory[fd] = 0; 273 switch (redir->nfile.type) { 274 case NFROM: 275 fname = redir->nfile.expfname; 276 if (flags & REDIR_VFORK) 277 eflags = O_NONBLOCK; 278 else 279 eflags = 0; 280 if ((f = open(fname, O_RDONLY|eflags)) < 0) 281 goto eopen; 282 VTRACE(DBG_REDIR, ("openredirect(< '%s') -> %d [%#x]", 283 fname, f, eflags)); 284 if (eflags) 285 (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags); 286 break; 287 case NFROMTO: 288 fname = redir->nfile.expfname; 289 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) 290 goto ecreate; 291 VTRACE(DBG_REDIR, ("openredirect(<> '%s') -> %d", fname, f)); 292 break; 293 case NTO: 294 if (Cflag) { 295 fname = redir->nfile.expfname; 296 if ((f = open(fname, O_WRONLY)) == -1) { 297 if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 298 0666)) < 0) 299 goto ecreate; 300 } else if (fstat(f, &sb) == -1) { 301 int serrno = errno; 302 close(f); 303 errno = serrno; 304 goto ecreate; 305 } else if (S_ISREG(sb.st_mode)) { 306 close(f); 307 errno = EEXIST; 308 goto ecreate; 309 } 310 break; 311 } 312 /* FALLTHROUGH */ 313 case NCLOBBER: 314 fname = redir->nfile.expfname; 315 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 316 goto ecreate; 317 VTRACE(DBG_REDIR, ("openredirect(> '%s') -> %d", fname, f)); 318 break; 319 case NAPPEND: 320 fname = redir->nfile.expfname; 321 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) 322 goto ecreate; 323 VTRACE(DBG_REDIR, ("openredirect(>> '%s') -> %d", fname, f)); 324 break; 325 case NTOFD: 326 case NFROMFD: 327 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 328 if (fd < 10 && redir->ndup.dupfd < 10 && 329 memory[redir->ndup.dupfd]) 330 memory[fd] = 1; 331 else if (copyfd(redir->ndup.dupfd, fd, 332 (flags & REDIR_KEEP) == 0) < 0) 333 error("Redirect (from %d to %d) failed: %s", 334 redir->ndup.dupfd, fd, strerror(errno)); 335 VTRACE(DBG_REDIR, ("openredirect: %d%c&%d\n", fd, 336 "<>"[redir->nfile.type==NTOFD], redir->ndup.dupfd)); 337 } else { 338 (void) close(fd); 339 VTRACE(DBG_REDIR, ("openredirect: %d%c&-\n", fd, 340 "<>"[redir->nfile.type==NTOFD])); 341 } 342 INTON; 343 return; 344 case NHERE: 345 case NXHERE: 346 f = openhere(redir); 347 VTRACE(DBG_REDIR, ("openredirect: %d<<...", fd)); 348 break; 349 default: 350 abort(); 351 } 352 353 cloexec = fd > 2 && (flags & REDIR_KEEP) == 0 && !posix; 354 if (f != fd) { 355 VTRACE(DBG_REDIR, (" -> %d", fd)); 356 if (copyfd(f, fd, cloexec) < 0) { 357 int e = errno; 358 359 close(f); 360 error("redirect reassignment (fd %d) failed: %s", fd, 361 strerror(e)); 362 } 363 close(f); 364 } else if (cloexec) 365 (void)fcntl(f, F_SETFD, FD_CLOEXEC); 366 VTRACE(DBG_REDIR, ("%s\n", cloexec ? " cloexec" : "")); 367 368 INTON; 369 return; 370 ecreate: 371 exerrno = 1; 372 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 373 eopen: 374 exerrno = 1; 375 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 376 } 377 378 379 /* 380 * Handle here documents. Normally we fork off a process to write the 381 * data to a pipe. If the document is short, we can stuff the data in 382 * the pipe without forking. 383 */ 384 385 STATIC int 386 openhere(const union node *redir) 387 { 388 int pip[2]; 389 int len = 0; 390 391 if (pipe(pip) < 0) 392 error("Pipe call failed"); 393 if (redir->type == NHERE) { 394 len = strlen(redir->nhere.doc->narg.text); 395 if (len <= PIPESIZE) { 396 xwrite(pip[1], redir->nhere.doc->narg.text, len); 397 goto out; 398 } 399 } 400 if (forkshell(NULL, NULL, FORK_NOJOB) == 0) { 401 close(pip[0]); 402 signal(SIGINT, SIG_IGN); 403 signal(SIGQUIT, SIG_IGN); 404 signal(SIGHUP, SIG_IGN); 405 #ifdef SIGTSTP 406 signal(SIGTSTP, SIG_IGN); 407 #endif 408 signal(SIGPIPE, SIG_DFL); 409 if (redir->type == NHERE) 410 xwrite(pip[1], redir->nhere.doc->narg.text, len); 411 else 412 expandhere(redir->nhere.doc, pip[1]); 413 _exit(0); 414 } 415 out: 416 close(pip[1]); 417 return pip[0]; 418 } 419 420 421 422 /* 423 * Undo the effects of the last redirection. 424 */ 425 426 void 427 popredir(void) 428 { 429 struct redirtab *rp = redirlist; 430 431 INTOFF; 432 free_rl(rp, 1); 433 redirlist = rp->next; 434 ckfree(rp); 435 INTON; 436 } 437 438 /* 439 * Undo all redirections. Called on error or interrupt. 440 */ 441 442 #ifdef mkinit 443 444 INCLUDE "redir.h" 445 446 RESET { 447 while (redirlist) 448 popredir(); 449 } 450 451 SHELLPROC { 452 clearredir(0); 453 } 454 455 #endif 456 457 /* Return true if fd 0 has already been redirected at least once. */ 458 int 459 fd0_redirected_p(void) 460 { 461 return fd0_redirected != 0; 462 } 463 464 /* 465 * Discard all saved file descriptors. 466 */ 467 468 void 469 clearredir(int vforked) 470 { 471 struct redirtab *rp; 472 struct renamelist *rl; 473 474 for (rp = redirlist ; rp ; rp = rp->next) { 475 if (!vforked) 476 free_rl(rp, 0); 477 else for (rl = rp->renamed; rl; rl = rl->next) 478 if (rl->into >= 0) 479 close(rl->into); 480 } 481 } 482 483 484 485 /* 486 * Copy a file descriptor to be == to. 487 * cloexec indicates if we want close-on-exec or not. 488 * Returns -1 if any error occurs. 489 */ 490 491 STATIC int 492 copyfd(int from, int to, int cloexec) 493 { 494 int newfd; 495 496 if (cloexec && to > 2) 497 newfd = dup3(from, to, O_CLOEXEC); 498 else 499 newfd = dup2(from, to); 500 501 return newfd; 502 } 503 504 /* 505 * rename fd from to be fd to (closing from). 506 * close-on-exec is never set on 'to' (unless 507 * from==to and it was set on from) - ie: a no-op 508 * returns to (or errors() if an error occurs). 509 * 510 * This is mostly used for rearranging the 511 * results from pipe(). 512 */ 513 int 514 movefd(int from, int to) 515 { 516 if (from == to) 517 return to; 518 519 (void) close(to); 520 if (copyfd(from, to, 0) != to) { 521 int e = errno; 522 523 (void) close(from); 524 error("Unable to make fd %d: %s", to, strerror(e)); 525 } 526 (void) close(from); 527 528 return to; 529 } 530 531 STATIC void 532 find_big_fd(void) 533 { 534 int i, fd; 535 static int last_start = 3; /* aim to keep sh fd's under 20 */ 536 537 if (last_start < 10) 538 last_start++; 539 540 for (i = (1 << last_start); i >= 10; i >>= 1) { 541 if ((fd = fcntl(0, F_DUPFD, i - 1)) >= 0) { 542 close(fd); 543 break; 544 } 545 } 546 547 fd = (i / 5) * 4; 548 if (fd < 10) 549 fd = 10; 550 551 big_sh_fd = fd; 552 } 553 554 /* 555 * If possible, move file descriptor fd out of the way 556 * of expected user fd values. Returns the new fd 557 * (which may be the input fd if things do not go well.) 558 * Always set close-on-exec on the result, and close 559 * the input fd unless it is to be our result. 560 */ 561 int 562 to_upper_fd(int fd) 563 { 564 int i; 565 566 VTRACE(DBG_REDIR|DBG_OUTPUT, ("to_upper_fd(%d)", fd)); 567 if (big_sh_fd < 10) 568 find_big_fd(); 569 do { 570 i = fcntl(fd, F_DUPFD_CLOEXEC, big_sh_fd); 571 if (i >= 0) { 572 if (fd != i) 573 close(fd); 574 VTRACE(DBG_REDIR|DBG_OUTPUT, ("-> %d\n", i)); 575 return i; 576 } 577 if (errno != EMFILE && errno != EINVAL) 578 break; 579 find_big_fd(); 580 } while (big_sh_fd > 10); 581 582 /* 583 * If we wanted to move this fd to some random high number 584 * we certainly do not intend to pass it through exec, even 585 * if the reassignment failed. 586 */ 587 (void)fcntl(fd, F_SETFD, FD_CLOEXEC); 588 VTRACE(DBG_REDIR|DBG_OUTPUT, (" fails ->%d\n", fd)); 589 return fd; 590 } 591 592 void 593 register_sh_fd(int fd, void (*cb)(int, int)) 594 { 595 struct shell_fds *fp; 596 597 fp = ckmalloc(sizeof (struct shell_fds)); 598 if (fp != NULL) { 599 fp->nxt = sh_fd_list; 600 sh_fd_list = fp; 601 602 fp->fd = fd; 603 fp->cb = cb; 604 } 605 } 606 607 void 608 sh_close(int fd) 609 { 610 struct shell_fds **fpp, *fp; 611 612 fpp = &sh_fd_list; 613 while ((fp = *fpp) != NULL) { 614 if (fp->fd == fd) { 615 *fpp = fp->nxt; 616 ckfree(fp); 617 break; 618 } 619 fpp = &fp->nxt; 620 } 621 (void)close(fd); 622 } 623 624 STATIC struct shell_fds * 625 sh_fd(int fd) 626 { 627 struct shell_fds *fp; 628 629 for (fp = sh_fd_list; fp != NULL; fp = fp->nxt) 630 if (fp->fd == fd) 631 return fp; 632 return NULL; 633 } 634 635 STATIC void 636 renumber_sh_fd(struct shell_fds *fp) 637 { 638 int to; 639 640 if (fp == NULL) 641 return; 642 643 #ifndef F_DUPFD_CLOEXEC 644 #define F_DUPFD_CLOEXEC F_DUPFD 645 #define CLOEXEC(fd) (fcntl((fd), F_SETFD, fcntl((fd),F_GETFD) | FD_CLOEXEC)) 646 #else 647 #define CLOEXEC(fd) 648 #endif 649 650 /* 651 * if we have had a collision, and the sh fd was a "big" one 652 * try moving the sh fd base to a higher number (if possible) 653 * so future sh fds are less likely to be in the user's sights 654 * (incl this one when moved) 655 */ 656 if (fp->fd >= big_sh_fd) 657 find_big_fd(); 658 659 to = fcntl(fp->fd, F_DUPFD_CLOEXEC, big_sh_fd); 660 if (to == -1) 661 to = fcntl(fp->fd, F_DUPFD_CLOEXEC, big_sh_fd/2); 662 if (to == -1) 663 to = fcntl(fp->fd, F_DUPFD_CLOEXEC, fp->fd + 1); 664 if (to == -1) 665 to = fcntl(fp->fd, F_DUPFD_CLOEXEC, 10); 666 if (to == -1) 667 to = fcntl(fp->fd, F_DUPFD_CLOEXEC, 3); 668 if (to == -1) 669 error("insufficient file descriptors available"); 670 CLOEXEC(to); 671 672 if (fp->fd == to) /* impossible? */ 673 return; 674 675 (*fp->cb)(fp->fd, to); 676 (void)close(fp->fd); 677 fp->fd = to; 678 } 679 680 static const struct flgnames { 681 const char *name; 682 uint16_t minch; 683 uint32_t value; 684 } nv[] = { 685 #ifdef O_APPEND 686 { "append", 2, O_APPEND }, 687 #endif 688 #ifdef O_ASYNC 689 { "async", 2, O_ASYNC }, 690 #endif 691 #ifdef O_SYNC 692 { "sync", 2, O_SYNC }, 693 #endif 694 #ifdef O_NONBLOCK 695 { "nonblock", 3, O_NONBLOCK }, 696 #endif 697 #ifdef O_FSYNC 698 { "fsync", 2, O_FSYNC }, 699 #endif 700 #ifdef O_DSYNC 701 { "dsync", 2, O_DSYNC }, 702 #endif 703 #ifdef O_RSYNC 704 { "rsync", 2, O_RSYNC }, 705 #endif 706 #ifdef O_ALTIO 707 { "altio", 2, O_ALT_IO }, 708 #endif 709 #ifdef O_DIRECT 710 { "direct", 2, O_DIRECT }, 711 #endif 712 #ifdef O_NOSIGPIPE 713 { "nosigpipe", 3, O_NOSIGPIPE }, 714 #endif 715 #ifdef O_CLOEXEC 716 { "cloexec", 2, O_CLOEXEC }, 717 #endif 718 { 0, 0, 0 } 719 }; 720 #define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_DSYNC|O_RSYNC|\ 721 O_ALT_IO|O_DIRECT|O_NOSIGPIPE|O_CLOEXEC) 722 723 static int 724 getflags(int fd, int p) 725 { 726 int c, f; 727 728 if (sh_fd(fd) != NULL) { 729 if (!p) 730 return -1; 731 error("Can't get status for fd=%d (%s)", fd, 732 "Bad file descriptor"); /*XXX*/ 733 } 734 735 if ((c = fcntl(fd, F_GETFD)) == -1) { 736 if (!p) 737 return -1; 738 error("Can't get status for fd=%d (%s)", fd, strerror(errno)); 739 } 740 if ((f = fcntl(fd, F_GETFL)) == -1) { 741 if (!p) 742 return -1; 743 error("Can't get flags for fd=%d (%s)", fd, strerror(errno)); 744 } 745 if (c & FD_CLOEXEC) 746 f |= O_CLOEXEC; 747 return f & ALLFLAGS; 748 } 749 750 static void 751 printone(int fd, int p, int verbose, int pfd) 752 { 753 int f = getflags(fd, p); 754 const struct flgnames *fn; 755 756 if (f == -1) 757 return; 758 759 if (pfd) 760 outfmt(out1, "%d: ", fd); 761 for (fn = nv; fn->name; fn++) { 762 if (f & fn->value) { 763 outfmt(out1, "%s%s", verbose ? "+" : "", fn->name); 764 f &= ~fn->value; 765 } else if (verbose) 766 outfmt(out1, "-%s", fn->name); 767 else 768 continue; 769 if (f || (verbose && fn[1].name)) 770 outfmt(out1, ","); 771 } 772 if (verbose && f) /* f should be normally be 0 */ 773 outfmt(out1, " +%#x", f); 774 outfmt(out1, "\n"); 775 } 776 777 static void 778 parseflags(char *s, int *p, int *n) 779 { 780 int *v, *w; 781 const struct flgnames *fn; 782 size_t len; 783 784 *p = 0; 785 *n = 0; 786 for (s = strtok(s, ","); s; s = strtok(NULL, ",")) { 787 switch (*s++) { 788 case '+': 789 v = p; 790 w = n; 791 break; 792 case '-': 793 v = n; 794 w = p; 795 break; 796 default: 797 error("Missing +/- indicator before flag %s", s-1); 798 } 799 800 len = strlen(s); 801 for (fn = nv; fn->name; fn++) 802 if (len >= fn->minch && strncmp(s,fn->name,len) == 0) { 803 *v |= fn->value; 804 *w &=~ fn->value; 805 break; 806 } 807 if (fn->name == 0) 808 error("Bad flag `%s'", s); 809 } 810 } 811 812 static void 813 setone(int fd, int pos, int neg, int verbose) 814 { 815 int f = getflags(fd, 1); 816 int n, cloexec; 817 818 if (f == -1) 819 return; 820 821 cloexec = -1; 822 if ((pos & O_CLOEXEC) && !(f & O_CLOEXEC)) 823 cloexec = FD_CLOEXEC; 824 if ((neg & O_CLOEXEC) && (f & O_CLOEXEC)) 825 cloexec = 0; 826 827 if (cloexec != -1 && fcntl(fd, F_SETFD, cloexec) == -1) 828 error("Can't set status for fd=%d (%s)", fd, strerror(errno)); 829 830 pos &= ~O_CLOEXEC; 831 neg &= ~O_CLOEXEC; 832 f &= ~O_CLOEXEC; 833 n = f; 834 n |= pos; 835 n &= ~neg; 836 if (n != f && fcntl(fd, F_SETFL, n) == -1) 837 error("Can't set flags for fd=%d (%s)", fd, strerror(errno)); 838 if (verbose) 839 printone(fd, 1, verbose, 1); 840 } 841 842 int 843 fdflagscmd(int argc, char *argv[]) 844 { 845 char *num; 846 int verbose = 0, ch, pos = 0, neg = 0; 847 char *setflags = NULL; 848 849 optreset = 1; optind = 1; /* initialize getopt */ 850 while ((ch = getopt(argc, argv, ":vs:")) != -1) 851 switch ((char)ch) { 852 case 'v': 853 verbose = 1; 854 break; 855 case 's': 856 if (setflags) 857 goto msg; 858 setflags = optarg; 859 break; 860 case '?': 861 default: 862 msg: 863 error("Usage: fdflags [-v] [-s <flags> fd] [fd...]"); 864 /* NOTREACHED */ 865 } 866 867 argc -= optind, argv += optind; 868 869 if (setflags) 870 parseflags(setflags, &pos, &neg); 871 872 if (argc == 0) { 873 int i; 874 875 if (setflags) 876 goto msg; 877 878 for (i = 0; i <= max_user_fd; i++) 879 printone(i, 0, verbose, 1); 880 return 0; 881 } 882 883 while ((num = *argv++) != NULL) { 884 int fd = number(num); 885 886 while (num[0] == '0' && num[1] != '\0') /* skip 0's */ 887 num++; 888 if (strlen(num) > 5) 889 error("%s too big to be a file descriptor", num); 890 891 if (setflags) 892 setone(fd, pos, neg, verbose); 893 else 894 printone(fd, 1, verbose, argc > 1); 895 } 896 return 0; 897 } 898 899 #undef MAX /* in case we inherited them from somewhere */ 900 #undef MIN 901 902 #define MIN(a,b) (/*CONSTCOND*/((a)<=(b)) ? (a) : (b)) 903 #define MAX(a,b) (/*CONSTCOND*/((a)>=(b)) ? (a) : (b)) 904 905 /* now make the compiler work for us... */ 906 #define MIN_REDIR MIN(MIN(MIN(MIN(NTO,NFROM), MIN(NTOFD,NFROMFD)), \ 907 MIN(MIN(NCLOBBER,NAPPEND), MIN(NHERE,NXHERE))), NFROMTO) 908 #define MAX_REDIR MAX(MAX(MAX(MAX(NTO,NFROM), MAX(NTOFD,NFROMFD)), \ 909 MAX(MAX(NCLOBBER,NAPPEND), MAX(NHERE,NXHERE))), NFROMTO) 910 911 static const char *redir_sym[MAX_REDIR - MIN_REDIR + 1] = { 912 [NTO - MIN_REDIR]= ">", 913 [NFROM - MIN_REDIR]= "<", 914 [NTOFD - MIN_REDIR]= ">&", 915 [NFROMFD - MIN_REDIR]= "<&", 916 [NCLOBBER - MIN_REDIR]= ">|", 917 [NAPPEND - MIN_REDIR]= ">>", 918 [NHERE - MIN_REDIR]= "<<", 919 [NXHERE - MIN_REDIR]= "<<", 920 [NFROMTO - MIN_REDIR]= "<>", 921 }; 922 923 int 924 outredir(struct output *out, union node *n, int sep) 925 { 926 if (n == NULL) 927 return 0; 928 if (n->type < MIN_REDIR || n->type > MAX_REDIR || 929 redir_sym[n->type - MIN_REDIR] == NULL) 930 return 0; 931 932 if (sep) 933 outc(sep, out); 934 935 /* 936 * ugly, but all redir node types have "fd" in same slot... 937 * (and code other places assumes it as well) 938 */ 939 if ((redir_sym[n->type - MIN_REDIR][0] == '<' && n->nfile.fd != 0) || 940 (redir_sym[n->type - MIN_REDIR][0] == '>' && n->nfile.fd != 1)) 941 outfmt(out, "%d", n->nfile.fd); 942 943 outstr(redir_sym[n->type - MIN_REDIR], out); 944 945 switch (n->type) { 946 case NHERE: 947 outstr("'...'", out); 948 break; 949 case NXHERE: 950 outstr("...", out); 951 break; 952 case NTOFD: 953 case NFROMFD: 954 if (n->ndup.dupfd < 0) 955 outc('-', out); 956 else 957 outfmt(out, "%d", n->ndup.dupfd); 958 break; 959 default: 960 outstr(n->nfile.expfname, out); 961 break; 962 } 963 return 1; 964 } 965