mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-09-21 16:42:11 +02:00
convert TMOUT input timeout handling to use native readline timeouts if readline is being used; change TMOUT SIGALRM processing not to run in a signal handler context to exit; fix for adding multiline commands containing |& to the history list; history -r should not change history_lines_this_session if reading from the history file
This commit is contained in:
@@ -13316,3 +13316,47 @@ doc/bash.1,doc/bashref.texi,lib/readline/doc/hsuser.texi
|
||||
maximum in the file to avoid partial history entries or history
|
||||
entries without a timestamp (if the file has them)
|
||||
From https://savannah.gnu.org/bugs/?68650
|
||||
|
||||
8/28
|
||||
----
|
||||
|
||||
eval.c
|
||||
- alrm_catcher: change to only be active if readline isn't being used;
|
||||
all it does now is set a flag (input_timeout_seen)
|
||||
- read_command: use rl_set_timeout and rl_timeout_event_hook to
|
||||
implement the timeout specified by $TMOUT if readline is being used;
|
||||
use SIGALRM only if readline is not being used (--nolineediting)
|
||||
- alrm_handler: renamed alrm_catcher to this; add call to tcflush to
|
||||
make sure tty input buffer is empty if we time out reading input
|
||||
- input_timeout_hook: new function, used by both readline and non-
|
||||
readline paths, just calls alrm_handler
|
||||
|
||||
shell.h
|
||||
- extern declaration for input_timeout_seen
|
||||
|
||||
externs.h
|
||||
- extern declaration for input_timeout_hook()
|
||||
|
||||
quit.h
|
||||
- CHECK_INPUT_TIMEOUT: new signal macro, calls input_timeout_hook
|
||||
if we have caught SIGALRM and set input_timeout_seen
|
||||
|
||||
parse.y
|
||||
- yy_stream_get: add calls to CHECK_INPUT_TIMEOUT around call to
|
||||
stream_getc
|
||||
|
||||
input.c
|
||||
- stream_getc: if we get SIGALRM and set input_timeout_seen, reset
|
||||
the local buffer variables and return EOF. Caller will handle
|
||||
checking for input_timeout_seen and calling input_timeout_hook()
|
||||
|
||||
parse.y
|
||||
- no_semi_successors: add BAR_AND to list of tokens that should not
|
||||
be converted from newline to semicolon
|
||||
Report from Alberto Millán <hambled@gmail.com>
|
||||
|
||||
8/31
|
||||
----
|
||||
builtins/history.def
|
||||
- history_builtin: history -r should increase history_lines_this_session
|
||||
only if *not* reading from $HISTFILE
|
||||
|
||||
@@ -1037,6 +1037,7 @@ tests/assoc16.sub f
|
||||
tests/assoc17.sub f
|
||||
tests/assoc18.sub f
|
||||
tests/assoc19.sub f
|
||||
tests/assoc20.sub f
|
||||
tests/attr.tests f
|
||||
tests/attr.right f
|
||||
tests/attr1.sub f
|
||||
|
||||
@@ -293,7 +293,7 @@ history_builtin (WORD_LIST *list)
|
||||
if (flags & AFLAG) /* Append session's history to file. */
|
||||
{
|
||||
result = maybe_append_history (filename, using_histfile);
|
||||
if (using_histfile)
|
||||
if (result == 0 && using_histfile)
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
else if (flags & WFLAG) /* Write entire history. */
|
||||
@@ -317,7 +317,9 @@ history_builtin (WORD_LIST *list)
|
||||
I/O and permission errors. */
|
||||
if (result > 0)
|
||||
history_error (filename, result, 1);
|
||||
if (result == 0)
|
||||
/* Only act like these are new history entries if we are not reading
|
||||
from $HISTFILE */
|
||||
if (result == 0 && using_histfile == 0)
|
||||
history_lines_this_session += history_lines_read_from_file;
|
||||
}
|
||||
else if (flags & NFLAG) /* Read `new' history from file. */
|
||||
|
||||
+1
-1
@@ -8939,7 +8939,7 @@ Several shell options settable with the
|
||||
builtin will modify history expansion behavior
|
||||
(see the description of the
|
||||
.B shopt
|
||||
builtin below).and
|
||||
builtin below).
|
||||
If the
|
||||
.B histverify
|
||||
shell option is enabled, and
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_TERMIOS_H)
|
||||
# include <termios.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
@@ -44,6 +48,12 @@
|
||||
#include "input.h"
|
||||
#include "execute_cmd.h"
|
||||
|
||||
/* If we are using readline timeouts and timeout hooks */
|
||||
#if defined (READLINE)
|
||||
# include "bashline.h"
|
||||
# include <readline/readline.h>
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
@@ -53,8 +63,12 @@
|
||||
#endif
|
||||
|
||||
static void send_pwd_to_eterm (void);
|
||||
static void alrm_handler (int);
|
||||
static sighandler alrm_catcher (int);
|
||||
|
||||
int input_timeout_set = 0;
|
||||
volatile sig_atomic_t input_timeout_seen = 0;
|
||||
|
||||
/* Read and execute commands until EOF is reached. This assumes that
|
||||
the input source has already been initialized. */
|
||||
int
|
||||
@@ -254,16 +268,29 @@ pretty_print_loop (void)
|
||||
}
|
||||
|
||||
static sighandler
|
||||
alrm_catcher(int i)
|
||||
alrm_catcher (int i)
|
||||
{
|
||||
char *msg;
|
||||
input_timeout_seen = 1;
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
msg = _("\007timed out waiting for input: auto-logout\n");
|
||||
write (1, msg, strlen (msg));
|
||||
static void
|
||||
alrm_handler(int i)
|
||||
{
|
||||
printf ("\007%s\n", _("timed out waiting for input: auto-logout"));
|
||||
fflush (stdout);
|
||||
|
||||
tcflush (fileno (stdin), TCIFLUSH);
|
||||
bash_logout (); /* run ~/.bash_logout if this is a login shell */
|
||||
jump_to_top_level (EXITPROG);
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
/* We can use this for both readline and non-readline cases */
|
||||
int
|
||||
input_timeout_hook (void)
|
||||
{
|
||||
alrm_handler (SIGALRM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send an escape sequence to emacs term mode to tell it the
|
||||
@@ -405,8 +432,19 @@ read_command (void)
|
||||
tmout_len = (int)strtol (t, &e, 10);
|
||||
if (e != t && *e == '\0' && tmout_len > 0)
|
||||
{
|
||||
old_alrm = set_signal_handler (SIGALRM, alrm_catcher);
|
||||
alarm (tmout_len);
|
||||
input_timeout_set = 1;
|
||||
if (no_line_editing)
|
||||
{
|
||||
old_alrm = set_signal_handler (SIGALRM, alrm_catcher);
|
||||
alarm (tmout_len);
|
||||
}
|
||||
#if defined (READLINE)
|
||||
else
|
||||
{
|
||||
rl_timeout_event_hook = input_timeout_hook;
|
||||
rl_set_timeout (tmout_len, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,10 +454,21 @@ read_command (void)
|
||||
current_command_line_count = 0;
|
||||
result = parse_command ();
|
||||
|
||||
if (interactive && tmout_var && (tmout_len > 0))
|
||||
if (interactive && input_timeout_set)
|
||||
{
|
||||
alarm(0);
|
||||
set_signal_handler (SIGALRM, old_alrm);
|
||||
if (no_line_editing)
|
||||
{
|
||||
alarm(0);
|
||||
set_signal_handler (SIGALRM, old_alrm);
|
||||
}
|
||||
#if defined (READLINE)
|
||||
else
|
||||
{
|
||||
rl_clear_timeout ();
|
||||
rl_timeout_event_hook = NULL;
|
||||
}
|
||||
#endif
|
||||
input_timeout_set = 0;
|
||||
}
|
||||
|
||||
return (result);
|
||||
|
||||
@@ -102,6 +102,7 @@ extern int reader_loop (void);
|
||||
extern int pretty_print_loop (void);
|
||||
extern int parse_command (void);
|
||||
extern int read_command (void);
|
||||
extern int input_timeout_hook (void);
|
||||
|
||||
/* Functions from braces.c. */
|
||||
#if defined (BRACE_EXPANSION)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* input.c -- functions to perform buffered input with synchronization. */
|
||||
|
||||
/* Copyright (C) 1992-2023 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1992-2026 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -114,6 +114,11 @@ stream_getc (FILE *stream)
|
||||
}
|
||||
else if (interrupt_state || terminating_signal) /* QUIT; */
|
||||
local_index = local_bufused = 0;
|
||||
else if (input_timeout_seen) /* CHECK_INPUT_TIMEOUT; */
|
||||
{
|
||||
local_index = local_bufused = 0;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
local_index = 0;
|
||||
}
|
||||
|
||||
@@ -1844,12 +1844,14 @@ yy_stream_get (void)
|
||||
int result;
|
||||
|
||||
result = EOF;
|
||||
CHECK_INPUT_TIMEOUT;
|
||||
if (bash_input.location.file)
|
||||
{
|
||||
/* XXX - don't need terminate_immediately; stream_getc checks
|
||||
for terminating signals itself if read returns < 0 */
|
||||
result = stream_getc (bash_input.location.file);
|
||||
}
|
||||
CHECK_INPUT_TIMEOUT;
|
||||
return (result);
|
||||
}
|
||||
|
||||
@@ -6024,7 +6026,7 @@ reset_readline_prompt (void)
|
||||
semi-colons. When concatenating multiple lines of history, the
|
||||
newline separator for such tokens is replaced with a space. */
|
||||
static const int no_semi_successors[] = {
|
||||
'\n', '{', '(', ')', ';', '&', '|',
|
||||
'\n', '{', '(', ')', ';', '&', '|', BAR_AND,
|
||||
CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, THEN, UNTIL,
|
||||
WHILE, AND_AND, OR_OR, IN, DOLPAREN, DOLBRACE,
|
||||
0
|
||||
|
||||
@@ -88,4 +88,10 @@ do { \
|
||||
if (interrupt_state) zreset (); \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_INPUT_TIMEOUT \
|
||||
do { \
|
||||
if (input_timeout_seen) \
|
||||
input_timeout_hook (); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _QUIT_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* shell.h -- The data structures used by the shell */
|
||||
|
||||
/* Copyright (C) 1993-2024 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1993-2026 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -114,6 +114,8 @@ extern int indirection_level;
|
||||
extern int shell_compatibility_level;
|
||||
extern const int default_compatibility_level;
|
||||
extern int running_under_emacs;
|
||||
extern int input_timeout_set;
|
||||
extern volatile sig_atomic_t input_timeout_seen;
|
||||
|
||||
extern int pretty_print_mode;
|
||||
|
||||
|
||||
@@ -430,3 +430,4 @@ declare -A aa=([/homes/cj/key]="/homes/cj/Desktop" )
|
||||
declare -A aa=([/homes/cj/Documents]="/homes/cj/Library" [/homes/cj/key]="/homes/cj/Desktop" )
|
||||
declare -A aa=([/homes/cj/Documents]="/homes/cj/Library" [/homes/cj/key]="/homes/cj/Desktop:/homes/cj/Documents:/homes/cj/Applications" )
|
||||
declare -A aa=([/homes/cj/Documents]="/homes/cj/Library" [/homes/cj/key]="/homes/cj/Desktop:/homes/cj/Documents:/homes/cj/Applications" )
|
||||
assoc20.sub
|
||||
|
||||
@@ -275,3 +275,6 @@ test_runsub ./assoc18.sub
|
||||
|
||||
# tests with tilde expansion in keys and values post-bash-5.2
|
||||
test_runsub ./assoc19.sub
|
||||
|
||||
# new bash-5.4 kv-pair compound assignment word splitting behavior
|
||||
test_runsub ./assoc20.sub
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# 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/>.
|
||||
#
|
||||
# Originally by Zachary Santer <zsanter@gmail.com>
|
||||
# Modified by Chet Ramey <chet.ramey@case.edu> for the Bash test suite
|
||||
#
|
||||
|
||||
: ${THIS_SH:=./bash}
|
||||
|
||||
set -o nounset -o noglob +o braceexpand
|
||||
shopt -s lastpipe
|
||||
unset CDPATH TMOUT
|
||||
declare -r -x LC_ALL='C'
|
||||
|
||||
main () {
|
||||
|
||||
local declaration
|
||||
if (( ${#} == 0 )) then
|
||||
declaration='declare -A assoc
|
||||
'
|
||||
else
|
||||
declaration="${1} -A "
|
||||
fi
|
||||
|
||||
while (( test_count < 512 )); do
|
||||
(( ++test_count ))
|
||||
|
||||
# Create an associative array compound assignment containing random-length
|
||||
# quoted arrays, unquoted scalars, and literals
|
||||
|
||||
local -i array_count=0
|
||||
local -i scalar_count=0
|
||||
|
||||
local script="\
|
||||
set -o nounset -o noglob +o braceexpand
|
||||
shopt -s lastpipe
|
||||
unset CDPATH TMOUT
|
||||
declare -r -x LC_ALL='C'
|
||||
|
||||
main () {
|
||||
|
||||
"
|
||||
|
||||
local test_case=''
|
||||
|
||||
local assignment_contents=''
|
||||
|
||||
while (( ( SRANDOM & 7 ) > 0 )) do
|
||||
|
||||
local -i type_selector="$(( SRANDOM & 32767 ))"
|
||||
if (( type_selector < 10923 )) then
|
||||
assignment_contents+=" '${SRANDOM//[01]/& }'"
|
||||
else
|
||||
local -a list=()
|
||||
local -i element_count
|
||||
for (( element_count = SRANDOM & 7; element_count > 0; --element_count )) do
|
||||
list+=( "${SRANDOM}" )
|
||||
done
|
||||
if (( type_selector < 21845 )) then
|
||||
local array_name="array_$(( array_count++ ))"
|
||||
list=( "${list[@]//[01]/& }" )
|
||||
test_case+=" local -a ${array_name}=( ${list[*]@Q} )"$'\n'
|
||||
assignment_contents+=" \"\${${array_name}[@]}\""
|
||||
else
|
||||
local scalar_name="scalar_$(( scalar_count++ ))"
|
||||
test_case+=" local ${scalar_name}='${list[*]}'"$'\n'
|
||||
assignment_contents+=" \${${scalar_name}}"
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
test_case+="\
|
||||
|
||||
${declaration}assoc=(${assignment_contents} )
|
||||
set --${assignment_contents}"
|
||||
|
||||
script+="${test_case}"'
|
||||
|
||||
breakage="false"
|
||||
if (( ( ( ${#} + 1 ) / 2 ) != ${#assoc[@]} )) then
|
||||
breakage="true"
|
||||
fi
|
||||
while [[ ${breakage} == "false" && ${#} -gt 1 ]] do
|
||||
if [[ ${assoc[${1}]} != "${2}" ]] then
|
||||
breakage="true"
|
||||
fi
|
||||
shift 2
|
||||
done
|
||||
if [[ ${breakage} == "false" && ${#} -eq 1 && -n ${assoc[${1}]} ]] then
|
||||
breakage="true"
|
||||
fi
|
||||
[[ ${breakage} == "false" ]]
|
||||
exit
|
||||
|
||||
}
|
||||
|
||||
main
|
||||
'
|
||||
|
||||
if ! ${THIS_SH} -c "${script}"; then
|
||||
(( ++error_count ))
|
||||
printf '========\n'
|
||||
printf '%s\n' "${test_case}"
|
||||
printf '========\n'
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
declare -i test_count=0
|
||||
declare -i error_count=0
|
||||
|
||||
|
||||
main # local
|
||||
main export
|
||||
|
||||
exit ${error_count}
|
||||
Reference in New Issue
Block a user