aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-02-20 16:37:59 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-02-20 16:37:59 +0100
commitbb095f483827567452ee3501779a84f36719288d (patch)
tree26e844ece54913569de12bc0ae76cc77ffcfdf77 /shell
parentd5bfe26c457a97a8b525b6c27f5498525a5829bf (diff)
downloadbusybox-w32-bb095f483827567452ee3501779a84f36719288d.tar.gz
busybox-w32-bb095f483827567452ee3501779a84f36719288d.tar.bz2
busybox-w32-bb095f483827567452ee3501779a84f36719288d.zip
hush: implement "return NUM in trap sets $? after trap"
function old new delta builtin_return 47 67 +20 check_and_run_traps 243 259 +16 run_pipe 1583 1597 +14 hush_main 1076 1086 +10 run_list 1054 1055 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/0 up/down: 61/0) Total: 61 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/ash_test/ash-misc/exitcode_trap3.right2
-rwxr-xr-xshell/ash_test/ash-misc/exitcode_trap3.tests9
-rw-r--r--shell/ash_test/ash-misc/exitcode_trap4.right2
-rwxr-xr-xshell/ash_test/ash-misc/exitcode_trap4.tests8
-rw-r--r--shell/ash_test/ash-misc/exitcode_trap5.right3
-rwxr-xr-xshell/ash_test/ash-misc/exitcode_trap5.tests10
-rw-r--r--shell/hush.c31
-rw-r--r--shell/hush_test/hush-misc/exitcode_trap3.right2
-rwxr-xr-xshell/hush_test/hush-misc/exitcode_trap3.tests9
-rw-r--r--shell/hush_test/hush-misc/exitcode_trap4.right2
-rwxr-xr-xshell/hush_test/hush-misc/exitcode_trap4.tests8
-rw-r--r--shell/hush_test/hush-misc/exitcode_trap5.right3
-rwxr-xr-xshell/hush_test/hush-misc/exitcode_trap5.tests10
13 files changed, 98 insertions, 1 deletions
diff --git a/shell/ash_test/ash-misc/exitcode_trap3.right b/shell/ash_test/ash-misc/exitcode_trap3.right
new file mode 100644
index 000000000..f275cdc45
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap3.right
@@ -0,0 +1,2 @@
1TERM
242:42
diff --git a/shell/ash_test/ash-misc/exitcode_trap3.tests b/shell/ash_test/ash-misc/exitcode_trap3.tests
new file mode 100755
index 000000000..98745e463
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap3.tests
@@ -0,0 +1,9 @@
1# "return" in trap should not use last command's exitcode,
2# but exitcode on entering the trap.
3trap "echo TERM;return" term
4f() {
5 (sleep 1; kill $$) &
6 until (exit 42) do (exit 42); done
7}
8f
9echo 42:$?
diff --git a/shell/ash_test/ash-misc/exitcode_trap4.right b/shell/ash_test/ash-misc/exitcode_trap4.right
new file mode 100644
index 000000000..ed6989593
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap4.right
@@ -0,0 +1,2 @@
1TERM
211:11
diff --git a/shell/ash_test/ash-misc/exitcode_trap4.tests b/shell/ash_test/ash-misc/exitcode_trap4.tests
new file mode 100755
index 000000000..36dba90bd
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap4.tests
@@ -0,0 +1,8 @@
1# "return" in trap sets $? after trap
2trap "echo TERM;return 11" term
3f() {
4 (sleep 1; kill $$) &
5 until (exit 42) do (exit 42); done
6}
7f
8echo 11:$?
diff --git a/shell/ash_test/ash-misc/exitcode_trap5.right b/shell/ash_test/ash-misc/exitcode_trap5.right
new file mode 100644
index 000000000..1ad4443b4
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap5.right
@@ -0,0 +1,3 @@
1TERM
2Nested
3Zero:0
diff --git a/shell/ash_test/ash-misc/exitcode_trap5.tests b/shell/ash_test/ash-misc/exitcode_trap5.tests
new file mode 100755
index 000000000..332a06463
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap5.tests
@@ -0,0 +1,10 @@
1# "return" in trap sets $? after trap...
2# ...but not a nested one!
3g() { echo Nested; return 22; }
4trap "echo TERM;false;g" term
5f() {
6 (kill $$) &
7 sleep 1
8}
9f
10echo Zero:$?
diff --git a/shell/hush.c b/shell/hush.c
index bced388bf..6172f2285 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -988,6 +988,9 @@ struct globals {
988# define G_fatal_sig_mask 0 988# define G_fatal_sig_mask 0
989#endif 989#endif
990#if ENABLE_HUSH_TRAP 990#if ENABLE_HUSH_TRAP
991# if ENABLE_HUSH_FUNCTIONS
992 int return_exitcode;
993# endif
991 char **traps; /* char *traps[NSIG] */ 994 char **traps; /* char *traps[NSIG] */
992# define G_traps G.traps 995# define G_traps G.traps
993#else 996#else
@@ -2097,6 +2100,7 @@ static int check_and_run_traps(void)
2097 } while (sig < NSIG); 2100 } while (sig < NSIG);
2098 break; 2101 break;
2099 got_sig: 2102 got_sig:
2103#if ENABLE_HUSH_TRAP
2100 if (G_traps && G_traps[sig]) { 2104 if (G_traps && G_traps[sig]) {
2101 debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]); 2105 debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]);
2102 if (G_traps[sig][0]) { 2106 if (G_traps[sig][0]) {
@@ -2110,12 +2114,18 @@ static int check_and_run_traps(void)
2110 save_rcode = G.last_exitcode; 2114 save_rcode = G.last_exitcode;
2111 builtin_eval(argv); 2115 builtin_eval(argv);
2112 free(argv[1]); 2116 free(argv[1]);
2113//FIXME: shouldn't it be set to 128 + sig instead?
2114 G.last_exitcode = save_rcode; 2117 G.last_exitcode = save_rcode;
2118# if ENABLE_HUSH_FUNCTIONS
2119 if (G.return_exitcode >= 0) {
2120 debug_printf_exec("trap exitcode:%d\n", G.return_exitcode);
2121 G.last_exitcode = G.return_exitcode;
2122 }
2123# endif
2115 last_sig = sig; 2124 last_sig = sig;
2116 } /* else: "" trap, ignoring signal */ 2125 } /* else: "" trap, ignoring signal */
2117 continue; 2126 continue;
2118 } 2127 }
2128#endif
2119 /* not a trap: special action */ 2129 /* not a trap: special action */
2120 switch (sig) { 2130 switch (sig) {
2121 case SIGINT: 2131 case SIGINT:
@@ -8127,6 +8137,10 @@ static int run_function(const struct function *funcp, char **argv)
8127 IF_HUSH_LOCAL(leave_var_nest_level();) 8137 IF_HUSH_LOCAL(leave_var_nest_level();)
8128 8138
8129 G_flag_return_in_progress = sv_flg; 8139 G_flag_return_in_progress = sv_flg;
8140# if ENABLE_HUSH_TRAP
8141 debug_printf_exec("G.return_exitcode=-1\n");
8142 G.return_exitcode = -1; /* invalidate stashed return value */
8143# endif
8130 8144
8131 restore_G_args(&sv, argv); 8145 restore_G_args(&sv, argv);
8132 8146
@@ -9628,6 +9642,9 @@ static int run_list(struct pipe *pi)
9628 debug_printf_exec(": builtin/func exitcode %d\n", rcode); 9642 debug_printf_exec(": builtin/func exitcode %d\n", rcode);
9629 G.last_exitcode = rcode; 9643 G.last_exitcode = rcode;
9630 check_and_run_traps(); 9644 check_and_run_traps();
9645#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
9646 rcode = G.last_exitcode; /* "return" in trap can change it, read back */
9647#endif
9631#if ENABLE_HUSH_LOOPS 9648#if ENABLE_HUSH_LOOPS
9632 /* Was it "break" or "continue"? */ 9649 /* Was it "break" or "continue"? */
9633 if (G.flag_break_continue) { 9650 if (G.flag_break_continue) {
@@ -9684,6 +9701,9 @@ static int run_list(struct pipe *pi)
9684 check_traps: 9701 check_traps:
9685 G.last_exitcode = rcode; 9702 G.last_exitcode = rcode;
9686 check_and_run_traps(); 9703 check_and_run_traps();
9704#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
9705 rcode = G.last_exitcode; /* "return" in trap can change it, read back */
9706#endif
9687 } 9707 }
9688 9708
9689 /* Handle "set -e" */ 9709 /* Handle "set -e" */
@@ -9907,6 +9927,9 @@ int hush_main(int argc, char **argv)
9907 INIT_G(); 9927 INIT_G();
9908 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ 9928 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
9909 G.last_exitcode = EXIT_SUCCESS; 9929 G.last_exitcode = EXIT_SUCCESS;
9930#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
9931 G.return_exitcode = -1;
9932#endif
9910 9933
9911#if ENABLE_HUSH_FAST 9934#if ENABLE_HUSH_FAST
9912 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 9935 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
@@ -11745,6 +11768,12 @@ static int FAST_FUNC builtin_return(char **argv)
11745 * 255 <== we also do this 11768 * 255 <== we also do this
11746 */ 11769 */
11747 rc = parse_numeric_argv1(argv, G.last_exitcode, 0); 11770 rc = parse_numeric_argv1(argv, G.last_exitcode, 0);
11771# if ENABLE_HUSH_TRAP
11772 if (argv[1]) { /* "return ARG" inside a running trap sets $? */
11773 debug_printf_exec("G.return_exitcode=%d\n", rc);
11774 G.return_exitcode = rc;
11775 }
11776# endif
11748 return rc; 11777 return rc;
11749} 11778}
11750#endif 11779#endif
diff --git a/shell/hush_test/hush-misc/exitcode_trap3.right b/shell/hush_test/hush-misc/exitcode_trap3.right
new file mode 100644
index 000000000..f275cdc45
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap3.right
@@ -0,0 +1,2 @@
1TERM
242:42
diff --git a/shell/hush_test/hush-misc/exitcode_trap3.tests b/shell/hush_test/hush-misc/exitcode_trap3.tests
new file mode 100755
index 000000000..98745e463
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap3.tests
@@ -0,0 +1,9 @@
1# "return" in trap should not use last command's exitcode,
2# but exitcode on entering the trap.
3trap "echo TERM;return" term
4f() {
5 (sleep 1; kill $$) &
6 until (exit 42) do (exit 42); done
7}
8f
9echo 42:$?
diff --git a/shell/hush_test/hush-misc/exitcode_trap4.right b/shell/hush_test/hush-misc/exitcode_trap4.right
new file mode 100644
index 000000000..ed6989593
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap4.right
@@ -0,0 +1,2 @@
1TERM
211:11
diff --git a/shell/hush_test/hush-misc/exitcode_trap4.tests b/shell/hush_test/hush-misc/exitcode_trap4.tests
new file mode 100755
index 000000000..36dba90bd
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap4.tests
@@ -0,0 +1,8 @@
1# "return" in trap sets $? after trap
2trap "echo TERM;return 11" term
3f() {
4 (sleep 1; kill $$) &
5 until (exit 42) do (exit 42); done
6}
7f
8echo 11:$?
diff --git a/shell/hush_test/hush-misc/exitcode_trap5.right b/shell/hush_test/hush-misc/exitcode_trap5.right
new file mode 100644
index 000000000..1ad4443b4
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap5.right
@@ -0,0 +1,3 @@
1TERM
2Nested
3Zero:0
diff --git a/shell/hush_test/hush-misc/exitcode_trap5.tests b/shell/hush_test/hush-misc/exitcode_trap5.tests
new file mode 100755
index 000000000..332a06463
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap5.tests
@@ -0,0 +1,10 @@
1# "return" in trap sets $? after trap...
2# ...but not a nested one!
3g() { echo Nested; return 22; }
4trap "echo TERM;false;g" term
5f() {
6 (kill $$) &
7 sleep 1
8}
9f
10echo Zero:$?