jj. Fixed a bug that caused single quotes to be stripped from ANSI-C quoting
inside double-quoted command substitutions.
+kk. Fixed a bug that could cause core dumps when `return' was executed as the
+ last element of a pipeline inside a shell function.
+
+ll. Fixed a bug that caused DEBUG trap strings to overwrite commands stored in
+ the jobs list.
+
2. Changes to Readline
a. Fixed a problem that caused segmentation faults when using readline in
ii. Fixed a bug that could cause file descriptors > 10 to not be closed even
when closed explicitly by a script.
+jj. Fixed a bug that caused single quotes to be stripped from ANSI-C quoting
+ inside double-quoted command substitutions.
+
2. Changes to Readline
a. Fixed a problem that caused segmentation faults when using readline in
m. Fixed a bug that could cause a core dump when an edited history entry was
re-executed under certain conditions.
+n. Fixed a bug that caused readline to reference freed memory when attmpting
+ to display a portion of the prompt.
+
3. New Features in Bash
a. Changed the parameter pattern replacement functions to not anchor the
- make sure that parameter_brace_substring leaves this_command_name
set to either NULL or its previous value after setting it so that
arithmetic evaluation errors while expanding substring values
- contain meaningful informationn
+ contain meaningful information
+
+ 6/9
+ ---
+execute_cmd.c
+ - make sure that SUBSHELL_ASYNC and SUBSHELL_PIPE are set as flag bits
+ in subshell_environment, rather than setting only a single value
+ - change execute_subshell_builtin_or_function to give the `return'
+ builtin a place to longjmp to when executed in a subshell or pipeline
+ (mostly as the last command in a pipeline). Bug reported by
+ Oleg Verych <olecom@gmail.com>
+ - in execute_simple_command, make sure to call execute_disk_command
+ with the_printed_command_except_trap to keep DEBUG trap command
+ strings from overwriting the command strings associated with jobs
+ and printed in job control messages. Bug reported by Daniel Kahn
+ Gillmor <dkg-debian.org@fifthhorseman.net>
+
+[bash-3.2-alpha frozen]
- new function, alloc_undo_entry (enum undo_code what, int start, int end, char *text)
takes care of allocating and populating a struct for an individual
undo list entry
+ - new function: _rl_copy_undo_entry(UNDO_LIST *entry)
+ - new function: _rl_copy_undo_list(UNDO_LIST *head)
+lib/readline/rlprivate.h
+ - new extern declarations for _rl_copy_undo_{entry,list}
+
+execute_cmd.c
+ - change execute_cond_node so that quoting the rhs of the =~
+ operator forces string matching, like the == and != operators
+
+ 5/23
+ ----
+redir.c
+ - add_undo_redirect now takes as an additional argument the type of
+ redirection we're trying to undo
+ - don't add a "preservation" redirection for fds > SHELL_FD_BASE if
+ the redirection is closing the fd
-
+ 5/24
+ ----
+subst.c
+ - make sure that parameter_brace_substring leaves this_command_name
+ set to either NULL or its previous value after setting it so that
+ arithmetic evaluation errors while expanding substring values
+ contain meaningful information
+
+ 6/9
+ ---
+execute_cmd.c
+ - make sure that SUBSHELL_ASYNC and SUBSHELL_PIPE are set as flag bits
+ in subshell_environment, rather than setting only a single value
+ - change execute_subshell_builtin_or_function to give the `return'
+ builtin a place to longjmp to when executed in a subshell or pipeline
+ (mostly as the last command in a pipeline). Bug reported by
+ Oleg Verych <olecom@gmail.com>
+ - in execute_simple_command, make sure to call execute_disk_command
+ with the_printed_command_except_trap to keep DEBUG trap command
+ strings from overwriting the command strings associated with jobs
+ and printed in job control messages. Bug reported by Daniel Kahn
+ Gillmor <dkg-debian.org@fifthhorseman.net>
tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \
tests/printenv$(EXEEXT) mksignames$(EXEEXT) lsignames.h \
mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \
- buildversion.o mksignames.o signames.o
+ buildversion.o mksignames.o signames.o buildsignames.o
CREATED_CONFIGURE = config.h config.cache config.status config.log \
stamp-h po/POTFILES
CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
@%:@! /bin/sh
@%:@ From configure.in for Bash 3.2, version 3.188.
@%:@ Guess values for system-dependent variables and create Makefiles.
-@%:@ Generated by GNU Autoconf 2.59 for bash 3.2-alpha.
+@%:@ Generated by GNU Autoconf 2.59 for bash 3.2-devel.
@%:@
@%:@ Report bugs to <bug-bash@gnu.org>.
@%:@
# Identity of this package.
PACKAGE_NAME='bash'
PACKAGE_TARNAME='bash'
-PACKAGE_VERSION='3.2-alpha'
-PACKAGE_STRING='bash 3.2-alpha'
+PACKAGE_VERSION='3.2-devel'
+PACKAGE_STRING='bash 3.2-devel'
PACKAGE_BUGREPORT='bug-bash@gnu.org'
ac_unique_file="shell.h"
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures bash 3.2-alpha to adapt to many kinds of systems.
+\`configure' configures bash 3.2-devel to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of bash 3.2-alpha:";;
+ short | recursive ) echo "Configuration of bash 3.2-devel:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-bash configure 3.2-alpha
+bash configure 3.2-devel
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by bash $as_me 3.2-alpha, which was
+It was created by bash $as_me 3.2-devel, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
BASHVERS=3.2
-RELSTATUS=alpha
+RELSTATUS=devel
case "$RELSTATUS" in
alp*|bet*|dev*|rc*) DEBUG='-DDEBUG' MALLOC_DEBUG='-DMALLOC_DEBUG' ;;
} >&5
cat >&5 <<_CSEOF
-This file was extended by bash $as_me 3.2-alpha, which was
+This file was extended by bash $as_me 3.2-devel, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-bash config.status 3.2-alpha
+bash config.status 3.2-devel
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
-m4trace:configure.in:30: -1- AC_INIT([bash], [3.2-alpha], [bug-bash@gnu.org])
+m4trace:configure.in:30: -1- AC_INIT([bash], [3.2-devel], [bug-bash@gnu.org])
m4trace:configure.in:30: -1- m4_pattern_forbid([^_?A[CHUM]_])
m4trace:configure.in:30: -1- m4_pattern_forbid([_AC_])
m4trace:configure.in:30: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
AC_REVISION([for Bash 3.2, version 3.188])dnl
define(bashvers, 3.2)
-define(relstatus, alpha)
+define(relstatus, devel)
AC_INIT([bash], bashvers-relstatus, [bug-bash@gnu.org])
/* Subshells are neither login nor interactive. */
login_shell = interactive = 0;
- subshell_environment = user_subshell ? SUBSHELL_PAREN : SUBSHELL_ASYNC;
+ if (user_subshell)
+ subshell_environment = SUBSHELL_PAREN;
+ else
+ {
+ subshell_environment = 0; /* XXX */
+ if (asynchronous)
+ subshell_environment |= SUBSHELL_ASYNC;
+ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ subshell_environment |= SUBSHELL_PIPE;
+ }
reset_terminating_signals (); /* in sig.c */
/* Cancel traps, in trap.c. */
if (function_value)
return_code = return_catch_value;
else
- return_code = execute_command_internal
- (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
+ return_code = execute_command_internal (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
/* If we are asked to, invert the return value. */
if (invert)
do_piping (pipe_in, pipe_out);
- subshell_environment = SUBSHELL_ASYNC;
+ if (async)
+ subshell_environment |= SUBSHELL_ASYNC;
+ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ subshell_environment |= SUBSHELL_PIPE;
if (do_redirections (redirects, RX_ACTIVE) == 0)
exit (EXECUTION_SUCCESS);
}
if (command_line == 0)
- command_line = savestring (the_printed_command);
+ command_line = savestring (the_printed_command_except_trap);
execute_disk_command (words, simple_command->redirects, command_line,
pipe_in, pipe_out, async, fds_to_close,
struct fd_bitmap *fds_to_close;
int flags;
{
- int result, r;
+ int result, r, funcvalue;
#if defined (JOB_CONTROL)
int jobs_hack;
/* A subshell is neither a login shell nor interactive. */
login_shell = interactive = 0;
- subshell_environment = SUBSHELL_ASYNC;
+ if (async)
+ subshell_environment |= SUBSHELL_ASYNC;
+ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ subshell_environment |= SUBSHELL_PIPE;
maybe_make_export_env (); /* XXX - is this needed? */
so we don't go back up to main(). */
result = setjmp (top_level);
+ /* Give the return builtin a place to jump to when executed in a subshell
+ or pipeline */
+ funcvalue = 0;
+ if (return_catch_flag && builtin == return_builtin)
+ funcvalue = setjmp (return_catch);
+
if (result == EXITPROG)
exit (last_command_exit_value);
else if (result)
exit (EXECUTION_FAILURE);
+ else if (funcvalue)
+ exit (return_catch_value);
else
{
r = execute_builtin (builtin, words, flags, 1);
/* Subshells are neither login nor interactive. */
login_shell = interactive = 0;
- subshell_environment = user_subshell ? SUBSHELL_PAREN : SUBSHELL_ASYNC;
+ if (user_subshell)
+ subshell_environment = SUBSHELL_PAREN;
+ else
+ {
+ subshell_environment = 0; /* XXX */
+ if (asynchronous)
+ subshell_environment |= SUBSHELL_ASYNC;
+ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ subshell_environment |= SUBSHELL_PIPE;
+ }
reset_terminating_signals (); /* in sig.c */
/* Cancel traps, in trap.c. */
if (function_value)
return_code = return_catch_value;
else
- return_code = execute_command_internal
- (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
+ return_code = execute_command_internal (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
/* If we are asked to, invert the return value. */
if (invert)
}
else if (cond->type == COND_BINARY)
{
+ rmatch = 0;
patmatch = ((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') &&
(cond->op->word[0] == '!' || cond->op->word[0] == '=') ||
(cond->op->word[0] == '=' && cond->op->word[1] == '\0'));
arg1 = cond_expand_word (cond->left->op, 0);
if (arg1 == 0)
arg1 = nullstr;
- arg2 = cond_expand_word (cond->right->op, patmatch);
+ arg2 = cond_expand_word (cond->right->op, patmatch||rmatch);
if (arg2 == 0)
arg2 = nullstr;
do_piping (pipe_in, pipe_out);
- subshell_environment = SUBSHELL_ASYNC;
+ if (async)
+ subshell_environment |= SUBSHELL_ASYNC;
+ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ subshell_environment |= SUBSHELL_PIPE;
if (do_redirections (redirects, RX_ACTIVE) == 0)
exit (EXECUTION_SUCCESS);
}
if (command_line == 0)
+#if 0
command_line = savestring (the_printed_command);
+#else
+ command_line = savestring (the_printed_command_except_trap);
+#endif
execute_disk_command (words, simple_command->redirects, command_line,
pipe_in, pipe_out, async, fds_to_close,
struct fd_bitmap *fds_to_close;
int flags;
{
- int result, r;
+ int result, r, funcvalue;
#if defined (JOB_CONTROL)
int jobs_hack;
/* A subshell is neither a login shell nor interactive. */
login_shell = interactive = 0;
- subshell_environment = SUBSHELL_ASYNC;
+ if (async)
+ subshell_environment |= SUBSHELL_ASYNC;
+ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ subshell_environment |= SUBSHELL_PIPE;
maybe_make_export_env (); /* XXX - is this needed? */
so we don't go back up to main(). */
result = setjmp (top_level);
+ /* Give the return builtin a place to jump to when executed in a subshell
+ or pipeline */
+ funcvalue = 0;
+ if (return_catch_flag && builtin == return_builtin)
+ funcvalue = setjmp (return_catch);
+
if (result == EXITPROG)
exit (last_command_exit_value);
else if (result)
exit (EXECUTION_FAILURE);
+ else if (funcvalue)
+ exit (return_catch_value);
else
{
r = execute_builtin (builtin, words, flags, 1);
extern int last_command_exit_value, last_command_exit_signal;
extern int loop_level, breaking;
extern int sourcelevel;
+extern int running_trap;
extern sh_builtin_func_t *this_shell_builtin;
extern char *shell_name, *this_command_name;
extern sigset_t top_level_mask;
#endif /* !errno */
#define DEFAULT_CHILD_MAX 32
-#if 1
-#define MAX_JOBS_IN_ARRAY 4096 /* production*/
+#if !defined (DEBUG)
+#define MAX_JOBS_IN_ARRAY 4096 /* production */
#else
#define MAX_JOBS_IN_ARRAY 128 /* testing */
#endif
extern int last_command_exit_value, last_command_exit_signal;
extern int loop_level, breaking;
extern int sourcelevel;
+extern int running_trap;
extern sh_builtin_func_t *this_shell_builtin;
extern char *shell_name, *this_command_name;
extern sigset_t top_level_mask;
reap_dead_jobs ();
realloc_jobs_list ();
-
+
return (js.j_lastj);
}
{
PROCESS *t, *p;
+itrace("add_process: name = %s running_trap = %d", name, running_trap);
#if defined (RECYCLES_PIDS)
int j;
p = find_process (pid, 0, &j);
{
if (jobs[i])
{
- if ((jobs[i]->flags & J_NOHUP) == 0)
- killpg (jobs[i]->pgrp, SIGHUP);
+ if (jobs[i]->flags & J_NOHUP)
+ continue;
+ killpg (jobs[i]->pgrp, SIGHUP);
if (STOPPED (i))
killpg (jobs[i]->pgrp, SIGCONT);
}
sigemptyset (&oset);
sigprocmask (SIG_BLOCK, &set, &oset);
+itrace("make_child: command = %s", command ? command : "");
making_children ();
#if defined (BUFFERED_INPUT)
: 0;
if (sigchld || block == 0)
waitpid_flags |= WNOHANG;
+ CHECK_TERMSIG;
pid = WAITPID (-1, &status, waitpid_flags);
/* WCONTINUED may be rejected by waitpid as invalid even when defined */
/* If waitpid returns 0, there are running children. If it returns -1,
the only other error POSIX says it can return is EINTR. */
+ CHECK_TERMSIG;
if (pid <= 0)
continue; /* jumps right to the test */
temp_handler = trap_to_sighandler (SIGINT);
restore_sigint_handler ();
if (temp_handler == SIG_DFL)
- termination_unwind_protect (SIGINT);
+ termsig_handler (SIGINT);
else if (temp_handler != SIG_IGN)
(*temp_handler) (SIGINT);
}
fprintf (stderr, "\n");
if (dir == 0)
dir = current_working_directory ();
+itrace("calling pretty_print_job for job %d", job);
pretty_print_job (job, JLIST_STANDARD, stderr);
if (dir && (strcmp (dir, jobs[job]->wd) != 0))
fprintf (stderr,
if (tcsetpgrp (shell_tty, pgrp) < 0)
{
/* Maybe we should print an error message? */
-#ifdef DEBUG
+#if 0
sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld",
shell_tty, (long)getpid(), (long)pgrp);
#endif
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
--- /dev/null
+a returns 5
+b returns 4
+c returns 3
+d returns 2
+in e
+e returned 25
+x is 25
+ZZ
+abcde
+defghi
+ZZ
+5
+0
+AVAR
+AVAR
+foo
+foo
+AVAR
+5
+5
+f1
+f1 ()
+{
+ ( return 5 );
+ status=$?;
+ echo $status;
+ return $status
+}
+before: try to assign to FUNCNAME
+outside: FUNCNAME =
+before: FUNCNAME = func
+FUNCNAME = func2
+after: FUNCNAME = func
+outside2: FUNCNAME =
+function
+zf is a function
+zf ()
+{
+ echo this is zf
+}
+f is a function
+f ()
+{
+ echo f-x;
+ echo f-y
+} 1>&2
+subshell
+f is a function
+f ()
+{
+ echo f-x;
+ echo f-y
+} 1>&2
+f2 is a function
+f2 ()
+{
+ echo f2-a;
+ function f3 ()
+ {
+ echo f3-a;
+ echo f3-b
+ } 1>&2;
+ f3
+}
+subshell
+f2 is a function
+f2 ()
+{
+ echo f2-a;
+ function f3 ()
+ {
+ echo f3-a;
+ echo f3-b
+ } 1>&2;
+ f3
+}
+f4 is a function
+f4 ()
+{
+ echo f4-a;
+ function f5 ()
+ {
+ echo f5-a;
+ echo f5-b
+ } 1>&2;
+ f5
+} 2>&1
+subshell
+f4 is a function
+f4 ()
+{
+ echo f4-a;
+ function f5 ()
+ {
+ echo f5-a;
+ echo f5-b
+ } 1>&2;
+ f5
+} 2>&1
+testgrp is a function
+testgrp ()
+{
+ echo testgrp-a;
+ {
+ echo tg-x;
+ echo tg-y
+ } 1>&2;
+ echo testgrp-b
+}
+subshell
+testgrp is a function
+testgrp ()
+{
+ echo testgrp-a;
+ {
+ echo tg-x;
+ echo tg-y
+ } 1>&2;
+ echo testgrp-b
+}
+funca is a function
+funca ()
+{
+ ( echo func-a )
+}
+funcb is a function
+funcb ()
+{
+ ( echo func-b )
+}
+funcc is a function
+funcc ()
+{
+ ( echo func-c ) 2>&1
+}
+func-a
+func-b
+func-c
+expect 5 10
+5 10
+expect 20
+20
+expect 5 20
+5 20
+expect 5 30
+5 30
+expect 2 40
+2 40
+expect 5 20
+5 20
myfunction
myfunction | cat
+segv()
+{
+ echo foo | return 5
+}
+
+segv
+echo $?
+
exit 0
--- /dev/null
+a()
+{
+ x=$((x - 1))
+ return 5
+}
+
+b()
+{
+ x=$((x - 1))
+ a
+ echo a returns $?
+ return 4
+}
+
+c()
+{
+ x=$((x - 1))
+ b
+ echo b returns $?
+ return 3
+}
+
+d()
+{
+ x=$((x - 1))
+ c
+ echo c returns $?
+ return 2
+}
+
+e()
+{
+ d
+ echo d returns $?
+ echo in e
+ x=$((x - 1))
+ return $x
+}
+
+f()
+{
+ e
+ echo e returned $?
+ echo x is $x
+ return 0
+}
+
+x=30
+f
+
+# make sure unsetting a local variable preserves the `local' attribute
+f1()
+{
+ local zz
+ zz=abcde
+ echo $zz
+ unset zz
+ zz=defghi
+ echo $zz
+}
+
+zz=ZZ
+echo $zz
+f1
+echo $zz
+
+unset -f f1
+f1()
+{
+ return 5
+}
+
+( f1 )
+echo $?
+
+unset -f f1
+f1()
+{
+ sleep 5
+ return 5
+}
+
+f1 &
+wait
+echo $?
+
+unset -f f1
+
+f1()
+{
+ echo $AVAR
+ printenv AVAR
+}
+
+AVAR=AVAR
+echo $AVAR
+f1
+AVAR=foo f1
+echo $AVAR
+
+unset -f f1
+# make sure subshells can do a `return' if we're executing in a function
+f1()
+{
+ ( return 5 )
+ status=$?
+ echo $status
+ return $status
+}
+
+f1
+echo $?
+
+declare -F f1 # should print just the name
+declare -f f1 # should print the definition, too
+
+# no functions should be exported, right?
+declare -xF
+declare -xf
+
+# FUNCNAME tests
+func2()
+{
+ echo FUNCNAME = $FUNCNAME
+}
+
+func()
+{
+ echo before: FUNCNAME = $FUNCNAME
+ func2
+ echo after: FUNCNAME = $FUNCNAME
+}
+
+echo before: try to assign to FUNCNAME
+FUCNAME=7
+
+echo outside: FUNCNAME = $FUNCNAME
+func
+echo outside2: FUNCNAME = $FUNCNAME
+
+# test exported functions (and cached exportstr)
+zf()
+{
+ echo this is zf
+}
+export -f zf
+
+${THIS_SH} -c 'type -t zf'
+${THIS_SH} -c 'type zf'
+
+${THIS_SH} ./func1.sub
+
+# tests for functions whose bodies are not group commands, with and without
+# attached redirections
+${THIS_SH} ./func2.sub
+
+# test for some posix-specific function behavior
+${THIS_SH} ./func3.sub
+
+unset -f myfunction
+myfunction() {
+ echo "bad shell function redirection"
+} >> /dev/null
+
+myfunction
+myfunction | cat
+
+exit 0