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" ]; }