f01d4141e53e73354c1b408a21f118bffa734749
[platform/upstream/bash.git] / redir.c
1 /* redir.c -- Functions to perform input and output redirection. */
2
3 /* Copyright (C) 1997 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne Again SHell.
6
7    Bash is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 1, or (at your option)
10    any later version.
11
12    Bash is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Bash; see the file COPYING.  If not, write to the Free
19    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 #include "config.h"
21
22 #if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
23   #pragma alloca
24 #endif /* _AIX && RISC6000 && !__GNUC__ */
25
26 #include <stdio.h>
27 #include "bashtypes.h"
28 #ifndef _MINIX
29 #  include <sys/file.h>
30 #endif
31 #include "filecntl.h"
32 #include "posixstat.h"
33
34 #if defined (HAVE_UNISTD_H)
35 #  include <unistd.h>
36 #endif
37
38 #include <errno.h>
39
40 #if !defined (errno)
41 extern int errno;
42 #endif
43
44 #include "bashansi.h"
45
46 #include "memalloc.h"
47 #include "shell.h"
48 #include "flags.h"
49 #include "execute_cmd.h"
50 #include "redir.h"
51
52 #if defined (BUFFERED_INPUT)
53 #  include "input.h"
54 #endif
55
56 extern int posixly_correct;
57 extern int interactive, interactive_shell;
58 extern REDIRECT *redirection_undo_list;
59 extern REDIRECT *exec_redirection_undo_list;
60
61 /* Static functions defined and used in this file. */
62 static void add_undo_close_redirect ();
63 static void add_exec_redirect ();
64 static int add_undo_redirect ();
65 static int do_redirection_internal ();
66 static int expandable_redirection_filename ();
67
68 /* Spare redirector used when translating [N]>&WORD or [N]<&WORD to a new
69    redirection and when creating the redirection undo list. */
70 static REDIRECTEE rd;
71
72 /* Set to errno when a here document cannot be created for some reason.
73    Used to print a reasonable error message. */
74 static int heredoc_errno;
75
76 void
77 redirection_error (temp, error)
78      REDIRECT *temp;
79      int error;
80 {
81   char *filename;
82
83   if (expandable_redirection_filename (temp))
84     {
85       if (posixly_correct && !interactive_shell)
86         disallow_filename_globbing++;
87       filename = redirection_expand (temp->redirectee.filename);
88       if (posixly_correct && !interactive_shell)
89         disallow_filename_globbing--;
90       if (filename == 0)
91         filename = savestring (temp->redirectee.filename->word);
92       if (filename == 0)
93         {
94           filename = xmalloc (1);
95           filename[0] = '\0';
96         }
97     }
98   else
99     filename = itos (temp->redirectee.dest);
100
101   switch (error)
102     {
103     case AMBIGUOUS_REDIRECT:
104       internal_error ("%s: ambiguous redirect", filename);
105       break;
106
107     case NOCLOBBER_REDIRECT:
108       internal_error ("%s: cannot overwrite existing file", filename);
109       break;
110
111 #if defined (RESTRICTED_SHELL)
112     case RESTRICTED_REDIRECT:
113       internal_error ("%s: restricted: cannot redirect output", filename);
114       break;
115 #endif /* RESTRICTED_SHELL */
116
117     case HEREDOC_REDIRECT:
118       internal_error ("cannot create temp file for here document: %s", strerror (heredoc_errno));
119       break;
120
121     default:
122       internal_error ("%s: %s", filename, strerror (error));
123       break;
124     }
125
126   FREE (filename);
127 }
128
129 /* Perform the redirections on LIST.  If FOR_REAL, then actually make
130    input and output file descriptors, otherwise just do whatever is
131    neccessary for side effecting.  INTERNAL says to remember how to
132    undo the redirections later, if non-zero.  If SET_CLEXEC is non-zero,
133    file descriptors opened in do_redirection () have their close-on-exec
134    flag set. */
135 int
136 do_redirections (list, for_real, internal, set_clexec)
137      REDIRECT *list;
138      int for_real, internal, set_clexec;
139 {
140   int error;
141   REDIRECT *temp;
142
143   if (internal)
144     {
145       if (redirection_undo_list)
146         {
147           dispose_redirects (redirection_undo_list);
148           redirection_undo_list = (REDIRECT *)NULL;
149         }
150       if (exec_redirection_undo_list)
151         dispose_exec_redirects ();
152     }
153
154   for (temp = list; temp; temp = temp->next)
155     {
156       error = do_redirection_internal (temp, for_real, internal, set_clexec);
157       if (error)
158         {
159           redirection_error (temp, error);
160           return (error);
161         }
162     }
163   return (0);
164 }
165
166 /* Return non-zero if the redirection pointed to by REDIRECT has a
167    redirectee.filename that can be expanded. */
168 static int
169 expandable_redirection_filename (redirect)
170      REDIRECT *redirect;
171 {
172   switch (redirect->instruction)
173     {
174     case r_output_direction:
175     case r_appending_to:
176     case r_input_direction:
177     case r_inputa_direction:
178     case r_err_and_out:
179     case r_input_output:
180     case r_output_force:
181     case r_duplicating_input_word:
182     case r_duplicating_output_word:
183       return 1;
184
185     default:
186       return 0;
187     }
188 }
189
190 /* Expand the word in WORD returning a string.  If WORD expands to
191    multiple words (or no words), then return NULL. */
192 char *
193 redirection_expand (word)
194      WORD_DESC *word;
195 {
196   char *result;
197   WORD_LIST *tlist1, *tlist2;
198
199   tlist1 = make_word_list (copy_word (word), (WORD_LIST *)NULL);
200   tlist2 = expand_words_no_vars (tlist1);
201   dispose_words (tlist1);
202
203   if (!tlist2 || tlist2->next)
204     {
205       /* We expanded to no words, or to more than a single word.
206          Dispose of the word list and return NULL. */
207       if (tlist2)
208         dispose_words (tlist2);
209       return ((char *)NULL);
210     }
211   result = string_list (tlist2);  /* XXX savestring (tlist2->word->word)? */
212   dispose_words (tlist2);
213   return (result);
214 }
215
216 /* Write the text of the here document pointed to by REDIRECTEE to the file
217    descriptor FD, which is already open to a temp file.  Return 0 if the
218    write is successful, otherwise return errno. */
219 static int
220 write_here_document (fd, redirectee)
221      int fd;
222      WORD_DESC *redirectee;
223 {
224   char *document;
225   int document_len, fd2;
226   FILE *fp;
227   register WORD_LIST *t, *tlist;
228
229   /* Expand the text if the word that was specified had
230      no quoting.  The text that we expand is treated
231      exactly as if it were surrounded by double quotes. */
232
233   if (redirectee->flags & W_QUOTED)
234     {
235       document = redirectee->word;
236       document_len = strlen (document);
237       /* Set errno to something reasonable if the write fails. */
238       if (write (fd, document, document_len) < document_len)
239         {
240           if (errno == 0)
241             errno = ENOSPC;
242           return (errno);
243         }
244       else
245         return 0;
246     }
247
248   tlist = expand_string (redirectee->word, Q_HERE_DOCUMENT);
249   if (tlist)
250     {
251       /* Try using buffered I/O (stdio) and writing a word
252          at a time, letting stdio do the work of buffering
253          for us rather than managing our own strings.  Most
254          stdios are not particularly fast, however -- this
255          may need to be reconsidered later. */
256       if ((fd2 = dup (fd)) < 0 || (fp = fdopen (fd2, "w")) == NULL)
257         {
258           if (fd2 >= 0)
259             close (fd2);
260           return (errno);
261         }
262       errno = 0;
263       for (t = tlist; t; t = t->next)
264         {
265           /* This is essentially the body of
266              string_list_internal expanded inline. */
267           document = t->word->word;
268           document_len = strlen (document);
269           if (t != tlist)
270             putc (' ', fp);     /* separator */
271           fwrite (document, document_len, 1, fp);
272           if (ferror (fp))
273             {
274               if (errno == 0)
275                 errno = ENOSPC;
276               fd2 = errno;
277               fclose(fp);
278               dispose_words (tlist);
279               return (fd2);
280             }
281         }
282       fclose (fp);
283       dispose_words (tlist);
284     }
285   return 0;
286 }
287
288 /* Create a temporary file holding the text of the here document pointed to
289    by REDIRECTEE, and return a file descriptor open for reading to the temp
290    file.  Return -1 on any error, and make sure errno is set appropriately. */
291 static int
292 here_document_to_fd (redirectee)
293      WORD_DESC *redirectee;
294 {
295   char filename[24];
296   int r, fd;
297   static int fnum = 0;
298
299   do
300     {
301       /* Make the filename for the temp file. */
302       sprintf (filename, "/tmp/t%d-%d-sh", (int)getpid (), fnum++);
303
304       /* Make sure we open it exclusively. */
305       fd = open (filename, O_TRUNC | O_WRONLY | O_CREAT | O_EXCL, 0600);
306     }
307   while (fd < 0 && errno == EEXIST);
308
309   /* If we failed for some reason other than the file existing, abort */
310   if (fd < 0)
311     return (fd);
312
313   errno = r = 0;                /* XXX */
314   /* write_here_document returns 0 on success, errno on failure. */
315   if (redirectee->word)
316     r = write_here_document (fd, redirectee);
317
318   close (fd);
319   if (r)
320     {
321       unlink (filename);
322       errno = r;
323       return (-1);
324     }
325
326   /* XXX - this is raceable */
327   /* Make the document really temporary.  Also make it the input. */
328   fd = open (filename, O_RDONLY, 0600);
329
330   if (fd < 0)
331     {
332       r = errno;
333       unlink (filename);
334       errno = r;
335       return -1;
336     }
337
338   if (unlink (filename) < 0)
339     {
340       r = errno;
341       close (fd);
342       errno = r;
343       return (-1);
344     }
345
346   return (fd);
347 }
348
349 /* Open FILENAME with FLAGS in noclobber mode, hopefully avoiding most
350    race conditions and avoiding the problem where the file is replaced
351    between the stat(2) and open(2). */
352 static int
353 noclobber_open (filename, flags, ri)
354      char *filename;
355      int flags;
356      enum r_instruction ri;
357 {
358   int r, fd;
359   struct stat finfo, finfo2;
360
361   /* If the file exists and is a regular file, return an error
362      immediately. */
363   r = stat (filename, &finfo);
364   if (r == 0 && (S_ISREG (finfo.st_mode)))
365     return (NOCLOBBER_REDIRECT);
366
367   /* If the file was not present (r != 0), make sure we open it
368      exclusively so that if it is created before we open it, our open
369      will fail.  Make sure that we do not truncate an existing file.
370      Note that we don't turn on O_EXCL unless the stat failed -- if
371      the file was not a regular file, we leave O_EXCL off. */
372   flags &= ~O_TRUNC;
373   if (r != 0)
374     {
375       fd = open (filename, flags|O_EXCL, 0666);
376       return ((fd < 0 && errno == EEXIST) ? NOCLOBBER_REDIRECT : fd);
377     }
378   fd = open (filename, flags, 0666);
379
380   /* If the open failed, return the file descriptor right away. */
381   if (fd < 0)
382     return (errno == EEXIST ? NOCLOBBER_REDIRECT : fd);
383
384   /* OK, the open succeeded, but the file may have been changed from a
385      non-regular file to a regular file between the stat and the open.
386      We are assuming that the O_EXCL open handles the case where FILENAME
387      did not exist and is symlinked to an existing file between the stat
388      and open. */
389
390   /* If we can open it and fstat the file descriptor, and neither check
391      revealed that it was a regular file, and the file has not been replaced,
392      return the file descriptor. */
393   if ((fstat (fd, &finfo2) == 0) && (S_ISREG (finfo2.st_mode) == 0) &&
394       r == 0 && (S_ISREG (finfo.st_mode) == 0) &&
395       same_file (filename, filename, &finfo, &finfo2))
396     return fd;
397
398   /* The file has been replaced.  badness. */
399   close (fd);  
400   errno = EEXIST;
401   return (NOCLOBBER_REDIRECT);
402 }
403
404 /* Do the specific redirection requested.  Returns errno or one of the
405    special redirection errors (*_REDIRECT) in case of error, 0 on success.
406    If FOR_REAL is zero, then just do whatever is neccessary to produce the
407    appropriate side effects.   REMEMBERING, if non-zero, says to remember
408    how to undo each redirection.  If SET_CLEXEC is non-zero, then
409    we set all file descriptors > 2 that we open to be close-on-exec.  */
410 static int
411 do_redirection_internal (redirect, for_real, remembering, set_clexec)
412      REDIRECT *redirect;
413      int for_real, remembering, set_clexec;
414 {
415   WORD_DESC *redirectee;
416   int redir_fd, fd, redirector, r;
417   char *redirectee_word;
418   enum r_instruction ri;
419   REDIRECT *new_redirect;
420
421   redirectee = redirect->redirectee.filename;
422   redir_fd = redirect->redirectee.dest;
423   redirector = redirect->redirector;
424   ri = redirect->instruction;
425
426   if (ri == r_duplicating_input_word || ri == r_duplicating_output_word)
427     {
428       /* We have [N]>&WORD or [N]<&WORD.  Expand WORD, then translate
429          the redirection into a new one and continue. */
430       redirectee_word = redirection_expand (redirectee);
431
432       if (redirectee_word == 0)
433         return (AMBIGUOUS_REDIRECT);
434       else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0')
435         {
436           rd.dest = 0L;
437           new_redirect = make_redirection (redirector, r_close_this, rd);
438         }
439       else if (all_digits (redirectee_word))
440         {
441           if (ri == r_duplicating_input_word)
442             {
443               rd.dest = atol (redirectee_word);
444               new_redirect = make_redirection (redirector, r_duplicating_input, rd);
445             }
446           else
447             {
448               rd.dest = atol (redirectee_word);
449               new_redirect = make_redirection (redirector, r_duplicating_output, rd);
450             }
451         }
452       else if (ri == r_duplicating_output_word && redirector == 1)
453         {
454           if (posixly_correct == 0)
455             {
456               rd.filename = make_bare_word (redirectee_word);
457               new_redirect = make_redirection (1, r_err_and_out, rd);
458             }
459           else
460             new_redirect = copy_redirect (redirect);
461         }
462       else
463         {
464           free (redirectee_word);
465           return (AMBIGUOUS_REDIRECT);
466         }
467
468       free (redirectee_word);
469
470       /* Set up the variables needed by the rest of the function from the
471          new redirection. */
472       if (new_redirect->instruction == r_err_and_out)
473         {
474           char *alloca_hack;
475
476           /* Copy the word without allocating any memory that must be
477              explicitly freed. */
478           redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC));
479           xbcopy ((char *)new_redirect->redirectee.filename,
480                  (char *)redirectee, sizeof (WORD_DESC));
481
482           alloca_hack = (char *)
483             alloca (1 + strlen (new_redirect->redirectee.filename->word));
484           redirectee->word = alloca_hack;
485           strcpy (redirectee->word, new_redirect->redirectee.filename->word);
486         }
487       else
488         /* It's guaranteed to be an integer, and shouldn't be freed. */
489         redirectee = new_redirect->redirectee.filename;
490
491       redir_fd = new_redirect->redirectee.dest;
492       redirector = new_redirect->redirector;
493       ri = new_redirect->instruction;
494
495       /* Overwrite the flags element of the old redirect with the new value. */
496       redirect->flags = new_redirect->flags;
497       dispose_redirects (new_redirect);
498     }
499
500   switch (ri)
501     {
502     case r_output_direction:
503     case r_appending_to:
504     case r_input_direction:
505     case r_inputa_direction:
506     case r_err_and_out:         /* command &>filename */
507     case r_input_output:
508     case r_output_force:
509       if (posixly_correct && !interactive_shell)
510         disallow_filename_globbing++;
511       redirectee_word = redirection_expand (redirectee);
512       if (posixly_correct && !interactive_shell)
513         disallow_filename_globbing--;
514
515       if (redirectee_word == 0)
516         return (AMBIGUOUS_REDIRECT);
517
518 #if defined (RESTRICTED_SHELL)
519       if (restricted && (WRITE_REDIRECT (ri)))
520         {
521           free (redirectee_word);
522           return (RESTRICTED_REDIRECT);
523         }
524 #endif /* RESTRICTED_SHELL */
525
526       /* If we are in noclobber mode, you are not allowed to overwrite
527          existing files.  Check before opening. */
528       if (noclobber && OUTPUT_REDIRECT (ri))
529         {
530           fd = noclobber_open (redirectee_word, redirect->flags, ri);
531           if (fd == NOCLOBBER_REDIRECT)
532             {
533               free (redirectee_word);
534               return (NOCLOBBER_REDIRECT);
535             }
536         }
537       else
538         {
539           fd = open (redirectee_word, redirect->flags, 0666);
540 #if defined (AFS)
541           if ((fd < 0) && (errno == EACCES))
542             fd = open (redirectee_word, redirect->flags & ~O_CREAT, 0666);
543 #endif /* AFS */
544         }
545       free (redirectee_word);
546
547       if (fd < 0)
548         return (errno);
549
550       if (for_real)
551         {
552           if (remembering)
553             /* Only setup to undo it if the thing to undo is active. */
554             if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1))
555               add_undo_redirect (redirector);
556             else
557               add_undo_close_redirect (redirector);
558
559 #if defined (BUFFERED_INPUT)
560           check_bash_input (redirector);
561 #endif
562
563           if ((fd != redirector) && (dup2 (fd, redirector) < 0))
564             return (errno);
565
566 #if defined (BUFFERED_INPUT)
567           /* Do not change the buffered stream for an implicit redirection
568              of /dev/null to fd 0 for asynchronous commands without job
569              control (r_inputa_direction). */
570           if (ri == r_input_direction || ri == r_input_output)
571             duplicate_buffered_stream (fd, redirector);
572 #endif /* BUFFERED_INPUT */
573
574           /*
575            * If we're remembering, then this is the result of a while, for
576            * or until loop with a loop redirection, or a function/builtin
577            * executing in the parent shell with a redirection.  In the
578            * function/builtin case, we want to set all file descriptors > 2
579            * to be close-on-exec to duplicate the effect of the old
580            * for i = 3 to NOFILE close(i) loop.  In the case of the loops,
581            * both sh and ksh leave the file descriptors open across execs.
582            * The Posix standard mentions only the exec builtin.
583            */
584           if (set_clexec && (redirector > 2))
585             SET_CLOSE_ON_EXEC (redirector);
586         }
587
588       if (fd != redirector)
589         {
590 #if defined (BUFFERED_INPUT)
591           if (INPUT_REDIRECT (ri))
592             close_buffered_fd (fd);
593           else
594 #endif /* !BUFFERED_INPUT */
595             close (fd);         /* Don't close what we just opened! */
596         }
597
598       /* If we are hacking both stdout and stderr, do the stderr
599          redirection here. */
600       if (ri == r_err_and_out)
601         {
602           if (for_real)
603             {
604               if (remembering)
605                 add_undo_redirect (2);
606               if (dup2 (1, 2) < 0)
607                 return (errno);
608             }
609         }
610       break;
611
612     case r_reading_until:
613     case r_deblank_reading_until:
614       /* REDIRECTEE is a pointer to a WORD_DESC containing the text of
615          the new input.  Place it in a temporary file. */
616       if (redirectee)
617         {
618           fd = here_document_to_fd (redirectee);
619
620           if (fd < 0)
621             {
622               heredoc_errno = errno;
623               return (HEREDOC_REDIRECT);
624             }
625
626           if (for_real)
627             {
628               if (remembering)
629                 /* Only setup to undo it if the thing to undo is active. */
630                 if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1))
631                   add_undo_redirect (redirector);
632                 else
633                   add_undo_close_redirect (redirector);
634
635 #if defined (BUFFERED_INPUT)
636               check_bash_input (redirector);
637 #endif
638               if (fd != redirector && dup2 (fd, redirector) < 0)
639                 {
640                   r = errno;
641                   close (fd);
642                   return (r);
643                 }
644
645 #if defined (BUFFERED_INPUT)
646               duplicate_buffered_stream (fd, redirector);
647 #endif
648
649               if (set_clexec && (redirector > 2))
650                 SET_CLOSE_ON_EXEC (redirector);
651             }
652
653 #if defined (BUFFERED_INPUT)
654           close_buffered_fd (fd);
655 #else
656           close (fd);
657 #endif
658         }
659       break;
660
661     case r_duplicating_input:
662     case r_duplicating_output:
663       if (for_real && (redir_fd != redirector))
664         {
665           if (remembering)
666             /* Only setup to undo it if the thing to undo is active. */
667             if (fcntl (redirector, F_GETFD, 0) != -1)
668               add_undo_redirect (redirector);
669             else
670               add_undo_close_redirect (redirector);
671
672 #if defined (BUFFERED_INPUT)
673           check_bash_input (redirector);
674 #endif
675           /* This is correct.  2>&1 means dup2 (1, 2); */
676           if (dup2 (redir_fd, redirector) < 0)
677             return (errno);
678
679 #if defined (BUFFERED_INPUT)
680           if (ri == r_duplicating_input)
681             duplicate_buffered_stream (redir_fd, redirector);
682 #endif /* BUFFERED_INPUT */
683
684           /* First duplicate the close-on-exec state of redirectee.  dup2
685              leaves the flag unset on the new descriptor, which means it
686              stays open.  Only set the close-on-exec bit for file descriptors
687              greater than 2 in any case, since 0-2 should always be open
688              unless closed by something like `exec 2<&-'. */
689           /* if ((already_set || set_unconditionally) && (ok_to_set))
690                 set_it () */
691           if (((fcntl (redir_fd, F_GETFD, 0) == 1) || set_clexec) &&
692                (redirector > 2))
693             SET_CLOSE_ON_EXEC (redirector);
694         }
695       break;
696
697     case r_close_this:
698       if (for_real)
699         {
700           if (remembering && (fcntl (redirector, F_GETFD, 0) != -1))
701             add_undo_redirect (redirector);
702
703 #if defined (BUFFERED_INPUT)
704           check_bash_input (redirector);
705           close_buffered_fd (redirector);
706 #else /* !BUFFERED_INPUT */
707           close (redirector);
708 #endif /* !BUFFERED_INPUT */
709         }
710       break;
711
712     case r_duplicating_input_word:
713     case r_duplicating_output_word:
714       break;
715     }
716   return (0);
717 }
718
719 #define SHELL_FD_BASE   10
720
721 /* Remember the file descriptor associated with the slot FD,
722    on REDIRECTION_UNDO_LIST.  Note that the list will be reversed
723    before it is executed.  Any redirections that need to be undone
724    even if REDIRECTION_UNDO_LIST is discarded by the exec builtin
725    are also saved on EXEC_REDIRECTION_UNDO_LIST. */
726 static int
727 add_undo_redirect (fd)
728      int fd;
729 {
730   int new_fd, clexec_flag;
731   REDIRECT *new_redirect, *closer, *dummy_redirect;
732
733   new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE);
734
735   if (new_fd < 0)
736     {
737       sys_error ("redirection error");
738       return (-1);
739     }
740
741   clexec_flag = fcntl (fd, F_GETFD, 0);
742
743   rd.dest = 0L;
744   closer = make_redirection (new_fd, r_close_this, rd);
745   dummy_redirect = copy_redirects (closer);
746
747   rd.dest = (long)new_fd;
748   new_redirect = make_redirection (fd, r_duplicating_output, rd);
749   new_redirect->next = closer;
750
751   closer->next = redirection_undo_list;
752   redirection_undo_list = new_redirect;
753
754   /* Save redirections that need to be undone even if the undo list
755      is thrown away by the `exec' builtin. */
756   add_exec_redirect (dummy_redirect);
757
758   /* File descriptors used only for saving others should always be
759      marked close-on-exec.  Unfortunately, we have to preserve the
760      close-on-exec state of the file descriptor we are saving, since
761      fcntl (F_DUPFD) sets the new file descriptor to remain open
762      across execs.  If, however, the file descriptor whose state we
763      are saving is <= 2, we can just set the close-on-exec flag,
764      because file descriptors 0-2 should always be open-on-exec,
765      and the restore above in do_redirection() will take care of it. */
766   if (clexec_flag || fd < 3)
767     SET_CLOSE_ON_EXEC (new_fd);
768
769   return (0);
770 }
771
772 /* Set up to close FD when we are finished with the current command
773    and its redirections. */
774 static void
775 add_undo_close_redirect (fd)
776      int fd;
777 {
778   REDIRECT *closer;
779
780   rd.dest = 0L;
781   closer = make_redirection (fd, r_close_this, rd);
782   closer->next = redirection_undo_list;
783   redirection_undo_list = closer;
784 }
785
786 static void
787 add_exec_redirect (dummy_redirect)
788      REDIRECT *dummy_redirect;
789 {
790   dummy_redirect->next = exec_redirection_undo_list;
791   exec_redirection_undo_list = dummy_redirect;
792 }
793
794 /* Return non-zero if any of the redirections in REDIRS alter the standard
795    input. */
796 int
797 stdin_redirects (redirs)
798      REDIRECT *redirs;
799 {
800   REDIRECT *rp;
801   int n;
802
803   for (n = 0, rp = redirs; rp; rp = rp->next)
804     switch (rp->instruction)
805       {
806       case r_input_direction:
807       case r_inputa_direction:
808       case r_input_output:
809       case r_reading_until:
810       case r_deblank_reading_until:
811         n++;
812         break;
813       case r_duplicating_input:
814       case r_duplicating_input_word:
815       case r_close_this:
816         n += (rp->redirector == 0);
817         break;
818       case r_output_direction:
819       case r_appending_to:
820       case r_duplicating_output:
821       case r_err_and_out:
822       case r_output_force:
823       case r_duplicating_output_word:
824         break;
825       }
826
827   return n;
828 }