1*1c3b0983Skre /* $NetBSD: redir.c,v 1.76 2024/11/11 22:57:42 kre Exp $ */ 249f0ad86Scgd 361f28255Scgd /*- 437ed7877Sjtc * Copyright (c) 1991, 1993 537ed7877Sjtc * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * This code is derived from software contributed to Berkeley by 861f28255Scgd * Kenneth Almquist. 961f28255Scgd * 1061f28255Scgd * Redistribution and use in source and binary forms, with or without 1161f28255Scgd * modification, are permitted provided that the following conditions 1261f28255Scgd * are met: 1361f28255Scgd * 1. Redistributions of source code must retain the above copyright 1461f28255Scgd * notice, this list of conditions and the following disclaimer. 1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1661f28255Scgd * notice, this list of conditions and the following disclaimer in the 1761f28255Scgd * documentation and/or other materials provided with the distribution. 18b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors 1961f28255Scgd * may be used to endorse or promote products derived from this software 2061f28255Scgd * without specific prior written permission. 2161f28255Scgd * 2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3261f28255Scgd * SUCH DAMAGE. 3361f28255Scgd */ 3461f28255Scgd 35cd799663Schristos #include <sys/cdefs.h> 3661f28255Scgd #ifndef lint 3749f0ad86Scgd #if 0 3807bae7edSchristos static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; 3949f0ad86Scgd #else 40*1c3b0983Skre __RCSID("$NetBSD: redir.c,v 1.76 2024/11/11 22:57:42 kre Exp $"); 4149f0ad86Scgd #endif 4261f28255Scgd #endif /* not lint */ 4361f28255Scgd 4407bae7edSchristos #include <sys/types.h> 45d06f1504Schristos #include <sys/param.h> /* PIPE_BUF */ 467792ef1aSchristos #include <sys/stat.h> 4707bae7edSchristos #include <signal.h> 4807bae7edSchristos #include <string.h> 4907bae7edSchristos #include <fcntl.h> 5007bae7edSchristos #include <errno.h> 5107bae7edSchristos #include <unistd.h> 5207bae7edSchristos #include <stdlib.h> 5307bae7edSchristos 5461f28255Scgd /* 5561f28255Scgd * Code for dealing with input/output redirection. 5661f28255Scgd */ 5761f28255Scgd 586f482334Schristos #include "main.h" 59168f1d4aSchristos #include "builtins.h" 6061f28255Scgd #include "shell.h" 6161f28255Scgd #include "nodes.h" 6261f28255Scgd #include "jobs.h" 63f629aa28Schristos #include "options.h" 6461f28255Scgd #include "expand.h" 6561f28255Scgd #include "redir.h" 6661f28255Scgd #include "output.h" 6761f28255Scgd #include "memalloc.h" 680ff2aa10Skre #include "mystring.h" 6961f28255Scgd #include "error.h" 70b86d4a74Skre #include "show.h" 7161f28255Scgd 7261f28255Scgd 7344f76837Syamt #define CLOSED -1 /* fd was not open before redir */ 74*1c3b0983Skre 75d06f1504Schristos #ifndef PIPE_BUF 7661f28255Scgd # define PIPESIZE 4096 /* amount of buffering in a pipe */ 77d06f1504Schristos #else 78d06f1504Schristos # define PIPESIZE PIPE_BUF 79d06f1504Schristos #endif 8061f28255Scgd 81f2dc7540Skre #ifndef FD_CLOEXEC 82f2dc7540Skre # define FD_CLOEXEC 1 /* well known from before there was a name */ 83f2dc7540Skre #endif 84f2dc7540Skre 85f2dc7540Skre #ifndef F_DUPFD_CLOEXEC 86f2dc7540Skre #define F_DUPFD_CLOEXEC F_DUPFD 87*1c3b0983Skre #define CLOEXEC(fd) (fcntl((fd), F_SETFD, \ 88*1c3b0983Skre (fcntl_int)(fcntl((fd), F_GETFD) | FD_CLOEXEC))) 89f2dc7540Skre #else 90*1c3b0983Skre #define CLOEXEC(fd) __nothing 91f2dc7540Skre #endif 92f2dc7540Skre 93*1c3b0983Skre /* yes, this is correct, bizarre parens and all -- used only as a cast */ 94*1c3b0983Skre #define fcntl_int void *)(intptr_t 95*1c3b0983Skre #undef fcntl_int 96*1c3b0983Skre #define fcntl_int int 97*1c3b0983Skre 9861f28255Scgd 9961f28255Scgd MKINIT 1001fad4bb6Schristos struct renamelist { 1011fad4bb6Schristos struct renamelist *next; 1021fad4bb6Schristos int orig; 1031fad4bb6Schristos int into; 104*1c3b0983Skre int cloexec; /* orig had FD_CLOEXEC set (into always does) */ 1051fad4bb6Schristos }; 1061fad4bb6Schristos 1071fad4bb6Schristos MKINIT 10861f28255Scgd struct redirtab { 10961f28255Scgd struct redirtab *next; 1101fad4bb6Schristos struct renamelist *renamed; 11161f28255Scgd }; 11261f28255Scgd 11361f28255Scgd 11461f28255Scgd MKINIT struct redirtab *redirlist; 11561f28255Scgd 11637ed7877Sjtc /* 11737ed7877Sjtc * We keep track of whether or not fd0 has been redirected. This is for 11837ed7877Sjtc * background commands, where we want to redirect fd0 to /dev/null only 11937ed7877Sjtc * if it hasn't already been redirected. 12037ed7877Sjtc */ 1211fad4bb6Schristos STATIC int fd0_redirected = 0; 12261f28255Scgd 1231fad4bb6Schristos /* 1241fad4bb6Schristos * And also where to put internal use fds that should be out of the 1251fad4bb6Schristos * way of user defined fds (normally) 1261fad4bb6Schristos */ 1271fad4bb6Schristos STATIC int big_sh_fd = 0; 128*1c3b0983Skre STATIC int biggest_sh_fd = 2; 1291fad4bb6Schristos 1301fad4bb6Schristos STATIC const struct renamelist *is_renamed(const struct renamelist *, int); 131*1c3b0983Skre STATIC void fd_rename(struct redirtab *, int, int, int); 13252967993Skre STATIC int * saved_redirected_fd(int); 1331fad4bb6Schristos STATIC void free_rl(struct redirtab *, int); 1345dd90992Schristos STATIC void openredirect(union node *, char[10], int); 135071e965cSyamt STATIC int openhere(const union node *); 136*1c3b0983Skre STATIC int copyfd(int, int, int, int); 1371fad4bb6Schristos STATIC void find_big_fd(void); 13861f28255Scgd 13951c4dfe4Skre 14051c4dfe4Skre struct shell_fds { /* keep track of internal shell fds */ 14151c4dfe4Skre struct shell_fds *nxt; 14251c4dfe4Skre void (*cb)(int, int); 14351c4dfe4Skre int fd; 14451c4dfe4Skre }; 14551c4dfe4Skre 14651c4dfe4Skre STATIC struct shell_fds *sh_fd_list; 14751c4dfe4Skre 14852967993Skre STATIC int pick_new_fd(int); 14951c4dfe4Skre STATIC void renumber_sh_fd(struct shell_fds *); 15051c4dfe4Skre STATIC struct shell_fds *sh_fd(int); 15151c4dfe4Skre 1521fad4bb6Schristos STATIC const struct renamelist * 1531fad4bb6Schristos is_renamed(const struct renamelist *rl, int fd) 1541fad4bb6Schristos { 1551fad4bb6Schristos while (rl != NULL) { 1561fad4bb6Schristos if (rl->orig == fd) 1571fad4bb6Schristos return rl; 1581fad4bb6Schristos rl = rl->next; 1591fad4bb6Schristos } 1601fad4bb6Schristos return NULL; 1611fad4bb6Schristos } 1621fad4bb6Schristos 16352967993Skre STATIC int * 16452967993Skre saved_redirected_fd(int fd) 16552967993Skre { 16652967993Skre struct redirtab *rt; 16752967993Skre struct renamelist *rl; 16852967993Skre 16952967993Skre for (rt = redirlist; rt != NULL; rt = rt->next) { 17052967993Skre for (rl = rt->renamed; rl != NULL; rl = rl->next) { 17152967993Skre if (rl->into == fd) 17252967993Skre return &rl->into; 17352967993Skre } 17452967993Skre } 17552967993Skre return NULL; 17652967993Skre } 17752967993Skre 1781fad4bb6Schristos STATIC void 1791fad4bb6Schristos free_rl(struct redirtab *rt, int reset) 1801fad4bb6Schristos { 1811fad4bb6Schristos struct renamelist *rl, *rn = rt->renamed; 1821fad4bb6Schristos 1831fad4bb6Schristos while ((rl = rn) != NULL) { 1841fad4bb6Schristos rn = rl->next; 185*1c3b0983Skre 1861fad4bb6Schristos if (rl->orig == 0) 1871fad4bb6Schristos fd0_redirected--; 188*1c3b0983Skre 189ab6821e0Skre VTRACE(DBG_REDIR, ("popredir %d%s: %s", 190ab6821e0Skre rl->orig, rl->orig==0 ? " (STDIN)" : "", 191*1c3b0983Skre reset == POPREDIR_UNDO ? "" : 192*1c3b0983Skre reset == POPREDIR_PERMANENT ? "make permanent" : 193*1c3b0983Skre "no reset\n")); 194*1c3b0983Skre 195*1c3b0983Skre switch (reset) { 196*1c3b0983Skre case POPREDIR_UNDO: 197ab6821e0Skre if (rl->into < 0) { 198ab6821e0Skre VTRACE(DBG_REDIR, (" closed\n")); 1991fad4bb6Schristos close(rl->orig); 200ab6821e0Skre } else { 201*1c3b0983Skre VTRACE(DBG_REDIR, 202*1c3b0983Skre (" from %d%s\n", rl->into, 203*1c3b0983Skre rl->cloexec ? " (colexec)" : "")); 204*1c3b0983Skre copyfd(rl->into, rl->orig, rl->cloexec, 1); 2051fad4bb6Schristos } 206*1c3b0983Skre break; 207*1c3b0983Skre 208*1c3b0983Skre case POPREDIR_PERMANENT: 209*1c3b0983Skre if (rl->into < 0) { 210*1c3b0983Skre VTRACE(DBG_REDIR, (" was closed\n")); 211*1c3b0983Skre /* nothing to do */ 212*1c3b0983Skre } else { 213*1c3b0983Skre VTRACE(DBG_REDIR, 214*1c3b0983Skre (" close savefd %d\n", rl->into)); 215*1c3b0983Skre close(rl->into); 216*1c3b0983Skre } 217*1c3b0983Skre break; 218*1c3b0983Skre 219*1c3b0983Skre default: 220*1c3b0983Skre /* nothing to do */ 221*1c3b0983Skre break; 222ab6821e0Skre } 2231fad4bb6Schristos ckfree(rl); 2241fad4bb6Schristos } 2251fad4bb6Schristos rt->renamed = NULL; 2261fad4bb6Schristos } 2271fad4bb6Schristos 2281fad4bb6Schristos STATIC void 229*1c3b0983Skre fd_rename(struct redirtab *rt, int from, int to, int cloexec) 2301fad4bb6Schristos { 231ab6821e0Skre /* XXX someday keep a short list (8..10) of freed renamelists XXX */ 2321fad4bb6Schristos struct renamelist *rl = ckmalloc(sizeof(struct renamelist)); 2331fad4bb6Schristos 234*1c3b0983Skre /* 235*1c3b0983Skre * Note this list is operated as LIFO so saved fd's are 236*1c3b0983Skre * undone in the opposite order to that they were saved 237*1c3b0983Skre * (needed to ensure correct results) 238*1c3b0983Skre */ 2391fad4bb6Schristos rl->next = rt->renamed; 2401fad4bb6Schristos rt->renamed = rl; 2411fad4bb6Schristos 2421fad4bb6Schristos rl->orig = from; 2431fad4bb6Schristos rl->into = to; 244*1c3b0983Skre rl->cloexec = cloexec; 2451fad4bb6Schristos } 24661f28255Scgd 24761f28255Scgd /* 24861f28255Scgd * Process a list of redirection commands. If the REDIR_PUSH flag is set, 24961f28255Scgd * old file descriptors are stashed away so that the redirection can be 25061f28255Scgd * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 25161f28255Scgd * standard output, and the standard error if it becomes a duplicate of 25261f28255Scgd * stdout, is saved in memory. 25361f28255Scgd */ 25461f28255Scgd 25561f28255Scgd void 256c02b3bbdSchristos redirect(union node *redir, int flags) 25761f28255Scgd { 25861f28255Scgd union node *n; 259cd799663Schristos struct redirtab *sv = NULL; 26061f28255Scgd int i; 26161f28255Scgd int fd; 26261f28255Scgd char memory[10]; /* file descriptors to write to memory */ 26361f28255Scgd 264ab6821e0Skre CTRACE(DBG_REDIR, ("redirect(F=0x%x):%s\n", flags, redir?"":" NONE")); 265*1c3b0983Skre 26661f28255Scgd for (i = 10 ; --i >= 0 ; ) 26761f28255Scgd memory[i] = 0; 26861f28255Scgd memory[1] = flags & REDIR_BACKQ; 26961f28255Scgd if (flags & REDIR_PUSH) { 270ab6821e0Skre /* 271ab6821e0Skre * We don't have to worry about REDIR_VFORK here, as 272edcb4544Schristos * flags & REDIR_PUSH is never true if REDIR_VFORK is set. 273edcb4544Schristos */ 27461f28255Scgd sv = ckmalloc(sizeof (struct redirtab)); 2751fad4bb6Schristos sv->renamed = NULL; 27661f28255Scgd sv->next = redirlist; 27761f28255Scgd redirlist = sv; 27861f28255Scgd } 27961f28255Scgd for (n = redir ; n ; n = n->nfile.next) { 28052967993Skre int *renamed; 28152967993Skre 28261f28255Scgd fd = n->nfile.fd; 28352967993Skre VTRACE(DBG_REDIR, ("redir %d (max=%d limit=%ld) ", 28452967993Skre fd, max_user_fd, user_fd_limit)); 28552967993Skre if (fd < user_fd_limit && fd > max_user_fd) 286c1cbf199Skre max_user_fd = fd; 28751a7b242Skre if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && 28851a7b242Skre n->ndup.dupfd == fd) { 28951a7b242Skre VTRACE(DBG_REDIR, ("!cloexec\n")); 29051a7b242Skre if (sh_fd(fd) != NULL || 29151a7b242Skre saved_redirected_fd(fd) != NULL) 29251a7b242Skre error("fd %d: %s", fd, strerror(EBADF)); 29351a7b242Skre /* redirect from/to same file descriptor */ 29451a7b242Skre /* make sure it stays open */ 295*1c3b0983Skre if (fcntl(fd, F_SETFD, (fcntl_int)0) < 0) 29651a7b242Skre error("fd %d: %s", fd, strerror(errno)); 29751a7b242Skre continue; 29851a7b242Skre } 29952967993Skre if ((renamed = saved_redirected_fd(fd)) != NULL) { 30052967993Skre int to = pick_new_fd(fd); 30152967993Skre 30252967993Skre VTRACE(DBG_REDIR, 30352967993Skre ("redirect: moved holding fd %d to %d\n", fd, to)); 30452967993Skre *renamed = to; 30552967993Skre if (to != fd) /* always... */ 30652967993Skre (void)close(fd); 30752967993Skre } 30851c4dfe4Skre renumber_sh_fd(sh_fd(fd)); 309fb758fd8Schristos 3101fad4bb6Schristos if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) { 311c88e74efSkre int bigfd; 312*1c3b0983Skre int cloexec; 313*1c3b0983Skre 314*1c3b0983Skre cloexec = fcntl(fd, F_GETFD); 315*1c3b0983Skre if (cloexec >= 0) 316*1c3b0983Skre cloexec &= FD_CLOEXEC; 317*1c3b0983Skre else 318*1c3b0983Skre cloexec = 0; 319c88e74efSkre 32061f28255Scgd INTOFF; 3211fad4bb6Schristos if (big_sh_fd < 10) 3221fad4bb6Schristos find_big_fd(); 323c88e74efSkre if ((bigfd = big_sh_fd) < max_user_fd) 324c88e74efSkre bigfd = max_user_fd; 325*1c3b0983Skre if ((i = fcntl(fd, F_DUPFD, 326*1c3b0983Skre (fcntl_int)(bigfd + 1))) == -1) { 327fb758fd8Schristos switch (errno) { 328fb758fd8Schristos case EBADF: 32944f76837Syamt i = CLOSED; 33044f76837Syamt break; 3311fad4bb6Schristos case EMFILE: 3321fad4bb6Schristos case EINVAL: 3331fad4bb6Schristos find_big_fd(); 334*1c3b0983Skre i = fcntl(fd, F_DUPFD, 335*1c3b0983Skre (fcntl_int) big_sh_fd); 3361fad4bb6Schristos if (i >= 0) 3371fad4bb6Schristos break; 33852967993Skre if (errno == EMFILE || errno == EINVAL) 339*1c3b0983Skre i = fcntl(fd, F_DUPFD, 340*1c3b0983Skre (fcntl_int) 3); 34152967993Skre if (i >= 0) 34252967993Skre break; 3431fad4bb6Schristos /* FALLTHRU */ 344fb758fd8Schristos default: 345c88e74efSkre error("%d: %s", fd, strerror(errno)); 346ee9e50eaSmycroft /* NOTREACHED */ 347fb758fd8Schristos } 3481fad4bb6Schristos } 349*1c3b0983Skre if (i > biggest_sh_fd) 350*1c3b0983Skre biggest_sh_fd = i; 3511fad4bb6Schristos if (i >= 0) 352*1c3b0983Skre (void)fcntl(i, F_SETFD, (fcntl_int) FD_CLOEXEC); 353*1c3b0983Skre fd_rename(sv, fd, i, cloexec); 354*1c3b0983Skre VTRACE(DBG_REDIR, ("fd %d saved as %d%s ", fd, i, 355*1c3b0983Skre cloexec ? "+" : "")); 35661f28255Scgd INTON; 35761f28255Scgd } 358ab6821e0Skre VTRACE(DBG_REDIR, ("%s\n", fd == 0 ? "STDIN" : "")); 3595916a085Ssef if (fd == 0) 3605916a085Ssef fd0_redirected++; 3615dd90992Schristos openredirect(n, memory, flags); 36261f28255Scgd } 36361f28255Scgd if (memory[1]) 36461f28255Scgd out1 = &memout; 36561f28255Scgd if (memory[2]) 36661f28255Scgd out2 = &memout; 36761f28255Scgd } 36861f28255Scgd 36961f28255Scgd 37061f28255Scgd STATIC void 3715dd90992Schristos openredirect(union node *redir, char memory[10], int flags) 37261f28255Scgd { 373a2572443Schristos struct stat sb; 37461f28255Scgd int fd = redir->nfile.fd; 37561f28255Scgd char *fname; 37661f28255Scgd int f; 377e47a2585Schristos int eflags, cloexec; 37861f28255Scgd 37961f28255Scgd /* 38061f28255Scgd * We suppress interrupts so that we won't leave open file 38161f28255Scgd * descriptors around. This may not be such a good idea because 38261f28255Scgd * an open of a device or a fifo can block indefinitely. 38361f28255Scgd */ 38461f28255Scgd INTOFF; 3851fad4bb6Schristos if (fd < 10) 38661f28255Scgd memory[fd] = 0; 38761f28255Scgd switch (redir->nfile.type) { 38861f28255Scgd case NFROM: 38961f28255Scgd fname = redir->nfile.expfname; 3905dd90992Schristos if (flags & REDIR_VFORK) 3915dd90992Schristos eflags = O_NONBLOCK; 3925dd90992Schristos else 3935dd90992Schristos eflags = 0; 3945dd90992Schristos if ((f = open(fname, O_RDONLY|eflags)) < 0) 3956e50d7a8Schristos goto eopen; 396b86d4a74Skre VTRACE(DBG_REDIR, ("openredirect(< '%s') -> %d [%#x]", 397b86d4a74Skre fname, f, eflags)); 3985dd90992Schristos if (eflags) 399*1c3b0983Skre (void)fcntl(f, F_SETFL, 400*1c3b0983Skre (fcntl_int)(fcntl(f, F_GETFL) & ~eflags)); 4016e50d7a8Schristos break; 4026e50d7a8Schristos case NFROMTO: 4036e50d7a8Schristos fname = redir->nfile.expfname; 40400655d6cSkre if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0) 4056e50d7a8Schristos goto ecreate; 406b86d4a74Skre VTRACE(DBG_REDIR, ("openredirect(<> '%s') -> %d", fname, f)); 40761f28255Scgd break; 40861f28255Scgd case NTO: 409a2572443Schristos if (Cflag) { 410a2572443Schristos fname = redir->nfile.expfname; 4119e91d168Schristos if ((f = open(fname, O_WRONLY)) == -1) { 412a2572443Schristos if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 413a2572443Schristos 0666)) < 0) 414a2572443Schristos goto ecreate; 4159e91d168Schristos } else if (fstat(f, &sb) == -1) { 4169e91d168Schristos int serrno = errno; 417a2572443Schristos close(f); 4189e91d168Schristos errno = serrno; 419a2572443Schristos goto ecreate; 4209e91d168Schristos } else if (S_ISREG(sb.st_mode)) { 4219e91d168Schristos close(f); 422a2572443Schristos errno = EEXIST; 423a2572443Schristos goto ecreate; 424a2572443Schristos } 425ab6821e0Skre VTRACE(DBG_REDIR, ("openredirect(>| '%s') -> %d", 426ab6821e0Skre fname, f)); 427a2572443Schristos break; 428a2572443Schristos } 429f629aa28Schristos /* FALLTHROUGH */ 430f629aa28Schristos case NCLOBBER: 43161f28255Scgd fname = redir->nfile.expfname; 432a2572443Schristos if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 4336e50d7a8Schristos goto ecreate; 434b86d4a74Skre VTRACE(DBG_REDIR, ("openredirect(> '%s') -> %d", fname, f)); 4356e50d7a8Schristos break; 43661f28255Scgd case NAPPEND: 43761f28255Scgd fname = redir->nfile.expfname; 43861f28255Scgd if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) 4396e50d7a8Schristos goto ecreate; 440b86d4a74Skre VTRACE(DBG_REDIR, ("openredirect(>> '%s') -> %d", fname, f)); 4416e50d7a8Schristos break; 44261f28255Scgd case NTOFD: 44361f28255Scgd case NFROMFD: 44461f28255Scgd if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 44552967993Skre if (sh_fd(redir->ndup.dupfd) != NULL || 44652967993Skre saved_redirected_fd(redir->ndup.dupfd) != NULL) 447c88e74efSkre error("Redirect (from %d to %d) failed: %s", 448c88e74efSkre redir->ndup.dupfd, fd, strerror(EBADF)); 4491fad4bb6Schristos if (fd < 10 && redir->ndup.dupfd < 10 && 4501fad4bb6Schristos memory[redir->ndup.dupfd]) 45161f28255Scgd memory[fd] = 1; 452698541ceSkre else if (copyfd(redir->ndup.dupfd, fd, 453*1c3b0983Skre (flags & REDIR_KEEP) == 0, 0) < 0) 454698541ceSkre error("Redirect (from %d to %d) failed: %s", 455698541ceSkre redir->ndup.dupfd, fd, strerror(errno)); 456b86d4a74Skre VTRACE(DBG_REDIR, ("openredirect: %d%c&%d\n", fd, 457b86d4a74Skre "<>"[redir->nfile.type==NTOFD], redir->ndup.dupfd)); 458b86d4a74Skre } else { 459698541ceSkre (void) close(fd); 460b86d4a74Skre VTRACE(DBG_REDIR, ("openredirect: %d%c&-\n", fd, 461b86d4a74Skre "<>"[redir->nfile.type==NTOFD])); 462b86d4a74Skre } 4636e50d7a8Schristos INTON; 4646e50d7a8Schristos return; 46561f28255Scgd case NHERE: 46661f28255Scgd case NXHERE: 467b86d4a74Skre VTRACE(DBG_REDIR, ("openredirect: %d<<...", fd)); 468ab6821e0Skre f = openhere(redir); 4696e50d7a8Schristos break; 47061f28255Scgd default: 47161f28255Scgd abort(); 47261f28255Scgd } 4736e50d7a8Schristos 474*1c3b0983Skre if (f > biggest_sh_fd) 475*1c3b0983Skre biggest_sh_fd = f; 476*1c3b0983Skre 47784071b75Skre cloexec = fd > 2 && (flags & REDIR_KEEP) == 0 && !posix; 4786e50d7a8Schristos if (f != fd) { 479b86d4a74Skre VTRACE(DBG_REDIR, (" -> %d", fd)); 480*1c3b0983Skre if (copyfd(f, fd, cloexec, 1) < 0) { 481698541ceSkre int e = errno; 482698541ceSkre 48351a7b242Skre VTRACE(DBG_REDIR, (" failed: %s\n", strerror(e))); 484698541ceSkre error("redirect reassignment (fd %d) failed: %s", fd, 485698541ceSkre strerror(e)); 486698541ceSkre } 487e47a2585Schristos } else if (cloexec) 488*1c3b0983Skre (void)fcntl(f, F_SETFD, (fcntl_int) FD_CLOEXEC); 489b86d4a74Skre VTRACE(DBG_REDIR, ("%s\n", cloexec ? " cloexec" : "")); 490d18385a5Schristos 49161f28255Scgd INTON; 4926e50d7a8Schristos return; 4936e50d7a8Schristos ecreate: 494899c734bSmsaitoh exerrno = 1; 4956e50d7a8Schristos error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 4966e50d7a8Schristos eopen: 497899c734bSmsaitoh exerrno = 1; 4986e50d7a8Schristos error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 49961f28255Scgd } 50061f28255Scgd 50161f28255Scgd 50261f28255Scgd /* 50361f28255Scgd * Handle here documents. Normally we fork off a process to write the 50461f28255Scgd * data to a pipe. If the document is short, we can stuff the data in 50561f28255Scgd * the pipe without forking. 50661f28255Scgd */ 50761f28255Scgd 50861f28255Scgd STATIC int 509071e965cSyamt openhere(const union node *redir) 51061f28255Scgd { 51161f28255Scgd int pip[2]; 51207bae7edSchristos int len = 0; 51361f28255Scgd 51461f28255Scgd if (pipe(pip) < 0) 51561f28255Scgd error("Pipe call failed"); 516*1c3b0983Skre if (pip[1] > biggest_sh_fd) 517*1c3b0983Skre biggest_sh_fd = pip[1]; 51816d85571Skre len = strlen(redir->nhere.text); 51916d85571Skre VTRACE(DBG_REDIR, ("openhere(%p) [%d] \"%.*s\"%s\n", redir, len, 52016d85571Skre (len < 40 ? len : 40), redir->nhere.text, (len < 40 ? "" : "..."))); 52116d85571Skre if (len <= PIPESIZE) { /* XXX eventually copy FreeBSD method */ 52216d85571Skre xwrite(pip[1], redir->nhere.text, len); 52361f28255Scgd goto out; 52461f28255Scgd } 525ab6821e0Skre VTRACE(DBG_REDIR, (" forking [%d,%d]\n", pip[0], pip[1])); 5269f61b804Splunky if (forkshell(NULL, NULL, FORK_NOJOB) == 0) { 52761f28255Scgd close(pip[0]); 52861f28255Scgd signal(SIGINT, SIG_IGN); 52961f28255Scgd signal(SIGQUIT, SIG_IGN); 53061f28255Scgd signal(SIGHUP, SIG_IGN); 53161f28255Scgd #ifdef SIGTSTP 53261f28255Scgd signal(SIGTSTP, SIG_IGN); 53361f28255Scgd #endif 53461f28255Scgd signal(SIGPIPE, SIG_DFL); 53516d85571Skre xwrite(pip[1], redir->nhere.text, len); 536b8bee70dSkre VTRACE(DBG_PROCS|DBG_REDIR, ("wrote here doc. exiting(0)\n")); 53761f28255Scgd _exit(0); 53861f28255Scgd } 539ab6821e0Skre VTRACE(DBG_REDIR, ("openhere (closing %d)", pip[1])); 540*1c3b0983Skre out:; 54161f28255Scgd close(pip[1]); 542ab6821e0Skre VTRACE(DBG_REDIR, (" (pipe fd=%d)", pip[0])); 54361f28255Scgd return pip[0]; 54461f28255Scgd } 54561f28255Scgd 54661f28255Scgd 54761f28255Scgd 54861f28255Scgd /* 549*1c3b0983Skre * if (reset == POPREDIR_UNDO) 55061f28255Scgd * Undo the effects of the last redirection. 551*1c3b0983Skre * else if (reset == POPREDIR_PERMANENT) 552*1c3b0983Skre * Make the last redirection permanent 553*1c3b0983Skre * else / * reset == POPREDIR_DISCARD * / 554*1c3b0983Skre * Just throw away the redirection 55561f28255Scgd */ 55661f28255Scgd 55761f28255Scgd void 558*1c3b0983Skre popredir(int reset) 559c02b3bbdSchristos { 56048250187Stls struct redirtab *rp = redirlist; 56161f28255Scgd 56261f28255Scgd INTOFF; 563*1c3b0983Skre free_rl(rp, reset); 56461f28255Scgd redirlist = rp->next; 56561f28255Scgd ckfree(rp); 56661f28255Scgd INTON; 56761f28255Scgd } 56861f28255Scgd 56961f28255Scgd /* 57061f28255Scgd * Undo all redirections. Called on error or interrupt. 57161f28255Scgd */ 57261f28255Scgd 57361f28255Scgd #ifdef mkinit 57461f28255Scgd 57561f28255Scgd INCLUDE "redir.h" 57661f28255Scgd 57761f28255Scgd RESET { 57861f28255Scgd while (redirlist) 579*1c3b0983Skre popredir(POPREDIR_UNDO); 58061f28255Scgd } 58161f28255Scgd 58261f28255Scgd SHELLPROC { 583edcb4544Schristos clearredir(0); 58461f28255Scgd } 58561f28255Scgd 58661f28255Scgd #endif 58761f28255Scgd 58837ed7877Sjtc /* Return true if fd 0 has already been redirected at least once. */ 58937ed7877Sjtc int 5901fad4bb6Schristos fd0_redirected_p(void) 5911fad4bb6Schristos { 59237ed7877Sjtc return fd0_redirected != 0; 59337ed7877Sjtc } 59461f28255Scgd 59561f28255Scgd /* 59661f28255Scgd * Discard all saved file descriptors. 59761f28255Scgd */ 59861f28255Scgd 59961f28255Scgd void 600da4f7877Smatt clearredir(int vforked) 601edcb4544Schristos { 60248250187Stls struct redirtab *rp; 6031fad4bb6Schristos struct renamelist *rl; 60461f28255Scgd 605*1c3b0983Skre /* 606*1c3b0983Skre * This happens only in a child process attempting to 607*1c3b0983Skre * exec a script which failed ENOEXEC. Any redirections 608*1c3b0983Skre * that have been made are for that script, after it 609*1c3b0983Skre * is done, we exit, there is nothing to restore, so 610*1c3b0983Skre * just make the refirectoins permanent. 611*1c3b0983Skre * 612*1c3b0983Skre * free_rl() does that does that for us, unless we're 613*1c3b0983Skre * a child of a vfork() in which case that is unsafe to 614*1c3b0983Skre * call - that should never happen, but just in case, fale 615*1c3b0983Skre * it here 616*1c3b0983Skre */ 617*1c3b0983Skre 61861f28255Scgd for (rp = redirlist ; rp ; rp = rp->next) { 619edcb4544Schristos if (!vforked) 620*1c3b0983Skre free_rl(rp, POPREDIR_PERMANENT); 6211fad4bb6Schristos else for (rl = rp->renamed; rl; rl = rl->next) 6221fad4bb6Schristos if (rl->into >= 0) 6231fad4bb6Schristos close(rl->into); 62461f28255Scgd } 62561f28255Scgd } 62661f28255Scgd 62761f28255Scgd 62861f28255Scgd 62961f28255Scgd /* 630*1c3b0983Skre * Copy a file descriptor (from) to (also) be 'to'.. 631698541ceSkre * cloexec indicates if we want close-on-exec or not. 632*1c3b0983Skre * move indicates if "from" should be closed on success (yes if set). 633698541ceSkre * Returns -1 if any error occurs. 63461f28255Scgd */ 63561f28255Scgd 636698541ceSkre STATIC int 637*1c3b0983Skre copyfd(int from, int to, int cloexec, int move) 6384ce0d34aScgd { 63961f28255Scgd int newfd; 64061f28255Scgd 641f2dc7540Skre if (cloexec && to > 2) { 642f2dc7540Skre #ifdef O_CLOEXEC 643d18385a5Schristos newfd = dup3(from, to, O_CLOEXEC); 644f2dc7540Skre #else 645f2dc7540Skre newfd = dup2(from, to); 646*1c3b0983Skre if (newfd >= 0) 647*1c3b0983Skre fcntl(newfd, F_SETFD, 648*1c3b0983Skre (fcntl_int)(fcntl(newfd, F_GETFD) | FD_CLOEXEC)); 649f2dc7540Skre #endif 650f2dc7540Skre } else 651db28d566Spooka newfd = dup2(from, to); 652698541ceSkre 653*1c3b0983Skre if (move && newfd == to && from != to) 654*1c3b0983Skre close(from); 655*1c3b0983Skre 656*1c3b0983Skre if (newfd != to) { 657*1c3b0983Skre if (newfd < 0) 658*1c3b0983Skre error("Unable to dup(%d->%d): %s", from, to, 659*1c3b0983Skre strerror(errno)); 660*1c3b0983Skre else { 661*1c3b0983Skre close(newfd); 662*1c3b0983Skre error("Moving fd %d to %d made %d!", from, to, newfd); 663*1c3b0983Skre } 664*1c3b0983Skre } 665*1c3b0983Skre 666*1c3b0983Skre if (newfd > biggest_sh_fd) 667*1c3b0983Skre biggest_sh_fd = newfd; 668*1c3b0983Skre 66961f28255Scgd return newfd; 6705916a085Ssef } 6711fad4bb6Schristos 672698541ceSkre /* 673698541ceSkre * rename fd from to be fd to (closing from). 674698541ceSkre * close-on-exec is never set on 'to' (unless 675698541ceSkre * from==to and it was set on from) - ie: a no-op 676698541ceSkre * returns to (or errors() if an error occurs). 677698541ceSkre * 678698541ceSkre * This is mostly used for rearranging the 679698541ceSkre * results from pipe(). 680698541ceSkre */ 6811fad4bb6Schristos int 6821fad4bb6Schristos movefd(int from, int to) 6831fad4bb6Schristos { 684*1c3b0983Skre if (from > biggest_sh_fd) 685*1c3b0983Skre biggest_sh_fd = from; 686*1c3b0983Skre if (to > biggest_sh_fd) 687*1c3b0983Skre biggest_sh_fd = to; 688*1c3b0983Skre 6891fad4bb6Schristos if (from == to) 6901fad4bb6Schristos return to; 6911fad4bb6Schristos 6921fad4bb6Schristos (void)close(to); 693*1c3b0983Skre if (copyfd(from, to, 0, 1) != to) { 694698541ceSkre int e = errno; 695698541ceSkre 696698541ceSkre (void) close(from); 697698541ceSkre error("Unable to make fd %d: %s", to, strerror(e)); 698698541ceSkre } 6991fad4bb6Schristos 7001fad4bb6Schristos return to; 7011fad4bb6Schristos } 7021fad4bb6Schristos 7031fad4bb6Schristos STATIC void 7041fad4bb6Schristos find_big_fd(void) 7051fad4bb6Schristos { 7061fad4bb6Schristos int i, fd; 707374c12e6Skre static int last_start = 3; /* aim to keep sh fd's under 20 */ 7081fad4bb6Schristos 70951c4dfe4Skre if (last_start < 10) 71051c4dfe4Skre last_start++; 71151c4dfe4Skre 71251c4dfe4Skre for (i = (1 << last_start); i >= 10; i >>= 1) { 713*1c3b0983Skre if ((fd = fcntl(0, F_DUPFD, (fcntl_int)(i - 1))) >= 0) { 714*1c3b0983Skre if (fd > biggest_sh_fd) 715*1c3b0983Skre biggest_sh_fd = fd; 7161fad4bb6Schristos close(fd); 7171fad4bb6Schristos break; 7181fad4bb6Schristos } 7191fad4bb6Schristos } 7201fad4bb6Schristos 7211fad4bb6Schristos fd = (i / 5) * 4; 72251c4dfe4Skre if (fd < 10) 7231fad4bb6Schristos fd = 10; 7241fad4bb6Schristos 7251fad4bb6Schristos big_sh_fd = fd; 7261fad4bb6Schristos } 7271fad4bb6Schristos 728698541ceSkre /* 729698541ceSkre * If possible, move file descriptor fd out of the way 730698541ceSkre * of expected user fd values. Returns the new fd 731698541ceSkre * (which may be the input fd if things do not go well.) 732698541ceSkre * Always set close-on-exec on the result, and close 733698541ceSkre * the input fd unless it is to be our result. 734698541ceSkre */ 7351fad4bb6Schristos int 7361fad4bb6Schristos to_upper_fd(int fd) 7371fad4bb6Schristos { 7381fad4bb6Schristos int i; 7391fad4bb6Schristos 740b86d4a74Skre VTRACE(DBG_REDIR|DBG_OUTPUT, ("to_upper_fd(%d)", fd)); 74152967993Skre if (big_sh_fd < 10 || big_sh_fd >= user_fd_limit) 7421fad4bb6Schristos find_big_fd(); 7431fad4bb6Schristos do { 744*1c3b0983Skre i = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) big_sh_fd); 7451fad4bb6Schristos if (i >= 0) { 746*1c3b0983Skre if (i > biggest_sh_fd) 747*1c3b0983Skre biggest_sh_fd = i; 7481fad4bb6Schristos if (fd != i) 7491fad4bb6Schristos close(fd); 750b86d4a74Skre VTRACE(DBG_REDIR|DBG_OUTPUT, ("-> %d\n", i)); 7511fad4bb6Schristos return i; 7521fad4bb6Schristos } 75351c4dfe4Skre if (errno != EMFILE && errno != EINVAL) 7541fad4bb6Schristos break; 7551fad4bb6Schristos find_big_fd(); 7561fad4bb6Schristos } while (big_sh_fd > 10); 7571fad4bb6Schristos 75807ee700aSkre /* 759698541ceSkre * If we wanted to move this fd to some random high number 76007ee700aSkre * we certainly do not intend to pass it through exec, even 76107ee700aSkre * if the reassignment failed. 76207ee700aSkre */ 763*1c3b0983Skre (void)fcntl(fd, F_SETFD, (fcntl_int) FD_CLOEXEC); 764b86d4a74Skre VTRACE(DBG_REDIR|DBG_OUTPUT, (" fails ->%d\n", fd)); 7651fad4bb6Schristos return fd; 7661fad4bb6Schristos } 767168f1d4aSchristos 76851c4dfe4Skre void 76951c4dfe4Skre register_sh_fd(int fd, void (*cb)(int, int)) 77051c4dfe4Skre { 77151c4dfe4Skre struct shell_fds *fp; 77251c4dfe4Skre 77351c4dfe4Skre fp = ckmalloc(sizeof (struct shell_fds)); 77451c4dfe4Skre if (fp != NULL) { 77551c4dfe4Skre fp->nxt = sh_fd_list; 77651c4dfe4Skre sh_fd_list = fp; 77751c4dfe4Skre 77851c4dfe4Skre fp->fd = fd; 77951c4dfe4Skre fp->cb = cb; 78051c4dfe4Skre } 78151c4dfe4Skre } 78251c4dfe4Skre 78351c4dfe4Skre void 78451c4dfe4Skre sh_close(int fd) 78551c4dfe4Skre { 78651c4dfe4Skre struct shell_fds **fpp, *fp; 78751c4dfe4Skre 78851c4dfe4Skre fpp = &sh_fd_list; 78951c4dfe4Skre while ((fp = *fpp) != NULL) { 79051c4dfe4Skre if (fp->fd == fd) { 79151c4dfe4Skre *fpp = fp->nxt; 79251c4dfe4Skre ckfree(fp); 79351c4dfe4Skre break; 79451c4dfe4Skre } 79551c4dfe4Skre fpp = &fp->nxt; 79651c4dfe4Skre } 79751c4dfe4Skre (void)close(fd); 79851c4dfe4Skre } 79951c4dfe4Skre 80051c4dfe4Skre STATIC struct shell_fds * 80151c4dfe4Skre sh_fd(int fd) 80251c4dfe4Skre { 80351c4dfe4Skre struct shell_fds *fp; 80451c4dfe4Skre 80551c4dfe4Skre for (fp = sh_fd_list; fp != NULL; fp = fp->nxt) 80651c4dfe4Skre if (fp->fd == fd) 80751c4dfe4Skre return fp; 80851c4dfe4Skre return NULL; 80951c4dfe4Skre } 81051c4dfe4Skre 81152967993Skre STATIC int 81252967993Skre pick_new_fd(int fd) 81352967993Skre { 81452967993Skre int to; 81552967993Skre 816*1c3b0983Skre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) big_sh_fd); 81752967993Skre if (to == -1 && big_sh_fd >= 22) 818*1c3b0983Skre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) (big_sh_fd / 2)); 81952967993Skre if (to == -1) 820*1c3b0983Skre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) (fd + 1)); 82152967993Skre if (to == -1) 822*1c3b0983Skre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) 10); 82352967993Skre if (to == -1) 824*1c3b0983Skre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) 3); 82552967993Skre if (to == -1) 82652967993Skre error("insufficient file descriptors available"); 82752967993Skre CLOEXEC(to); 828*1c3b0983Skre if (to > biggest_sh_fd) 829*1c3b0983Skre biggest_sh_fd = to; 83052967993Skre return to; 83152967993Skre } 83252967993Skre 83351c4dfe4Skre STATIC void 83451c4dfe4Skre renumber_sh_fd(struct shell_fds *fp) 83551c4dfe4Skre { 83651c4dfe4Skre int to; 83751c4dfe4Skre 83851c4dfe4Skre if (fp == NULL) 83951c4dfe4Skre return; 84051c4dfe4Skre 841374c12e6Skre /* 842374c12e6Skre * if we have had a collision, and the sh fd was a "big" one 843374c12e6Skre * try moving the sh fd base to a higher number (if possible) 844374c12e6Skre * so future sh fds are less likely to be in the user's sights 845374c12e6Skre * (incl this one when moved) 846374c12e6Skre */ 847374c12e6Skre if (fp->fd >= big_sh_fd) 848374c12e6Skre find_big_fd(); 849374c12e6Skre 85052967993Skre to = pick_new_fd(fp->fd); 85151c4dfe4Skre 85251c4dfe4Skre if (fp->fd == to) /* impossible? */ 85351c4dfe4Skre return; 85451c4dfe4Skre 85552967993Skre VTRACE(DBG_REDIR, ("renumber_sh_fd: moved shell fd %d to %d\n", 85652967993Skre fp->fd, to)); 85752967993Skre 85851c4dfe4Skre (*fp->cb)(fp->fd, to); 85951c4dfe4Skre (void)close(fp->fd); 86051c4dfe4Skre fp->fd = to; 86151c4dfe4Skre } 86251c4dfe4Skre 8630ff2aa10Skre static const struct flgnames { 864168f1d4aSchristos const char *name; 8651f81ff14Skre uint16_t minch; 866168f1d4aSchristos uint32_t value; 867168f1d4aSchristos } nv[] = { 868168f1d4aSchristos #ifdef O_APPEND 8691f81ff14Skre { "append", 2, O_APPEND }, 870f2dc7540Skre #else 871f2dc7540Skre # define O_APPEND 0 872168f1d4aSchristos #endif 873168f1d4aSchristos #ifdef O_ASYNC 8741f81ff14Skre { "async", 2, O_ASYNC }, 875f2dc7540Skre #else 876f2dc7540Skre # define O_ASYNC 0 877168f1d4aSchristos #endif 878168f1d4aSchristos #ifdef O_SYNC 8791f81ff14Skre { "sync", 2, O_SYNC }, 880f2dc7540Skre #else 881f2dc7540Skre # define O_SYNC 0 882168f1d4aSchristos #endif 883168f1d4aSchristos #ifdef O_NONBLOCK 8841f81ff14Skre { "nonblock", 3, O_NONBLOCK }, 885f2dc7540Skre #else 886f2dc7540Skre # define O_NONBLOCK 0 887168f1d4aSchristos #endif 888168f1d4aSchristos #ifdef O_FSYNC 8891f81ff14Skre { "fsync", 2, O_FSYNC }, 890f2dc7540Skre #else 891f2dc7540Skre # define O_FSYNC 0 892168f1d4aSchristos #endif 893168f1d4aSchristos #ifdef O_DSYNC 8941f81ff14Skre { "dsync", 2, O_DSYNC }, 895f2dc7540Skre #else 896f2dc7540Skre # define O_DSYNC 0 897168f1d4aSchristos #endif 898168f1d4aSchristos #ifdef O_RSYNC 8991f81ff14Skre { "rsync", 2, O_RSYNC }, 900f2dc7540Skre #else 901f2dc7540Skre # define O_RSYNC 0 902168f1d4aSchristos #endif 903e405eb35Skamil #ifdef O_ALT_IO 9041f81ff14Skre { "altio", 2, O_ALT_IO }, 905f2dc7540Skre #else 906f2dc7540Skre # define O_ALT_IO 0 907168f1d4aSchristos #endif 908168f1d4aSchristos #ifdef O_DIRECT 9091f81ff14Skre { "direct", 2, O_DIRECT }, 910f2dc7540Skre #else 911f2dc7540Skre # define O_DIRECT 0 912168f1d4aSchristos #endif 913168f1d4aSchristos #ifdef O_NOSIGPIPE 9141f81ff14Skre { "nosigpipe", 3, O_NOSIGPIPE }, 915f2dc7540Skre #else 916f2dc7540Skre # define O_NOSIGPIPE 0 917168f1d4aSchristos #endif 918f2dc7540Skre 919f2dc7540Skre #define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_DSYNC|O_RSYNC|\ 920f2dc7540Skre O_ALT_IO|O_DIRECT|O_NOSIGPIPE) 921f2dc7540Skre 922f2dc7540Skre #ifndef O_CLOEXEC 9238d9b0751Skre # define O_CLOEXEC ((~ALLFLAGS) ^ ((~ALLFLAGS) & ((~ALLFLAGS) - 1))) 924f2dc7540Skre #endif 925f2dc7540Skre 926f2dc7540Skre /* for any system we support, close on exec is always defined */ 9271f81ff14Skre { "cloexec", 2, O_CLOEXEC }, 9281f81ff14Skre { 0, 0, 0 } 929168f1d4aSchristos }; 930f2dc7540Skre 931f2dc7540Skre #ifndef O_ACCMODE 932f2dc7540Skre # define O_ACCMODE 0 933f2dc7540Skre #endif 934f2dc7540Skre #ifndef O_RDONLY 935f2dc7540Skre # define O_RDONLY 0 936f2dc7540Skre #endif 937f2dc7540Skre #ifndef O_WRONLY 938f2dc7540Skre # define O_WRONLY 0 939f2dc7540Skre #endif 940f2dc7540Skre #ifndef O_RWDR 941f2dc7540Skre # define O_RWDR 0 942f2dc7540Skre #endif 943f2dc7540Skre #ifndef O_SHLOCK 944f2dc7540Skre # define O_SHLOCK 0 945f2dc7540Skre #endif 946f2dc7540Skre #ifndef O_EXLOCK 947f2dc7540Skre # define O_EXLOCK 0 948f2dc7540Skre #endif 949f2dc7540Skre #ifndef O_NOFOLLOW 950f2dc7540Skre # define O_NOFOLLOW 0 951f2dc7540Skre #endif 952f2dc7540Skre #ifndef O_CREAT 953f2dc7540Skre # define O_CREAT 0 954f2dc7540Skre #endif 955f2dc7540Skre #ifndef O_TRUNC 956f2dc7540Skre # define O_TRUNC 0 957f2dc7540Skre #endif 958f2dc7540Skre #ifndef O_EXCL 959f2dc7540Skre # define O_EXCL 0 960f2dc7540Skre #endif 961f2dc7540Skre #ifndef O_NOCTTY 962f2dc7540Skre # define O_NOCTTY 0 963f2dc7540Skre #endif 964f2dc7540Skre #ifndef O_DIRECTORY 965f2dc7540Skre # define O_DIRECTORY 0 966f2dc7540Skre #endif 967f2dc7540Skre #ifndef O_REGULAR 968f2dc7540Skre # define O_REGULAR 0 969f2dc7540Skre #endif 970f2dc7540Skre /* 971f2dc7540Skre * flags that F_GETFL might return that we want to ignore 972f2dc7540Skre * 973f2dc7540Skre * F_GETFL should not actually return these, they're all just open() 974f2dc7540Skre * modifiers, rather than state, but just in case... 975f2dc7540Skre */ 976f2dc7540Skre #define IGNFLAGS (O_ACCMODE|O_RDONLY|O_WRONLY|O_RDWR|O_SHLOCK|O_EXLOCK| \ 977f2dc7540Skre O_NOFOLLOW|O_CREAT|O_TRUNC|O_EXCL|O_NOCTTY|O_DIRECTORY|O_REGULAR) 978168f1d4aSchristos 979168f1d4aSchristos static int 980*1c3b0983Skre getflags(int fd, int p, int all) 981168f1d4aSchristos { 982168f1d4aSchristos int c, f; 983168f1d4aSchristos 984*1c3b0983Skre if (!all && (sh_fd(fd) != NULL || saved_redirected_fd(fd) != NULL)) { 98551c4dfe4Skre if (!p) 98651c4dfe4Skre return -1; 987c88e74efSkre error("Can't get status for fd=%d (%s)", fd, strerror(EBADF)); 98851c4dfe4Skre } 98951c4dfe4Skre 990168f1d4aSchristos if ((c = fcntl(fd, F_GETFD)) == -1) { 991168f1d4aSchristos if (!p) 992168f1d4aSchristos return -1; 993168f1d4aSchristos error("Can't get status for fd=%d (%s)", fd, strerror(errno)); 994168f1d4aSchristos } 995168f1d4aSchristos if ((f = fcntl(fd, F_GETFL)) == -1) { 996168f1d4aSchristos if (!p) 997168f1d4aSchristos return -1; 998168f1d4aSchristos error("Can't get flags for fd=%d (%s)", fd, strerror(errno)); 999168f1d4aSchristos } 1000f2dc7540Skre f &= ~IGNFLAGS; /* clear anything we know about, but ignore */ 10010ff2aa10Skre if (c & FD_CLOEXEC) 1002168f1d4aSchristos f |= O_CLOEXEC; 1003f2dc7540Skre return f; 1004168f1d4aSchristos } 1005168f1d4aSchristos 1006168f1d4aSchristos static void 10070ff2aa10Skre printone(int fd, int p, int verbose, int pfd) 1008168f1d4aSchristos { 1009*1c3b0983Skre int f = getflags(fd, p, verbose > 1); 10100ff2aa10Skre const struct flgnames *fn; 1011168f1d4aSchristos 1012168f1d4aSchristos if (f == -1) 1013168f1d4aSchristos return; 1014168f1d4aSchristos 10150ff2aa10Skre if (pfd) 1016168f1d4aSchristos outfmt(out1, "%d: ", fd); 10170ff2aa10Skre for (fn = nv; fn->name; fn++) { 10180ff2aa10Skre if (f & fn->value) { 10190ff2aa10Skre outfmt(out1, "%s%s", verbose ? "+" : "", fn->name); 10200ff2aa10Skre f &= ~fn->value; 1021168f1d4aSchristos } else if (verbose) 10220ff2aa10Skre outfmt(out1, "-%s", fn->name); 1023168f1d4aSchristos else 1024168f1d4aSchristos continue; 10250ff2aa10Skre if (f || (verbose && fn[1].name)) 1026168f1d4aSchristos outfmt(out1, ","); 1027168f1d4aSchristos } 10280ff2aa10Skre if (verbose && f) /* f should be normally be 0 */ 10290ff2aa10Skre outfmt(out1, " +%#x", f); 1030168f1d4aSchristos outfmt(out1, "\n"); 1031168f1d4aSchristos } 1032168f1d4aSchristos 10330ff2aa10Skre static void 1034168f1d4aSchristos parseflags(char *s, int *p, int *n) 1035168f1d4aSchristos { 10360ff2aa10Skre int *v, *w; 10370ff2aa10Skre const struct flgnames *fn; 10381f81ff14Skre size_t len; 1039168f1d4aSchristos 1040168f1d4aSchristos *p = 0; 1041168f1d4aSchristos *n = 0; 1042168f1d4aSchristos for (s = strtok(s, ","); s; s = strtok(NULL, ",")) { 10430ff2aa10Skre switch (*s++) { 1044168f1d4aSchristos case '+': 1045168f1d4aSchristos v = p; 10460ff2aa10Skre w = n; 1047168f1d4aSchristos break; 1048168f1d4aSchristos case '-': 1049168f1d4aSchristos v = n; 10500ff2aa10Skre w = p; 1051168f1d4aSchristos break; 1052168f1d4aSchristos default: 10530ff2aa10Skre error("Missing +/- indicator before flag %s", s-1); 1054168f1d4aSchristos } 1055168f1d4aSchristos 10561f81ff14Skre len = strlen(s); 10570ff2aa10Skre for (fn = nv; fn->name; fn++) 10581f81ff14Skre if (len >= fn->minch && strncmp(s,fn->name,len) == 0) { 10590ff2aa10Skre *v |= fn->value; 10600ff2aa10Skre *w &=~ fn->value; 1061168f1d4aSchristos break; 1062168f1d4aSchristos } 10630ff2aa10Skre if (fn->name == 0) 1064168f1d4aSchristos error("Bad flag `%s'", s); 1065168f1d4aSchristos } 1066168f1d4aSchristos } 1067168f1d4aSchristos 1068168f1d4aSchristos static void 1069168f1d4aSchristos setone(int fd, int pos, int neg, int verbose) 1070168f1d4aSchristos { 1071*1c3b0983Skre int f = getflags(fd, 1, 0); 10720ff2aa10Skre int n, cloexec; 10730ff2aa10Skre 1074168f1d4aSchristos if (f == -1) 1075168f1d4aSchristos return; 1076168f1d4aSchristos 10770ff2aa10Skre cloexec = -1; 1078168f1d4aSchristos if ((pos & O_CLOEXEC) && !(f & O_CLOEXEC)) 1079168f1d4aSchristos cloexec = FD_CLOEXEC; 1080168f1d4aSchristos if ((neg & O_CLOEXEC) && (f & O_CLOEXEC)) 1081168f1d4aSchristos cloexec = 0; 1082168f1d4aSchristos 1083*1c3b0983Skre /* Don't allow O_CLOEXEC on stdin, stdout, or stderr */ 1084*1c3b0983Skre if ((cloexec > 0 && fd <= 2 && (errno = EINVAL)) || 1085*1c3b0983Skre (cloexec != -1 && fcntl(fd, F_SETFD, (fcntl_int) cloexec) == -1)) 1086168f1d4aSchristos error("Can't set status for fd=%d (%s)", fd, strerror(errno)); 1087168f1d4aSchristos 1088168f1d4aSchristos pos &= ~O_CLOEXEC; 1089168f1d4aSchristos neg &= ~O_CLOEXEC; 1090168f1d4aSchristos f &= ~O_CLOEXEC; 10910ff2aa10Skre n = f; 1092168f1d4aSchristos n |= pos; 1093168f1d4aSchristos n &= ~neg; 1094*1c3b0983Skre if (n != f && fcntl(fd, F_SETFL, (fcntl_int)n) == -1) 1095168f1d4aSchristos error("Can't set flags for fd=%d (%s)", fd, strerror(errno)); 1096168f1d4aSchristos if (verbose) 10970ff2aa10Skre printone(fd, 1, verbose, 1); 1098168f1d4aSchristos } 1099168f1d4aSchristos 1100168f1d4aSchristos int 1101168f1d4aSchristos fdflagscmd(int argc, char *argv[]) 1102168f1d4aSchristos { 1103168f1d4aSchristos char *num; 1104168f1d4aSchristos int verbose = 0, ch, pos = 0, neg = 0; 1105168f1d4aSchristos char *setflags = NULL; 1106168f1d4aSchristos 1107168f1d4aSchristos optreset = 1; optind = 1; /* initialize getopt */ 1108*1c3b0983Skre while ((ch = getopt(argc, argv, ":vs:" 1109*1c3b0983Skre #ifdef DEBUG 1110*1c3b0983Skre "V" 1111*1c3b0983Skre #endif 1112*1c3b0983Skre )) != -1) 1113168f1d4aSchristos switch ((char)ch) { 1114*1c3b0983Skre #ifdef DEBUG 1115*1c3b0983Skre case 'V': 1116*1c3b0983Skre verbose = 2; 1117*1c3b0983Skre break; 1118*1c3b0983Skre #endif 1119168f1d4aSchristos case 'v': 1120168f1d4aSchristos verbose = 1; 1121168f1d4aSchristos break; 1122168f1d4aSchristos case 's': 11230ff2aa10Skre if (setflags) 11240ff2aa10Skre goto msg; 1125168f1d4aSchristos setflags = optarg; 1126168f1d4aSchristos break; 1127168f1d4aSchristos case '?': 1128168f1d4aSchristos default: 1129168f1d4aSchristos msg: 11300ff2aa10Skre error("Usage: fdflags [-v] [-s <flags> fd] [fd...]"); 1131168f1d4aSchristos /* NOTREACHED */ 1132168f1d4aSchristos } 1133168f1d4aSchristos 1134168f1d4aSchristos argc -= optind, argv += optind; 1135168f1d4aSchristos 11360ff2aa10Skre if (setflags) 11370ff2aa10Skre parseflags(setflags, &pos, &neg); 1138168f1d4aSchristos 1139168f1d4aSchristos if (argc == 0) { 1140c1cbf199Skre int i; 11410ff2aa10Skre 1142168f1d4aSchristos if (setflags) 1143168f1d4aSchristos goto msg; 11440ff2aa10Skre 1145c1cbf199Skre for (i = 0; i <= max_user_fd; i++) 11460ff2aa10Skre printone(i, 0, verbose, 1); 1147*1c3b0983Skre if (verbose > 1) 1148*1c3b0983Skre while (i <= biggest_sh_fd) 1149*1c3b0983Skre printone(i++, 0, verbose, 1); 1150168f1d4aSchristos 1151b65a5b90Skre } else while ((num = *argv++) != NULL) { 11520ff2aa10Skre int fd = number(num); 11530ff2aa10Skre 11549df68badSkre while (num[0] == '0' && num[1] != '\0') /* skip 0's */ 11559df68badSkre num++; 115652967993Skre if (strlen(num) > 5 || 115752967993Skre (fd >= user_fd_limit && fd > max_user_fd)) 115852967993Skre error("%s: too big to be a file descriptor", num); 11590ff2aa10Skre 1160168f1d4aSchristos if (setflags) 1161168f1d4aSchristos setone(fd, pos, neg, verbose); 1162168f1d4aSchristos else 11630ff2aa10Skre printone(fd, 1, verbose, argc > 1); 1164168f1d4aSchristos } 1165b65a5b90Skre flushout(out1); 1166b65a5b90Skre if (io_err(out1)) { 1167b65a5b90Skre out2str("fdflags: I/O error\n"); 1168b65a5b90Skre return 1; 1169b65a5b90Skre } 1170168f1d4aSchristos return 0; 1171168f1d4aSchristos } 11723b297678Skre 11733b297678Skre #undef MAX /* in case we inherited them from somewhere */ 11743b297678Skre #undef MIN 11753b297678Skre 11763b297678Skre #define MIN(a,b) (/*CONSTCOND*/((a)<=(b)) ? (a) : (b)) 11773b297678Skre #define MAX(a,b) (/*CONSTCOND*/((a)>=(b)) ? (a) : (b)) 11783b297678Skre 11793b297678Skre /* now make the compiler work for us... */ 11803b297678Skre #define MIN_REDIR MIN(MIN(MIN(MIN(NTO,NFROM), MIN(NTOFD,NFROMFD)), \ 11813b297678Skre MIN(MIN(NCLOBBER,NAPPEND), MIN(NHERE,NXHERE))), NFROMTO) 11823b297678Skre #define MAX_REDIR MAX(MAX(MAX(MAX(NTO,NFROM), MAX(NTOFD,NFROMFD)), \ 11833b297678Skre MAX(MAX(NCLOBBER,NAPPEND), MAX(NHERE,NXHERE))), NFROMTO) 11843b297678Skre 11853b297678Skre static const char *redir_sym[MAX_REDIR - MIN_REDIR + 1] = { 11863b297678Skre [NTO - MIN_REDIR]= ">", 11873b297678Skre [NFROM - MIN_REDIR]= "<", 11883b297678Skre [NTOFD - MIN_REDIR]= ">&", 11893b297678Skre [NFROMFD - MIN_REDIR]= "<&", 11903b297678Skre [NCLOBBER - MIN_REDIR]= ">|", 11913b297678Skre [NAPPEND - MIN_REDIR]= ">>", 11923b297678Skre [NHERE - MIN_REDIR]= "<<", 11933b297678Skre [NXHERE - MIN_REDIR]= "<<", 11943b297678Skre [NFROMTO - MIN_REDIR]= "<>", 11953b297678Skre }; 11963b297678Skre 11973b297678Skre int 11983b297678Skre outredir(struct output *out, union node *n, int sep) 11993b297678Skre { 12003b297678Skre if (n == NULL) 12013b297678Skre return 0; 12023b297678Skre if (n->type < MIN_REDIR || n->type > MAX_REDIR || 12033b297678Skre redir_sym[n->type - MIN_REDIR] == NULL) 12043b297678Skre return 0; 12053b297678Skre 12063b297678Skre if (sep) 12073b297678Skre outc(sep, out); 12083b297678Skre 12093b297678Skre /* 12103b297678Skre * ugly, but all redir node types have "fd" in same slot... 12113b297678Skre * (and code other places assumes it as well) 12123b297678Skre */ 12133b297678Skre if ((redir_sym[n->type - MIN_REDIR][0] == '<' && n->nfile.fd != 0) || 12143b297678Skre (redir_sym[n->type - MIN_REDIR][0] == '>' && n->nfile.fd != 1)) 12153b297678Skre outfmt(out, "%d", n->nfile.fd); 12163b297678Skre 12173b297678Skre outstr(redir_sym[n->type - MIN_REDIR], out); 12183b297678Skre 12193b297678Skre switch (n->type) { 12203b297678Skre case NHERE: 12213b297678Skre outstr("'...'", out); 12223b297678Skre break; 12233b297678Skre case NXHERE: 12243b297678Skre outstr("...", out); 12253b297678Skre break; 12263b297678Skre case NTOFD: 12273b297678Skre case NFROMFD: 12283b297678Skre if (n->ndup.dupfd < 0) 12293b297678Skre outc('-', out); 12303b297678Skre else 12313b297678Skre outfmt(out, "%d", n->ndup.dupfd); 12323b297678Skre break; 12333b297678Skre default: 12343b297678Skre outstr(n->nfile.expfname, out); 12353b297678Skre break; 12363b297678Skre } 12373b297678Skre return 1; 12383b297678Skre } 1239