NetBSD/bin/sh/trap.c

589 lines
12 KiB
C
Raw Normal View History

Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
/* $NetBSD: trap.c,v 1.40 2017/05/07 15:01:18 kre Exp $ */
1995-03-21 12:01:59 +03:00
1993-03-21 12:45:37 +03:00
/*-
1994-05-11 21:09:42 +04:00
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
1993-03-21 12:45:37 +03:00
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
1993-03-21 12:45:37 +03:00
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
1997-07-05 01:01:48 +04:00
#include <sys/cdefs.h>
1993-03-21 12:45:37 +03:00
#ifndef lint
1995-03-21 12:01:59 +03:00
#if 0
static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
1995-03-21 12:01:59 +03:00
#else
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
__RCSID("$NetBSD: trap.c,v 1.40 2017/05/07 15:01:18 kre Exp $");
1995-03-21 12:01:59 +03:00
#endif
1993-03-21 12:45:37 +03:00
#endif /* not lint */
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
#include <stdio.h>
1993-03-21 12:45:37 +03:00
#include "shell.h"
#include "main.h"
#include "nodes.h" /* for other headers */
#include "eval.h"
#include "jobs.h"
#include "show.h"
1993-03-21 12:45:37 +03:00
#include "options.h"
#include "builtins.h"
1993-03-21 12:45:37 +03:00
#include "syntax.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "trap.h"
#include "mystring.h"
#include "var.h"
1993-03-21 12:45:37 +03:00
/*
* Sigmode records the current value of the signal handlers for the various
* modes. A value of zero means that the current handler is not known.
* S_HARD_IGN indicates that the signal was ignored on entry to the shell,
*/
#define S_DFL 1 /* default signal handling (SIG_DFL) */
#define S_CATCH 2 /* signal is caught */
#define S_IGN 3 /* signal is ignored (SIG_IGN) */
#define S_HARD_IGN 4 /* signal is ignored permenantly */
1994-05-11 21:09:42 +04:00
#define S_RESET 5 /* temporary - to reset a hard ignored sig */
1993-03-21 12:45:37 +03:00
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
char *trap[NSIG]; /* trap handler commands */
MKINIT char sigmode[NSIG]; /* current value of signal */
static volatile char gotsig[NSIG];/* indicates specified signal received */
volatile int pendingsigs; /* indicates some signal received */
1993-03-21 12:45:37 +03:00
static int getsigaction(int, sig_t *);
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
STATIC const char *trap_signame(int);
/*
* return the signal number described by `p' (as a number or a name)
* or -1 if it isn't one
*/
static int
signame_to_signum(const char *p)
{
int i;
if (is_number(p))
return number(p);
if (strcasecmp(p, "exit") == 0 )
return 0;
if (strncasecmp(p, "sig", 3) == 0)
p += 3;
for (i = 0; i < NSIG; ++i)
if (strcasecmp (p, sys_signame[i]) == 0)
return i;
return -1;
}
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
/*
* return the name of a signal used by the "trap" command
*/
STATIC const char *
trap_signame(int signo)
{
static char nbuf[12];
const char *p = NULL;
if (signo == 0)
return "EXIT";
if (signo > 0 && signo < NSIG)
p = sys_signame[signo];
if (p != NULL)
return p;
(void)snprintf(nbuf, sizeof nbuf, "%d", signo);
return nbuf;
}
/*
* Print a list of valid signal names
*/
static void
printsignals(void)
{
int n;
out1str("EXIT ");
for (n = 1; n < NSIG; n++) {
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
out1fmt("%s", trap_signame(n));
if ((n == NSIG/2) || n == (NSIG - 1))
out1str("\n");
else
out1c(' ');
}
}
1993-03-21 12:45:37 +03:00
/*
* The trap builtin.
*/
int
trapcmd(int argc, char **argv)
{
1993-03-21 12:45:37 +03:00
char *action;
char **ap;
int signo;
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
int errs = 0;
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
int printonly = 0;
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
ap = argv + 1;
if (argc == 2 && strcmp(*ap, "-l") == 0) {
printsignals();
return 0;
}
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
if (argc == 2 && strcmp(*ap, "-") == 0) {
for (signo = 0; signo < NSIG; signo++) {
if (trap[signo] == NULL)
continue;
INTOFF;
ckfree(trap[signo]);
trap[signo] = NULL;
if (signo != 0)
setsignal(signo, 0);
INTON;
}
return 0;
}
if (argc >= 2 && strcmp(*ap, "-p") == 0) {
printonly = 1;
ap++;
argc--;
}
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
if (argc > 1 && strcmp(*ap, "--") == 0) {
argc--;
ap++;
}
1993-03-21 12:45:37 +03:00
if (argc <= 1) {
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
int count;
if (printonly) {
for (count = 0, signo = 0 ; signo < NSIG ; signo++)
if (trap[signo] == NULL) {
if (count == 0)
out1str("trap -- -");
out1fmt(" %s", trap_signame(signo));
/* oh! unlucky 13 */
if (++count >= 13) {
out1str("\n");
count = 0;
}
}
if (count)
out1str("\n");
}
for (count = 0, signo = 0 ; signo < NSIG ; signo++)
if (trap[signo] != NULL && trap[signo][0] == '\0') {
if (count == 0)
out1str("trap -- ''");
out1fmt(" %s", trap_signame(signo));
/*
* the prefix is 10 bytes, with 4 byte
* signal names (common) we have room in
* the 70 bytes left on a normal line for
* 70/(4+1) signals, that's 14, but to
* allow for the occasional longer sig name
* we output one less...
*/
if (++count >= 13) {
out1str("\n");
count = 0;
}
}
if (count)
out1str("\n");
for (signo = 0 ; signo < NSIG ; signo++)
if (trap[signo] != NULL && trap[signo][0] != '\0') {
out1str("trap -- ");
print_quoted(trap[signo]);
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
out1fmt(" %s\n", trap_signame(signo));
}
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
1993-03-21 12:45:37 +03:00
return 0;
}
action = NULL;
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
if (!printonly && !is_number(*ap)) {
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
if ((*ap)[0] == '-' && (*ap)[1] == '\0')
ap++; /* reset to default */
else
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
action = *ap++; /* can be '' for "ignore" */
argc--;
}
if (argc < 2) { /* there must be at least 1 condition */
out2str("Usage: trap [-l]\n"
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
" trap -p [condition ...]\n"
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
" trap action condition ...\n"
" trap N condition ...\n");
return 2;
}
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
1993-03-21 12:45:37 +03:00
while (*ap) {
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
signo = signame_to_signum(*ap);
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
if (signo < 0 || signo >= NSIG) {
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
/* This is not a fatal error, so sayeth posix */
outfmt(out2, "trap: '%s' bad condition\n", *ap);
errs = 1;
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
ap++;
continue;
}
ap++;
if (printonly) {
out1str("trap -- ");
if (trap[signo] == NULL)
out1str("-");
else
print_quoted(trap[signo]);
out1fmt(" %s\n", trap_signame(signo));
continue;
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
}
1993-03-21 12:45:37 +03:00
INTOFF;
if (action)
action = savestr(action);
1993-03-21 12:45:37 +03:00
if (trap[signo])
ckfree(trap[signo]);
1993-03-21 12:45:37 +03:00
trap[signo] = action;
1993-03-21 12:45:37 +03:00
if (signo != 0)
setsignal(signo, 0);
1993-03-21 12:45:37 +03:00
INTON;
}
Fix several problems with the implementation of the "trap" command (that is, with the command itself, not with the traps that are executed, if any). - "trap -- -l" is not rational, permit the (non-std) -l option only when given as the sole arg (ie: "trap -l"). - "trap --" is the same as just "trap" (and -- is ignored for below) - "trap action" generates a usage message (there must be at least one condition) - "trap N [condition...]" (the old form with a numeric first arg, to reset traps to default, instead of "trap - condition...") is properly detected. In particular while "trap 1 2 3" resets sighup sigint and siquit handlers to default, "trap hup int quit" runs the "hup" command on sigint or sigquit and does nothing to sighup at all. - actions can start with "-" (as can commands in general) - it may be unusual or even unwise, but it is not prohibited, and should work - bad conditions (signal names/numbers) are just a usage error (resulting in non-zero "exit status" (and a diagnostic on stderr)) they do not cause the script to abort (as a syntax error in a special builtin would.) (so says posix, very explicitly.) - when outputting the trap list ("trap") properly quote null actions (ignored conditions). This has the side effect of also generating an explicit null string ('') in other cases where null values are output, such as when reporting var values ("set") but that's OK, and might be better (VAR= and VAR='' mean the same, but the latter is more obvious.) We still do not properly handle traps=$(trap) (ie: it does not work at all, and should) but that's a different problem that needs fixing in another place.
2017-04-29 18:12:21 +03:00
return errs;
1993-03-21 12:45:37 +03:00
}
/*
* Clear traps on a fork or vfork.
* Takes one arg vfork, to tell it to not be destructive of
* the parents variables.
1993-03-21 12:45:37 +03:00
*/
void
clear_traps(int vforked)
{
1993-03-21 12:45:37 +03:00
char **tp;
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
for (tp = trap ; tp < &trap[NSIG] ; tp++) {
1993-03-21 12:45:37 +03:00
if (*tp && **tp) { /* trap not NULL or SIG_IGN */
INTOFF;
if (!vforked) {
ckfree(*tp);
*tp = NULL;
}
1993-03-21 12:45:37 +03:00
if (tp != &trap[0])
setsignal(tp - trap, vforked);
1993-03-21 12:45:37 +03:00
INTON;
}
}
}
/*
* Set the signal handler for the specified signal. The routine figures
* out what it should be set to.
*/
sig_t
setsignal(int signo, int vforked)
{
1993-03-21 12:45:37 +03:00
int action;
sig_t sigact = SIG_DFL, sig;
char *t, tsig;
1993-03-21 12:45:37 +03:00
if ((t = trap[signo]) == NULL)
action = S_DFL;
else if (*t != '\0')
action = S_CATCH;
else
action = S_IGN;
if (rootshell && !vforked && action == S_DFL) {
1993-03-21 12:45:37 +03:00
switch (signo) {
case SIGINT:
if (iflag || minusc || sflag == 0)
1993-03-21 12:45:37 +03:00
action = S_CATCH;
break;
case SIGQUIT:
#ifdef DEBUG
if (debug)
break;
#endif
/* FALLTHROUGH */
case SIGTERM:
if (iflag)
action = S_IGN;
break;
#if JOBS
case SIGTSTP:
case SIGTTOU:
1994-05-11 21:09:42 +04:00
if (mflag)
1993-03-21 12:45:37 +03:00
action = S_IGN;
break;
#endif
}
}
1994-05-11 21:09:42 +04:00
t = &sigmode[signo - 1];
tsig = *t;
if (tsig == 0) {
/*
* current setting unknown
1993-03-21 12:45:37 +03:00
*/
if (!getsigaction(signo, &sigact)) {
/*
* Pretend it worked; maybe we should give a warning
* here, but other shells don't. We don't alter
* sigmode, so that we retry every time.
*/
return 0;
}
1993-03-21 12:45:37 +03:00
if (sigact == SIG_IGN) {
/*
* POSIX 3.14.13 states that non-interactive shells
* should ignore trap commands for signals that were
* ignored upon entry, and leaves the behavior
* unspecified for interactive shells. On interactive
* shells, or if job control is on, and we have a job
* control related signal, we allow the trap to work.
*
* This change allows us to be POSIX compliant, and
* at the same time override the default behavior if
* we need to by setting the interactive flag.
*/
if ((mflag && (signo == SIGTSTP ||
signo == SIGTTIN || signo == SIGTTOU)) || iflag) {
tsig = S_IGN;
} else
tsig = S_HARD_IGN;
1993-03-21 12:45:37 +03:00
} else {
tsig = S_RESET; /* force to be set */
1993-03-21 12:45:37 +03:00
}
}
if (tsig == S_HARD_IGN || tsig == action)
1993-03-21 12:45:37 +03:00
return 0;
switch (action) {
case S_DFL: sigact = SIG_DFL; break;
case S_CATCH: sigact = onsig; break;
case S_IGN: sigact = SIG_IGN; break;
}
sig = signal(signo, sigact);
if (sig != SIG_ERR) {
sigset_t ss;
if (!vforked)
*t = action;
if (action == S_CATCH)
(void)siginterrupt(signo, 1);
/*
* If our parent accidentally blocked signals for
* us make sure we unblock them
*/
(void)sigemptyset(&ss);
(void)sigaddset(&ss, signo);
(void)sigprocmask(SIG_UNBLOCK, &ss, NULL);
}
return sig;
1993-03-21 12:45:37 +03:00
}
1994-05-11 21:09:42 +04:00
/*
* Return the current setting for sig w/o changing it.
*/
static int
getsigaction(int signo, sig_t *sigact)
{
1994-05-11 21:09:42 +04:00
struct sigaction sa;
if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
return 0;
*sigact = (sig_t) sa.sa_handler;
return 1;
1994-05-11 21:09:42 +04:00
}
1993-03-21 12:45:37 +03:00
/*
* Ignore a signal.
*/
void
ignoresig(int signo, int vforked)
{
1994-05-11 21:09:42 +04:00
if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
1993-03-21 12:45:37 +03:00
signal(signo, SIG_IGN);
}
if (!vforked)
sigmode[signo - 1] = S_HARD_IGN;
1993-03-21 12:45:37 +03:00
}
#ifdef mkinit
INCLUDE <signal.h>
1993-03-21 12:45:37 +03:00
INCLUDE "trap.h"
SHELLPROC {
char *sm;
clear_traps(0);
for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
1993-03-21 12:45:37 +03:00
if (*sm == S_IGN)
*sm = S_HARD_IGN;
}
}
#endif
/*
* Signal handler.
*/
void
onsig(int signo)
{
1993-03-21 12:45:37 +03:00
signal(signo, onsig);
if (signo == SIGINT && trap[SIGINT] == NULL) {
onint();
return;
}
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
gotsig[signo] = 1;
1993-03-21 12:45:37 +03:00
pendingsigs++;
}
/*
* Called to execute a trap. Perhaps we should avoid entering new trap
* handlers while we are executing a trap handler.
*/
void
dotrap(void)
{
1993-03-21 12:45:37 +03:00
int i;
int savestatus;
char *tr;
1993-03-21 12:45:37 +03:00
for (;;) {
for (i = 1 ; ; i++) {
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
if (i >= NSIG) {
pendingsigs = 0;
return;
}
if (gotsig[i])
1993-08-07 01:50:14 +04:00
break;
1993-03-21 12:45:37 +03:00
}
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
gotsig[i] = 0;
1993-03-21 12:45:37 +03:00
savestatus=exitstatus;
tr = savestr(trap[i]); /* trap code may free trap[i] */
evalstring(tr, 0);
ckfree(tr);
1993-03-21 12:45:37 +03:00
exitstatus=savestatus;
}
}
int
lastsig(void)
{
int i;
1993-03-21 12:45:37 +03:00
Enhance the trap command to make it possible to do what POSIX wants (even if no shell in existence, that I am aware of, does that). That is, POSIX says ... [of the trap command with no args] The shell shall format the output, including the proper use of quoting, so that it is suitable for re-input to the shell as commands that achieve the same trapping results. For example: save_traps=$(trap) ... eval "$save_traps" It is obvious what the intent is there. But no shell makes it work. An example using bash (as the NetBSD shell, still does not do the save_traps= stuff correctly - but that is a problem for a different time and place...) Given this script printf 'At start: '; trap printf '\n' traps=$(trap) trap 'echo hello' INT printf 'inside : '; trap printf '\n' eval "${traps}" printf 'At end : '; trap printf '\n' One would expect that (assuming no traps are set at the start, and there aren't) that the first trap will print nothing, then the inside trap will show the trap that was set, and then when we get to the end everything will be back to nothing again. But: At start: inside : trap -- 'echo hello' SIGINT At end : trap -- 'echo hello' SIGINT And of course. when you think about it, it is obvious why this happens. The first "trap" command prints nothing ... nothing has changed when we get to the "traps=$(trap)" command ... that trap command also prints nothing. So this does traps=''. When we do eval "${traps}" we are doing eval "", and it is hardly surprising that this accomplishes nothing! Now we cannot rationally change the "trap" command without args to behave in a way that would make it useful for the posix purpose (and here, what they're aiming for is good, it should be possible to accomplish that objective) so is there some other way? I think I have seen some shell (but I do not remember which one) that actually has "trap -" that resets all traps to the default, so with that, if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"' then things would actually work - kind of - that version has race conditions, so is not really safe to use (it will work, most of the time...) But, both ksh93 and bash have a -p arg to "trap" that allows information about the current trap status of named signals to be reported. Unfortunately they don't do quite the same thing, but that's not important right now, either would be usable, and they are, but it is a lot of effort, not nearly as simple as the posix example. First, while "trap -p" (with no signals specified) works, it works just the same (in both bash and ksh93, aside from output format) as "trap". That is, that is useless. But we can to trap_int=$(trap -p int) trap_hup=$(trap -p hup) ... and then reset them all, one by one, later... (bash syntax) test -n "${trap_int}" && eval "${trap_int}" || trap - int test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup (ksh93 syntax) trap "${trap_int:-}" int trap "${trap_hup:-}" hup the test (for bash) and variable with default for ksh93, is needed because they both still print nothing if the signal action is the default. So, this modification attempts to fix all of that... 1) we add trap -p, but make it always output something for every signal listed (all of the signals if none are given) even if the signal action is the default. 2) choose the bash output format for trap -p, over the ksh93 format, even though the simpler usage just above makes the ksh93 form seem better. But it isn't. Consider: ksh93$ trap -p int hup echo hello One of the two traps has "echo hello" as its action, the other is still at the default, but which? From bash... bash$ trap -p int hup trap -- 'echo hello' SIGINT And now we know! Given the bash 'trap -p' format, the following function produces ksh93 format output (for use with named signals only) instead... ksh93_trap_p() { for _ARG_ do _TRAP_=$(trap -p "${_ARG_}") || return 1 eval set -- "${_TRAP_}" printf '%s' "$3${3:+ }" done return 0 } [ It needs to be entered without the indentation, that '}"' line has to be at the margin. If the shell running that has local vars (bash does) then _ARG_ and _TRAP_ should be made local. ] So the bash format was chosen (except we do not include the "SIG" on the signal names. That's irrelevant.) If no traps are set, "trap -p" will say (on NetBSD of course)... trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5 trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18 trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30 Obviously if traps are set, the relevant signal names will be removed from that list, and additional lines added for the trapped signals. With args, the signals names are listed, one line each, whatever the status of the trap for that signal is: $ trap -p HUP INT QUIT trap -- - HUP trap -- 'echo interrupted' INT trap -- - QUIT 3) we add "trap -" to reset all traps to default. (It is easy, and seems useful.) 4) While here, lots of generic cleanup. In particular, get rid of the NSIG+1 nonsense, and anything that ever believes a signo == NSIG is in any way rational. Before there was a bunch of confusion, as we need all the signals for traps, plus one more for the EXIT trap, which looks like we then need NSIG+1. But EXIT is 0, NSIG includes signals from 0..NSIG-1 but there is no signal 0, EXIT uses that slot, so we do not need to add and extra one, NSIG is enough. (To see the effect of this, use a /bin/sh from before this fix, and compare the output from trap '' 64 and trap '' 65 both invalid signal numbers. Then try just "trap" and watch your shell drop core...) Eventually NSIG needs to go away completely (from user apps), it is not POSIX, it isn't really useful (unless we make lots of assumptions about how signals are numbered, which are not guaranteed, so even if apps, like this sh, work on NetBSD, they're not portable,) and it isn't necessary (or will not be, soon.) But that is for another day... 5) As is kind of obvious above, when listing "all" traps, list all the ones still at their defaults, and all the ignored signals, on as few lines as possible (it could all be on one line - technically it would work as well, but it would have made this cvs log message really ugly...) Signals with a non-null action still get listed one to a line (even if several do have the exact same action.) 6) Man page updates as well. After this change, the following script: printf 'At start: '; trap printf '\n' trap -p >/tmp/out.$$ trap 'echo hello' INT printf 'inside : '; trap printf '\n' . /tmp/out.$$; rm /tmp/out.$$ printf 'At end : '; trap printf '\n' which is just the example from above, using "trap -p" instead of just "trap" to save the traps, and modified to a form that will work with the NetBSD shell today produces: At start: inside : trap -- 'echo hello' INT At end : [Do I get a prize for longest commit log message of the year?]
2017-05-07 18:01:18 +03:00
for (i = NSIG; --i > 0; )
if (gotsig[i])
return i;
return SIGINT; /* XXX */
}
1993-03-21 12:45:37 +03:00
/*
* Controls whether the shell is interactive or not.
*/
void
setinteractive(int on)
{
1994-05-11 21:09:42 +04:00
static int is_interactive;
1993-03-21 12:45:37 +03:00
if (on == is_interactive)
return;
setsignal(SIGINT, 0);
setsignal(SIGQUIT, 0);
setsignal(SIGTERM, 0);
1993-03-21 12:45:37 +03:00
is_interactive = on;
}
/*
* Called to exit the shell.
*/
void
exitshell(int status)
{
1993-03-21 12:45:37 +03:00
struct jmploc loc1, loc2;
char *p;
TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
1994-05-11 21:09:42 +04:00
if (setjmp(loc1.loc)) {
goto l1;
}
if (setjmp(loc2.loc)) {
goto l2;
}
1993-03-21 12:45:37 +03:00
handler = &loc1;
if ((p = trap[0]) != NULL && *p != '\0') {
trap[0] = NULL;
evalstring(p, 0);
1993-03-21 12:45:37 +03:00
}
l1: handler = &loc2; /* probably unnecessary */
flushall();
#if JOBS
setjobctl(0);
#endif
l2: _exit(status);
1998-07-28 09:31:22 +04:00
/* NOTREACHED */
1993-03-21 12:45:37 +03:00
}