From ebdfd6dc4d46b815edfc9ecd968c033babfe87eb Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Sun, 16 Jan 2011 13:56:41 +0000 Subject: [PATCH] sh: If exit is used without args from a trap action, exit on the signal. This is useful so that it is easier to exit on a signal than to reset the trap to default and resend the signal. It matches ksh93. POSIX says that 'exit' without args from a trap action uses the exit status from the last command before the trap, which is different from 'exit $?' and matches this if the previous command is assumed to have exited on the signal. If the signal is SIGSTOP, SIGTSTP, SIGTTIN or SIGTTOU, or if the default action for the signal is to ignore it, a normal _exit(2) is done with exit status 128+signal_number. --- bin/sh/trap.c | 25 +++++++++++++++++++++--- tools/regression/bin/sh/builtins/trap6.0 | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 tools/regression/bin/sh/builtins/trap6.0 diff --git a/bin/sh/trap.c b/bin/sh/trap.c index d2e53086b102..048c75cdc19a 100644 --- a/bin/sh/trap.c +++ b/bin/sh/trap.c @@ -79,6 +79,7 @@ static volatile sig_atomic_t gotsig[NSIG]; /* indicates specified signal received */ static int ignore_sigchld; /* Used while handling SIGCHLD traps. */ volatile sig_atomic_t gotwinch; +static int last_trapsig; static int exiting; /* exitshell() has been called */ static int exiting_exitstatus; /* value passed to exitshell() */ @@ -441,6 +442,7 @@ dotrap(void) */ if (i == SIGCHLD) ignore_sigchld++; + last_trapsig = i; savestatus = exitstatus; evalstring(trap[i], 0); exitstatus = savestatus; @@ -495,9 +497,16 @@ exitshell_savedstatus(void) { struct jmploc loc1, loc2; char *p; + int sig = 0; + sigset_t sigs; - if (!exiting) - exiting_exitstatus = oexitstatus; + if (!exiting) { + if (in_dotrap && last_trapsig) { + sig = last_trapsig; + exiting_exitstatus = sig + 128; + } else + exiting_exitstatus = oexitstatus; + } exitstatus = oexitstatus = exiting_exitstatus; if (setjmp(loc1.loc)) { goto l1; @@ -515,5 +524,15 @@ l1: handler = &loc2; /* probably unnecessary */ #if JOBS setjobctl(0); #endif -l2: _exit(exiting_exitstatus); +l2: + if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN && + sig != SIGTTOU) { + signal(sig, SIG_DFL); + sigemptyset(&sigs); + sigaddset(&sigs, sig); + sigprocmask(SIG_UNBLOCK, &sigs, NULL); + kill(getpid(), sig); + /* If the default action is to ignore, fall back to _exit(). */ + } + _exit(exiting_exitstatus); } diff --git a/tools/regression/bin/sh/builtins/trap6.0 b/tools/regression/bin/sh/builtins/trap6.0 new file mode 100644 index 000000000000..bd2bf7efe769 --- /dev/null +++ b/tools/regression/bin/sh/builtins/trap6.0 @@ -0,0 +1,9 @@ +# $FreeBSD$ + +v=$( + ${SH} -c 'trap "echo ok; exit" USR1; kill -USR1 $$' & + # Suppress possible message about exit on signal + wait $! >/dev/null 2>&1 +) +r=$(kill -l $?) +[ "$v" = "ok" ] && { [ "$r" = "USR1" ] || [ "$r" = "usr1" ]; }