change behaviour of argument-less exit in traps to match SUSv4; Debian #599484 (original patch from Jonathan Nieder, thanks!) in a variant that appears to handle nested traps well

This commit is contained in:
tg 2010-11-01 17:29:05 +00:00
parent e57379aab7
commit 27dce9168a
5 changed files with 59 additions and 23 deletions

14
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.395 2010/10/01 19:04:37 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.396 2010/11/01 17:29:00 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R39 2010/10/01
@(#)MIRBSD KSH R39 2010/11/01
description:
Check version of shell.
stdin:
@ -4845,6 +4845,16 @@ expected-stdout:
E 0
F 0
---
name: exit-trap-1
description:
Check that "exit" with no arguments behaves SUSv4 conformant.
stdin:
trap 'echo hi; exit' EXIT
exit 9
expected-stdout:
hi
expected-exit: 9
---
name: test-stlt-1
description:
Check that test also can handle string1 < string2 etc.

View File

@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.163 2010/09/15 21:08:18 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.164 2010/11/01 17:29:02 tg Exp $");
#if HAVE_KILLPG
/*
@ -2293,7 +2293,8 @@ c_exitreturn(const char **wp)
warningf(true, "%s: %s", arg, "bad number");
} else
exstat = n;
}
} else if (trap_exstat != -1)
exstat = trap_exstat;
if (wp[0][0] == 'r') { /* return */
struct env *ep;

View File

@ -26,7 +26,7 @@
#include <sys/file.h>
#endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.102 2010/09/14 21:26:13 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.103 2010/11/01 17:29:03 tg Exp $");
/*-
* MirOS: This is the default mapping type, and need not be specified.
@ -1066,6 +1066,8 @@ inittraps(void)
int i;
const char *cs;
trap_exstat = -1;
/* Populate sigtraps based on sys_signame and sys_siglist. */
for (i = 0; i <= NSIG; i++) {
sigtraps[i].signal = i;
@ -1271,22 +1273,29 @@ runtraps(int flag)
intrsig = 0;
if (flag & TF_FATAL)
fatal_trap = 0;
++trap_nested;
for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
if (p->set && (!flag ||
((p->flags & flag) && p->trap == NULL)))
runtrap(p);
runtrap(p, false);
if (!--trap_nested)
runtrap(NULL, true);
}
void
runtrap(Trap *p)
runtrap(Trap *p, bool is_last)
{
int i = p->signal;
char *trapstr = p->trap;
int oexstat;
int old_changed = 0;
int old_changed = 0, i;
char *trapstr;
if (p == NULL)
/* just clean up, see runtraps() above */
goto donetrap;
i = p->signal;
trapstr = p->trap;
p->set = 0;
if (trapstr == NULL) { /* SIG_DFL */
if (trapstr == NULL) {
/* SIG_DFL */
if (p->flags & TF_FATAL) {
/* eg, SIGHUP */
exstat = 128 + i;
@ -1297,22 +1306,23 @@ runtrap(Trap *p)
exstat = 128 + i;
unwind(LINTR);
}
return;
goto donetrap;
}
if (trapstr[0] == '\0') /* SIG_IGN */
return;
if (trapstr[0] == '\0')
/* SIG_IGN */
goto donetrap;
if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */
old_changed = p->flags & TF_CHANGED;
p->flags &= ~TF_CHANGED;
p->trap = NULL;
}
oexstat = exstat;
if (trap_exstat == -1)
trap_exstat = exstat;
/*
* Note: trapstr is fully parsed before anything is executed, thus
* no problem with afree(p->trap) in settrap() while still in use.
*/
command(trapstr, current_lineno);
exstat = oexstat;
if (i == SIGEXIT_ || i == SIGERR_) {
if (p->flags & TF_CHANGED)
/* don't clear TF_CHANGED */
@ -1321,6 +1331,13 @@ runtrap(Trap *p)
p->trap = trapstr;
p->flags |= old_changed;
}
donetrap:
/* we're the last trap of a sequence executed */
if (is_last && trap_exstat != -1) {
exstat = trap_exstat;
trap_exstat = -1;
}
}
/* clear pending traps and reset user's trap handlers; used after fork(2) */

10
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h>
#endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.172 2010/09/14 21:26:14 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.173 2010/11/01 17:29:04 tg Exp $");
extern char **environ;
@ -672,10 +672,14 @@ unwind(int i)
/* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) &&
sigtraps[SIGEXIT_].trap)) {
runtrap(&sigtraps[SIGEXIT_]);
++trap_nested;
runtrap(&sigtraps[SIGEXIT_], trap_nested == 1);
--trap_nested;
i = LLEAVE;
} else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
runtrap(&sigtraps[SIGERR_]);
++trap_nested;
runtrap(&sigtraps[SIGERR_], trap_nested == 1);
--trap_nested;
i = LLEAVE;
}
while (1) {

10
sh.h
View File

@ -154,9 +154,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.418 2010/10/08 17:56:57 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.419 2010/11/01 17:29:05 tg Exp $");
#endif
#define MKSH_VERSION "R39 2010/10/01"
#define MKSH_VERSION "R39 2010/11/01"
#ifndef MKSH_INCLUDES_ONLY
@ -584,6 +584,8 @@ EXTERN struct mksh_kshstate_v {
int exstat_; /* exit status */
int subst_exstat_; /* exit status of last $(..)/`..` */
struct env env_; /* top-level parsing & execution env. */
short trap_exstat_; /* exit status before running a trap */
uint8_t trap_nested_; /* running nested traps */
uint8_t shell_flags_[FNFLAGS];
} kshstate_v;
EXTERN struct mksh_kshstate_f {
@ -602,6 +604,8 @@ EXTERN struct mksh_kshstate_f {
#define kshppid kshstate_f.kshppid_
#define exstat kshstate_v.exstat_
#define subst_exstat kshstate_v.subst_exstat_
#define trap_exstat kshstate_v.trap_exstat_
#define trap_nested kshstate_v.trap_nested_
/* evil hack: return hash(kshstate_f concat (kshstate_f'.h:=hash(arg))) */
uint32_t evilhash(const char *);
@ -1526,7 +1530,7 @@ void intrcheck(void);
int fatal_trap_check(void);
int trap_pending(void);
void runtraps(int intr);
void runtrap(Trap *);
void runtrap(Trap *, bool);
void cleartraps(void);
void restoresigs(void);
void settrap(Trap *, const char *);