Be less conservative about when we do clear_traps() when we have

traps_invalid (that is, when we actually nuke the parent shell's
caught traps in a subshell).  This allows more reasonable use of
"trap -p" (and similar) in subshells than existed before (and in
particular, that command can be in a function now - there can also
be several related commands like
	traps=$(trap -p INT; trap -p QUIT; trap -p HUP)
A side effect of all of this is that
	(eval "$(trap -p)"; ...)
now allows copying caught traps into a subshell environment, if desired.

Also att the ksh93 variant (the one not picked by POSIX as it isn't
generally as useful) of "trap -p" (but call it "trap -P" which extracts
just the trap action for named signals (giving more than one is usually
undesirable).   This allows
	eval "$(trap -P INT)"
to run the action for SIGINT traps, without needing to attempt to parse
the "trap -p" output.
This commit is contained in:
kre 2020-08-20 23:09:56 +00:00
parent 7a2f8a050c
commit 4a370dce6a
2 changed files with 48 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: eval.c,v 1.180 2020/05/14 08:34:17 msaitoh Exp $ */ /* $NetBSD: eval.c,v 1.181 2020/08/20 23:09:56 kre Exp $ */
/*- /*-
* Copyright (c) 1993 * Copyright (c) 1993
@ -37,7 +37,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
#else #else
__RCSID("$NetBSD: eval.c,v 1.180 2020/05/14 08:34:17 msaitoh Exp $"); __RCSID("$NetBSD: eval.c,v 1.181 2020/08/20 23:09:56 kre Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@ -280,8 +280,10 @@ evaltree(union node *n, int flags)
next = NULL; next = NULL;
CTRACE(DBG_EVAL, ("pid %d, evaltree(%p: %s(%d), %#x) called\n", CTRACE(DBG_EVAL, ("pid %d, evaltree(%p: %s(%d), %#x) called\n",
getpid(), n, NODETYPENAME(n->type), n->type, flags)); getpid(), n, NODETYPENAME(n->type), n->type, flags));
/*
if (n->type != NCMD && traps_invalid) if (n->type != NCMD && traps_invalid)
free_traps(); free_traps();
*/
switch (n->type) { switch (n->type) {
case NSEMI: case NSEMI:
evaltree(n->nbinary.ch1, sflags); evaltree(n->nbinary.ch1, sflags);
@ -302,6 +304,8 @@ evaltree(union node *n, int flags)
next = n->nbinary.ch2; next = n->nbinary.ch2;
break; break;
case NREDIR: case NREDIR:
if (traps_invalid)
free_traps();
evalredir(n, flags); evalredir(n, flags);
break; break;
case NSUBSHELL: case NSUBSHELL:
@ -309,9 +313,13 @@ evaltree(union node *n, int flags)
do_etest = !(flags & EV_TESTED); do_etest = !(flags & EV_TESTED);
break; break;
case NBACKGND: case NBACKGND:
if (traps_invalid)
free_traps();
evalsubshell(n, flags); evalsubshell(n, flags);
break; break;
case NIF: { case NIF: {
if (traps_invalid)
free_traps();
evaltree(n->nif.test, EV_TESTED); evaltree(n->nif.test, EV_TESTED);
if (nflag || evalskip) if (nflag || evalskip)
goto out1; goto out1;
@ -325,15 +333,23 @@ evaltree(union node *n, int flags)
} }
case NWHILE: case NWHILE:
case NUNTIL: case NUNTIL:
if (traps_invalid)
free_traps();
evalloop(n, sflags); evalloop(n, sflags);
break; break;
case NFOR: case NFOR:
if (traps_invalid)
free_traps();
evalfor(n, sflags); evalfor(n, sflags);
break; break;
case NCASE: case NCASE:
if (traps_invalid)
free_traps();
evalcase(n, sflags); evalcase(n, sflags);
break; break;
case NDEFUN: case NDEFUN:
if (traps_invalid)
free_traps();
CTRACE(DBG_EVAL, ("Defining fn %s @%d%s\n", CTRACE(DBG_EVAL, ("Defining fn %s @%d%s\n",
n->narg.text, n->narg.lineno, n->narg.text, n->narg.lineno,
fnline1 ? " LINENO=1" : "")); fnline1 ? " LINENO=1" : ""));
@ -350,6 +366,8 @@ evaltree(union node *n, int flags)
exitstatus = 1; exitstatus = 1;
break; break;
case NPIPE: case NPIPE:
if (traps_invalid)
free_traps();
evalpipe(n); evalpipe(n);
do_etest = !(flags & EV_TESTED); do_etest = !(flags & EV_TESTED);
break; break;
@ -1043,6 +1061,10 @@ evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
* command eval trap * command eval trap
* eval command trap * eval command trap
* without zapping the traps completely, in all other cases we do. * without zapping the traps completely, in all other cases we do.
* Function calls also do not zap the traps (but commands they execute
* probably will) - this allows a function like
* trapstate() { trap -p; }
* called as save_traps=$(trapstate).
* *
* The test here permits eval "anything" but when evalstring() comes * The test here permits eval "anything" but when evalstring() comes
* back here again, the "anything" will be validated. * back here again, the "anything" will be validated.
@ -1055,6 +1077,7 @@ evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
* trapcmd() takes care of doing free_traps() if it is needed there. * trapcmd() takes care of doing free_traps() if it is needed there.
*/ */
if (traps_invalid && if (traps_invalid &&
cmdentry.cmdtype != CMDFUNCTION &&
((cmdentry.cmdtype!=CMDSPLBLTIN && cmdentry.cmdtype!=CMDBUILTIN) || ((cmdentry.cmdtype!=CMDSPLBLTIN && cmdentry.cmdtype!=CMDBUILTIN) ||
(cmdentry.u.bltin != trapcmd && cmdentry.u.bltin != evalcmd))) (cmdentry.u.bltin != trapcmd && cmdentry.u.bltin != evalcmd)))
free_traps(); free_traps();

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.c,v 1.54 2020/08/20 16:15:50 kre Exp $ */ /* $NetBSD: trap.c,v 1.55 2020/08/20 23:09:56 kre Exp $ */
/*- /*-
* Copyright (c) 1991, 1993 * Copyright (c) 1991, 1993
@ -37,7 +37,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
#else #else
__RCSID("$NetBSD: trap.c,v 1.54 2020/08/20 16:15:50 kre Exp $"); __RCSID("$NetBSD: trap.c,v 1.55 2020/08/20 23:09:56 kre Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@ -232,6 +232,8 @@ trapcmd(int argc, char **argv)
ap = argv + 1; ap = argv + 1;
CTRACE(DBG_TRAP, ("trapcmd: ")); CTRACE(DBG_TRAP, ("trapcmd: "));
if (argc == 3 && strcmp(ap[1], "--") == 0)
argc--;
if (argc == 2 && strcmp(*ap, "-l") == 0) { if (argc == 2 && strcmp(*ap, "-l") == 0) {
CTRACE(DBG_TRAP, ("-l\n")); CTRACE(DBG_TRAP, ("-l\n"));
out1str("EXIT"); out1str("EXIT");
@ -253,9 +255,9 @@ trapcmd(int argc, char **argv)
traps_invalid = 0; traps_invalid = 0;
return 0; return 0;
} }
if (argc >= 2 && strcmp(*ap, "-p") == 0) { if (argc >= 2 && (strcmp(*ap, "-p") == 0 || strcmp(*ap, "-P") == 0)) {
CTRACE(DBG_TRAP, ("-p ")); CTRACE(DBG_TRAP, ("%s ", *ap));
printonly = 1; printonly = 1 + (ap[0][1] == 'p');
ap++; ap++;
argc--; argc--;
} }
@ -265,6 +267,9 @@ trapcmd(int argc, char **argv)
ap++; ap++;
} }
if (printonly == 1 && argc < 2)
goto usage;
if (argc <= 1) { if (argc <= 1) {
int count; int count;
@ -339,8 +344,10 @@ trapcmd(int argc, char **argv)
} }
if (argc < 2) { /* there must be at least 1 condition */ if (argc < 2) { /* there must be at least 1 condition */
usage:
out2str("Usage: trap [-l]\n" out2str("Usage: trap [-l]\n"
" trap -p [condition ...]\n" " trap -p [condition ...]\n"
" trap -P condition ...\n"
" trap action condition ...\n" " trap action condition ...\n"
" trap N condition ...\n"); " trap N condition ...\n");
return 2; return 2;
@ -365,12 +372,17 @@ trapcmd(int argc, char **argv)
* (action will always be "-") here, if someone * (action will always be "-") here, if someone
* really wants to get that particular output * really wants to get that particular output
*/ */
out1str("trap -- "); if (printonly == 1) {
if (trap[signo] == NULL) if (trap[signo] != NULL)
out1str("-"); out1fmt("%s\n", trap[signo]);
else } else {
print_quoted(trap[signo]); out1str("trap -- ");
out1fmt(" %s\n", trap_signame(signo)); if (trap[signo] == NULL)
out1str("-");
else
print_quoted(trap[signo]);
out1fmt(" %s\n", trap_signame(signo));
}
continue; continue;
} }