Re: [PATCH v2] ash: fix wait -n behavior for multiple PIDs and pipe jobs

"Roberto A. Foglietta via busybox" <[email protected]> Wed, 1 Apr 2026 13:23:19 +0200
Newsgroups gmane.linux.busybox
Message-ID <CAJGKYO6uwjc0M-ZmKnUC=GaTdFvMzca+40zf5o_55ZnZPks13g@mail.gmail.com>
On Wed, 1 Apr 2026 at 02:18, Roberto A. Foglietta
<[email protected]> wrote:
>
> On Wed, 1 Apr 2026 at 01:29, Luiz Angelo Daros de Luca
> <[email protected]> wrote:
> >
> > > Please, create a patch file (otherwise space and tab can mixup) on the
> > > top of the HEAD of this branch:
> > >
> > > - https://github.com/robang74/busybox/tree/bugfixes
> > >
> > > and I am going to transfer your patch to that branch as well.
> > > Contributions of others before your patch (especially when already
> > > tested) are not going to be removed but integrated unless your patch
> > > provides sensitive benefits like a relevant size reduction or
> > > complexity.
> > >
> > > Best regards, R-
> >
> > Hi Roberto,
> >
> > At this moment, my main goal is to have this patch reviewed and merged
> > directly into the official BusyBox upstream. Since the patch was
> > developed and tested against the official master branch, I would
> > prefer to keep the focus there for now.
>
> https://github.com/robang74/busybox/tree/ashfix2
>

Two patches can be interesting for the m-list: the first is a size
reduction, the second seems to be a necessary bug fixing.

https://github.com/robang74/busybox/tree/bugfixes

Best regards, R-

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
0001-robang74-bugfixes-addons-patches.patch (text/x-patch, 3.1 KB)
commit 779a9b7d0bd72bdacb3bfe2d57008cf606449169
Author: Roberto A. Foglietta <[email protected]>
Date:   Wed Apr 1 11:04:42 2026 +0200

    ash: waitcmd() more readeability and smaller size, same tests results
    
       text    data     bss     dec     hex filename
    1105644   16915    1856 1124415  11283f busybox
    1105619   16915    1856 1124390  112826 busybox (-25 bytes)
    
    for i in shell/ash_test/ash-misc/wait*.tests ; do ./busybox ash $i; done
    
    Wait 1 returned: 42. (expects 42)
    p1 active: 1 (expects 0)
    p2 active: 1 (expects 1)
    Wait 2 returned: 41 (expects 41)
    Wait 3 returned: 41 (expects 41)
    Wait 4 returned: 127 (expects 127)
    Wait 5 returned: 42 (expects 42)
    Wait 6 returned: 42 (expects 42)
    Wait 7 returned: 42 (expects 42)
    Wait 8 returned: 42 (expects 42)
    Wait 9 returned: 42 (expects 42)
    Wait 10 returned: 42 (expects 42)
    Wait 11 returned: 127 (expects 127)
    Wait 12 returned: 42 (expects 42)
    p7 active: 0 (expects 0)
    Wait 13 returned: 127 (expects 127)
    P1 done
    P2 done
    Wait returned: 0
    First wait -n returned: 42 (expects 42)
    Second wait -n returned: 43 (expects 41)
    Third wait -n returned: 43 (expects 43)
    Three:3
    Zero:0
    Three:3
    0
    3
    Background1
    Ok:0
    Test1 (wait with zero exit status of bg process)
    Test2 (wait with non-zero exit status of bg process)
    Test3 (pipeline wait for whole job)
    Ok:0
    Test4 (wait exit code with signal)
    Test5 (wait -n exits 127 if nothing to wait for)
    wait -n
    from USR1
    prints after USR1
    wait
    from USR1
    prints after USR1 (2)
    
    Signed-off-by: Roberto A. Foglietta <[email protected]>

diff --git a/shell/ash.c b/shell/ash.c
index 99cd9d984..1e8d5657c 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4282,6 +4282,9 @@ sprint_status48(char *os, int status, int sigonly)
 	return s - os;
 }
 
+#define joblstidx(p) ((p)->nprocs - 1)
+#define joblstjob(p) ({ struct job *_p=(p); _p->ps[joblstidx(_p)]; })
+
 /* Called only on finished or stopped jobs (no members are running) */
 static int
 getstatus(struct job *job)
@@ -4291,7 +4294,7 @@ getstatus(struct job *job)
 	struct procstat *ps;
 
 	/* Fetch last member's status */
-	ps = job->ps + job->nprocs - 1;
+	ps = job->ps + joblstidx(job);
 	status = ps->ps_status;
 	if (pipefail) {
 		/* "set -o pipefail" mode: use last _nonzero_ status */
@@ -4867,11 +4870,8 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
 				 */
 oneout:
 				jp->waited = 1;
-				status = jp->ps[jp->nprocs - 1].ps_status;
-				if (status != -1 && !WIFSTOPPED(status)) {
-					retval = WEXITSTATUS(status);
-					if (WIFSIGNALED(status))
-						retval = 128 | WTERMSIG(status);
+				if (!WIFSTOPPED(joblstjob(jp).ps_status)) {
+					retval = getstatus(jp);
 					goto ret;
 				}
 			}
@@ -4887,7 +4887,7 @@ oneout:
 			while (1) {
 				if (!job)
 					goto repeat;
-				if (job->ps[job->nprocs - 1].ps_pid == pid)
+				if (joblstjob(job).ps_pid == pid)
 					break;
 				job = job->prev_job;
 			}
________________________________________________________________________
files in commited:
	shell/ash.c
0002-robang74-bugfixes-addons-patches.patch (text/x-patch, 856 B)
commit 980d370456f115332efe132315448d539ade7340
Author: Roberto A. Foglietta <[email protected]>
Date:   Wed Apr 1 13:16:24 2026 +0200

    ash: prevents waitone() returns after INTOFF before INTON
    
    Requires thisjob = NULL (ok) set explicetely or INTON; return NULL;
    
    Signed-off-by: Roberto A. Foglietta <[email protected]>

diff --git a/shell/ash.c b/shell/ash.c
index 1e8d5657c..9c6a00614 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4403,7 +4403,7 @@ static struct job *waitone(int block, struct job *job)
 	pid = waitproc(block, &status);
 	TRACE(("wait returns pid %d, status=%d\n", pid, status));
 	if (pid <= 0)
-		return NULL;
+		goto out;
 
 	for (jp = curjob; jp; jp = jp->prev_job) {
 		int jobstate;
________________________________________________________________________
files in commited:
	shell/ash.c