diff options
Diffstat (limited to 'redir.c')
-rw-r--r-- | redir.c | 317 |
1 files changed, 254 insertions, 63 deletions
@@ -1,22 +1,23 @@ /* redir.c -- Functions to perform input and output redirection. */ -/* Copyright (C) 1997-2005 Free Software Foundation, Inc. +/* Copyright (C) 1997-2009 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + along with Bash. If not, see <http://www.gnu.org/licenses/>. +*/ + #include "config.h" #if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) @@ -43,8 +44,10 @@ extern int errno; #include "bashansi.h" #include "bashintl.h" - #include "memalloc.h" + +#define NEED_FPURGE_DECL + #include "shell.h" #include "flags.h" #include "execute_cmd.h" @@ -54,6 +57,8 @@ extern int errno; # include "input.h" #endif +#define SHELL_FD_BASE 10 + int expanding_redir; extern int posixly_correct; @@ -63,9 +68,10 @@ extern REDIRECT *exec_redirection_undo_list; /* Static functions defined and used in this file. */ static void add_undo_close_redirect __P((int)); static void add_exec_redirect __P((REDIRECT *)); -static int add_undo_redirect __P((int, enum r_instruction)); +static int add_undo_redirect __P((int, enum r_instruction, int)); static int expandable_redirection_filename __P((REDIRECT *)); static int stdin_redirection __P((enum r_instruction, int)); +static int undoablefd __P((int)); static int do_redirection_internal __P((REDIRECT *, int)); static int write_here_document __P((int, WORD_DESC *)); @@ -76,6 +82,9 @@ static int redir_special_open __P((int, char *, int, int, enum r_instruction)); static int noclobber_open __P((char *, int, int, enum r_instruction)); static int redir_open __P((char *, int, int, enum r_instruction)); +static int redir_varassign __P((REDIRECT *, int)); +static int redir_varvalue __P((REDIRECT *)); + /* Spare redirector used when translating [N]>&WORD[-] or [N]<&WORD[-] to a new redirection and when creating the redirection undo list. */ static REDIRECTEE rd; @@ -93,12 +102,15 @@ redirection_error (temp, error) int oflags; allocname = 0; - if (temp->redirector < 0) + if (temp->rflags & REDIR_VARASSIGN) + filename = savestring (temp->redirector.filename->word); + else if (temp->redirector.dest < 0) /* This can happen when read_token_word encounters overflow, like in exec 4294967297>x */ filename = _("file descriptor out of range"); #ifdef EBADF - else if (temp->redirector >= 0 && errno == EBADF) + /* This error can never involve NOCLOBBER */ + else if (error != NOCLOBBER_REDIRECT && temp->redirector.dest >= 0 && error == EBADF) { /* If we're dealing with two file descriptors, we have to guess about which one is invalid; in the cases of r_{duplicating,move}_input and @@ -111,14 +123,27 @@ redirection_error (temp, error) case r_move_output: filename = allocname = itos (temp->redirectee.dest); break; + case r_duplicating_input_word: + if (temp->redirector.dest == 0) /* Guess */ + filename = temp->redirectee.filename->word; /* XXX */ + else + filename = allocname = itos (temp->redirector.dest); + break; + case r_duplicating_output_word: + if (temp->redirector.dest == 1) /* Guess */ + filename = temp->redirectee.filename->word; /* XXX */ + else + filename = allocname = itos (temp->redirector.dest); + break; default: - filename = allocname = itos (temp->redirector); + filename = allocname = itos (temp->redirector.dest); break; } } #endif else if (expandable_redirection_filename (temp)) { +expandable_filename: if (posixly_correct && interactive_shell == 0) { oflags = temp->redirectee.filename->flags; @@ -152,7 +177,11 @@ redirection_error (temp, error) #endif /* RESTRICTED_SHELL */ case HEREDOC_REDIRECT: - internal_error (_("cannot create temp file for here document: %s"), strerror (heredoc_errno)); + internal_error (_("cannot create temp file for here-document: %s"), strerror (heredoc_errno)); + break; + + case BADVAR_REDIRECT: + internal_error (_("%s: cannot assign fd to variable"), filename); break; default: @@ -213,6 +242,7 @@ expandable_redirection_filename (redirect) case r_input_direction: case r_inputa_direction: case r_err_and_out: + case r_append_err_and_out: case r_input_output: case r_output_force: case r_duplicating_input_word: @@ -267,7 +297,9 @@ write_here_string (fd, redirectee) char *herestr; int herelen, n, e; + expanding_redir = 1; herestr = expand_string_to_string (redirectee->word, 0); + expanding_redir = 0; herelen = STRLEN (herestr); n = write (fd, herestr, herelen); @@ -319,7 +351,10 @@ write_here_document (fd, redirectee) return 0; } + expanding_redir = 1; tlist = expand_string (redirectee->word, Q_HERE_DOCUMENT); + expanding_redir = 0; + if (tlist) { /* Try using buffered I/O (stdio) and writing a word @@ -375,7 +410,7 @@ here_document_to_fd (redirectee, ri) char *filename; int r, fd, fd2; - fd = sh_mktmpfd ("sh-thd", MT_USERANDOM, &filename); + fd = sh_mktmpfd ("sh-thd", MT_USERANDOM|MT_USETMPDIR, &filename); /* If we failed for some reason other than the file existing, abort */ if (fd < 0) @@ -481,7 +516,7 @@ redir_special_open (spec, filename, flags, mode, ri) if (all_digits (filename+8) && legal_number (filename+8, &lfd) && lfd == (int)lfd) { fd = lfd; - fd = fcntl (fd, F_DUPFD, 10); + fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); } else fd = AMBIGUOUS_REDIRECT; @@ -490,13 +525,13 @@ redir_special_open (spec, filename, flags, mode, ri) #if !defined (HAVE_DEV_STDIN) case RF_DEVSTDIN: - fd = fcntl (0, F_DUPFD, 10); + fd = fcntl (0, F_DUPFD, SHELL_FD_BASE); break; case RF_DEVSTDOUT: - fd = fcntl (1, F_DUPFD, 10); + fd = fcntl (1, F_DUPFD, SHELL_FD_BASE); break; case RF_DEVSTDERR: - fd = fcntl (2, F_DUPFD, 10); + fd = fcntl (2, F_DUPFD, SHELL_FD_BASE); break; #endif @@ -606,6 +641,18 @@ redir_open (filename, flags, mode, ri) return fd; } +static int +undoablefd (fd) + int fd; +{ + int clexec; + + clexec = fcntl (fd, F_GETFD, 0); + if (clexec == -1 || (fd >= SHELL_FD_BASE && clexec == 1)) + return 0; + return 1; +} + /* Do the specific redirection requested. Returns errno or one of the special redirection errors (*_REDIRECT) in case of error, 0 on success. If flags & RX_ACTIVE is zero, then just do whatever is neccessary to @@ -624,10 +671,11 @@ do_redirection_internal (redirect, flags) char *redirectee_word; enum r_instruction ri; REDIRECT *new_redirect; + REDIRECTEE sd; redirectee = redirect->redirectee.filename; redir_fd = redirect->redirectee.dest; - redirector = redirect->redirector; + redirector = redirect->redirector.dest; ri = redirect->instruction; if (redirect->flags & RX_INTERNAL) @@ -635,8 +683,9 @@ do_redirection_internal (redirect, flags) if (TRANSLATE_REDIRECT (ri)) { - /* We have [N]>&WORD[-] or [N]<&WORD[-]. Expand WORD, then translate - the redirection into a new one and continue. */ + /* We have [N]>&WORD[-] or [N]<&WORD[-] (or {V}>&WORD[-] or {V}<&WORD-). + and WORD, then translate the redirection into a new one and + continue. */ redirectee_word = redirection_expand (redirectee); /* XXX - what to do with [N]<&$w- where w is unset or null? ksh93 @@ -645,11 +694,13 @@ do_redirection_internal (redirect, flags) return (AMBIGUOUS_REDIRECT); else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') { + sd = redirect->redirector; rd.dest = 0; - new_redirect = make_redirection (redirector, r_close_this, rd); + new_redirect = make_redirection (sd, r_close_this, rd, 0); } else if (all_digits (redirectee_word)) { + sd = redirect->redirector; if (legal_number (redirectee_word, &lfd) && (int)lfd == lfd) rd.dest = lfd; else @@ -657,23 +708,24 @@ do_redirection_internal (redirect, flags) switch (ri) { case r_duplicating_input_word: - new_redirect = make_redirection (redirector, r_duplicating_input, rd); + new_redirect = make_redirection (sd, r_duplicating_input, rd, 0); break; case r_duplicating_output_word: - new_redirect = make_redirection (redirector, r_duplicating_output, rd); + new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); break; case r_move_input_word: - new_redirect = make_redirection (redirector, r_move_input, rd); + new_redirect = make_redirection (sd, r_move_input, rd, 0); break; case r_move_output_word: - new_redirect = make_redirection (redirector, r_move_output, rd); + new_redirect = make_redirection (sd, r_move_output, rd, 0); break; } } - else if (ri == r_duplicating_output_word && redirector == 1) + else if (ri == r_duplicating_output_word && (redirect->rflags & REDIR_VARASSIGN) == 0 && redirector == 1) { + sd = redirect->redirector; rd.filename = make_bare_word (redirectee_word); - new_redirect = make_redirection (1, r_err_and_out, rd); + new_redirect = make_redirection (sd, r_err_and_out, rd, 0); } else { @@ -705,7 +757,7 @@ do_redirection_internal (redirect, flags) redirectee = new_redirect->redirectee.filename; redir_fd = new_redirect->redirectee.dest; - redirector = new_redirect->redirector; + redirector = new_redirect->redirector.dest; ri = new_redirect->instruction; /* Overwrite the flags element of the old redirect with the new value. */ @@ -720,6 +772,7 @@ do_redirection_internal (redirect, flags) case r_input_direction: case r_inputa_direction: case r_err_and_out: /* command &>filename */ + case r_append_err_and_out: /* command &>> filename */ case r_input_output: case r_output_force: if (posixly_correct && interactive_shell == 0) @@ -753,11 +806,14 @@ do_redirection_internal (redirect, flags) if (flags & RX_ACTIVE) { + if (redirect->rflags & REDIR_VARASSIGN) + redirector = fcntl (fd, F_DUPFD, SHELL_FD_BASE); /* XXX try this for now */ + if (flags & RX_UNDOABLE) { /* Only setup to undo it if the thing to undo is active. */ if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector, ri); + add_undo_redirect (redirector, ri, -1); else add_undo_close_redirect (redirector); } @@ -766,7 +822,30 @@ do_redirection_internal (redirect, flags) check_bash_input (redirector); #endif - if ((fd != redirector) && (dup2 (fd, redirector) < 0)) + /* Make sure there is no pending output before we change the state + of the underlying file descriptor, since the builtins use stdio + for output. */ + if (redirector == 1 && fileno (stdout) == redirector) + { + fflush (stdout); + fpurge (stdout); + } + else if (redirector == 2 && fileno (stderr) == redirector) + { + fflush (stderr); + fpurge (stderr); + } + + if (redirect->rflags & REDIR_VARASSIGN) + { + if ((r = redir_varassign (redirect, redirector)) < 0) + { + close (redirector); + close (fd); + return (r); /* XXX */ + } + } + else if ((fd != redirector) && (dup2 (fd, redirector) < 0)) return (errno); #if defined (BUFFERED_INPUT) @@ -802,13 +881,13 @@ do_redirection_internal (redirect, flags) } /* If we are hacking both stdout and stderr, do the stderr - redirection here. */ - if (ri == r_err_and_out) + redirection here. XXX - handle {var} here? */ + if (ri == r_err_and_out || ri == r_append_err_and_out) { if (flags & RX_ACTIVE) { if (flags & RX_UNDOABLE) - add_undo_redirect (2, ri); + add_undo_redirect (2, ri, -1); if (dup2 (1, 2) < 0) return (errno); } @@ -830,13 +909,16 @@ do_redirection_internal (redirect, flags) return (HEREDOC_REDIRECT); } + if (redirect->rflags & REDIR_VARASSIGN) + redirector = fcntl (fd, F_DUPFD, SHELL_FD_BASE); /* XXX try this for now */ + if (flags & RX_ACTIVE) { if (flags & RX_UNDOABLE) { /* Only setup to undo it if the thing to undo is active. */ if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector, ri); + add_undo_redirect (redirector, ri, -1); else add_undo_close_redirect (redirector); } @@ -844,7 +926,16 @@ do_redirection_internal (redirect, flags) #if defined (BUFFERED_INPUT) check_bash_input (redirector); #endif - if (fd != redirector && dup2 (fd, redirector) < 0) + if (redirect->rflags & REDIR_VARASSIGN) + { + if ((r = redir_varassign (redirect, redirector)) < 0) + { + close (redirector); + close (fd); + return (r); /* XXX */ + } + } + else if (fd != redirector && dup2 (fd, redirector) < 0) { r = errno; close (fd); @@ -872,22 +963,32 @@ do_redirection_internal (redirect, flags) case r_duplicating_output: case r_move_input: case r_move_output: + if ((flags & RX_ACTIVE) && (redirect->rflags & REDIR_VARASSIGN)) + redirector = fcntl (redir_fd, F_DUPFD, SHELL_FD_BASE); /* XXX try this for now */ + if ((flags & RX_ACTIVE) && (redir_fd != redirector)) { if (flags & RX_UNDOABLE) { /* Only setup to undo it if the thing to undo is active. */ if (fcntl (redirector, F_GETFD, 0) != -1) - add_undo_redirect (redirector, ri); + add_undo_redirect (redirector, ri, redir_fd); else add_undo_close_redirect (redirector); } - #if defined (BUFFERED_INPUT) check_bash_input (redirector); #endif + if (redirect->rflags & REDIR_VARASSIGN) + { + if ((r = redir_varassign (redirect, redirector)) < 0) + { + close (redirector); + return (r); /* XXX */ + } + } /* This is correct. 2>&1 means dup2 (1, 2); */ - if (dup2 (redir_fd, redirector) < 0) + else if (dup2 (redir_fd, redirector) < 0) return (errno); #if defined (BUFFERED_INPUT) @@ -915,17 +1016,43 @@ do_redirection_internal (redirect, flags) #endif SET_CLOSE_ON_EXEC (redirector); + /* When undoing saving of non-standard file descriptors (>=3) using + file descriptors >= SHELL_FD_BASE, we set the saving fd to be + close-on-exec and use a flag to decide how to set close-on-exec + when the fd is restored. */ + if ((redirect->flags & RX_INTERNAL) && (redirect->flags & RX_SAVCLEXEC) && redirector >= 3 && redir_fd >= SHELL_FD_BASE) + SET_OPEN_ON_EXEC (redirector); + /* dup-and-close redirection */ if (ri == r_move_input || ri == r_move_output) - close (redir_fd); + { + xtrace_fdchk (redir_fd); + + close (redir_fd); +#if defined (COPROCESS_SUPPORT) + coproc_fdchk (redir_fd); /* XXX - loses coproc fds */ +#endif + } } break; case r_close_this: if (flags & RX_ACTIVE) { + if (redirect->rflags & REDIR_VARASSIGN) + { + redirector = redir_varvalue (redirect); + if (redirector < 0) + return AMBIGUOUS_REDIRECT; + } + if ((flags & RX_UNDOABLE) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector, ri); + add_undo_redirect (redirector, ri, -1); + +#if defined (COPROCESS_SUPPORT) + coproc_fdchk (redirector); +#endif + xtrace_fdchk (redirector); #if defined (BUFFERED_INPUT) check_bash_input (redirector); @@ -943,22 +1070,31 @@ do_redirection_internal (redirect, flags) return (0); } -#define SHELL_FD_BASE 10 - /* Remember the file descriptor associated with the slot FD, on REDIRECTION_UNDO_LIST. Note that the list will be reversed before it is executed. Any redirections that need to be undone even if REDIRECTION_UNDO_LIST is discarded by the exec builtin - are also saved on EXEC_REDIRECTION_UNDO_LIST. */ + are also saved on EXEC_REDIRECTION_UNDO_LIST. FDBASE says where to + start the duplicating. If it's less than SHELL_FD_BASE, we're ok, + and can use SHELL_FD_BASE (-1 == don't care). If it's >= SHELL_FD_BASE, + we have to make sure we don't use fdbase to save a file descriptor, + since we're going to use it later (e.g., make sure we don't save fd 0 + to fd 10 if we have a redirection like 0<&10). If the value of fdbase + puts the process over its fd limit, causing fcntl to fail, we try + again with SHELL_FD_BASE. */ static int -add_undo_redirect (fd, ri) +add_undo_redirect (fd, ri, fdbase) int fd; enum r_instruction ri; + int fdbase; { int new_fd, clexec_flag; REDIRECT *new_redirect, *closer, *dummy_redirect; + REDIRECTEE sd; - new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); + new_fd = fcntl (fd, F_DUPFD, (fdbase < SHELL_FD_BASE) ? SHELL_FD_BASE : fdbase+1); + if (new_fd < 0) + new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); if (new_fd < 0) { @@ -968,17 +1104,21 @@ add_undo_redirect (fd, ri) clexec_flag = fcntl (fd, F_GETFD, 0); + sd.dest = new_fd; rd.dest = 0; - closer = make_redirection (new_fd, r_close_this, rd); + closer = make_redirection (sd, r_close_this, rd, 0); closer->flags |= RX_INTERNAL; dummy_redirect = copy_redirects (closer); + sd.dest = fd; rd.dest = new_fd; if (fd == 0) - new_redirect = make_redirection (fd, r_duplicating_input, rd); + new_redirect = make_redirection (sd, r_duplicating_input, rd, 0); else - new_redirect = make_redirection (fd, r_duplicating_output, rd); + new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); new_redirect->flags |= RX_INTERNAL; + if (clexec_flag == 0 && fd >= 3 && new_fd >= SHELL_FD_BASE) + new_redirect->flags |= RX_SAVCLEXEC; new_redirect->next = closer; closer->next = redirection_undo_list; @@ -990,17 +1130,20 @@ add_undo_redirect (fd, ri) /* experimental: if we're saving a redirection to undo for a file descriptor above SHELL_FD_BASE, add a redirection to be undone if the exec builtin - causes redirections to be discarded. */ - if (fd >= SHELL_FD_BASE && ri != r_close_this) + causes redirections to be discarded. There needs to be a difference + between fds that are used to save other fds and then are the target of + user redirctions and fds that are just the target of user redirections. + We use the close-on-exec flag to tell the difference; fds > SHELL_FD_BASE + that have the close-on-exec flag set are assumed to be fds used internally + to save others. */ + if (fd >= SHELL_FD_BASE && ri != r_close_this && clexec_flag) { + sd.dest = fd; rd.dest = new_fd; - new_redirect = make_redirection (fd, r_duplicating_output, rd); -#if 0 - closer = copy_redirects (new_redirect); - add_exec_redirect (closer); -#else + new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); + new_redirect->flags |= RX_INTERNAL; + add_exec_redirect (new_redirect); -#endif } /* File descriptors used only for saving others should always be @@ -1013,6 +1156,8 @@ add_undo_redirect (fd, ri) and the restore above in do_redirection() will take care of it. */ if (clexec_flag || fd < 3) SET_CLOSE_ON_EXEC (new_fd); + else if (redirection_undo_list->flags & RX_SAVCLEXEC) + SET_CLOSE_ON_EXEC (new_fd); return (0); } @@ -1024,9 +1169,11 @@ add_undo_close_redirect (fd) int fd; { REDIRECT *closer; + REDIRECTEE sd; + sd.dest = fd; rd.dest = 0; - closer = make_redirection (fd, r_close_this, rd); + closer = make_redirection (sd, r_close_this, rd, 0); closer->flags |= RX_INTERNAL; closer->next = redirection_undo_list; redirection_undo_list = closer; @@ -1064,6 +1211,7 @@ stdin_redirection (ri, redirector) case r_appending_to: case r_duplicating_output: case r_err_and_out: + case r_append_err_and_out: case r_output_force: case r_duplicating_output_word: return (0); @@ -1081,6 +1229,49 @@ stdin_redirects (redirs) int n; for (n = 0, rp = redirs; rp; rp = rp->next) - n += stdin_redirection (rp->instruction, rp->redirector); + if ((rp->rflags & REDIR_VARASSIGN) == 0) + n += stdin_redirection (rp->instruction, rp->redirector.dest); return n; } + +/* These don't yet handle array references */ +static int +redir_varassign (redir, fd) + REDIRECT *redir; + int fd; +{ + WORD_DESC *w; + SHELL_VAR *v; + + w = redir->redirector.filename; + v = bind_var_to_int (w->word, fd); + if (v == 0 || readonly_p (v) || noassign_p (v)) + return BADVAR_REDIRECT; + + return 0; +} + +static int +redir_varvalue (redir) + REDIRECT *redir; +{ + SHELL_VAR *v; + char *val; + intmax_t vmax; + int i; + + /* XXX - handle set -u here? */ + v = find_variable (redir->redirector.filename->word); + if (v == 0 || invisible_p (v)) + return -1; + + val = get_variable_value (v); + if (val == 0 || *val == 0) + return -1; + + if (legal_number (val, &vmax) < 0) + return -1; + + i = vmax; /* integer truncation */ + return i; +} |