|
Packit |
a69f91 |
/* exp_trap.c - Expect's trap command
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
Written by: Don Libes, NIST, 9/1/93
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
Design and implementation of this program was paid for by U.S. tax
|
|
Packit |
a69f91 |
dollars. Therefore it is public domain. However, the author and NIST
|
|
Packit |
a69f91 |
would appreciate credit if this program or parts of it are used.
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#include "expect_cf.h"
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#include <stdio.h>
|
|
Packit |
a69f91 |
#include <signal.h>
|
|
Packit |
a69f91 |
#include <sys/types.h>
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#ifdef HAVE_SYS_WAIT_H
|
|
Packit |
a69f91 |
#include <sys/wait.h>
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
#ifdef HAVE_STRING_H
|
|
Packit |
a69f91 |
#include <string.h>
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#if defined(SIGCLD) && !defined(SIGCHLD)
|
|
Packit |
a69f91 |
#define SIGCHLD SIGCLD
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#include "tcl.h"
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#include "exp_rename.h"
|
|
Packit |
a69f91 |
#include "exp_prog.h"
|
|
Packit |
a69f91 |
#include "exp_command.h"
|
|
Packit |
a69f91 |
#include "exp_log.h"
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#ifdef TCL_DEBUGGER
|
|
Packit |
a69f91 |
#include "tcldbg.h"
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#define NO_SIG 0
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
static struct trap {
|
|
Packit |
a69f91 |
char *action; /* Tcl command to execute upon sig */
|
|
Packit |
a69f91 |
/* Each is handled by the eval_trap_action */
|
|
Packit |
a69f91 |
int mark; /* TRUE if signal has occurred */
|
|
Packit |
a69f91 |
Tcl_Interp *interp; /* interp to use or 0 if we should use the */
|
|
Packit |
a69f91 |
/* interpreter active at the time the sig */
|
|
Packit |
a69f91 |
/* is processed */
|
|
Packit |
a69f91 |
int code; /* return our new code instead of code */
|
|
Packit |
a69f91 |
/* available when signal is processed */
|
|
Packit |
a69f91 |
CONST char *name; /* name of signal */
|
|
Packit |
a69f91 |
int reserved; /* if unavailable for trapping */
|
|
Packit |
a69f91 |
} traps[NSIG];
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
int sigchld_count = 0; /* # of sigchlds caught but not yet processed */
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
static int eval_trap_action();
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
static int got_sig; /* this records the last signal received */
|
|
Packit |
a69f91 |
/* it is only a hint and can be wiped out */
|
|
Packit |
a69f91 |
/* by multiple signals, but it will always */
|
|
Packit |
a69f91 |
/* be left with a valid signal that is */
|
|
Packit |
a69f91 |
/* pending */
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
static Tcl_AsyncHandler async_handler;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
static CONST char *
|
|
Packit |
a69f91 |
signal_to_string(sig)
|
|
Packit |
a69f91 |
int sig;
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
if (sig <= 0 || sig > NSIG) return("SIGNAL OUT OF RANGE");
|
|
Packit |
a69f91 |
return(traps[sig].name);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* current sig being processed by user sig handler */
|
|
Packit |
a69f91 |
static int current_sig = NO_SIG;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
int exp_nostack_dump = FALSE; /* TRUE if user has requested unrolling of */
|
|
Packit |
a69f91 |
/* stack with no trace */
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/*ARGSUSED*/
|
|
Packit |
a69f91 |
static int
|
|
Packit |
a69f91 |
tophalf(clientData,interp,code)
|
|
Packit |
a69f91 |
ClientData clientData;
|
|
Packit |
a69f91 |
Tcl_Interp *interp;
|
|
Packit |
a69f91 |
int code;
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
struct trap *trap; /* last trap processed */
|
|
Packit |
a69f91 |
int rc;
|
|
Packit |
a69f91 |
int i;
|
|
Packit |
a69f91 |
Tcl_Interp *sig_interp;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
expDiagLog("sighandler: handling signal(%d)\r\n",got_sig);
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (got_sig <= 0 || got_sig >= NSIG) {
|
|
Packit |
a69f91 |
expErrorLog("caught impossible signal %d\r\n",got_sig);
|
|
Packit |
a69f91 |
abort();
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* start to work on this sig. got_sig can now be overwritten */
|
|
Packit |
a69f91 |
/* and it won't cause a problem */
|
|
Packit |
a69f91 |
current_sig = got_sig;
|
|
Packit |
a69f91 |
trap = &traps[current_sig];
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
trap->mark = FALSE;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* decrement below looks dangerous */
|
|
Packit |
a69f91 |
/* Don't we need to temporarily block bottomhalf? */
|
|
Packit |
a69f91 |
if (current_sig == SIGCHLD) {
|
|
Packit |
a69f91 |
sigchld_count--;
|
|
Packit |
a69f91 |
expDiagLog("sigchld_count-- == %d\n",sigchld_count);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (!trap->action) {
|
|
Packit |
a69f91 |
/* In this one case, we let ourselves be called when no */
|
|
Packit |
a69f91 |
/* signaler predefined, since we are calling explicitly */
|
|
Packit |
a69f91 |
/* from another part of the program, and it is just simpler */
|
|
Packit |
a69f91 |
if (current_sig == 0) return code;
|
|
Packit |
a69f91 |
expErrorLog("caught unexpected signal: %s (%d)\r\n",
|
|
Packit |
a69f91 |
signal_to_string(current_sig),current_sig);
|
|
Packit |
a69f91 |
abort();
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (trap->interp) {
|
|
Packit |
a69f91 |
/* if trap requested original interp, use it */
|
|
Packit |
a69f91 |
sig_interp = trap->interp;
|
|
Packit |
a69f91 |
} else if (interp) {
|
|
Packit |
a69f91 |
/* else if another interp is available, use it */
|
|
Packit |
a69f91 |
sig_interp = interp;
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
/* fall back to exp_interp */
|
|
Packit |
a69f91 |
sig_interp = exp_interp;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
rc = eval_trap_action(sig_interp,current_sig,trap,code);
|
|
Packit |
a69f91 |
current_sig = NO_SIG;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/*
|
|
Packit |
a69f91 |
* scan for more signals to process
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* first check for additional SIGCHLDs */
|
|
Packit |
a69f91 |
if (sigchld_count) {
|
|
Packit |
a69f91 |
got_sig = SIGCHLD;
|
|
Packit |
a69f91 |
traps[SIGCHLD].mark = TRUE;
|
|
Packit |
a69f91 |
Tcl_AsyncMark(async_handler);
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
got_sig = -1;
|
|
Packit |
a69f91 |
for (i=1;i
|
|
Packit |
a69f91 |
if (traps[i].mark) {
|
|
Packit |
a69f91 |
got_sig = i;
|
|
Packit |
a69f91 |
Tcl_AsyncMark(async_handler);
|
|
Packit |
a69f91 |
break;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
return rc;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#ifdef REARM_SIG
|
|
Packit |
a69f91 |
int sigchld_sleep;
|
|
Packit |
a69f91 |
static int rearm_sigchld = FALSE; /* TRUE if sigchld needs to be */
|
|
Packit |
a69f91 |
/* rearmed (i.e., because it has */
|
|
Packit |
a69f91 |
/* just gone off) */
|
|
Packit |
a69f91 |
static int rearming_sigchld = FALSE;
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* called upon receipt of a user-declared signal */
|
|
Packit |
a69f91 |
static void
|
|
Packit |
a69f91 |
bottomhalf(sig)
|
|
Packit |
a69f91 |
int sig;
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
#ifdef REARM_SIG
|
|
Packit |
a69f91 |
/*
|
|
Packit |
a69f91 |
* tiny window of death if same signal should arrive here
|
|
Packit |
a69f91 |
* before we've reinstalled it
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* In SV, sigchld must be rearmed after wait to avoid recursion */
|
|
Packit |
a69f91 |
if (sig != SIGCHLD) {
|
|
Packit |
a69f91 |
signal(sig,bottomhalf);
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
/* request rearm */
|
|
Packit |
a69f91 |
rearm_sigchld = TRUE;
|
|
Packit |
a69f91 |
if (rearming_sigchld) sigchld_sleep = TRUE;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
traps[sig].mark = TRUE;
|
|
Packit |
a69f91 |
got_sig = sig; /* just a hint - can be wiped out by another */
|
|
Packit |
a69f91 |
Tcl_AsyncMark(async_handler);
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* if we are called while this particular async is being processed */
|
|
Packit |
a69f91 |
/* original async_proc will turn off "mark" so that when async_proc */
|
|
Packit |
a69f91 |
/* is recalled, it will see that nothing was left to do */
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* In case of SIGCHLD though, we must recall it as many times as
|
|
Packit |
a69f91 |
* we have received it.
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
if (sig == SIGCHLD) {
|
|
Packit |
a69f91 |
sigchld_count++;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
#if 0
|
|
Packit |
a69f91 |
/* if we are doing an i_read, restart it */
|
|
Packit |
a69f91 |
#ifdef HAVE_SIGLONGJMP
|
|
Packit |
a69f91 |
if (env_valid && (sig != 0)) siglongjmp(env,2);
|
|
Packit |
a69f91 |
#else
|
|
Packit |
a69f91 |
if (env_valid && (sig != 0)) longjmp(env,2);
|
|
Packit |
a69f91 |
#endif /* HAVE_SIGLONGJMP */
|
|
Packit |
a69f91 |
#endif /* 0 */
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/*ARGSUSED*/
|
|
Packit |
a69f91 |
void
|
|
Packit |
a69f91 |
exp_rearm_sigchld(interp)
|
|
Packit |
a69f91 |
Tcl_Interp *interp;
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
#ifdef REARM_SIG
|
|
Packit |
a69f91 |
if (rearm_sigchld) {
|
|
Packit |
a69f91 |
rearm_sigchld = FALSE;
|
|
Packit |
a69f91 |
rearming_sigchld = TRUE;
|
|
Packit |
a69f91 |
signal(SIGCHLD,bottomhalf);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
rearming_sigchld = FALSE;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* if the rearming immediately caused another SIGCHLD, slow down */
|
|
Packit |
a69f91 |
/* It's probably one of Tcl's intermediary pipeline processes that */
|
|
Packit |
a69f91 |
/* Tcl hasn't caught up with yet. */
|
|
Packit |
a69f91 |
if (sigchld_sleep) {
|
|
Packit |
a69f91 |
exp_dsleep(interp,0.2);
|
|
Packit |
a69f91 |
sigchld_sleep = FALSE;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
void
|
|
Packit |
a69f91 |
exp_init_trap()
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
int i;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
for (i=1;i
|
|
Packit |
a69f91 |
traps[i].name = Tcl_SignalId(i);
|
|
Packit |
a69f91 |
traps[i].action = 0;
|
|
Packit |
a69f91 |
traps[i].reserved = FALSE;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/*
|
|
Packit |
a69f91 |
* fix up any special cases
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
#if defined(SIGCLD)
|
|
Packit |
a69f91 |
/* Tcl names it SIGCLD, not good for portable scripts */
|
|
Packit |
a69f91 |
traps[SIGCLD].name = "SIGCHLD";
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
#if defined(SIGALRM)
|
|
Packit |
a69f91 |
traps[SIGALRM].reserved = TRUE;
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
#if defined(SIGKILL)
|
|
Packit |
a69f91 |
traps[SIGKILL].reserved = TRUE;
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
#if defined(SIGSTOP)
|
|
Packit |
a69f91 |
traps[SIGSTOP].reserved = TRUE;
|
|
Packit |
a69f91 |
#endif
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
async_handler = Tcl_AsyncCreate(tophalf,(ClientData)0);
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* given signal index or name as string, */
|
|
Packit |
a69f91 |
/* returns signal index or -1 if bad arg */
|
|
Packit |
a69f91 |
int
|
|
Packit |
a69f91 |
exp_string_to_signal(interp,s)
|
|
Packit |
a69f91 |
Tcl_Interp *interp;
|
|
Packit |
a69f91 |
char *s;
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
int sig;
|
|
Packit |
a69f91 |
CONST char *name;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* try interpreting as an integer */
|
|
Packit |
a69f91 |
if (1 == sscanf(s,"%d",&sig)) {
|
|
Packit |
a69f91 |
if (sig > 0 && sig < NSIG) return sig;
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
/* try interpreting as a string */
|
|
Packit |
a69f91 |
for (sig=1;sig
|
|
Packit |
a69f91 |
name = traps[sig].name;
|
|
Packit |
a69f91 |
if (streq(s,name) || streq(s,name+3)) return(sig);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
exp_error(interp,"invalid signal %s",s);
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
return -1;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/*ARGSUSED*/
|
|
Packit |
a69f91 |
int
|
|
Packit |
a69f91 |
Exp_TrapObjCmd(clientData, interp, objc, objv)
|
|
Packit |
a69f91 |
ClientData clientData;
|
|
Packit |
a69f91 |
Tcl_Interp *interp;
|
|
Packit |
a69f91 |
int objc;
|
|
Packit |
a69f91 |
Tcl_Obj *CONST objv[];
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
char *action = 0;
|
|
Packit |
a69f91 |
int n; /* number of signals in list */
|
|
Packit |
a69f91 |
Tcl_Obj **list; /* list of signals */
|
|
Packit |
a69f91 |
char *arg;
|
|
Packit |
a69f91 |
int len; /* length of action */
|
|
Packit |
a69f91 |
int i;
|
|
Packit |
a69f91 |
int show_name = FALSE; /* if user asked for current sig by name */
|
|
Packit |
a69f91 |
int show_number = FALSE;/* if user asked for current sig by number */
|
|
Packit |
a69f91 |
int show_max = FALSE; /* if user asked for NSIG-1 */
|
|
Packit |
a69f91 |
int rc = TCL_OK;
|
|
Packit |
a69f91 |
int new_code = FALSE; /* if action result should overwrite orig */
|
|
Packit |
a69f91 |
Tcl_Interp *new_interp = interp;/* interp in which to evaluate */
|
|
Packit |
a69f91 |
/* action when signal occurs */
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
objc--; objv++;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
while (objc) {
|
|
Packit |
a69f91 |
arg = Tcl_GetString(*objv);
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (streq(arg,"-code")) {
|
|
Packit |
a69f91 |
objc--; objv++;
|
|
Packit |
a69f91 |
new_code = TRUE;
|
|
Packit |
a69f91 |
} else if (streq(arg,"-interp")) {
|
|
Packit |
a69f91 |
objc--; objv++;
|
|
Packit |
a69f91 |
new_interp = 0;
|
|
Packit |
a69f91 |
} else if (streq(arg,"-name")) {
|
|
Packit |
a69f91 |
objc--; objv++;
|
|
Packit |
a69f91 |
show_name = TRUE;
|
|
Packit |
a69f91 |
} else if (streq(arg,"-number")) {
|
|
Packit |
a69f91 |
objc--; objv++;
|
|
Packit |
a69f91 |
show_number = TRUE;
|
|
Packit |
a69f91 |
} else if (streq(arg,"-max")) {
|
|
Packit |
a69f91 |
objc--; objv++;
|
|
Packit |
a69f91 |
show_max = TRUE;
|
|
Packit |
a69f91 |
} else break;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (show_name || show_number || show_max) {
|
|
Packit |
a69f91 |
if (objc > 0) goto usage_error;
|
|
Packit |
a69f91 |
if (show_max) {
|
|
Packit |
a69f91 |
Tcl_SetObjResult(interp,Tcl_NewIntObj(NSIG-1));
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (current_sig == NO_SIG) {
|
|
Packit |
a69f91 |
Tcl_SetResult(interp,"no signal in progress",TCL_STATIC);
|
|
Packit |
a69f91 |
return TCL_ERROR;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
if (show_name) {
|
|
Packit |
a69f91 |
/* skip over "SIG" */
|
|
Packit |
a69f91 |
/* TIP 27: Casting away the CONST should be ok because of TCL_STATIC
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
Tcl_SetResult(interp,(char*)signal_to_string(current_sig) + 3,TCL_STATIC);
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
Tcl_SetObjResult(interp,Tcl_NewIntObj(current_sig));
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
return TCL_OK;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (objc == 0 || objc > 2) goto usage_error;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (objc == 1) {
|
|
Packit |
a69f91 |
int sig = exp_string_to_signal(interp,arg);
|
|
Packit |
a69f91 |
if (sig == -1) return TCL_ERROR;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (traps[sig].action) {
|
|
Packit |
a69f91 |
Tcl_SetResult(interp,traps[sig].action,TCL_STATIC);
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
Tcl_SetResult(interp,"SIG_DFL",TCL_STATIC);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
return TCL_OK;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
action = arg;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* objv[1] is the list of signals - crack it open */
|
|
Packit |
a69f91 |
if (TCL_OK != Tcl_ListObjGetElements(interp,objv[1],&n,&list)) {
|
|
Packit |
a69f91 |
return TCL_ERROR;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
for (i=0;i
|
|
Packit |
a69f91 |
char *s;
|
|
Packit |
a69f91 |
int sig;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
s = Tcl_GetString(list[i]);
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
sig = exp_string_to_signal(interp,s);
|
|
Packit |
a69f91 |
if (sig == -1) {
|
|
Packit |
a69f91 |
rc = TCL_ERROR;
|
|
Packit |
a69f91 |
break;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (traps[sig].reserved) {
|
|
Packit |
a69f91 |
exp_error(interp,"cannot trap %s",signal_to_string(sig));
|
|
Packit |
a69f91 |
rc = TCL_ERROR;
|
|
Packit |
a69f91 |
break;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
expDiagLog("trap: setting up signal %d (\"%s\")\r\n",sig,s);
|
|
Packit |
a69f91 |
if (traps[sig].action) ckfree(traps[sig].action);
|
|
Packit |
a69f91 |
if (streq(action,"SIG_DFL")) {
|
|
Packit |
a69f91 |
/* should've been free'd by now if nec. */
|
|
Packit |
a69f91 |
traps[sig].action = 0;
|
|
Packit |
a69f91 |
signal(sig,SIG_DFL);
|
|
Packit |
a69f91 |
#ifdef REARM_SIG
|
|
Packit |
a69f91 |
if (sig == SIGCHLD)
|
|
Packit |
a69f91 |
rearm_sigchld = FALSE;
|
|
Packit |
a69f91 |
#endif /*REARM_SIG*/
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
len = 1 + strlen(action);
|
|
Packit |
a69f91 |
traps[sig].action = ckalloc(len);
|
|
Packit |
a69f91 |
memcpy(traps[sig].action,action,len);
|
|
Packit |
a69f91 |
traps[sig].interp = new_interp;
|
|
Packit |
a69f91 |
traps[sig].code = new_code;
|
|
Packit |
a69f91 |
if (streq(action,"SIG_IGN")) {
|
|
Packit |
a69f91 |
signal(sig,SIG_IGN);
|
|
Packit |
a69f91 |
} else signal(sig,bottomhalf);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
/* It is no longer necessary to free the split list since it */
|
|
Packit |
a69f91 |
/* is still owned by Tcl, yes? */
|
|
Packit |
a69f91 |
/* ckfree((char *)list); */
|
|
Packit |
a69f91 |
return(rc);
|
|
Packit |
a69f91 |
usage_error:
|
|
Packit |
a69f91 |
exp_error(interp,"usage: trap [command or SIG_DFL or SIG_IGN] {list of signals}");
|
|
Packit |
a69f91 |
return TCL_ERROR;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* called by tophalf() to process the given signal */
|
|
Packit |
a69f91 |
static int
|
|
Packit |
a69f91 |
eval_trap_action(interp,sig,trap,oldcode)
|
|
Packit |
a69f91 |
Tcl_Interp *interp;
|
|
Packit |
a69f91 |
int sig;
|
|
Packit |
a69f91 |
struct trap *trap;
|
|
Packit |
a69f91 |
int oldcode;
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
int code_flag;
|
|
Packit |
a69f91 |
int newcode;
|
|
Packit |
a69f91 |
Tcl_Obj *eip; /* errorInfo */
|
|
Packit |
a69f91 |
Tcl_Obj *ecp; /* errorCode */
|
|
Packit |
a69f91 |
Tcl_Obj *irp; /* interp's result */
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
expDiagLogU("async event handler: Tcl_Eval(");
|
|
Packit |
a69f91 |
expDiagLogU(trap->action);
|
|
Packit |
a69f91 |
expDiagLogU(")\r\n");
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* save to prevent user from redefining trap->code while trap */
|
|
Packit |
a69f91 |
/* is executing */
|
|
Packit |
a69f91 |
code_flag = trap->code;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (!code_flag) {
|
|
Packit |
a69f91 |
/*
|
|
Packit |
a69f91 |
* save return values
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
eip = Tcl_GetVar2Ex(interp,"errorInfo","",TCL_GLOBAL_ONLY);
|
|
Packit |
a69f91 |
if (eip) eip = Tcl_DuplicateObj(eip);
|
|
Packit |
a69f91 |
ecp = Tcl_GetVar2Ex(interp,"errorCode","",TCL_GLOBAL_ONLY);
|
|
Packit |
a69f91 |
if (ecp) ecp = Tcl_DuplicateObj(ecp);
|
|
Packit |
a69f91 |
irp = Tcl_GetObjResult(interp);
|
|
Packit |
a69f91 |
if (irp) irp = Tcl_DuplicateObj(irp);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
newcode = Tcl_GlobalEval(interp,trap->action);
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/*
|
|
Packit |
a69f91 |
* if new code is to be ignored (usual case - see "else" below)
|
|
Packit |
a69f91 |
* allow only OK/RETURN from trap, otherwise complain
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (code_flag) {
|
|
Packit |
a69f91 |
expDiagLog("return value = %d for trap %s, action ",newcode,signal_to_string(sig));
|
|
Packit |
a69f91 |
expDiagLogU(trap->action);
|
|
Packit |
a69f91 |
expDiagLogU("\r\n");
|
|
Packit |
a69f91 |
if (0 != strcmp(Tcl_GetStringResult(interp),"")) {
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/*
|
|
Packit |
a69f91 |
* Check errorinfo and see if it contains -nostack.
|
|
Packit |
a69f91 |
* This shouldn't be necessary, but John changed the
|
|
Packit |
a69f91 |
* top level interp so that it distorts arbitrary
|
|
Packit |
a69f91 |
* return values into TCL_ERROR, so by the time we
|
|
Packit |
a69f91 |
* get back, we'll have lost the value of errorInfo
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
eip = Tcl_GetVar2Ex(interp,"errorInfo","",TCL_GLOBAL_ONLY);
|
|
Packit |
a69f91 |
if (eip) {
|
|
Packit |
a69f91 |
exp_nostack_dump = (0 == strncmp("-nostack",Tcl_GetString(eip),8));
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
} else if (newcode != TCL_OK && newcode != TCL_RETURN) {
|
|
Packit |
a69f91 |
if (newcode != TCL_ERROR) {
|
|
Packit |
a69f91 |
exp_error(interp,"return value = %d for trap %s, action %s\r\n",newcode,signal_to_string(sig),trap->action);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
Tcl_BackgroundError(interp);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (!code_flag) {
|
|
Packit |
a69f91 |
/*
|
|
Packit |
a69f91 |
* restore values
|
|
Packit |
a69f91 |
*/
|
|
Packit |
a69f91 |
Tcl_ResetResult(interp); /* turns off Tcl's internal */
|
|
Packit |
a69f91 |
/* flags: ERR_IN_PROGRESS, ERROR_CODE_SET */
|
|
Packit |
a69f91 |
/* This also wipes clean errorInfo/Code/result which is why */
|
|
Packit |
a69f91 |
/* all the calls to Tcl_Dup earlier */
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
if (eip) {
|
|
Packit |
a69f91 |
/* odd that Tcl doesn't have a call that does all this at once */
|
|
Packit |
a69f91 |
int len;
|
|
Packit |
a69f91 |
char *s = Tcl_GetStringFromObj(eip,&len;;
|
|
Packit |
a69f91 |
Tcl_AddObjErrorInfo(interp,s,len);
|
|
Packit |
a69f91 |
Tcl_DecrRefCount(eip);
|
|
Packit |
a69f91 |
/* we never incr'd it, but the code allows this */
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
Tcl_UnsetVar(interp,"errorInfo",0);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* restore errorCode. Note that Tcl_AddErrorInfo (above) */
|
|
Packit |
a69f91 |
/* resets it to NONE. If the previous value is NONE, it's */
|
|
Packit |
a69f91 |
/* important to avoid calling Tcl_SetErrorCode since this */
|
|
Packit |
a69f91 |
/* with cause Tcl to set its internal ERROR_CODE_SET flag. */
|
|
Packit |
a69f91 |
if (ecp) {
|
|
Packit |
a69f91 |
if (!streq("NONE",Tcl_GetString(ecp)))
|
|
Packit |
a69f91 |
Tcl_SetErrorCode(interp,ecp);
|
|
Packit |
a69f91 |
/* we're just passing on the errorcode obj */
|
|
Packit |
a69f91 |
/* presumably, Tcl will incr ref count */
|
|
Packit |
a69f91 |
} else {
|
|
Packit |
a69f91 |
Tcl_UnsetVar(interp,"errorCode",0);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
newcode = oldcode;
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
/* note that since newcode gets overwritten here by old code */
|
|
Packit |
a69f91 |
/* it is possible to return in the middle of a trap by using */
|
|
Packit |
a69f91 |
/* "return" (or "continue" for that matter)! */
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
return newcode;
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
static struct exp_cmd_data
|
|
Packit |
a69f91 |
cmd_data[] = {
|
|
Packit |
a69f91 |
{"trap", Exp_TrapObjCmd, 0, (ClientData)EXP_SPAWN_ID_BAD, 0},
|
|
Packit |
a69f91 |
{0}};
|
|
Packit |
a69f91 |
|
|
Packit |
a69f91 |
void
|
|
Packit |
a69f91 |
exp_init_trap_cmds(interp)
|
|
Packit |
a69f91 |
Tcl_Interp *interp;
|
|
Packit |
a69f91 |
{
|
|
Packit |
a69f91 |
exp_create_commands(interp,cmd_data);
|
|
Packit |
a69f91 |
}
|
|
Packit |
a69f91 |
|