fix for parameter expansions that contain valid and invalid expansions; avoid stale readdir() value in getcwd replacement; check libtinfow for termcap functions; fix to propagate exit status of builtins run in subshells back to calling shell

This commit is contained in:
Chet Ramey
2025-08-04 10:18:32 -04:00
parent c1d9c08853
commit e9053f2a3a
11 changed files with 183 additions and 41 deletions
+34
View File
@@ -11476,8 +11476,42 @@ command.h
- revert changes to COMMAND and SIMPLE_COM from 7/16
From a report by Jessica Clarke <jrtc27@jrtc27.com>
parse.y
- pipeline: in BAR_AND form of the pipeline production, use a
REDIRECT ** to manipulate the redirection list instead of trying
to cast a COMAND * to a SIMPLE_COM *
From a report by Jessica Clarke <jrtc27@jrtc27.com>
expr.c
- expassign,expshift: avoid C23 undefined behavior when performing
left and right arithmetic shifts
From https://savannah.gnu.org/patch/?10532
bkallus <benjamin.p.kallus.gr@dartmouth.edu>
7/28
----
subst.c
- expand_word_internal: if we see a `$' and call param_expand, pass a
local copy of expanded_something and OR it into expanded_something,
so this function can set it to 0 if we get a trailing $ or a $!
when there are no background pids.
From ahmedwaldsaaid@gmail.com via https://savannah.gnu.org/bugs/index.php?67358
Fix suggested by Oğuz <oguzismailuysal@gmail.com>
8/1
---
lib/sh/getcwd.c
- getcwd: set errno to 0 before calling readdir to avoid a stale
value if readdir() returns NULL and distinguish errors from the
end of the directory. If readdir() returns NULL without changing
errno, set it to ENOENT.
From a report by Richard Weinberger <richard@sigma-star.at>
aclocal.m4
- BASH_CHECK_LIB_TERMCAP: add libtinfow to the library list to search
From a report by Дилян Палаузов <dilyan.palauzov@aegee.org>
execute_cmd.c
- execute_subshell_builtin_or_function: fix to propagate exit statuses
of builtins run in subshells back to the calling shell
From https://savannah.gnu.org/support/?109840
Vendored
+7 -3
View File
@@ -934,10 +934,11 @@ AC_CACHE_VAL(bash_cv_termcap_lib,
[AC_CHECK_FUNC(tgetent, bash_cv_termcap_lib=libc,
[AC_CHECK_LIB(termcap, tgetent, bash_cv_termcap_lib=libtermcap,
[AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo,
[AC_CHECK_LIB(tinfow, tgetent, bash_cv_termcap_lib=libtinfow,
[AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses,
[AC_CHECK_LIB(ncursesw, tgetent, bash_cv_termcap_lib=libncursesw,
[AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])])])])])])
[AC_CHECK_LIB(ncursesw, tgetent, bash_cv_termcap_lib=libncursesw,
[AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])])])])])])])
if test "X$_bash_needmsg" = "Xyes"; then
AC_MSG_CHECKING(which library has the termcap functions)
fi
@@ -952,6 +953,9 @@ TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libtinfo; then
TERMCAP_LIB=-ltinfo
TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libtinfow; then
TERMCAP_LIB=-ltinfow
TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libncursesw; then
TERMCAP_LIB=-lncursesw
TERMCAP_DEP=
+4 -3
View File
@@ -79,12 +79,13 @@ $SHORT_DOC cd [-L|[-P [-e]]] [-@] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable. If DIR is "-", it is converted to $OLDPWD.
HOME shell variable. If DIR is "-", it is converted to $OLDPWD. If DIR is
the empty string, cd returns an error.
The variable CDPATH defines the search path for the directory containing
DIR. Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory. If DIR begins
with a slash (/), then CDPATH is not used.
A null directory name in CDPATH is the same as the current directory.
If DIR begins with a slash (/), then CDPATH is not used.
If the directory is not found, and the shell option `cdable_vars' is set,
the word is assumed to be a variable name. If that variable has a value,
Vendored
+114 -8
View File
@@ -5570,6 +5570,53 @@ printf "%s\n" "$ac_cv_lib_tinfo_tgetent" >&6; }
if test "x$ac_cv_lib_tinfo_tgetent" = xyes
then :
bash_cv_termcap_lib=libtinfo
else case e in #(
e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tgetent in -ltinfow" >&5
printf %s "checking for tgetent in -ltinfow... " >&6; }
if test ${ac_cv_lib_tinfow_tgetent+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) ac_check_lib_save_LIBS=$LIBS
LIBS="-ltinfow $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply.
The 'extern "C"' is for builds by C++ compilers;
although this is not generally supported in C code supporting it here
has little cost and some practical benefit (sr 110532). */
#ifdef __cplusplus
extern "C"
#endif
char tgetent (void);
int
main (void)
{
return tgetent ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"
then :
ac_cv_lib_tinfow_tgetent=yes
else case e in #(
e) ac_cv_lib_tinfow_tgetent=no ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfow_tgetent" >&5
printf "%s\n" "$ac_cv_lib_tinfow_tgetent" >&6; }
if test "x$ac_cv_lib_tinfow_tgetent" = xyes
then :
bash_cv_termcap_lib=libtinfow
else case e in #(
e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lcurses" >&5
printf %s "checking for tgetent in -lcurses... " >&6; }
@@ -5732,6 +5779,9 @@ esac
fi
;;
esac
fi
;;
esac
fi
if test "X$_bash_needmsg" = "Xyes"; then
@@ -5750,6 +5800,9 @@ TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libtinfo; then
TERMCAP_LIB=-ltinfo
TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libtinfow; then
TERMCAP_LIB=-ltinfow
TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libncursesw; then
TERMCAP_LIB=-lncursesw
TERMCAP_DEP=
@@ -9357,8 +9410,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
LIBS=$save_LIBS
test $gl_pthread_api = yes && break
done
echo "$as_me:9360: gl_pthread_api=$gl_pthread_api" >&5
echo "$as_me:9361: LIBPTHREAD=$LIBPTHREAD" >&5
echo "$as_me:9413: gl_pthread_api=$gl_pthread_api" >&5
echo "$as_me:9414: LIBPTHREAD=$LIBPTHREAD" >&5
gl_pthread_in_glibc=no
# On Linux with glibc >= 2.34, libc contains the fully functional
@@ -9384,7 +9437,7 @@ rm -rf conftest*
;;
esac
echo "$as_me:9387: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
echo "$as_me:9440: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
# Test for libpthread by looking for pthread_kill. (Not pthread_self,
# since it is defined as a macro on OSF/1.)
@@ -9562,7 +9615,7 @@ fi
fi
fi
echo "$as_me:9565: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
echo "$as_me:9618: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5
printf %s "checking whether POSIX threads API is available... " >&6; }
@@ -9809,8 +9862,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
LIBS=$save_LIBS
test $gl_pthread_api = yes && break
done
echo "$as_me:9812: gl_pthread_api=$gl_pthread_api" >&5
echo "$as_me:9813: LIBPTHREAD=$LIBPTHREAD" >&5
echo "$as_me:9865: gl_pthread_api=$gl_pthread_api" >&5
echo "$as_me:9866: LIBPTHREAD=$LIBPTHREAD" >&5
gl_pthread_in_glibc=no
# On Linux with glibc >= 2.34, libc contains the fully functional
@@ -9836,7 +9889,7 @@ rm -rf conftest*
;;
esac
echo "$as_me:9839: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
echo "$as_me:9892: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
# Test for libpthread by looking for pthread_kill. (Not pthread_self,
# since it is defined as a macro on OSF/1.)
@@ -10014,7 +10067,7 @@ fi
fi
fi
echo "$as_me:10017: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
echo "$as_me:10070: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5
printf %s "checking whether POSIX threads API is available... " >&6; }
@@ -22804,6 +22857,53 @@ printf "%s\n" "$ac_cv_lib_tinfo_tgetent" >&6; }
if test "x$ac_cv_lib_tinfo_tgetent" = xyes
then :
bash_cv_termcap_lib=libtinfo
else case e in #(
e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tgetent in -ltinfow" >&5
printf %s "checking for tgetent in -ltinfow... " >&6; }
if test ${ac_cv_lib_tinfow_tgetent+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) ac_check_lib_save_LIBS=$LIBS
LIBS="-ltinfow $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply.
The 'extern "C"' is for builds by C++ compilers;
although this is not generally supported in C code supporting it here
has little cost and some practical benefit (sr 110532). */
#ifdef __cplusplus
extern "C"
#endif
char tgetent (void);
int
main (void)
{
return tgetent ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"
then :
ac_cv_lib_tinfow_tgetent=yes
else case e in #(
e) ac_cv_lib_tinfow_tgetent=no ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfow_tgetent" >&5
printf "%s\n" "$ac_cv_lib_tinfow_tgetent" >&6; }
if test "x$ac_cv_lib_tinfow_tgetent" = xyes
then :
bash_cv_termcap_lib=libtinfow
else case e in #(
e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lcurses" >&5
printf %s "checking for tgetent in -lcurses... " >&6; }
@@ -22966,6 +23066,9 @@ esac
fi
;;
esac
fi
;;
esac
fi
if test "X$_bash_needmsg" = "Xyes"; then
@@ -22984,6 +23087,9 @@ TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libtinfo; then
TERMCAP_LIB=-ltinfo
TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libtinfow; then
TERMCAP_LIB=-ltinfow
TERMCAP_DEP=
elif test $bash_cv_termcap_lib = libncursesw; then
TERMCAP_LIB=-lncursesw
TERMCAP_DEP=
+3 -2
View File
@@ -5,7 +5,7 @@
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
.\" Last Change: Tue Jul 15 10:19:08 EDT 2025
.\" Last Change: Wed Jul 30 14:47:58 EDT 2025
.\"
.\" For bash_builtins, strip all but "SHELL BUILTIN COMMANDS" section
.\" For rbash, strip all but "RESTRICTED SHELL" section
@@ -21,7 +21,7 @@
.ds zY \" empty
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2025 July 15" "GNU Bash 5.3"
.TH BASH 1 "2025 July 30" "GNU Bash 5.3"
.\"
.ie \n(.g \{\
.ds ' \(aq
@@ -9260,6 +9260,7 @@ if \fIdir\fP is not supplied, the value of the
.SM
.B HOME
shell variable is used as \fIdir\fP.
If \fIdir\fP is the empty string, \fBcd\fP treats it as an error.
The variable
.SM
.B CDPATH
+1
View File
@@ -4241,6 +4241,7 @@ cd -P [-e] [-@@] [@var{directory}]
Change the current working directory to @var{directory}.
If @var{directory} is not supplied, the value of the @env{HOME}
shell variable is used as @var{directory}.
If @var{directory} is the empty string, @code{cd} treats it as an error.
If the shell variable
@env{CDPATH} exists,
and @var{directory} does not begin with a slash,
+3 -3
View File
@@ -2,10 +2,10 @@
Copyright (C) 1988-2025 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Sun May 18 13:42:18 EDT 2025
@set LASTCHANGE Wed Jul 30 14:47:36 EDT 2025
@set EDITION 5.3
@set VERSION 5.3
@set UPDATED 18 May 2025
@set UPDATED-MONTH May 2025
@set UPDATED 30 July 2025
@set UPDATED-MONTH July 2025
-2
View File
@@ -5536,10 +5536,8 @@ execute_subshell_builtin_or_function (WORD_LIST *words, REDIRECT *redirects,
if (result == EXITPROG || result == EXITBLTIN)
subshell_exit (last_command_exit_value);
#if 0 /* TAG:bash-5.4 https://savannah.gnu.org/support/?109840 6/5/2025 */
else if (result == ERREXIT)
subshell_exit (last_command_exit_value ? last_command_exit_value : EXECUTION_FAILURE);
#endif
else if (result)
subshell_exit (EXECUTION_FAILURE);
else if (funcvalue)
+12 -15
View File
@@ -186,8 +186,18 @@ getcwd (char *buf, size_t size)
dirstream = opendir (dotp);
if (dirstream == NULL)
goto lose;
while ((d = readdir (dirstream)) != NULL)
for (;;)
{
errno = 0;
d = readdir (dirstream);
if (d == NULL)
{
if (errno == 0)
errno = ENOENT;
break;
}
if (d->d_name[0] == '.' &&
(d->d_name[1] == '\0' ||
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
@@ -208,27 +218,14 @@ getcwd (char *buf, size_t size)
memcpy (&name[dotlist + dotsize - dotp + 1],
d->d_name, namlen + 1);
if (lstat (name, &st) < 0)
{
#if 0
int save = errno;
(void) closedir (dirstream);
errno = save;
goto lose;
#else
saved_errno = errno;
#endif
}
saved_errno = errno;
if (st.st_dev == thisdev && st.st_ino == thisino)
break;
}
}
if (d == NULL)
{
#if 0
int save = errno;
#else
int save = errno ? errno : saved_errno;
#endif
(void) closedir (dirstream);
errno = save;
goto lose;
+1
View File
@@ -0,0 +1 @@
timestamp
+4 -5
View File
@@ -11508,8 +11508,6 @@ add_string:
}
case '$':
if (expanded_something)
*expanded_something = 1;
local_expanded = 1;
temp_has_dollar_at = 0;
@@ -11521,12 +11519,15 @@ add_string:
if (word->flags & W_COMPLETE)
pflags |= PF_COMPLETE;
tword = param_expand (string, &sindex, quoted, expanded_something,
tword = param_expand (string, &sindex, quoted, &local_expanded,
&temp_has_dollar_at, &quoted_dollar_at,
&had_quoted_null, pflags);
has_dollar_at += temp_has_dollar_at;
split_on_spaces += (tword->flags & W_SPLITSPACE);
if (expanded_something)
*expanded_something |= local_expanded;
if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
{
free (string);
@@ -11586,7 +11587,6 @@ add_string:
if (expanded_something)
*expanded_something = 1;
local_expanded = 1;
if (word->flags & W_NOCOMSUB)
/* sindex + 1 because string[sindex] == '`' */
@@ -11768,7 +11768,6 @@ add_twochars:
*contains_dollar_at = 1;
if (expanded_something)
*expanded_something = 1;
local_expanded = 1;
}
}
else