posix change for undoing redirections after failed exec; change readline to set lines and columns after SIGTSTP/SIGCONT

This commit is contained in:
Chet Ramey
2025-01-28 10:15:16 -05:00
parent 25e213a551
commit 0390b4354a
15 changed files with 307 additions and 71 deletions
+51
View File
@@ -10870,3 +10870,54 @@ lib/readline/display.c
characters on the current line, and set _rl_last_c_pos accordingly
in both multibyte and singlebyte locales.
Fixes bug reported by Andreas Schwab <schwab@linux-m68k.org>
1/22
----
execute_cmd.c
- execute_builtin_or_function: if we're executing the exec builtin,
and there are redirections, let exec_builtin handle disposing of
redirection_undo_list if there is no program name to execute, so
it's still there if exec returns and doesn't exit the shell.
Then we can manage disposing of exec_redirection_undo_list and
letting the redirections be undone as normal.
This is POSIX interp 1896, with modifications from
https://www.austingroupbugs.net/view.php?id=1896#c7037
builtins/exec.def
- exec_builtin: dispose of redirection_undo_list and set it to NULL
if there is no program name operand; let execute_builtin_or_function
clean it up
1/23
----
lib/readline/terminal.c
- _rl_tcgetwinsize,_rl_tcsetwinsize: function wrappers for tcgetwinsize/
tcsetwinsize with fallbacks to ioctl if those functions aren't
available
- _rl_get_screensize: use _rl_tcgetwinsize
lib/readline/rlwinsize.h
- _rl_tcgetwinsize,_rl_tcsetwinsize: extern function declarations
lib/readine/rltty.c
- set_winsize: use _rl_tcgetwinsize/_rl_tcsetwinsize
- set_winsize: if _rl_tcgetwinsize succeeds, use the values to set
readline's idea of the screen size via _rl_set_screen_size
Inspired by a discussion with Olav Mørkrid <omega@funker.no>
1/24
----
lib/readline/signals.c
- _rl_handling_signal: new private variable, set to the signal we're
currently handling in _rl_signal_handler (SIGWINCH) or
_rl_handle_signal (all others). Only valid if RL_STATE_SIGHANDLER
is set
lib/readline/rlprivate.h
- _rl_handling_signal: new extern declaration
lib/readline/rltty.c
- set_winsize: only set readline's idea of the screen size if we're
executing in a signal handler context and handling SIGTSTP and the
application has indicated that it doesn't want the environment
variables LINES and COLUMNS to have priority (rl_prefer_env_winsize)
+1
View File
@@ -1181,6 +1181,7 @@ tests/exec13.sub f
tests/exec14.sub f
tests/exec15.sub f
tests/exec16.sub f
tests/exec17.sub f
tests/exp.tests f
tests/exp.right f
tests/exp1.sub f
+1 -1
View File
@@ -916,7 +916,7 @@ assign_array_var_from_string (SHELL_VAR *var, char *value, int flags)
return var;
nlist = expand_compound_array_assignment (var, value, flags);
/* This is were we set ASS_NOEXPAND and ASS_ONEWORD if we need to, since
/* This is where we set ASS_NOEXPAND and ASS_ONEWORD if we need to, since
expand_compound_array_assignment performs word expansions. Honors
array_expand_once; allows @ and * as associative array keys. */
aflags = flags | (array_expand_once ? ASS_NOEXPAND : 0) | ASS_ALLOWALLSUB;
+6 -5
View File
@@ -128,12 +128,13 @@ exec_builtin (WORD_LIST *list)
}
list = loptend;
/* First, let the redirections remain. */
dispose_redirects (redirection_undo_list);
redirection_undo_list = (REDIRECT *)NULL;
/* First, let the redirections remain if exec is called without operands */
if (list == 0)
return (EXECUTION_SUCCESS);
{
dispose_redirects (redirection_undo_list);
redirection_undo_list = (REDIRECT *)NULL;
return (EXECUTION_SUCCESS);
}
#if defined (RESTRICTED_SHELL)
if (restricted)
+36 -20
View File
@@ -2122,6 +2122,8 @@ If this variable is in the environment when
starts up, the shell enables each option in the list before
reading any startup files.
If this variable is exported, child shells will enable each option
in the list.
This variable is read-only.
<DT><B>BASHPID</B>
@@ -4822,10 +4824,9 @@ ${<I>parameter</I><B>/</B><I>pattern</I><B>/</B><I>string</I>}
<DT>${<I>parameter</I><B>/%</B><I>pattern</I><B>/</B><I>string</I>}<DD>
<B>Pattern substitution</B>.
The <I>pattern</I> is expanded to produce a pattern just as in
pathname expansion and matched against the expanded value of
<I>parameter</I>
using the rules described under
The <I>pattern</I> is expanded to produce a pattern
and matched against the expanded value of <I>parameter</I>
as described under
<B>Pattern Matching</B>
below.
@@ -4910,18 +4911,31 @@ ${<I>parameter</I><B>^</B><I>pattern</I>}
<B>Case modification</B>.
This expansion modifies the case of alphabetic characters in <I>parameter</I>.
The <I>pattern</I> is expanded to produce a pattern just as in
pathname expansion.
Each character in the expanded value of <I>parameter</I> is tested against
<I>pattern</I>, and, if it matches the pattern, its case is converted.
First, the <I>pattern</I> is expanded to produce a pattern
as described below under
<FONT SIZE=-1><B>Pattern Matching</B>.
</FONT>
<B>Bash</B>
then examines characters in the expanded value of <I>parameter</I>
against <I>pattern</I> as described below.
If a character matches the pattern, its case is converted.
The pattern should not attempt to match more than one character.
<DT><DD>
The <B>^</B> operator converts lowercase letters matching <I>pattern</I>
to uppercase; the <B>,</B> operator converts matching uppercase letters
to lowercase.
The <B>^^</B> and <B>,,</B> expansions convert each matched character in the
expanded value; the <B>^</B> and <B>,</B> expansions match and convert only
the first character in the expanded value.
Using
converts lowercase letters matching <I>pattern</I> to uppercase;
converts matching uppercase letters to lowercase.
The
<B>^</B> and <B>,</B> variants
examine the first character in the expanded value
and convert its case if it matches <I>pattern</I>;
the
<B>^^</B> and <B>,,</B> variants
examine all characters in the expanded value
and convert each one that matches <I>pattern</I>.
If <I>pattern</I> is omitted, it is treated like a <B>?</B>, which matches
every character.
<DT><DD>
@@ -5524,6 +5538,7 @@ as described above under
<P>
<B>Pattern Matching</B>
<P>
Any character that appears in a pattern, other than the special pattern
@@ -14819,9 +14834,6 @@ under
<DD>
<DT><B>compat44</B>
<DD>
<DT><B>compat50</B>
<DD>
These control aspects of the shell's compatibility mode
@@ -16523,7 +16535,11 @@ builtin command.
<DT>*<DD>
Importing function definitions from the shell environment at startup.
<DT>*<DD>
Parsing the value of
Parsing the values of
<FONT SIZE=-1><B>BASHOPTS</B>
</FONT>
and
<FONT SIZE=-1><B>SHELLOPTS</B>
</FONT>
@@ -16858,7 +16874,7 @@ Array variables may not (yet) be exported.
<DT><A HREF="#lbDJ">BUGS</A><DD>
</DL>
<HR>
This document was created by man2html from /usr/local/src/bash/bash-20241227/doc/bash.1.<BR>
Time: 08 January 2025 09:33:16 EST
This document was created by man2html from /usr/local/src/bash/bash-20250122/doc/bash.1.<BR>
Time: 28 January 2025 09:45:18 EST
</BODY>
</HTML>
+28 -16
View File
@@ -2990,11 +2990,9 @@ array in turn, and the expansion is the resultant list.
<dt><code class="code">${<var class="var">parameter</var>//<var class="var">pattern</var>/<var class="var">string</var>}</code></dt>
<dt><code class="code">${<var class="var">parameter</var>/#<var class="var">pattern</var>/<var class="var">string</var>}</code></dt>
<dt><code class="code">${<var class="var">parameter</var>/%<var class="var">pattern</var>/<var class="var">string</var>}</code></dt>
<dd><p>The <var class="var">pattern</var> is expanded to produce a pattern just as in
filename expansion and matched
against the expanded value of <var class="var">parameter</var>
according to the rules
described below (see <a class="pxref" href="#Pattern-Matching">Pattern Matching</a>).
<dd><p>The <var class="var">pattern</var> is expanded to produce a pattern
and matched against the expanded value of <var class="var">parameter</var>
as described below (see <a class="pxref" href="#Pattern-Matching">Pattern Matching</a>).
The longest match of <var class="var">pattern</var>
in the expanded value is replaced with <var class="var">string</var>.
<var class="var">string</var> undergoes tilde expansion, parameter and variable expansion,
@@ -3098,18 +3096,28 @@ array in turn, and the expansion is the resultant list.
<dt><code class="code">${<var class="var">parameter</var>,<var class="var">pattern</var>}</code></dt>
<dt><code class="code">${<var class="var">parameter</var>,,<var class="var">pattern</var>}</code></dt>
<dd><p>This expansion modifies the case of alphabetic characters in <var class="var">parameter</var>.
The <var class="var">pattern</var> is expanded to produce a pattern just as in
filename expansion.
Each character in the expanded value of <var class="var">parameter</var> is tested against
<var class="var">pattern</var>, and, if it matches the pattern, its case is converted.
First, the <var class="var">pattern</var> is expanded to produce a pattern
as described below in <a class="ref" href="#Pattern-Matching">Pattern Matching</a>.
</p>
<p><code class="code">Bash</code>
then examines characters in the expanded value of <var class="var">parameter</var>
against <var class="var">pattern</var> as described below.
If a character matches the pattern, its case is converted.
The pattern should not attempt to match more than one character.
</p>
<p>The &lsquo;<samp class="samp">^</samp>&rsquo; operator converts lowercase letters matching <var class="var">pattern</var>
to uppercase; the &lsquo;<samp class="samp">,</samp>&rsquo; operator converts matching uppercase letters
to lowercase.
The &lsquo;<samp class="samp">^^</samp>&rsquo; and &lsquo;<samp class="samp">,,</samp>&rsquo; expansions convert each matched character in the
expanded value; the &lsquo;<samp class="samp">^</samp>&rsquo; and &lsquo;<samp class="samp">,</samp>&rsquo; expansions match and convert only
the first character in the expanded value.
<p>Using
&lsquo;<samp class="samp">^</samp>&rsquo;
converts lowercase letters matching <var class="var">pattern</var> to uppercase;
&lsquo;<samp class="samp">,</samp>&rsquo;
converts matching uppercase letters to lowercase.
The
&lsquo;<samp class="samp">^</samp>&rsquo; and &lsquo;<samp class="samp">,</samp>&rsquo; variants
examine the first character in the expanded value
and convert its case if it matches <var class="var">pattern</var>;
the
&lsquo;<samp class="samp">^^</samp>&rsquo; and &lsquo;<samp class="samp">,,</samp>&rsquo; variants
examine all characters in the expanded value
and convert each one that matches <var class="var">pattern</var>.
If <var class="var">pattern</var> is omitted, it is treated like a &lsquo;<samp class="samp">?</samp>&rsquo;, which matches
every character.
</p>
@@ -7466,6 +7474,8 @@ as &lsquo;<samp class="samp">on</samp>&rsquo; by &lsquo;<samp class="samp">shopt
If this variable is in the environment when Bash
starts up, the shell enables each option in the list before
reading any startup files.
If this variable is exported, child shells will enable each option
in the list.
This variable is readonly.
</p>
</dd>
@@ -14603,6 +14613,8 @@ It may be omitted if the word designator begins with a &lsquo;<samp class="samp"
&lsquo;<samp class="samp">*</samp>&rsquo;, &lsquo;<samp class="samp">-</samp>&rsquo;, or &lsquo;<samp class="samp">%</samp>&rsquo;.
Words are numbered from the beginning of the line,
with the first word being denoted by 0 (zero).
That first word is usually the command word, and the arguments begin
with the second word.
Words are inserted into the current line separated by single spaces.
</p>
<p>For example,
@@ -14614,7 +14626,7 @@ When you type this, the preceding command is repeated in toto.
</p>
</dd>
<dt><code class="code">!!:$</code></dt>
<dd><p>designates the last argument of the preceding command.
<dd><p>designates the last word of the preceding command.
This may be shortened to <code class="code">!$</code>.
</p>
</dd>
+37 -19
View File
@@ -5570,7 +5570,7 @@ execute_builtin_or_function (WORD_LIST *words,
REDIRECT *redirects, struct fd_bitmap *fds_to_close,
int flags)
{
int result;
int result, has_exec_redirects;
REDIRECT *saved_undo_list;
#if defined (PROCESS_SUBSTITUTION)
int ofifo, nfifo, osize;
@@ -5597,17 +5597,25 @@ execute_builtin_or_function (WORD_LIST *words,
return (EX_REDIRFAIL); /* was EXECUTION_FAILURE */
}
/* Is this the exec builtin with redirections? We want to undo them and
throw away the exec_redirection_undo_list if exec has a program name
argument, fails to execute it, and does not exit the shell */
has_exec_redirects = (builtin == exec_builtin) && redirection_undo_list;
saved_undo_list = redirection_undo_list;
/* Calling the "exec" builtin changes redirections forever. */
if (builtin == exec_builtin)
{
dispose_redirects (saved_undo_list);
/* let exec_builtin handle disposing redirection_undo_list */
saved_undo_list = exec_redirection_undo_list;
exec_redirection_undo_list = (REDIRECT *)NULL;
}
else
dispose_exec_redirects ();
{
dispose_exec_redirects ();
redirection_undo_list = (REDIRECT *)NULL;
}
if (saved_undo_list)
{
@@ -5615,8 +5623,6 @@ execute_builtin_or_function (WORD_LIST *words,
add_unwind_protect (uw_cleanup_redirects, (char *)saved_undo_list);
}
redirection_undo_list = (REDIRECT *)NULL;
if (builtin)
result = execute_builtin (builtin, words, flags, 0);
else
@@ -5628,26 +5634,38 @@ execute_builtin_or_function (WORD_LIST *words,
if (ferror (stdout))
clearerr (stdout);
/* If we are executing the `command' builtin, but this_shell_builtin is
set to `exec_builtin', we know that we have something like
`command exec [redirection]', since otherwise `exec' would have
overwritten the shell and we wouldn't get here. In this case, we
want to behave as if the `command' builtin had not been specified
and preserve the redirections. */
if (builtin == command_builtin && this_shell_builtin == exec_builtin)
if (has_exec_redirects && redirection_undo_list)
{
int discard;
discard = 0;
/* We have returned from the exec builtin. If redirection_undo_list is
still non-null, we had an operand and failed to exit the shell for
some reason. We want to dispose of saved_undo_list, discard the frame,
and let the redirections be undone as usual. If redirection_undo_list
is NULL, then exec_builtin had no program name operand and disposed
of it. In that case, we should perform the redirections in
exec_redirection_undo_list (saved_undo_list) like usual. */
if (saved_undo_list)
{
dispose_redirects (saved_undo_list); /* exec_redirection_undo_list */
discard_unwind_frame ("saved-redirects");
}
saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL;
}
/* This code is no longer executed and remains only for explanatory reasons. */
else if (builtin == command_builtin && this_shell_builtin == exec_builtin)
{
/* If we are executing the `command' builtin, but this_shell_builtin is
set to `exec_builtin', we know that we have something like
`command exec [redirection]', since otherwise `exec' would have
overwritten the shell and we wouldn't get here. In this case, we
want to behave as if the `command' builtin had not been specified
and preserve the redirections. */
if (saved_undo_list)
{
dispose_redirects (saved_undo_list);
discard = 1;
dispose_redirects (saved_undo_list); /* redirection_undo_list */
discard_unwind_frame ("saved-redirects");
}
redirection_undo_list = exec_redirection_undo_list;
saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL;
if (discard)
discard_unwind_frame ("saved-redirects");
}
if (saved_undo_list)
+1
View File
@@ -640,6 +640,7 @@ extern int _rl_history_search_pos;
/* signals.c */
extern int volatile _rl_caught_signal;
extern int volatile _rl_handling_signal;
extern _rl_sigcleanup_func_t *_rl_sigcleanup;
extern void *_rl_sigcleanarg;
+15 -5
View File
@@ -80,15 +80,25 @@ static int ksrflow;
#endif
/* Dummy call to force a backgrounded readline to stop before it tries
to get the tty settings. */
to get the tty settings. But we use the information to set our idea
of the screen size if we're in a signal handling context, since it
doesn't make sense to waste it. */
static void
set_winsize (int tty)
{
#if defined (TIOCGWINSZ)
#if defined (TIOCGWINSZ) || defined (HAVE_TCGETWINSIZE)
struct winsize w;
if (ioctl (tty, TIOCGWINSZ, &w) == 0)
(void) ioctl (tty, TIOCSWINSZ, &w);
if (_rl_tcgetwinsize (tty, &w) == 0)
{
(void) _rl_tcsetwinsize (tty, &w);
/* We restrict this to the case where we're running a signal handler
and executing after a SIGTSTP. We can relax it later. */
#if defined (SIGTSTP)
if (RL_ISSTATE (RL_STATE_SIGHANDLER) && _rl_handling_signal == SIGTSTP && rl_prefer_env_winsize == 0)
_rl_set_screen_size (w.ws_row, w.ws_col); /* don't waste the info */
#endif
}
#endif /* TIOCGWINSZ */
}
+3
View File
@@ -55,4 +55,7 @@
# define tcflow(fd, action) ioctl(fd, TCXONC, action)
#endif
extern int _rl_tcgetwinsize (int, struct winsize *);
extern void _rl_tcsetwinsize (int, struct winsize *);
#endif /* _RL_WINSIZE_H */
+5
View File
@@ -88,6 +88,7 @@ int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */
/* Private variables. */
int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including <signal.h> everywhere */
int volatile _rl_handling_signal = 0;
/* If non-zero, print characters corresponding to received signals as long as
the user has indicated his desire to do so (_rl_echo_control_chars). */
@@ -133,6 +134,7 @@ _rl_signal_handler (int sig)
if (sig == SIGWINCH)
{
RL_SETSTATE(RL_STATE_SIGHANDLER);
_rl_handling_signal = SIGWINCH;
rl_resize_terminal ();
/* XXX - experimental for now */
@@ -142,6 +144,7 @@ _rl_signal_handler (int sig)
if (rl_signal_event_hook)
(*rl_signal_event_hook) ();
_rl_handling_signal = 0;
RL_UNSETSTATE(RL_STATE_SIGHANDLER);
}
else
@@ -177,6 +180,7 @@ _rl_handle_signal (int sig)
#endif /* !HAVE_POSIX_SIGNALS */
RL_SETSTATE(RL_STATE_SIGHANDLER);
_rl_handling_signal = sig;
#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
/* Since the signal will not be blocked while we are in the signal
@@ -301,6 +305,7 @@ _rl_handle_signal (int sig)
rl_reset_after_signal ();
}
_rl_handling_signal = 0;
RL_UNSETSTATE(RL_STATE_SIGHANDLER);
SIGHANDLER_RETURN;
}
+29 -5
View File
@@ -258,6 +258,30 @@ _win_get_screensize (int *swp, int *shp)
}
#endif
int
_rl_tcgetwinsize (int tty, struct winsize *wp)
{
#if defined (HAVE_TCGETWINSIZE)
return (tcgetwinsize (tty, wp));
#elif defined (TIOCGWINSZ)
return (ioctl (tty, TIOCGWINSZ, wp));
#else
return -1;
#endif
}
void
_rl_tcsetwinsize (int tty, struct winsize *wp)
{
#if defined (HAVE_TCGETWINSIZE)
tcsetwinsize (tty, wp);
#elif defined (TIOCGWINSZ)
ioctl (tty, TIOCSWINSZ, wp);
#else
;
#endif
}
/* Get readline's idea of the screen size. TTY is a file descriptor open
to the terminal. If IGNORE_ENV is true, we do not pay attention to the
values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being
@@ -266,19 +290,19 @@ void
_rl_get_screen_size (int tty, int ignore_env)
{
char *ss;
#if defined (TIOCGWINSZ)
#if defined (TIOCGWINSZ) || defined (HAVE_TCGETWINSIZE)
struct winsize window_size;
#endif /* TIOCGWINSZ */
#endif /* TIOCGWINSZ || HAVE_TCGETWINSIZE */
int wr, wc;
wr = wc = -1;
#if defined (TIOCGWINSZ)
if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
#if defined (TIOCGWINSZ) || defined (HAVE_TCGETWINSIZE)
if (_rl_tcgetwinsize (tty, &window_size) == 0)
{
wc = (int) window_size.ws_col;
wr = (int) window_size.ws_row;
}
#endif /* TIOCGWINSZ */
#endif /* TIOCGWINSZ || HAVE_TCGETWINSIZE */
#if defined (__EMX__)
_emx_get_screensize (&wc, &wr);
+22
View File
@@ -247,3 +247,25 @@ reached AND-AND body
reached OR-OR body
reached AND-AND group
reached OR-OR group
./exec17.sub: line 26: exec: notthere: not found
after failed exec: 127
./exec17.sub: line 31: exec: notthere: not found
after failed exec with output redirection
./exec17.sub: line 36: exec: notthere: not found
./exec17.sub: line 37: 4: Bad file descriptor
./exec17.sub: line 40: .: Is a directory
after failed redir stdout
after failed redir stderr
./exec17.sub: line 44: exec: notthere: not found
after failed exec with input redirection
./exec17.sub: line 50: exec: notthere: not found
after failed exec: 127
./exec17.sub: line 55: exec: notthere: not found
after failed exec with output redirection
./exec17.sub: line 60: exec: notthere: not found
./exec17.sub: line 61: 4: Bad file descriptor
./exec17.sub: line 64: .: Is a directory
after failed redir stdout
after failed redir stderr
./exec17.sub: line 68: exec: notthere: not found
after failed exec with input redirection
+69
View File
@@ -0,0 +1,69 @@
# This program 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# test behavior of redirections when the shell doesn't exit and exec gets a
# program name to execute as an operand
# set up a fixed path so we know notthere will not be found
PATH=/usr/bin:/bin
export PATH
FN=/tmp/output-$$
shopt -s execfail
# make sure execfail works right, otherwise none of the rest matters
exec notthere
echo after failed exec: $?
# basic redirection undoing if exec fails
rm -f $FN
exec notthere >$FN
echo after failed exec with output redirection
rm -f $FN
# undo successful redirections if exec fails but does not exit the shell
exec notthere 4>&2
echo foo >&4
# we should undo successful redirects if one of the redirections fails
exec >$FN 2>.
echo after failed redir stdout
echo after failed redir stderr >&2
exec notthere <<<'foo bar baz'
echo after failed exec with input redirection
# the command builtin should not make a difference here
# make sure execfail works right, otherwise none of the rest matters
command exec notthere
echo after failed exec: $?
# basic redirection undoing if exec fails
rm -f $FN
command exec notthere >$FN
echo after failed exec with output redirection
rm -f $FN
# undo successful redirections if exec fails but does not exit the shell
command exec notthere 4>&2
echo foo >&4
# we should undo successful redirects if one of the redirections fails
command exec >$FN 2>.
echo after failed redir stdout
echo after failed redir stderr >&2
command exec notthere <<<'foo bar baz'
echo after failed exec with input redirection
+3
View File
@@ -204,3 +204,6 @@ ${THIS_SH} ./exec15.sub
# problems with set -e and inverting commands' return status
${THIS_SH} ./exec16.sub
# test behavior of redirections when exec fails and does not exit the shell
${THIS_SH} ./exec17.sub