| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | /* redir.c -- Functions to perform input and output redirection. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | /* Copyright (C) 1997-2009 Free Software Foundation, Inc.
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    This file is part of GNU Bash, the Bourne Again SHell. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    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. | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    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. | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    You should have received a copy of the GNU General Public License | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #include "config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
 | 
					
						
							|  |  |  |   #pragma alloca
 | 
					
						
							|  |  |  | #endif /* _AIX && RISC6000 && !__GNUC__ */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include "bashtypes.h"
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | #if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #  include <sys/file.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include "filecntl.h"
 | 
					
						
							|  |  |  | #include "posixstat.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (HAVE_UNISTD_H)
 | 
					
						
							|  |  |  | #  include <unistd.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined (errno)
 | 
					
						
							|  |  |  | extern int errno; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bashansi.h"
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | #include "bashintl.h"
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #include "memalloc.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define NEED_FPURGE_DECL
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #include "shell.h"
 | 
					
						
							|  |  |  | #include "flags.h"
 | 
					
						
							|  |  |  | #include "execute_cmd.h"
 | 
					
						
							|  |  |  | #include "redir.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | #  include "input.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | #define SHELL_FD_BASE	10
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | int expanding_redir; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | extern int posixly_correct; | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | extern int last_command_exit_value; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | extern REDIRECT *redirection_undo_list; | 
					
						
							|  |  |  | extern REDIRECT *exec_redirection_undo_list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Static functions defined and used in this file. */ | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | static void add_exec_redirect __P((REDIRECT *)); | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | static int add_undo_redirect __P((int, enum r_instruction, int)); | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | static int add_undo_close_redirect __P((int)); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | static int expandable_redirection_filename __P((REDIRECT *)); | 
					
						
							|  |  |  | static int stdin_redirection __P((enum r_instruction, int)); | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | static int undoablefd __P((int)); | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | static int do_redirection_internal __P((REDIRECT *, int)); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int write_here_document __P((int, WORD_DESC *)); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | static int write_here_string __P((int, WORD_DESC *)); | 
					
						
							|  |  |  | static int here_document_to_fd __P((WORD_DESC *, enum r_instruction)); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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)); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | static int redir_varassign __P((REDIRECT *, int)); | 
					
						
							|  |  |  | static int redir_varvalue __P((REDIRECT *)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | /* Spare redirector used when translating [N]>&WORD[-] or [N]<&WORD[-] to
 | 
					
						
							|  |  |  |    a new redirection and when creating the redirection undo list. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | static REDIRECTEE rd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Set to errno when a here document cannot be created for some reason.
 | 
					
						
							|  |  |  |    Used to print a reasonable error message. */ | 
					
						
							|  |  |  | static int heredoc_errno; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | #define REDIRECTION_ERROR(r, e, fd) \
 | 
					
						
							|  |  |  | do { \ | 
					
						
							|  |  |  |   if ((r) < 0) \ | 
					
						
							|  |  |  |     { \ | 
					
						
							|  |  |  |       if (fd >= 0) \ | 
					
						
							|  |  |  | 	close (fd); \ | 
					
						
							|  |  |  |       last_command_exit_value = EXECUTION_FAILURE;\ | 
					
						
							|  |  |  |       return ((e) == 0 ? EINVAL : (e));\ | 
					
						
							|  |  |  |     } \ | 
					
						
							|  |  |  | } while (0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | void | 
					
						
							|  |  |  | redirection_error (temp, error) | 
					
						
							|  |  |  |      REDIRECT *temp; | 
					
						
							|  |  |  |      int error; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   char *filename, *allocname; | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   int oflags; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   allocname = 0; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   if (temp->rflags & REDIR_VARASSIGN) | 
					
						
							|  |  |  |     filename = savestring (temp->redirector.filename->word); | 
					
						
							|  |  |  |   else if (temp->redirector.dest < 0) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |     /* This can happen when read_token_word encounters overflow, like in
 | 
					
						
							|  |  |  |        exec 4294967297>x */ | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |     filename = _("file descriptor out of range"); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #ifdef EBADF
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   /* This error can never involve NOCLOBBER */ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   else if (error != NOCLOBBER_REDIRECT && temp->redirector.dest >= 0 && error == EBADF) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       /* 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 | 
					
						
							|  |  |  |          r_{duplicating,move}_output we're here because dup2() failed. */ | 
					
						
							|  |  |  |       switch (temp->instruction) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case r_duplicating_input: | 
					
						
							|  |  |  |         case r_duplicating_output: | 
					
						
							|  |  |  |         case r_move_input: | 
					
						
							|  |  |  |         case r_move_output: | 
					
						
							|  |  |  | 	  filename = allocname = itos (temp->redirectee.dest); | 
					
						
							|  |  |  | 	  break; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  filename = allocname = itos (temp->redirector.dest); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	  break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |   else if (expandable_redirection_filename (temp)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | expandable_filename: | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       if (posixly_correct && interactive_shell == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  oflags = temp->redirectee.filename->flags; | 
					
						
							|  |  |  | 	  temp->redirectee.filename->flags |= W_NOGLOB; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       filename = allocname = redirection_expand (temp->redirectee.filename); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       if (posixly_correct && interactive_shell == 0) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	temp->redirectee.filename->flags = oflags; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       if (filename == 0) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	filename = temp->redirectee.filename->word; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   else if (temp->redirectee.dest < 0) | 
					
						
							|  |  |  |     filename = "file descriptor out of range"; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |     filename = allocname = itos (temp->redirectee.dest); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   switch (error) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case AMBIGUOUS_REDIRECT: | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       internal_error (_("%s: ambiguous redirect"), filename); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case NOCLOBBER_REDIRECT: | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       internal_error (_("%s: cannot overwrite existing file"), filename); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (RESTRICTED_SHELL)
 | 
					
						
							|  |  |  |     case RESTRICTED_REDIRECT: | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       internal_error (_("%s: restricted: cannot redirect output"), filename); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  | #endif /* RESTRICTED_SHELL */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case HEREDOC_REDIRECT: | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       internal_error (_("cannot create temp file for here-document: %s"), strerror (heredoc_errno)); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |     case BADVAR_REDIRECT: | 
					
						
							|  |  |  |       internal_error (_("%s: cannot assign fd to variable"), filename); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     default: | 
					
						
							|  |  |  |       internal_error ("%s: %s", filename, strerror (error)); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   FREE (allocname); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | /* Perform the redirections on LIST.  If flags & RX_ACTIVE, then actually
 | 
					
						
							|  |  |  |    make input and output file descriptors, otherwise just do whatever is | 
					
						
							|  |  |  |    neccessary for side effecting.  flags & RX_UNDOABLE says to remember | 
					
						
							|  |  |  |    how to undo the redirections later, if non-zero.  If flags & RX_CLEXEC | 
					
						
							|  |  |  |    is non-zero, file descriptors opened in do_redirection () have their | 
					
						
							|  |  |  |    close-on-exec flag set. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | do_redirections (list, flags) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |      REDIRECT *list; | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |      int flags; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   int error; | 
					
						
							|  |  |  |   REDIRECT *temp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |   if (flags & RX_UNDOABLE) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       if (redirection_undo_list) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  dispose_redirects (redirection_undo_list); | 
					
						
							|  |  |  | 	  redirection_undo_list = (REDIRECT *)NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       if (exec_redirection_undo_list) | 
					
						
							|  |  |  | 	dispose_exec_redirects (); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (temp = list; temp; temp = temp->next) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       error = do_redirection_internal (temp, flags); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       if (error) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  redirection_error (temp, error); | 
					
						
							|  |  |  | 	  return (error); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return (0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Return non-zero if the redirection pointed to by REDIRECT has a
 | 
					
						
							|  |  |  |    redirectee.filename that can be expanded. */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | expandable_redirection_filename (redirect) | 
					
						
							|  |  |  |      REDIRECT *redirect; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (redirect->instruction) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case r_output_direction: | 
					
						
							|  |  |  |     case r_appending_to: | 
					
						
							|  |  |  |     case r_input_direction: | 
					
						
							|  |  |  |     case r_inputa_direction: | 
					
						
							|  |  |  |     case r_err_and_out: | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |     case r_append_err_and_out: | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     case r_input_output: | 
					
						
							|  |  |  |     case r_output_force: | 
					
						
							|  |  |  |     case r_duplicating_input_word: | 
					
						
							|  |  |  |     case r_duplicating_output_word: | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     case r_move_input_word: | 
					
						
							|  |  |  |     case r_move_output_word: | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Expand the word in WORD returning a string.  If WORD expands to
 | 
					
						
							|  |  |  |    multiple words (or no words), then return NULL. */ | 
					
						
							|  |  |  | char * | 
					
						
							|  |  |  | redirection_expand (word) | 
					
						
							|  |  |  |      WORD_DESC *word; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   char *result; | 
					
						
							|  |  |  |   WORD_LIST *tlist1, *tlist2; | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   WORD_DESC *w; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   w = copy_word (word); | 
					
						
							|  |  |  |   if (posixly_correct) | 
					
						
							|  |  |  |     w->flags |= W_NOSPLIT; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   tlist1 = make_word_list (w, (WORD_LIST *)NULL); | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |   expanding_redir = 1; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   tlist2 = expand_words_no_vars (tlist1); | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |   expanding_redir = 0; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   dispose_words (tlist1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!tlist2 || tlist2->next) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* We expanded to no words, or to more than a single word.
 | 
					
						
							|  |  |  | 	 Dispose of the word list and return NULL. */ | 
					
						
							|  |  |  |       if (tlist2) | 
					
						
							|  |  |  | 	dispose_words (tlist2); | 
					
						
							|  |  |  |       return ((char *)NULL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   result = string_list (tlist2);  /* XXX savestring (tlist2->word->word)? */ | 
					
						
							|  |  |  |   dispose_words (tlist2); | 
					
						
							|  |  |  |   return (result); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | static int | 
					
						
							|  |  |  | write_here_string (fd, redirectee) | 
					
						
							|  |  |  |      int fd; | 
					
						
							|  |  |  |      WORD_DESC *redirectee; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   char *herestr; | 
					
						
							|  |  |  |   int herelen, n, e; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   expanding_redir = 1; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   herestr = expand_string_to_string (redirectee->word, 0); | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   expanding_redir = 0; | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |   herelen = STRLEN (herestr); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   n = write (fd, herestr, herelen); | 
					
						
							|  |  |  |   if (n == herelen) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       n = write (fd, "\n", 1); | 
					
						
							|  |  |  |       herelen = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   e = errno; | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |   FREE (herestr); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   if (n != herelen) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (e == 0) | 
					
						
							|  |  |  | 	e = ENOSPC; | 
					
						
							|  |  |  |       return e; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | }   | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | /* Write the text of the here document pointed to by REDIRECTEE to the file
 | 
					
						
							|  |  |  |    descriptor FD, which is already open to a temp file.  Return 0 if the | 
					
						
							|  |  |  |    write is successful, otherwise return errno. */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | write_here_document (fd, redirectee) | 
					
						
							|  |  |  |      int fd; | 
					
						
							|  |  |  |      WORD_DESC *redirectee; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   char *document; | 
					
						
							|  |  |  |   int document_len, fd2; | 
					
						
							|  |  |  |   FILE *fp; | 
					
						
							|  |  |  |   register WORD_LIST *t, *tlist; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Expand the text if the word that was specified had
 | 
					
						
							|  |  |  |      no quoting.  The text that we expand is treated | 
					
						
							|  |  |  |      exactly as if it were surrounded by double quotes. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (redirectee->flags & W_QUOTED) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       document = redirectee->word; | 
					
						
							|  |  |  |       document_len = strlen (document); | 
					
						
							|  |  |  |       /* Set errno to something reasonable if the write fails. */ | 
					
						
							|  |  |  |       if (write (fd, document, document_len) < document_len) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  if (errno == 0) | 
					
						
							|  |  |  | 	    errno = ENOSPC; | 
					
						
							|  |  |  | 	  return (errno); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   expanding_redir = 1; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   tlist = expand_string (redirectee->word, Q_HERE_DOCUMENT); | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   expanding_redir = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   if (tlist) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* Try using buffered I/O (stdio) and writing a word
 | 
					
						
							|  |  |  | 	 at a time, letting stdio do the work of buffering | 
					
						
							|  |  |  | 	 for us rather than managing our own strings.  Most | 
					
						
							|  |  |  | 	 stdios are not particularly fast, however -- this | 
					
						
							|  |  |  | 	 may need to be reconsidered later. */ | 
					
						
							|  |  |  |       if ((fd2 = dup (fd)) < 0 || (fp = fdopen (fd2, "w")) == NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  if (fd2 >= 0) | 
					
						
							|  |  |  | 	    close (fd2); | 
					
						
							|  |  |  | 	  return (errno); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       errno = 0; | 
					
						
							|  |  |  |       for (t = tlist; t; t = t->next) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  /* This is essentially the body of
 | 
					
						
							|  |  |  | 	     string_list_internal expanded inline. */ | 
					
						
							|  |  |  | 	  document = t->word->word; | 
					
						
							|  |  |  | 	  document_len = strlen (document); | 
					
						
							|  |  |  | 	  if (t != tlist) | 
					
						
							|  |  |  | 	    putc (' ', fp);	/* separator */ | 
					
						
							|  |  |  | 	  fwrite (document, document_len, 1, fp); | 
					
						
							|  |  |  | 	  if (ferror (fp)) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      if (errno == 0) | 
					
						
							|  |  |  | 		errno = ENOSPC; | 
					
						
							|  |  |  | 	      fd2 = errno; | 
					
						
							|  |  |  | 	      fclose(fp); | 
					
						
							|  |  |  | 	      dispose_words (tlist); | 
					
						
							|  |  |  | 	      return (fd2); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       dispose_words (tlist); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       if (fclose (fp) != 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  if (errno == 0) | 
					
						
							|  |  |  | 	    errno = ENOSPC; | 
					
						
							|  |  |  | 	  return (errno); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Create a temporary file holding the text of the here document pointed to
 | 
					
						
							|  |  |  |    by REDIRECTEE, and return a file descriptor open for reading to the temp | 
					
						
							|  |  |  |    file.  Return -1 on any error, and make sure errno is set appropriately. */ | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | here_document_to_fd (redirectee, ri) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |      WORD_DESC *redirectee; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |      enum r_instruction ri; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   char *filename; | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   int r, fd, fd2; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   fd = sh_mktmpfd ("sh-thd", MT_USERANDOM|MT_USETMPDIR, &filename); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* If we failed for some reason other than the file existing, abort */ | 
					
						
							|  |  |  |   if (fd < 0) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       FREE (filename); | 
					
						
							|  |  |  |       return (fd); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   errno = r = 0;		/* XXX */ | 
					
						
							|  |  |  |   /* write_here_document returns 0 on success, errno on failure. */ | 
					
						
							|  |  |  |   if (redirectee->word) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     r = (ri != r_reading_string) ? write_here_document (fd, redirectee) | 
					
						
							|  |  |  | 				 : write_here_string (fd, redirectee); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (r) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       close (fd); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       unlink (filename); | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |       free (filename); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       errno = r; | 
					
						
							|  |  |  |       return (-1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   /* In an attempt to avoid races, we close the first fd only after opening
 | 
					
						
							|  |  |  |      the second. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   /* Make the document really temporary.  Also make it the input. */ | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  |   fd2 = open (filename, O_RDONLY|O_BINARY, 0600); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   if (fd2 < 0) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       r = errno; | 
					
						
							|  |  |  |       unlink (filename); | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |       free (filename); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       close (fd); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       errno = r; | 
					
						
							|  |  |  |       return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   close (fd); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   if (unlink (filename) < 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       r = errno; | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       close (fd2); | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |       free (filename); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       errno = r; | 
					
						
							|  |  |  |       return (-1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   free (filename); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   return (fd2); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | #define RF_DEVFD	1
 | 
					
						
							|  |  |  | #define RF_DEVSTDERR	2
 | 
					
						
							|  |  |  | #define RF_DEVSTDIN	3
 | 
					
						
							|  |  |  | #define RF_DEVSTDOUT	4
 | 
					
						
							|  |  |  | #define RF_DEVTCP	5
 | 
					
						
							|  |  |  | #define RF_DEVUDP	6
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* A list of pattern/value pairs for filenames that the redirection
 | 
					
						
							|  |  |  |    code handles specially. */ | 
					
						
							|  |  |  | static STRING_INT_ALIST _redir_special_filenames[] = { | 
					
						
							|  |  |  | #if !defined (HAVE_DEV_FD)
 | 
					
						
							|  |  |  |   { "/dev/fd/[0-9]*", RF_DEVFD }, | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #if !defined (HAVE_DEV_STDIN)
 | 
					
						
							|  |  |  |   { "/dev/stderr", RF_DEVSTDERR }, | 
					
						
							|  |  |  |   { "/dev/stdin", RF_DEVSTDIN }, | 
					
						
							|  |  |  |   { "/dev/stdout", RF_DEVSTDOUT }, | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #if defined (NETWORK_REDIRECTIONS)
 | 
					
						
							|  |  |  |   { "/dev/tcp/*/*", RF_DEVTCP }, | 
					
						
							|  |  |  |   { "/dev/udp/*/*", RF_DEVUDP }, | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |   { (char *)NULL, -1 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | redir_special_open (spec, filename, flags, mode, ri) | 
					
						
							|  |  |  |      int spec; | 
					
						
							|  |  |  |      char *filename; | 
					
						
							|  |  |  |      int flags, mode; | 
					
						
							|  |  |  |      enum r_instruction ri; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int fd; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #if !defined (HAVE_DEV_FD)
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   intmax_t lfd; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   fd = -1; | 
					
						
							|  |  |  |   switch (spec) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | #if !defined (HAVE_DEV_FD)
 | 
					
						
							|  |  |  |     case RF_DEVFD: | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       if (all_digits (filename+8) && legal_number (filename+8, &lfd) && lfd == (int)lfd) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  fd = lfd; | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	  fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       else | 
					
						
							|  |  |  | 	fd = AMBIGUOUS_REDIRECT; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined (HAVE_DEV_STDIN)
 | 
					
						
							|  |  |  |     case RF_DEVSTDIN: | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       fd = fcntl (0, F_DUPFD, SHELL_FD_BASE); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case RF_DEVSTDOUT: | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       fd = fcntl (1, F_DUPFD, SHELL_FD_BASE); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case RF_DEVSTDERR: | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       fd = fcntl (2, F_DUPFD, SHELL_FD_BASE); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (NETWORK_REDIRECTIONS)
 | 
					
						
							|  |  |  |     case RF_DEVTCP: | 
					
						
							|  |  |  |     case RF_DEVUDP: | 
					
						
							|  |  |  | #if defined (HAVE_NETWORK)
 | 
					
						
							|  |  |  |       fd = netopen (filename); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       internal_warning (_("/dev/(tcp|udp)/host/port not supported without networking")); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       fd = open (filename, flags, mode); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | #endif /* NETWORK_REDIRECTIONS */
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return fd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |        | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | /* Open FILENAME with FLAGS in noclobber mode, hopefully avoiding most
 | 
					
						
							|  |  |  |    race conditions and avoiding the problem where the file is replaced | 
					
						
							|  |  |  |    between the stat(2) and open(2). */ | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | noclobber_open (filename, flags, mode, ri) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |      char *filename; | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |      int flags, mode; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |      enum r_instruction ri; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int r, fd; | 
					
						
							|  |  |  |   struct stat finfo, finfo2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* If the file exists and is a regular file, return an error
 | 
					
						
							|  |  |  |      immediately. */ | 
					
						
							|  |  |  |   r = stat (filename, &finfo); | 
					
						
							|  |  |  |   if (r == 0 && (S_ISREG (finfo.st_mode))) | 
					
						
							|  |  |  |     return (NOCLOBBER_REDIRECT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* If the file was not present (r != 0), make sure we open it
 | 
					
						
							|  |  |  |      exclusively so that if it is created before we open it, our open | 
					
						
							|  |  |  |      will fail.  Make sure that we do not truncate an existing file. | 
					
						
							|  |  |  |      Note that we don't turn on O_EXCL unless the stat failed -- if | 
					
						
							|  |  |  |      the file was not a regular file, we leave O_EXCL off. */ | 
					
						
							|  |  |  |   flags &= ~O_TRUNC; | 
					
						
							|  |  |  |   if (r != 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       fd = open (filename, flags|O_EXCL, mode); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       return ((fd < 0 && errno == EEXIST) ? NOCLOBBER_REDIRECT : fd); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   fd = open (filename, flags, mode); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* If the open failed, return the file descriptor right away. */ | 
					
						
							|  |  |  |   if (fd < 0) | 
					
						
							|  |  |  |     return (errno == EEXIST ? NOCLOBBER_REDIRECT : fd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* OK, the open succeeded, but the file may have been changed from a
 | 
					
						
							|  |  |  |      non-regular file to a regular file between the stat and the open. | 
					
						
							|  |  |  |      We are assuming that the O_EXCL open handles the case where FILENAME | 
					
						
							|  |  |  |      did not exist and is symlinked to an existing file between the stat | 
					
						
							|  |  |  |      and open. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* If we can open it and fstat the file descriptor, and neither check
 | 
					
						
							|  |  |  |      revealed that it was a regular file, and the file has not been replaced, | 
					
						
							|  |  |  |      return the file descriptor. */ | 
					
						
							|  |  |  |   if ((fstat (fd, &finfo2) == 0) && (S_ISREG (finfo2.st_mode) == 0) && | 
					
						
							|  |  |  |       r == 0 && (S_ISREG (finfo.st_mode) == 0) && | 
					
						
							|  |  |  |       same_file (filename, filename, &finfo, &finfo2)) | 
					
						
							|  |  |  |     return fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* The file has been replaced.  badness. */ | 
					
						
							|  |  |  |   close (fd);   | 
					
						
							|  |  |  |   errno = EEXIST; | 
					
						
							|  |  |  |   return (NOCLOBBER_REDIRECT); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | static int | 
					
						
							|  |  |  | redir_open (filename, flags, mode, ri) | 
					
						
							|  |  |  |      char *filename; | 
					
						
							|  |  |  |      int flags, mode; | 
					
						
							|  |  |  |      enum r_instruction ri; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int fd, r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   r = find_string_in_alist (filename, _redir_special_filenames, 1); | 
					
						
							|  |  |  |   if (r >= 0) | 
					
						
							|  |  |  |     return (redir_special_open (r, filename, flags, mode, ri)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* If we are in noclobber mode, you are not allowed to overwrite
 | 
					
						
							|  |  |  |      existing files.  Check before opening. */ | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   if (noclobber && CLOBBERING_REDIRECT (ri)) | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       fd = noclobber_open (filename, flags, mode, ri); | 
					
						
							|  |  |  |       if (fd == NOCLOBBER_REDIRECT) | 
					
						
							|  |  |  | 	return (NOCLOBBER_REDIRECT); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       fd = open (filename, flags, mode); | 
					
						
							|  |  |  | #if defined (AFS)
 | 
					
						
							|  |  |  |       if ((fd < 0) && (errno == EACCES)) | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	  fd = open (filename, flags & ~O_CREAT, mode); | 
					
						
							|  |  |  | 	  errno = EACCES;	/* restore errno */ | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | #endif /* AFS */
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return fd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | /* Do the specific redirection requested.  Returns errno or one of the
 | 
					
						
							|  |  |  |    special redirection errors (*_REDIRECT) in case of error, 0 on success. | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |    If flags & RX_ACTIVE is zero, then just do whatever is neccessary to | 
					
						
							|  |  |  |    produce the appropriate side effects.   flags & RX_UNDOABLE, if non-zero, | 
					
						
							|  |  |  |    says to remember how to undo each redirection.  If flags & RX_CLEXEC is | 
					
						
							|  |  |  |    non-zero, then we set all file descriptors > 2 that we open to be | 
					
						
							|  |  |  |    close-on-exec.  */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | do_redirection_internal (redirect, flags) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |      REDIRECT *redirect; | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |      int flags; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   WORD_DESC *redirectee; | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   int redir_fd, fd, redirector, r, oflags; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   intmax_t lfd; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   char *redirectee_word; | 
					
						
							|  |  |  |   enum r_instruction ri; | 
					
						
							|  |  |  |   REDIRECT *new_redirect; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   REDIRECTEE sd; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   redirectee = redirect->redirectee.filename; | 
					
						
							|  |  |  |   redir_fd = redirect->redirectee.dest; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   redirector = redirect->redirector.dest; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   ri = redirect->instruction; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-10 14:15:34 +00:00
										 |  |  |   if (redirect->flags & RX_INTERNAL) | 
					
						
							|  |  |  |     flags |= RX_INTERNAL; | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   if (TRANSLATE_REDIRECT (ri)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |       /* 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. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       redirectee_word = redirection_expand (redirectee); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       /* XXX - what to do with [N]<&$w- where w is unset or null?  ksh93
 | 
					
						
							|  |  |  | 	       closes N. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       if (redirectee_word == 0) | 
					
						
							|  |  |  | 	return (AMBIGUOUS_REDIRECT); | 
					
						
							|  |  |  |       else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  sd = redirect->redirector; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	  rd.dest = 0; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  new_redirect = make_redirection (sd, r_close_this, rd, 0); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  |       else if (all_digits (redirectee_word)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  sd = redirect->redirector; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	  if (legal_number (redirectee_word, &lfd) && (int)lfd == lfd) | 
					
						
							|  |  |  | 	    rd.dest = lfd; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	  else | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	    rd.dest = -1;	/* XXX */ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	  switch (ri) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	    case r_duplicating_input_word: | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	      new_redirect = make_redirection (sd, r_duplicating_input, rd, 0); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	      break; | 
					
						
							|  |  |  | 	    case r_duplicating_output_word: | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	      new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	      break; | 
					
						
							|  |  |  | 	    case r_move_input_word: | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	      new_redirect = make_redirection (sd, r_move_input, rd, 0); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	      break; | 
					
						
							|  |  |  | 	    case r_move_output_word: | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	      new_redirect = make_redirection (sd, r_move_output, rd, 0); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	      break; | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |       else if (ri == r_duplicating_output_word && (redirect->rflags & REDIR_VARASSIGN) == 0 && redirector == 1) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  sd = redirect->redirector; | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	  rd.filename = make_bare_word (redirectee_word); | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  new_redirect = make_redirection (sd, r_err_and_out, rd, 0); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  free (redirectee_word); | 
					
						
							|  |  |  | 	  return (AMBIGUOUS_REDIRECT); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       free (redirectee_word); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* Set up the variables needed by the rest of the function from the
 | 
					
						
							|  |  |  | 	 new redirection. */ | 
					
						
							|  |  |  |       if (new_redirect->instruction == r_err_and_out) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  char *alloca_hack; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  /* Copy the word without allocating any memory that must be
 | 
					
						
							|  |  |  | 	     explicitly freed. */ | 
					
						
							|  |  |  | 	  redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC)); | 
					
						
							|  |  |  | 	  xbcopy ((char *)new_redirect->redirectee.filename, | 
					
						
							|  |  |  | 		 (char *)redirectee, sizeof (WORD_DESC)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  alloca_hack = (char *) | 
					
						
							|  |  |  | 	    alloca (1 + strlen (new_redirect->redirectee.filename->word)); | 
					
						
							|  |  |  | 	  redirectee->word = alloca_hack; | 
					
						
							|  |  |  | 	  strcpy (redirectee->word, new_redirect->redirectee.filename->word); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  | 	/* It's guaranteed to be an integer, and shouldn't be freed. */ | 
					
						
							|  |  |  | 	redirectee = new_redirect->redirectee.filename; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       redir_fd = new_redirect->redirectee.dest; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |       redirector = new_redirect->redirector.dest; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       ri = new_redirect->instruction; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* Overwrite the flags element of the old redirect with the new value. */ | 
					
						
							|  |  |  |       redirect->flags = new_redirect->flags; | 
					
						
							|  |  |  |       dispose_redirects (new_redirect); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (ri) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case r_output_direction: | 
					
						
							|  |  |  |     case r_appending_to: | 
					
						
							|  |  |  |     case r_input_direction: | 
					
						
							|  |  |  |     case r_inputa_direction: | 
					
						
							|  |  |  |     case r_err_and_out:		/* command &>filename */ | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |     case r_append_err_and_out:	/* command &>> filename */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     case r_input_output: | 
					
						
							|  |  |  |     case r_output_force: | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       if (posixly_correct && interactive_shell == 0) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	  oflags = redirectee->flags; | 
					
						
							|  |  |  | 	  redirectee->flags |= W_NOGLOB; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       redirectee_word = redirection_expand (redirectee); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       if (posixly_correct && interactive_shell == 0) | 
					
						
							|  |  |  | 	redirectee->flags = oflags; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (redirectee_word == 0) | 
					
						
							|  |  |  | 	return (AMBIGUOUS_REDIRECT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (RESTRICTED_SHELL)
 | 
					
						
							|  |  |  |       if (restricted && (WRITE_REDIRECT (ri))) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  free (redirectee_word); | 
					
						
							|  |  |  | 	  return (RESTRICTED_REDIRECT); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif /* RESTRICTED_SHELL */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       fd = redir_open (redirectee_word, redirect->flags, 0666, ri); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       free (redirectee_word); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       if (fd == NOCLOBBER_REDIRECT) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	return (fd); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       if (fd < 0) | 
					
						
							|  |  |  | 	return (errno); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       if (flags & RX_ACTIVE) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  if (redirect->rflags & REDIR_VARASSIGN) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 	      redirector = fcntl (fd, F_DUPFD, SHELL_FD_BASE);		/* XXX try this for now */ | 
					
						
							|  |  |  | 	      r = errno; | 
					
						
							|  |  |  | 	      if (redirector < 0) | 
					
						
							|  |  |  | 		sys_error (_("redirection error: cannot duplicate fd")); | 
					
						
							|  |  |  | 	      REDIRECTION_ERROR (redirector, r, fd); | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  if (flags & RX_UNDOABLE) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 	      /* Only setup to undo it if the thing to undo is active. */ | 
					
						
							|  |  |  | 	      if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 		r = add_undo_redirect (redirector, ri, -1); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	      else | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 		r = add_undo_close_redirect (redirector); | 
					
						
							|  |  |  | 	      if (r < 0 && (redirect->rflags & REDIR_VARASSIGN)) | 
					
						
							|  |  |  | 		close (redirector); | 
					
						
							|  |  |  | 	      REDIRECTION_ERROR (r, errno, fd); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	    } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | 	  check_bash_input (redirector); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	  /* 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); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  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)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	    return (errno); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | 	  /* Do not change the buffered stream for an implicit redirection
 | 
					
						
							|  |  |  | 	     of /dev/null to fd 0 for asynchronous commands without job | 
					
						
							|  |  |  | 	     control (r_inputa_direction). */ | 
					
						
							|  |  |  | 	  if (ri == r_input_direction || ri == r_input_output) | 
					
						
							|  |  |  | 	    duplicate_buffered_stream (fd, redirector); | 
					
						
							|  |  |  | #endif /* BUFFERED_INPUT */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  /*
 | 
					
						
							|  |  |  | 	   * If we're remembering, then this is the result of a while, for | 
					
						
							|  |  |  | 	   * or until loop with a loop redirection, or a function/builtin | 
					
						
							|  |  |  | 	   * executing in the parent shell with a redirection.  In the | 
					
						
							|  |  |  | 	   * function/builtin case, we want to set all file descriptors > 2 | 
					
						
							|  |  |  | 	   * to be close-on-exec to duplicate the effect of the old | 
					
						
							|  |  |  | 	   * for i = 3 to NOFILE close(i) loop.  In the case of the loops, | 
					
						
							|  |  |  | 	   * both sh and ksh leave the file descriptors open across execs. | 
					
						
							|  |  |  | 	   * The Posix standard mentions only the exec builtin. | 
					
						
							|  |  |  | 	   */ | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  if ((flags & RX_CLEXEC) && (redirector > 2)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	    SET_CLOSE_ON_EXEC (redirector); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (fd != redirector) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | 	  if (INPUT_REDIRECT (ri)) | 
					
						
							|  |  |  | 	    close_buffered_fd (fd); | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | #endif /* !BUFFERED_INPUT */
 | 
					
						
							|  |  |  | 	    close (fd);		/* Don't close what we just opened! */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* If we are hacking both stdout and stderr, do the stderr
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	 redirection here.  XXX - handle {var} here? */ | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       if (ri == r_err_and_out || ri == r_append_err_and_out) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  if (flags & RX_ACTIVE) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	      if (flags & RX_UNDOABLE) | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 		add_undo_redirect (2, ri, -1); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	      if (dup2 (1, 2) < 0) | 
					
						
							|  |  |  | 		return (errno); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case r_reading_until: | 
					
						
							|  |  |  |     case r_deblank_reading_until: | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     case r_reading_string: | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       /* REDIRECTEE is a pointer to a WORD_DESC containing the text of
 | 
					
						
							|  |  |  | 	 the new input.  Place it in a temporary file. */ | 
					
						
							|  |  |  |       if (redirectee) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	  fd = here_document_to_fd (redirectee, ri); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	  if (fd < 0) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      heredoc_errno = errno; | 
					
						
							|  |  |  | 	      return (HEREDOC_REDIRECT); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  if (redirect->rflags & REDIR_VARASSIGN) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 	      redirector = fcntl (fd, F_DUPFD, SHELL_FD_BASE);		/* XXX try this for now */ | 
					
						
							|  |  |  | 	      r = errno; | 
					
						
							|  |  |  | 	      if (redirector < 0) | 
					
						
							|  |  |  | 		sys_error (_("redirection error: cannot duplicate fd")); | 
					
						
							|  |  |  | 	      REDIRECTION_ERROR (redirector, r, fd); | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  if (flags & RX_ACTIVE) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	      if (flags & RX_UNDOABLE) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	        { | 
					
						
							|  |  |  | 		  /* Only setup to undo it if the thing to undo is active. */ | 
					
						
							|  |  |  | 		  if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 		    r = add_undo_redirect (redirector, ri, -1); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 		  else | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 		    r = add_undo_close_redirect (redirector); | 
					
						
							|  |  |  | 		  if (r < 0 && (redirect->rflags & REDIR_VARASSIGN)) | 
					
						
							|  |  |  | 		    close (redirector); | 
					
						
							|  |  |  | 		  REDIRECTION_ERROR (r, errno, fd); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	        } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | 	      check_bash_input (redirector); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	      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) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 		  r = errno; | 
					
						
							|  |  |  | 		  close (fd); | 
					
						
							|  |  |  | 		  return (r); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | 	      duplicate_buffered_stream (fd, redirector); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	      if ((flags & RX_CLEXEC) && (redirector > 2)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 		SET_CLOSE_ON_EXEC (redirector); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | 	  if (fd != redirector) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | 	    close_buffered_fd (fd); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | 	    close (fd); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case r_duplicating_input: | 
					
						
							|  |  |  |     case r_duplicating_output: | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     case r_move_input: | 
					
						
							|  |  |  |     case r_move_output: | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |       if ((flags & RX_ACTIVE) && (redirect->rflags & REDIR_VARASSIGN)) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  |         { | 
					
						
							|  |  |  | 	  redirector = fcntl (redir_fd, F_DUPFD, SHELL_FD_BASE);		/* XXX try this for now */ | 
					
						
							|  |  |  | 	  r = errno; | 
					
						
							|  |  |  | 	  if (redirector < 0) | 
					
						
							|  |  |  | 	    sys_error (_("redirection error: cannot duplicate fd")); | 
					
						
							|  |  |  | 	  REDIRECTION_ERROR (redirector, r, -1); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       if ((flags & RX_ACTIVE) && (redir_fd != redirector)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  if (flags & RX_UNDOABLE) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 	      /* Only setup to undo it if the thing to undo is active. */ | 
					
						
							|  |  |  | 	      if (fcntl (redirector, F_GETFD, 0) != -1) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 		r = add_undo_redirect (redirector, ri, redir_fd); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	      else | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 		r = add_undo_close_redirect (redirector); | 
					
						
							|  |  |  | 	      if (r < 0 && (redirect->rflags & REDIR_VARASSIGN)) | 
					
						
							|  |  |  | 		close (redirector); | 
					
						
							|  |  |  | 	      REDIRECTION_ERROR (r, errno, -1); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	    } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | 	  check_bash_input (redirector); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  if (redirect->rflags & REDIR_VARASSIGN) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      if ((r = redir_varassign (redirect, redirector)) < 0) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  close (redirector); | 
					
						
							|  |  |  | 		  return (r);	/* XXX */ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	  /* This is correct.  2>&1 means dup2 (1, 2); */ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  else if (dup2 (redir_fd, redirector) < 0) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	    return (errno); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	  if (ri == r_duplicating_input || ri == r_move_input) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	    duplicate_buffered_stream (redir_fd, redirector); | 
					
						
							|  |  |  | #endif /* BUFFERED_INPUT */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  /* First duplicate the close-on-exec state of redirectee.  dup2
 | 
					
						
							|  |  |  | 	     leaves the flag unset on the new descriptor, which means it | 
					
						
							|  |  |  | 	     stays open.  Only set the close-on-exec bit for file descriptors | 
					
						
							|  |  |  | 	     greater than 2 in any case, since 0-2 should always be open | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | 	     unless closed by something like `exec 2<&-'.  It should always | 
					
						
							|  |  |  | 	     be safe to set fds > 2 to close-on-exec if they're being used to | 
					
						
							|  |  |  | 	     save file descriptors < 2, since we don't need to preserve the | 
					
						
							|  |  |  | 	     state of the close-on-exec flag for those fds -- they should | 
					
						
							|  |  |  | 	     always be open. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	  /* if ((already_set || set_unconditionally) && (ok_to_set))
 | 
					
						
							|  |  |  | 		set_it () */ | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | #if 0
 | 
					
						
							|  |  |  | 	  if (((fcntl (redir_fd, F_GETFD, 0) == 1) || redir_fd < 2 || (flags & RX_CLEXEC)) && | 
					
						
							|  |  |  | 	       (redirector > 2)) | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	  if (((fcntl (redir_fd, F_GETFD, 0) == 1) || (redir_fd < 2 && (flags & RX_INTERNAL)) || (flags & RX_CLEXEC)) && | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	       (redirector > 2)) | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	    SET_CLOSE_ON_EXEC (redirector); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	  /* 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); | 
					
						
							|  |  |  | 	     | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	  /* dup-and-close redirection */ | 
					
						
							|  |  |  | 	  if (ri == r_move_input || ri == r_move_output) | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	      xtrace_fdchk (redir_fd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	      close (redir_fd); | 
					
						
							|  |  |  | #if defined (COPROCESS_SUPPORT)
 | 
					
						
							|  |  |  | 	      coproc_fdchk (redir_fd);	/* XXX - loses coproc fds */ | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case r_close_this: | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       if (flags & RX_ACTIVE) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  if (redirect->rflags & REDIR_VARASSIGN) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      redirector = redir_varvalue (redirect); | 
					
						
							|  |  |  | 	      if (redirector < 0) | 
					
						
							|  |  |  | 		return AMBIGUOUS_REDIRECT; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 	  r = 0; | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  if ((flags & RX_UNDOABLE) && (fcntl (redirector, F_GETFD, 0) != -1)) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 	      r = add_undo_redirect (redirector, ri, -1); | 
					
						
							|  |  |  | 	      REDIRECTION_ERROR (r, errno, redirector); | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if defined (COPROCESS_SUPPORT)
 | 
					
						
							|  |  |  | 	  coproc_fdchk (redirector); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 	  xtrace_fdchk (redirector); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if defined (BUFFERED_INPUT)
 | 
					
						
							|  |  |  | 	  check_bash_input (redirector); | 
					
						
							|  |  |  | 	  close_buffered_fd (redirector); | 
					
						
							|  |  |  | #else /* !BUFFERED_INPUT */
 | 
					
						
							|  |  |  | 	  close (redirector); | 
					
						
							|  |  |  | #endif /* !BUFFERED_INPUT */
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case r_duplicating_input_word: | 
					
						
							|  |  |  |     case r_duplicating_output_word: | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return (0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* 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 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    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 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  |    again with SHELL_FD_BASE.  Return 0 on success, -1 on error. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | add_undo_redirect (fd, ri, fdbase) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |      int fd; | 
					
						
							| 
									
										
										
										
											2006-10-10 14:15:34 +00:00
										 |  |  |      enum r_instruction ri; | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |      int fdbase; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   int new_fd, clexec_flag; | 
					
						
							|  |  |  |   REDIRECT *new_redirect, *closer, *dummy_redirect; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   REDIRECTEE sd; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (new_fd < 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       sys_error (_("redirection error: cannot duplicate fd")); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       return (-1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   clexec_flag = fcntl (fd, F_GETFD, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   sd.dest = new_fd; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   rd.dest = 0; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   closer = make_redirection (sd, r_close_this, rd, 0); | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |   closer->flags |= RX_INTERNAL; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   dummy_redirect = copy_redirects (closer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   sd.dest = fd; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   rd.dest = new_fd; | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   if (fd == 0) | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |     new_redirect = make_redirection (sd, r_duplicating_input, rd, 0); | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |     new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |   new_redirect->flags |= RX_INTERNAL; | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   if (clexec_flag == 0 && fd >= 3 && new_fd >= SHELL_FD_BASE) | 
					
						
							|  |  |  |     new_redirect->flags |= RX_SAVCLEXEC; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   new_redirect->next = closer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   closer->next = redirection_undo_list; | 
					
						
							|  |  |  |   redirection_undo_list = new_redirect; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Save redirections that need to be undone even if the undo list
 | 
					
						
							|  |  |  |      is thrown away by the `exec' builtin. */ | 
					
						
							|  |  |  |   add_exec_redirect (dummy_redirect); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |   /* 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 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |      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 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  |      user redirections and fds that are just the target of user redirections. | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |      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) | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |       sd.dest = fd; | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |       rd.dest = new_fd; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |       new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       new_redirect->flags |= RX_INTERNAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |       add_exec_redirect (new_redirect); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   /* File descriptors used only for saving others should always be
 | 
					
						
							|  |  |  |      marked close-on-exec.  Unfortunately, we have to preserve the | 
					
						
							|  |  |  |      close-on-exec state of the file descriptor we are saving, since | 
					
						
							|  |  |  |      fcntl (F_DUPFD) sets the new file descriptor to remain open | 
					
						
							|  |  |  |      across execs.  If, however, the file descriptor whose state we | 
					
						
							|  |  |  |      are saving is <= 2, we can just set the close-on-exec flag, | 
					
						
							|  |  |  |      because file descriptors 0-2 should always be open-on-exec, | 
					
						
							|  |  |  |      and the restore above in do_redirection() will take care of it. */ | 
					
						
							|  |  |  |   if (clexec_flag || fd < 3) | 
					
						
							|  |  |  |     SET_CLOSE_ON_EXEC (new_fd); | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   else if (redirection_undo_list->flags & RX_SAVCLEXEC) | 
					
						
							|  |  |  |     SET_CLOSE_ON_EXEC (new_fd); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return (0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Set up to close FD when we are finished with the current command
 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  |    and its redirections.  Return 0 on success, -1 on error. */ | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | add_undo_close_redirect (fd) | 
					
						
							|  |  |  |      int fd; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   REDIRECT *closer; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   REDIRECTEE sd; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   sd.dest = fd; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   rd.dest = 0; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |   closer = make_redirection (sd, r_close_this, rd, 0); | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |   closer->flags |= RX_INTERNAL; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   closer->next = redirection_undo_list; | 
					
						
							|  |  |  |   redirection_undo_list = closer; | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | add_exec_redirect (dummy_redirect) | 
					
						
							|  |  |  |      REDIRECT *dummy_redirect; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   dummy_redirect->next = exec_redirection_undo_list; | 
					
						
							|  |  |  |   exec_redirection_undo_list = dummy_redirect; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | /* Return 1 if the redirection specified by RI and REDIRECTOR alters the
 | 
					
						
							|  |  |  |    standard input. */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | stdin_redirection (ri, redirector) | 
					
						
							|  |  |  |      enum r_instruction ri; | 
					
						
							|  |  |  |      int redirector; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (ri) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case r_input_direction: | 
					
						
							|  |  |  |     case r_inputa_direction: | 
					
						
							|  |  |  |     case r_input_output: | 
					
						
							|  |  |  |     case r_reading_until: | 
					
						
							|  |  |  |     case r_deblank_reading_until: | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     case r_reading_string: | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       return (1); | 
					
						
							|  |  |  |     case r_duplicating_input: | 
					
						
							|  |  |  |     case r_duplicating_input_word: | 
					
						
							|  |  |  |     case r_close_this: | 
					
						
							|  |  |  |       return (redirector == 0); | 
					
						
							|  |  |  |     case r_output_direction: | 
					
						
							|  |  |  |     case r_appending_to: | 
					
						
							|  |  |  |     case r_duplicating_output: | 
					
						
							|  |  |  |     case r_err_and_out: | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |     case r_append_err_and_out: | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |     case r_output_force: | 
					
						
							|  |  |  |     case r_duplicating_output_word: | 
					
						
							|  |  |  |       return (0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return (0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | /* Return non-zero if any of the redirections in REDIRS alter the standard
 | 
					
						
							|  |  |  |    input. */ | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | stdin_redirects (redirs) | 
					
						
							|  |  |  |      REDIRECT *redirs; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   REDIRECT *rp; | 
					
						
							|  |  |  |   int n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (n = 0, rp = redirs; rp; rp = rp->next) | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  |     if ((rp->rflags & REDIR_VARASSIGN) == 0) | 
					
						
							|  |  |  |       n += stdin_redirection (rp->instruction, rp->redirector.dest); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   return n; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* 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; | 
					
						
							|  |  |  | } |