From e6f51ac6975963e538a28fe2060dd4511143449b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 27 Mar 2019 18:34:10 +0100 Subject: [PATCH] hush: fix "wait -n" to wait for a _job_, not a _process_ function old new delta checkjobs 163 183 +20 process_wait_result 449 463 +14 leave_var_nest_level 98 107 +9 enter_var_nest_level 32 38 +6 set_vars_and_save_old 147 150 +3 builtin_local 53 56 +3 builtin_wait 322 323 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 7/0 up/down: 56/0) Total: 56 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 7c907686e..fa9afa38e 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -923,7 +923,7 @@ struct globals { # define G_flag_return_in_progress 0 #endif smallint exiting; /* used to prevent EXIT trap recursion */ - /* These support $?, $#, and $1 */ + /* These support $? */ smalluint last_exitcode; smalluint expand_exitcode; smalluint last_bg_pid_exitcode; @@ -933,6 +933,9 @@ struct globals { # define G_global_args_malloced (G.global_args_malloced) #else # define G_global_args_malloced 0 +#endif +#if ENABLE_HUSH_BASH_COMPAT + int dead_job_exitcode; /* for "wait -n" */ #endif /* how many non-NULL argv's we have. NB: $# + 1 */ int global_argc; @@ -8657,6 +8660,9 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) pi->cmds[i].pid = 0; pi->alive_cmds--; if (!pi->alive_cmds) { +#if ENABLE_HUSH_BASH_COMPAT + G.dead_job_exitcode = job_exited_or_stopped(pi); +#endif if (G_interactive_fd) { printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->cmdtext); @@ -8763,11 +8769,7 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid) /* fg_pipe exited or stopped */ break; } - if (childpid == waitfor_pid /* "wait PID" */ -#if ENABLE_HUSH_BASH_COMPAT - || -1 == waitfor_pid /* "wait -n" (wait for any one child) */ -#endif - ) { + if (childpid == waitfor_pid) { /* "wait PID" */ debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status); rcode = WEXITSTATUS(status); if (WIFSIGNALED(status)) @@ -8778,6 +8780,15 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid) rcode++; break; /* "wait PID" called us, give it exitcode+1 */ } +#if ENABLE_HUSH_BASH_COMPAT + if (-1 == waitfor_pid /* "wait -n" (wait for any one job) */ + && G.dead_job_exitcode >= 0 /* some job did finish */ + ) { + debug_printf_exec("waitfor_pid:-1\n"); + rcode = G.dead_job_exitcode + 1; + break; + } +#endif /* This wasn't one of our processes, or */ /* fg_pipe still has running processes, do waitpid again */ } /* while (waitpid succeeds)... */ @@ -11510,9 +11521,11 @@ static int FAST_FUNC builtin_wait(char **argv) argv = skip_dash_dash(argv); #if ENABLE_HUSH_BASH_COMPAT - if (argv[0] && !argv[1] && strcmp(argv[0], "-n") == 0) { + if (argv[0] && strcmp(argv[0], "-n") == 0) { /* wait -n */ - return wait_for_child_or_signal(NULL, -1 /*(no job, wait for one child)*/); + /* (bash accepts "wait -n PID" too and ignores PID) */ + G.dead_job_exitcode = -1; + return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/); } #endif if (argv[0] == NULL) { @@ -11532,7 +11545,7 @@ static int FAST_FUNC builtin_wait(char **argv) * ^C <-- after ~4 sec from keyboard * $ */ - return wait_for_child_or_signal(NULL, 0 /*(no job and no pid to wait for)*/); + return wait_for_child_or_signal(NULL, 0 /*no job and no pid to wait for*/); } do {