With these changes sh(1)'s trap command should be POSIX-compliant,
while remaining (becoming :) compatible with other popular shells. Specifically these changes include: 1) Implement 'trap -l' to get a list of valid signals names. This is useful if you wanted to do something like reset all signal handlers to there defaults values, in which case something like this will do the trick. trap `trap -l` 2) Reformat the output of 'trap' so it can be saved and later eval'd to restore the saved settings. 3) Allow the use of signal names as well as signal numbers. 4) Fix trap handling of SIGCHLD so that commands like the following (albeit, contrived) won't cause sh(1) to recurse ad infinitum. trap uname 0 20 5) Make variables static that are used only in trap.c. 6) Minor 'style(9) police' mods.
This commit is contained in:
parent
f360d1effe
commit
f98e1b8071
156
bin/sh/trap.c
156
bin/sh/trap.c
@ -33,7 +33,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: trap.c,v 1.4 1996/09/01 10:21:47 peter Exp $
|
* $Id: trap.c,v 1.5 1996/12/14 06:19:32 steve Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
@ -72,43 +72,99 @@ static char const sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
|
|||||||
#define S_RESET 5 /* temporary - to reset a hard ignored sig */
|
#define S_RESET 5 /* temporary - to reset a hard ignored sig */
|
||||||
|
|
||||||
|
|
||||||
extern char nullstr[1]; /* null string */
|
|
||||||
|
|
||||||
char *trap[NSIG+1]; /* trap handler commands */
|
|
||||||
MKINIT char sigmode[NSIG]; /* current value of signal */
|
MKINIT char sigmode[NSIG]; /* current value of signal */
|
||||||
char gotsig[NSIG]; /* indicates specified signal received */
|
|
||||||
int pendingsigs; /* indicates some signal received */
|
int pendingsigs; /* indicates some signal received */
|
||||||
|
static char *trap[NSIG]; /* trap handler commands */
|
||||||
|
static char gotsig[NSIG]; /* indicates specified signal received */
|
||||||
|
static int ignore_sigchld; /* Used while handling SIGCHLD traps. */
|
||||||
|
|
||||||
static int getsigaction __P((int, sig_t *));
|
static int getsigaction __P((int, sig_t *));
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map a string to a signal number.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
sigstring_to_signum(sig)
|
||||||
|
char *sig;
|
||||||
|
{
|
||||||
|
|
||||||
|
if (is_number(sig)) {
|
||||||
|
int signo;
|
||||||
|
|
||||||
|
signo = atoi(sig);
|
||||||
|
return ((signo >= 0 && signo < NSIG) ? signo : (-1));
|
||||||
|
} else if (strcasecmp(sig, "exit") == 0) {
|
||||||
|
return (0);
|
||||||
|
} else {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (strncasecmp(sig, "sig", 3) == 0)
|
||||||
|
sig += 3;
|
||||||
|
for (n = 1; n < NSIG; n++)
|
||||||
|
if (strcasecmp(sys_signame[n], sig) == 0)
|
||||||
|
return (n);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a list of valid signal names.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
printsignals()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 1; n < NSIG; n++) {
|
||||||
|
out1fmt("%s", sys_signame[n]);
|
||||||
|
if (n == (NSIG / 2) || n == (NSIG - 1))
|
||||||
|
out1str("\n");
|
||||||
|
else
|
||||||
|
out1c(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The trap builtin.
|
* The trap builtin.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
trapcmd(argc, argv)
|
trapcmd(argc, argv)
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
{
|
{
|
||||||
char *action;
|
char *action;
|
||||||
char **ap;
|
|
||||||
int signo;
|
int signo;
|
||||||
|
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
for (signo = 0 ; signo <= NSIG ; signo++) {
|
for (signo = 0 ; signo < NSIG ; signo++) {
|
||||||
if (trap[signo] != NULL)
|
if (trap[signo] != NULL)
|
||||||
out1fmt("%d: %s\n", signo, trap[signo]);
|
out1fmt("trap -- '%s' %s\n", trap[signo],
|
||||||
|
(signo) ? sys_signame[signo] : "exit");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ap = argv + 1;
|
action = NULL;
|
||||||
if (is_number(*ap))
|
if (*++argv && strcmp(*argv, "--") == 0)
|
||||||
action = NULL;
|
argv++;
|
||||||
else
|
if (*argv && sigstring_to_signum(*argv) == -1) {
|
||||||
action = *ap++;
|
if ((*argv)[0] != '-') {
|
||||||
while (*ap) {
|
action = *argv;
|
||||||
if ((signo = number(*ap)) < 0 || signo > NSIG)
|
argv++;
|
||||||
error("%s: bad trap", *ap);
|
} else if ((*argv)[1] == '\0') {
|
||||||
|
argv++;
|
||||||
|
} else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
|
||||||
|
printsignals();
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
error("bad option %s", *argv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (*argv) {
|
||||||
|
if ((signo = sigstring_to_signum(*argv)) == -1)
|
||||||
|
error("bad signal %s", *argv);
|
||||||
INTOFF;
|
INTOFF;
|
||||||
if (action)
|
if (action)
|
||||||
action = savestr(action);
|
action = savestr(action);
|
||||||
@ -118,22 +174,21 @@ trapcmd(argc, argv)
|
|||||||
if (signo != 0)
|
if (signo != 0)
|
||||||
setsignal(signo);
|
setsignal(signo);
|
||||||
INTON;
|
INTON;
|
||||||
ap++;
|
argv++;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear traps on a fork.
|
* Clear traps on a fork.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
clear_traps() {
|
clear_traps()
|
||||||
|
{
|
||||||
char **tp;
|
char **tp;
|
||||||
|
|
||||||
for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
|
for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
|
||||||
if (*tp && **tp) { /* trap not NULL or SIG_IGN */
|
if (*tp && **tp) { /* trap not NULL or SIG_IGN */
|
||||||
INTOFF;
|
INTOFF;
|
||||||
ckfree(*tp);
|
ckfree(*tp);
|
||||||
@ -146,12 +201,10 @@ clear_traps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the signal handler for the specified signal. The routine figures
|
* Set the signal handler for the specified signal. The routine figures
|
||||||
* out what it should be set to.
|
* out what it should be set to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
long
|
long
|
||||||
setsignal(signo)
|
setsignal(signo)
|
||||||
int signo;
|
int signo;
|
||||||
@ -159,7 +212,6 @@ setsignal(signo)
|
|||||||
int action;
|
int action;
|
||||||
sig_t sigact = SIG_DFL;
|
sig_t sigact = SIG_DFL;
|
||||||
char *t;
|
char *t;
|
||||||
extern void onsig();
|
|
||||||
|
|
||||||
if ((t = trap[signo]) == NULL)
|
if ((t = trap[signo]) == NULL)
|
||||||
action = S_DFL;
|
action = S_DFL;
|
||||||
@ -197,7 +249,7 @@ setsignal(signo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t = &sigmode[signo - 1];
|
t = &sigmode[signo];
|
||||||
if (*t == 0) {
|
if (*t == 0) {
|
||||||
/*
|
/*
|
||||||
* current setting unknown
|
* current setting unknown
|
||||||
@ -231,6 +283,7 @@ setsignal(signo)
|
|||||||
return (long)signal(signo, sigact);
|
return (long)signal(signo, sigact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the current setting for sig w/o changing it.
|
* Return the current setting for sig w/o changing it.
|
||||||
*/
|
*/
|
||||||
@ -247,18 +300,19 @@ getsigaction(signo, sigact)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ignore a signal.
|
* Ignore a signal.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ignoresig(signo)
|
ignoresig(signo)
|
||||||
int signo;
|
int signo;
|
||||||
{
|
{
|
||||||
if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
|
|
||||||
|
if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
|
||||||
signal(signo, SIG_IGN);
|
signal(signo, SIG_IGN);
|
||||||
}
|
}
|
||||||
sigmode[signo - 1] = S_HARD_IGN;
|
sigmode[signo] = S_HARD_IGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -278,59 +332,65 @@ SHELLPROC {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signal handler.
|
* Signal handler.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
onsig(signo)
|
onsig(signo)
|
||||||
int signo;
|
int signo;
|
||||||
{
|
{
|
||||||
|
|
||||||
signal(signo, onsig);
|
signal(signo, onsig);
|
||||||
if (signo == SIGINT && trap[SIGINT] == NULL) {
|
if (signo == SIGINT && trap[SIGINT] == NULL) {
|
||||||
onint();
|
onint();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gotsig[signo - 1] = 1;
|
if (signo != SIGCHLD || !ignore_sigchld)
|
||||||
|
gotsig[signo] = 1;
|
||||||
pendingsigs++;
|
pendingsigs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to execute a trap. Perhaps we should avoid entering new trap
|
* Called to execute a trap. Perhaps we should avoid entering new trap
|
||||||
* handlers while we are executing a trap handler.
|
* handlers while we are executing a trap handler.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
dotrap() {
|
dotrap()
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
int savestatus;
|
int savestatus;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (i = 1 ; ; i++) {
|
for (i = 1; i < NSIG; i++) {
|
||||||
if (gotsig[i - 1])
|
if (gotsig[i]) {
|
||||||
|
gotsig[i] = 0;
|
||||||
|
if (trap[i]) {
|
||||||
|
/*
|
||||||
|
* Ignore SIGCHLD to avoid infinite recursion
|
||||||
|
* if the trap action does a fork.
|
||||||
|
*/
|
||||||
|
if (i == SIGCHLD)
|
||||||
|
ignore_sigchld++;
|
||||||
|
savestatus = exitstatus;
|
||||||
|
evalstring(trap[i]);
|
||||||
|
exitstatus = savestatus;
|
||||||
|
if (i == SIGCHLD)
|
||||||
|
ignore_sigchld--;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
if (i >= NSIG)
|
}
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
gotsig[i - 1] = 0;
|
if (i >= NSIG)
|
||||||
savestatus=exitstatus;
|
break;
|
||||||
evalstring(trap[i]);
|
|
||||||
exitstatus=savestatus;
|
|
||||||
}
|
}
|
||||||
done:
|
|
||||||
pendingsigs = 0;
|
pendingsigs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Controls whether the shell is interactive or not.
|
* Controls whether the shell is interactive or not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
setinteractive(on)
|
setinteractive(on)
|
||||||
int on;
|
int on;
|
||||||
@ -346,11 +406,9 @@ setinteractive(on)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to exit the shell.
|
* Called to exit the shell.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
exitshell(status)
|
exitshell(status)
|
||||||
int status;
|
int status;
|
||||||
|
Loading…
Reference in New Issue
Block a user