diff -ur bash-3.1-orig/builtins/set.def bash-3.1/builtins/set.def --- bash-3.1-orig/builtins/set.def 2004-12-19 17:20:25.000000000 +0000 +++ bash-3.1/builtins/set.def 2007-04-18 13:38:36.000000000 +0100 @@ -97,6 +97,8 @@ noglob same as -f nolog currently accepted but ignored notify same as -b + notify-sensibly + cause async notifications to behave more sensibly nounset same as -u onecmd same as -t physical same as -P @@ -203,6 +205,7 @@ #endif #if defined (JOB_CONTROL) { "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, + { "notify-sensibly", '\0', &asynchronous_sensibly, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, #endif /* JOB_CONTROL */ { "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, diff -ur bash-3.1-orig/flags.c bash-3.1/flags.c --- bash-3.1-orig/flags.c 2004-07-17 02:19:42.000000000 +0100 +++ bash-3.1/flags.c 2007-04-18 13:38:36.000000000 +0100 @@ -133,6 +133,9 @@ /* Non-zero means that we allow comments to appear in interactive commands. */ int interactive_comments = 1; +/* Non-zero enables sensible asynchronous job notification. */ +int asynchronous_sensibly = 0; + #if defined (RESTRICTED_SHELL) /* Non-zero means that this shell is `restricted'. A restricted shell disallows: changing directories, command or path names containing `/', diff -ur bash-3.1-orig/flags.h bash-3.1/flags.h --- bash-3.1-orig/flags.h 2003-09-12 22:27:26.000000000 +0100 +++ bash-3.1/flags.h 2007-04-18 13:38:58.000000000 +0100 @@ -47,7 +47,7 @@ echo_command_at_execute, no_invisible_vars, noclobber, hashing_enabled, forced_interactive, privileged_mode, asynchronous_notification, interactive_comments, no_symbolic_links, - function_trace_mode, error_trace_mode, pipefail_opt; + asynchronous_sensibly, function_trace_mode, error_trace_mode, pipefail_opt; #if 0 extern int lexical_scoping; diff -ur bash-3.1-orig/jobs.c bash-3.1/jobs.c --- bash-3.1-orig/jobs.c 2005-11-12 04:13:27.000000000 +0000 +++ bash-3.1/jobs.c 2007-04-18 13:38:36.000000000 +0100 @@ -2817,6 +2817,8 @@ return (result); } +int sigchld_pipe[2] = {-1, -1}; + /* sigchld_handler () flushes at least one of the children that we are waiting for. It gets run when we have gotten a SIGCHLD signal. */ static sighandler @@ -2952,7 +2954,14 @@ that this process belongs to is no longer running, then notify the user of that fact now. */ if (asynchronous_notification && interactive) - notify_of_job_status (); + { + char buf[1]; + buf[0] = 'x'; + if (!asynchronous_sensibly || + sigchld_pipe[1] == -1 || + write(sigchld_pipe[1], buf, 1) != 1) + notify_of_job_status (); + } return (children_exited); } @@ -3441,6 +3450,18 @@ if (shell_tty != fileno (stderr)) SET_CLOSE_ON_EXEC (shell_tty); + if (pipe(sigchld_pipe) < 0) { + sigchld_pipe[0] = sigchld_pipe[1] = -1; + } else { + dup2(sigchld_pipe[0], 254); + close(sigchld_pipe[0]); + sigchld_pipe[0] = 254; + dup2(sigchld_pipe[1], 253); + close(sigchld_pipe[1]); + sigchld_pipe[1] = 253; + fcntl(sigchld_pipe[0], F_SETFD, FD_CLOEXEC); + fcntl(sigchld_pipe[1], F_SETFD, FD_CLOEXEC); + } set_signal_handler (SIGCHLD, sigchld_handler); change_flag ('m', job_control ? '-' : '+'); diff -ur bash-3.1-orig/parse.y bash-3.1/parse.y --- bash-3.1-orig/parse.y 2005-11-12 04:14:18.000000000 +0000 +++ bash-3.1/parse.y 2007-04-18 13:39:37.000000000 +0100 @@ -35,6 +35,7 @@ #endif #include +#include #include "chartypes.h" #include @@ -1189,8 +1190,118 @@ char *current_readline_line = (char *)NULL; int current_readline_line_index = 0; +static char *my_readline_return_str; +static int my_readline_done; + +extern int sigchld_pipe[2]; + +static void + my_readline_callback(char *string) +{ + my_readline_return_str = string; + my_readline_done = 1; + rl_callback_handler_remove(); +} + +static void + clean_sigchld_pipe(void) +{ + if (sigchld_pipe[0] >= 0) + { + while (1) + { + fd_set rset; + int ret; + struct timeval tv; + + FD_ZERO(&rset); + FD_SET(sigchld_pipe[0], &rset); + + tv.tv_sec = tv.tv_usec = 0; + + ret = select(sigchld_pipe[0] + 1, &rset, NULL, NULL, &tv); + + if (ret > 0 && FD_ISSET(sigchld_pipe[0], &rset)) + { + char buf[1]; + read(sigchld_pipe[0], buf, 1); + } + else + { + break; + } + } + } +} + +static char * + my_readline(char *prompt) +{ + my_readline_return_str = NULL; + my_readline_done = 0; + rl_callback_handler_remove(); + rl_callback_handler_install(prompt, my_readline_callback); + while (1) + { + fd_set rset; + int ret; + int max; + + FD_ZERO(&rset); + FD_SET(0, &rset); + max = 1; + + if (sigchld_pipe[0] >= 0) + { + FD_SET(sigchld_pipe[0], &rset); + if (max < sigchld_pipe[0] + 1) + max = sigchld_pipe[0] + 1; + } + + ret = select(max, &rset, NULL, NULL, NULL); + + if (ret < 0) + { + if (errno == EINTR) + continue; + perror("bash: select"); + exit(1); + } + + if (sigchld_pipe[0] >= 0 && FD_ISSET(sigchld_pipe[0], &rset)) + { + clean_sigchld_pipe(); + + rl_crlf (); + +#if defined (JOB_CONTROL) + /* This can cause a problem when reading a command as the result + of a trap, when the trap is called from flush_child. This call + had better not cause jobs to disappear from the job table in + that case, or we will have big trouble. */ + notify_and_cleanup (); +#else /* !JOB_CONTROL */ + cleanup_dead_jobs (); +#endif /* !JOB_CONTROL */ + + putc ('\r', rl_outstream); + fflush (rl_outstream); + rl_on_new_line (); + rl_redisplay (); + } + + if (FD_ISSET(0, &rset)) + { + rl_callback_read_char(); + if (my_readline_done) + break; + } + } + return my_readline_return_str; +} + static int -yy_readline_get () + yy_readline_get () { SigHandler *old_sigint; int line_len; @@ -1213,7 +1324,7 @@ interrupt_immediately++; } - current_readline_line = readline (current_readline_prompt ? + current_readline_line = my_readline (current_readline_prompt ? current_readline_prompt : ""); if (signal_is_ignored (SIGINT) == 0 && old_sigint) @@ -1907,6 +2018,10 @@ i = 0; shell_input_line_terminator = 0; +#if defined (READLINE) + clean_sigchld_pipe(); +#endif + /* If the shell is interatctive, but not currently printing a prompt (interactive_shell && interactive == 0), we don't want to print notifies or cleanup the jobs -- we want to defer it until we do