[git commit] hush: fix "wait -n" to wait for a _job_, not a _process_

Denys Vlasenko vda.linux at googlemail.com
Wed Mar 27 17:35:19 UTC 2019


commit: https://git.busybox.net/busybox/commit/?id=e6f51ac6975963e538a28fe2060dd4511143449b
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 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 {


More information about the busybox-cvs mailing list