summaryrefslogtreecommitdiff
path: root/redir.c
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2010-10-11 14:49:26 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2010-10-11 15:19:40 -0700
commit011c1d1c0766c65517ebd495465c99e86edb63ec (patch)
tree30d8f6a13235af90897c3223554871ef52225462 /redir.c
parent40cfaccf7b178b6239b5cd0013ef80b7ff8e503e (diff)
downloadvyatta-bash-011c1d1c0766c65517ebd495465c99e86edb63ec.tar.gz
vyatta-bash-011c1d1c0766c65517ebd495465c99e86edb63ec.zip
Update to bash-4.1
Diffstat (limited to 'redir.c')
-rw-r--r--redir.c317
1 files changed, 254 insertions, 63 deletions
diff --git a/redir.c b/redir.c
index 0bd2d5f..c7a69f7 100644
--- a/redir.c
+++ b/redir.c
@@ -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;
+}