]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
change posix-mode implicit redirection from /dev/null for asynchronous commands so...
authorChet Ramey <chet.ramey@case.edu>
Tue, 6 Jan 2026 15:46:14 +0000 (10:46 -0500)
committerChet Ramey <chet.ramey@case.edu>
Tue, 6 Jan 2026 15:46:14 +0000 (10:46 -0500)
12 files changed:
CWRU/CWRU.chlog
MANIFEST
doc/bash.1
doc/bashref.texi
doc/version.texi
execute_cmd.c
jobs.c
redir.c
tests/redir.right
tests/redir.tests
tests/redir14.sub [new file with mode: 0644]
variables.c

index 9ec9fe60203f109094460f3b80e02f1dbc797db4..1b1a35f44c7300ce892782516bf712ae78500a01 100644 (file)
@@ -12482,3 +12482,33 @@ redir.c
        - stdin_redirection: now take the entire REDIRECT * as its argument,
          so we can do additional posix-mandated checking on redirections
          like 0<&0, to satisfy interp 1913
+       - stdin_redirection: if we are in posix mode, a redirection like
+         0<&0 does not count as an explicit stdin redirection for the purpose
+         of redirecting input from /dev/null, POSIX interp 1913
+
+doc/bash.1,doc/bashref.texi
+       - update the description of implicit redirection of stdin for async
+         commands from /dev/null with the caveat that an explicit redirection
+         of stdin overrides this
+       - update the posix mode section with info from interp 1913 about how
+         <&0 doesn't count as an explicit redirection of stdin
+
+                                1/2/2026
+                                --------
+jobs.c
+       - notify_of_job_status: hold onto the job's exit status without printing
+         a notification if the shell has started to run -c command and the
+         job is in a () subshell or a compound command with pipe input;
+         otherwise we get a spurious catch-all message
+
+                                   1/5
+                                   ---
+variables.c
+       - initialize_shell_variables: change string index and length variables
+         to size_t
+         Inspired by report from Marc Aurèle La France <tsi@tuyoix.net>
+
+jobs.c
+       - wait_for_background_pids: treat wait_for_single_pid returning > 256
+         as an error, same as returning < 0, and check errno appropriately
+         Report from Aleksey Covacevice <aleksey.covacevice@gmail.com>
index f2cacc8bf039b984722baa3074e5517184700bd1..0672c665bee8a91482a6886c55b3aa52f38bc2ed 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1492,6 +1492,7 @@ tests/redir10.sub f
 tests/redir11.sub      f
 tests/redir12.sub      f
 tests/redir13.in       f
+tests/redir14.sub      f
 tests/rhs-exp.tests    f
 tests/rhs-exp.right    f
 tests/rhs-exp1.sub     f
index c605d04ce1ee5910df03e2dba40ad89f31f3761b..6e5d9ac70fd203a4f7bbb2e42cc75c47f59ff293 100644 (file)
@@ -5,7 +5,7 @@
 .\"    Case Western Reserve University
 .\"    chet.ramey@case.edu
 .\"
-.\"    Last Change: Fri Dec 26 18:21:22 EST 2025
+.\"    Last Change: Wed Dec 31 18:30:12 EST 2025
 .\"
 .\" For bash_builtins, strip all but "SHELL BUILTIN COMMANDS" section
 .\" For rbash, strip all but "RESTRICTED SHELL" section
@@ -22,7 +22,7 @@
 .ds zX \" empty
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2025 December 26" "GNU Bash 5.3"
+.TH BASH 1 "2025 December 31" "GNU Bash 5.3"
 .\"
 .ie \n(.g \{\
 .ds ' \(aq
@@ -774,11 +774,18 @@ of a semicolon to delimit commands.
 .PP
 If a command is terminated by the control operator
 .BR & ,
-the shell executes the command in the \fIbackground\fP
+the shell executes the command asynchronously
 in a subshell.
+This is known as executing a command in the \fIbackground\fP,
+and these are referred to as \fIasynchronous\fP commands.
 The shell does not wait for the command to
 finish, and the return status is 0.
-These are referred to as \fIasynchronous\fP commands.
+When job control is not active,
+the standard input for asynchronous commands,
+in the absence of any explicit redirections involving the standard input,
+is redirected from
+.FN /dev/null .
+.PP
 Commands separated or terminated by
 .B ;
 (or an equivalent
@@ -5920,7 +5927,8 @@ for how to control this behavior when not in posix mode.
 .PP
 If a command is followed by a \fB&\fP and job control is not active, the
 default standard input for the command is the empty file
-.FN /dev/null .
+.FN /dev/null ,
+unless the command has an explicit redirection involving the standard input.
 Otherwise, the invoked command inherits the file descriptors of the calling
 shell as modified by redirections.
 .SH ENVIRONMENT
index f28f1b0184ee981de32036a2f5a50611a0f9e8e4..965d1c3a1bcc899008c513b39742ef68cd69b84e 100644 (file)
@@ -914,8 +914,9 @@ and these are referred to as @dfn{asynchronous} commands.
 The shell does not wait for the command to finish, and the return
 status is 0 (true).
 When job control is not active (@pxref{Job Control}),
-the standard input for asynchronous commands, in the absence of any
-explicit redirections, is redirected from @code{/dev/null}.
+the standard input for asynchronous commands,
+in the absence of any explicit redirections involving the standard input,
+is redirected from @file{/dev/null}.
 
 Commands separated or terminated by 
 @samp{;} (or equivalent @code{newline})
@@ -3867,7 +3868,8 @@ See the description of the @code{inherit_errexit} shell option
 in @sc{posix} mode.
 
 If a command is followed by a @samp{&} and job control is not active, the
-default standard input for the command is the empty file @file{/dev/null}.
+default standard input for the command is the empty file @file{/dev/null},
+unless the command has an explicit redirection involving the standard input.
 Otherwise, the invoked command inherits the file descriptors of the calling
 shell as modified by redirections.
 
@@ -9240,7 +9242,8 @@ The Bash @dfn{posix mode} changes the Bash
 behavior in these areas so that it conforms more strictly
 to the standard.
 
-Starting Bash with the @option{--posix} command-line option or executing
+Starting Bash with the @option{--posix} or @option{-o posix}
+command-line option or executing
 @samp{set -o posix} while Bash is running will cause Bash to conform more
 closely to the @sc{posix} standard by changing the behavior to
 match that specified by @sc{posix} in areas where the Bash default differs.
@@ -9364,6 +9367,16 @@ Bash will not insert a command without the execute bit set into the
 command hash table, even if it returns it as a (last-ditch) result
 from a @env{$PATH} search.
 
+@item
+Normally, when job control is not enabled,
+the shell implicitly redirects the standard input of
+asynchronous commands from @file{/dev/null}.
+A redirection to the standard input in this command inhibits this
+implicit redirection.
+In @sc{posix} mode, a redirection that redirects file descriptor 0
+to itself (e.g., @samp{<&0}) does not count as a redirection that
+overrides the implicit redirection from @file{/dev/null}.
+
 @item
 The message printed by the job control code and builtins when a job
 exits with a non-zero status is ``Done(status)''.
index 157c489534817b7de19a6cbbac1bf6a2ed624b3b..925fd9938b0397837aec2e67482cc671e86c5301 100644 (file)
@@ -2,11 +2,10 @@
 Copyright (C) 1988-2025 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Fri Dec 26 18:21:22 EST 2025
-
+@set LASTCHANGE Wed Dec 31 18:26:37 EST 2025
 
 @set EDITION 5.3
 @set VERSION 5.3
 
-@set UPDATED 26 December 2025
+@set UPDATED 31 December 2025
 @set UPDATED-MONTH December 2025
index 8c0fa563099f1ae3d66ccc9f2e4252878b323270..db1806e8719df4332fbccbe233aa5aef2106cc32 100644 (file)
@@ -847,7 +847,8 @@ execute_command_internal (COMMAND *command, int asynchronous, int pipe_in, int p
 #endif /* COMMAND_TIMING */
 
   /* Is this a compound command with a redirection from stdin? POSIX interp
-     1913 makes it matter. */
+     1913 makes it matter. There is an exception for 0<&0 or <&0 or equivalent
+     when in posix mode. */
   if (shell_control_structure (command->type) && command->redirects)
 {
     stdin_redirected = stdin_redirects (command->redirects);
@@ -4876,13 +4877,11 @@ run_builtin:
            {
              if ((cmdflags & CMD_STDIN_REDIR) &&
                    pipe_in == NO_PIPE &&
-#if 0  /*TAG:bash-5.4 POSIX interp 1913 */
                    /* POSIX interp 1913 says that the redirection of fd 0
-                      from /dev/null is unconditional. */
-                   (posixly_correct || stdin_redirects (simple_command->redirects) == 0))
-#else
+                      from /dev/null is performed unless the command has
+                      a redirection that's something like 0<&0 or <&0.
+                      See redir.c:stdin_redirection() for the details. */
                    (stdin_redirects (simple_command->redirects) == 0))
-#endif
                async_redirect_stdin ();
              setup_async_signals ();
            }
@@ -5917,15 +5916,15 @@ execute_disk_command (WORD_LIST *words, REDIRECT *redirects, char *command_line,
         in asynchronous children. */
       if (async)
        {
+/*itrace("execute_disk_command: async = 1 cmd_stdin_redir = %d stdin_redirects (redirects) = %d",
+       (cmdflags & CMD_STDIN_REDIR), stdin_redirects (redirects));*/
          if ((cmdflags & CMD_STDIN_REDIR) &&
                pipe_in == NO_PIPE &&
-#if 0  /*TAG:bash-5.4 POSIX interp 1913 */
                /* POSIX interp 1913 says that the redirection of fd 0
-                  from /dev/null is unconditional. */
-               (posixly_correct || stdin_redirects (redirects) == 0))
-#else
+                  from /dev/null is performed unless the command has
+                  a redirection that's something like 0<&0 or <&0.
+                  See redir.c:stdin_redirection() for the details. */
                (stdin_redirects (redirects) == 0))
-#endif
            async_redirect_stdin ();
          setup_async_signals ();
        }
diff --git a/jobs.c b/jobs.c
index d8f7aae4771f104c788ad3761615de432f403ad2..0b4b86223c40af09eb810364deb60386885153c4 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -2841,7 +2841,7 @@ wait_for_background_pids (int wflags, struct procstat *ps)
          ps->pid = pid;
          ps->status = (r < 0 || r > 256) ? 127 : r;
        }
-      if (r == -1 && errno == ECHILD)
+      if ((r < 0 || r > 256) && errno == ECHILD)
        {
          /* If we're mistaken about job state, compensate. */
          check_async = 0;
@@ -4603,6 +4603,14 @@ notify_of_job_status (int wanted)
                ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job)))
            continue;
 
+         /* hang onto the status if the shell is running -c command and the
+            command is running in a () subshell or a compound command with
+            pipe input */
+         else if (startup_state == 2 && (subshell_environment & (SUBSHELL_PAREN|SUBSHELL_PIPE)) &&
+               WIFSIGNALED (s) == 0 &&
+               ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job)))
+           continue;
+
          /* If job control is disabled, don't print the status messages.
             Mark dead jobs as notified so that they get cleaned up.  If
             startup_state == 2 and subshell_environment has the
@@ -4684,7 +4692,7 @@ notify_of_job_status (int wanted)
              /* XXX - this is a catch-all in case we missed a state */
              else
 {
-internal_debug("notify_of_job_status: catch-all setting J_NOTIFIED on job %d (%d), startup state = %d", job, jobs[job]->flags, startup_state);
+internal_debug("notify_of_job_status: catch-all setting J_NOTIFIED on job %d (%d), startup state = %d subshell_environment = %d", job, jobs[job]->flags, startup_state, subshell_environment);
                jobs[job]->flags |= J_NOTIFIED;
 }
              break;
diff --git a/redir.c b/redir.c
index d62318dc0922ca936dea63ecd8af6d7554fce868..7c689ba83bf896069be199fc82ca37b581457fa9 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -1400,8 +1400,15 @@ stdin_redirection (REDIRECT *rp)
     case r_reading_string:
       return (1);
     case r_duplicating_input:
-    case r_duplicating_input_word:
     case r_close_this:
+      return (rp->redirector.dest == 0
+#if 1 /*TAG: bash-5.4 POSIX interp 1913 */
+               && (posixly_correct == 0 || rp->redirectee.dest != 0)
+#endif
+               );
+    case r_duplicating_input_word:
+      /* we defer evaluation of this until later, so just return based on the
+        destination for now. */
       return (rp->redirector.dest == 0);
     case r_output_direction:
     case r_appending_to:
index f96ba0155ba12060028b28a634ad93bce1e77878..236f85e797b1651ab358f19df015343bb0fe8919 100644 (file)
@@ -195,3 +195,34 @@ after ERR trap: 1
 got error ERR
 ./redir12.sub: line 56: unreadable-file: Permission denied
 /tmp
+       redir14.sub
+standard 1 - <&0
+line 1
+line 2
+posix 1 - <&0
+standard 2 - 0<&0
+line 1
+line 2
+posix 2 - 0<&0
+standard 3 - subshell containing AND-OR list <&0
+line 1
+line 2
+posix 3 - subshell containing AND-OR list <&0
+standard - subshell with explicit redirection
+line 1
+line 2
+posix - subshell with explicit redirection
+line 1
+line 2
+standard 1 - compound command with AND-OR list with pipe input
+hello inpipe
+posix 1 - compound command with AND-OR list with pipe input
+hello inpipe
+standard 2 - simple command with AND-OR list with pipe input
+jello inpipe
+posix 2 - simple command with AND-OR list with pipe input
+jello inpipe
+standard 3 - subshell command with AND-OR list with pipe input
+hello inpipe
+posix 3 - subshell command with AND-OR list with pipe input
+hello inpipe
index 4790dae8e05ac9c111b7528a225da75bdae5d1d8..ef284908d7829861fec4402433b28ddaa660ae72 100644 (file)
@@ -224,3 +224,5 @@ test_runsub ./redir11.sub
 test_runsub ./redir12.sub
 
 ${THIS_SH} < ./redir13.in
+
+test_runsub ./redir14.sub
diff --git a/tests/redir14.sub b/tests/redir14.sub
new file mode 100644 (file)
index 0000000..8f6ad3f
--- /dev/null
@@ -0,0 +1,47 @@
+: ${TMPDIR:=/tmp} ${THIS_SH:=./bash}
+TMPFILE=$TMPDIR/redir-in-$$
+
+trap 'rm -f $TMPFILE' 0
+
+cat >$TMPFILE <<EOF
+line 1
+line 2
+EOF
+
+export TMPFILE
+echo standard 1 - '<&0'
+${THIS_SH} -c 'exec < $TMPFILE ; cat <&0 & wait'
+echo posix 1 - '<&0'
+${THIS_SH} -o posix -c 'exec < $TMPFILE ; cat <&0 & wait'
+
+echo standard 2 - '0<&0'
+${THIS_SH} -c 'exec < $TMPFILE ; cat 0<&0 & wait'
+echo posix 2 - '0<&0'
+${THIS_SH} -o posix -c 'exec < $TMPFILE ; cat 0<&0 & wait'
+
+echo standard 3 - subshell containing AND-OR list '<&0'
+${THIS_SH} -c 'exec < $TMPFILE ; ( cat <&0 & wait )'
+echo posix 3 - subshell containing AND-OR list '<&0'
+${THIS_SH} -o posix -c 'exec < $TMPFILE ; ( cat <&0 & wait )'
+
+echo standard - subshell with explicit redirection
+${THIS_SH} -c '( cat <&0 & wait ) <$TMPFILE'
+echo posix - subshell with explicit redirection
+${THIS_SH} -o posix -c '( cat <&0 & wait ) <$TMPFILE'
+
+# pipeline input inhibits the implicit redirection from /dev/null; posix mode
+# does not make a difference -- POSIX interp 1913
+echo standard 1 - compound command with AND-OR list with pipe input
+${THIS_SH} -c 'echo "hello inpipe" | { cat 0<&0 & wait; }'
+echo posix 1 - compound command with AND-OR list with pipe input
+${THIS_SH} -o posix -c 'echo "hello inpipe" | { cat 0<&0 & wait; }'
+
+echo standard 2 - simple command with AND-OR list with pipe input
+${THIS_SH} -c 'echo "jello inpipe" | cat 0<&0 & wait'
+echo posix 2 - simple command with AND-OR list with pipe input
+${THIS_SH} -o posix -c 'echo "jello inpipe" | cat 0<&0 & wait'
+
+echo standard 3 - subshell command with AND-OR list with pipe input
+${THIS_SH} -c 'echo "hello inpipe" | ( cat <&0 & wait )'
+echo posix 3 - subshell command with AND-OR list with pipe input
+${THIS_SH} -o posix -c 'echo "hello inpipe" | ( cat <&0 & wait )'
index 5ef53a928965335c70c5fadc4fb7a95ca9e4f678..a43f5316291bfc86f1e12087ef3fe8df51af98d7 100644 (file)
@@ -369,7 +369,8 @@ void
 initialize_shell_variables (char **env, int privmode)
 {
   char *name, *string, *temp_string;
-  int c, char_index, string_index, string_length, ro;
+  int c, ro;
+  size_t char_index, string_index, string_length;
   SHELL_VAR *temp_var;
 
   create_variable_tables ();
@@ -454,7 +455,7 @@ initialize_shell_variables (char **env, int privmode)
          STREQN (BASHARRAY_SUFFIX, name + char_index - BASHARRAY_SUFFLEN, BASHARRAY_SUFFLEN) &&
          *string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
        {
-         size_t namelen;
+         size_t namelen, slen;
          char *tname;          /* desired imported array variable name */
 
          namelen = char_index - BASHARRAY_PREFLEN - BASHARRAY_SUFFLEN;