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 <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2019-03-27 18:34:10 +01:00
parent 966f087ab4
commit e6f51ac697

View File

@ -923,7 +923,7 @@ struct globals {
# define G_flag_return_in_progress 0 # define G_flag_return_in_progress 0
#endif #endif
smallint exiting; /* used to prevent EXIT trap recursion */ smallint exiting; /* used to prevent EXIT trap recursion */
/* These support $?, $#, and $1 */ /* These support $? */
smalluint last_exitcode; smalluint last_exitcode;
smalluint expand_exitcode; smalluint expand_exitcode;
smalluint last_bg_pid_exitcode; smalluint last_bg_pid_exitcode;
@ -933,6 +933,9 @@ struct globals {
# define G_global_args_malloced (G.global_args_malloced) # define G_global_args_malloced (G.global_args_malloced)
#else #else
# define G_global_args_malloced 0 # define G_global_args_malloced 0
#endif
#if ENABLE_HUSH_BASH_COMPAT
int dead_job_exitcode; /* for "wait -n" */
#endif #endif
/* how many non-NULL argv's we have. NB: $# + 1 */ /* how many non-NULL argv's we have. NB: $# + 1 */
int global_argc; 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->cmds[i].pid = 0;
pi->alive_cmds--; pi->alive_cmds--;
if (!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) { if (G_interactive_fd) {
printf(JOB_STATUS_FORMAT, pi->jobid, printf(JOB_STATUS_FORMAT, pi->jobid,
"Done", pi->cmdtext); "Done", pi->cmdtext);
@ -8763,11 +8769,7 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid)
/* fg_pipe exited or stopped */ /* fg_pipe exited or stopped */
break; break;
} }
if (childpid == waitfor_pid /* "wait PID" */ if (childpid == waitfor_pid) { /* "wait PID" */
#if ENABLE_HUSH_BASH_COMPAT
|| -1 == waitfor_pid /* "wait -n" (wait for any one child) */
#endif
) {
debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status); debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status);
rcode = WEXITSTATUS(status); rcode = WEXITSTATUS(status);
if (WIFSIGNALED(status)) if (WIFSIGNALED(status))
@ -8778,6 +8780,15 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid)
rcode++; rcode++;
break; /* "wait PID" called us, give it exitcode+1 */ 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 */ /* This wasn't one of our processes, or */
/* fg_pipe still has running processes, do waitpid again */ /* fg_pipe still has running processes, do waitpid again */
} /* while (waitpid succeeds)... */ } /* while (waitpid succeeds)... */
@ -11510,9 +11521,11 @@ static int FAST_FUNC builtin_wait(char **argv)
argv = skip_dash_dash(argv); argv = skip_dash_dash(argv);
#if ENABLE_HUSH_BASH_COMPAT #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 */ /* 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 #endif
if (argv[0] == NULL) { if (argv[0] == NULL) {
@ -11532,7 +11545,7 @@ static int FAST_FUNC builtin_wait(char **argv)
* ^C <-- after ~4 sec from keyboard * ^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 { do {