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.
This commit is contained in:
Jilles Tjoelker 2011-01-16 13:56:41 +00:00
parent ea8345d6a7
commit ebdfd6dc4d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=217472
2 changed files with 31 additions and 3 deletions

View File

@ -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);
}

View File

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