From: Chet Ramey Date: Tue, 6 Jan 2026 15:46:14 +0000 (-0500) Subject: change posix-mode implicit redirection from /dev/null for asynchronous commands so... X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=e7c3acf10876963d15f4b6b8030717d308c12bd4;p=thirdparty%2Fbash.git change posix-mode implicit redirection from /dev/null for asynchronous commands so that 0<&0 does not count as an explicit redirection for austin-group interp 1913; fix spurious debug message about job notification for -c command; fix error handling for wait builtin if there are no children in a subshell --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 9ec9fe60..1b1a35f4 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 + +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 diff --git a/MANIFEST b/MANIFEST index f2cacc8b..0672c665 100644 --- 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 diff --git a/doc/bash.1 b/doc/bash.1 index c605d04c..6e5d9ac7 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -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 diff --git a/doc/bashref.texi b/doc/bashref.texi index f28f1b01..965d1c3a 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -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)''. diff --git a/doc/version.texi b/doc/version.texi index 157c4895..925fd993 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -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 diff --git a/execute_cmd.c b/execute_cmd.c index 8c0fa563..db1806e8 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -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 d8f7aae4..0b4b8622 100644 --- 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 d62318dc..7c689ba8 100644 --- 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: diff --git a/tests/redir.right b/tests/redir.right index f96ba015..236f85e7 100644 --- a/tests/redir.right +++ b/tests/redir.right @@ -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 diff --git a/tests/redir.tests b/tests/redir.tests index 4790dae8..ef284908 100644 --- a/tests/redir.tests +++ b/tests/redir.tests @@ -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 index 00000000..8f6ad3f2 --- /dev/null +++ b/tests/redir14.sub @@ -0,0 +1,47 @@ +: ${TMPDIR:=/tmp} ${THIS_SH:=./bash} +TMPFILE=$TMPDIR/redir-in-$$ + +trap 'rm -f $TMPFILE' 0 + +cat >$TMPFILE <