[PATCH] ash: improve trap and jobs builtins in child shells

Ron Yorston rmy at pobox.com
Thu Mar 30 10:05:04 UTC 2023


The trap and jobs builtins can be used to report information about
traps and jobs.  This works when they're called from the current
shell but in a child shell the required information is usually
cleared.  Special hacks allow:

- trap to work with command substitution;
- jobs to work with command substitution or in a pipeline.

Neither works with process substitution.

- Relax the test for the trap hack so it also supports pipelines.

- Pass the command to be evaluated to forkshell() in evalbackcmd()
  so trap and jobs both work with process substitution.

function                                             old     new   delta
forkchild                                            629     640     +11
argstr                                              1502    1496      -6
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 11/-6)               Total: 5 bytes

Signed-off-by: Ron Yorston <rmy at pobox.com>
---
 shell/ash.c                            | 13 +++++++------
 shell/ash_test/ash-signals/usage.right | 12 ++++++++++++
 shell/ash_test/ash-signals/usage.tests | 12 ++++++++++++
 3 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 559566b58..40b921be1 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5190,8 +5190,7 @@ forkchild(struct job *jp, union node *n, int mode)
 
 	closescript();
 
-	if (mode == FORK_NOJOB          /* is it `xxx` ? */
-	 && n && n->type == NCMD        /* is it single cmd? */
+	if (n && n->type == NCMD        /* is it single cmd? */
 	/* && n->ncmd.args->type == NARG - always true? */
 	 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
 	 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
@@ -5285,10 +5284,12 @@ forkchild(struct job *jp, union node *n, int mode)
 	) {
 		TRACE(("Job hack\n"));
 		/* "jobs": we do not want to clear job list for it,
-		 * instead we remove only _its_ own_ job from job list.
+		 * instead we remove only _its_ own_ job from job list
+		 * (if it has one).
 		 * This makes "jobs .... | cat" more useful.
 		 */
-		freejob(curjob);
+		if (jp)
+			freejob(curjob);
 		return;
 	}
 #endif
@@ -6607,9 +6608,9 @@ evalbackcmd(union node *n, struct backcmd *result
 
 	if (pipe(pip) < 0)
 		ash_msg_and_raise_perror("can't create pipe");
-	/* process substitution uses NULL job/node, like openhere() */
+	/* process substitution uses NULL job, like openhere() */
 	jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
-	if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) {
+	if (forkshell(jp, n, FORK_NOJOB) == 0) {
 		/* child */
 		FORCE_INT_ON;
 		close(pip[ip]);
diff --git a/shell/ash_test/ash-signals/usage.right b/shell/ash_test/ash-signals/usage.right
index c0dbd6c3c..df1ed2dd7 100644
--- a/shell/ash_test/ash-signals/usage.right
+++ b/shell/ash_test/ash-signals/usage.right
@@ -6,6 +6,18 @@ trap -- 'a' INT
 trap -- 'a' USR1
 trap -- 'a' USR2
 ___
+trap -- 'a' EXIT trap -- 'a' INT trap -- 'a' USR1 trap -- 'a' USR2
+___
+trap -- 'a' EXIT
+trap -- 'a' INT
+trap -- 'a' USR1
+trap -- 'a' USR2
+___
+trap -- 'a' EXIT
+trap -- 'a' INT
+trap -- 'a' USR1
+trap -- 'a' USR2
+___
 ___
 trap -- 'a' USR1
 trap -- 'a' USR2
diff --git a/shell/ash_test/ash-signals/usage.tests b/shell/ash_test/ash-signals/usage.tests
index d29c6e74a..34e24cceb 100755
--- a/shell/ash_test/ash-signals/usage.tests
+++ b/shell/ash_test/ash-signals/usage.tests
@@ -10,6 +10,18 @@ trap "a" EXIT INT USR1 USR2
 echo ___
 trap
 
+# show them by command substitution
+echo ___
+echo $(trap)
+
+# show them by pipe
+echo ___
+trap | cat
+
+# show them by process substitution
+echo ___
+cat <(trap)
+
 # clear one
 echo ___
 trap 0 INT
-- 
2.39.2



More information about the busybox mailing list