mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 13:33:52 +01:00
749 lines
18 KiB
C
749 lines
18 KiB
C
/*
|
|
* signals.c - signals handling code
|
|
*
|
|
* This file is part of zsh, the Z shell.
|
|
*
|
|
* Copyright (c) 1992-1997 Paul Falstad
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
* software and to distribute modified versions of this software for any
|
|
* purpose, provided that the above copyright notice and the following
|
|
* two paragraphs appear in all copies of this software.
|
|
*
|
|
* In no event shall Paul Falstad or the Zsh Development Group be liable
|
|
* to any party for direct, indirect, special, incidental, or consequential
|
|
* damages arising out of the use of this software and its documentation,
|
|
* even if Paul Falstad and the Zsh Development Group have been advised of
|
|
* the possibility of such damage.
|
|
*
|
|
* Paul Falstad and the Zsh Development Group specifically disclaim any
|
|
* warranties, including, but not limited to, the implied warranties of
|
|
* merchantability and fitness for a particular purpose. The software
|
|
* provided hereunder is on an "as is" basis, and Paul Falstad and the
|
|
* Zsh Development Group have no obligation to provide maintenance,
|
|
* support, updates, enhancements, or modifications.
|
|
*
|
|
*/
|
|
|
|
#include "zsh.mdh"
|
|
#include "signals.pro"
|
|
|
|
/* Array describing the state of each signal: an element contains *
|
|
* 0 for the default action or some ZSIG_* flags ored together. */
|
|
|
|
/**/
|
|
int sigtrapped[VSIGCOUNT];
|
|
|
|
/* trap functions for each signal */
|
|
|
|
/**/
|
|
List sigfuncs[VSIGCOUNT];
|
|
|
|
/* Variables used by signal queueing */
|
|
|
|
/**/
|
|
int queueing_enabled, queue_front, queue_rear;
|
|
/**/
|
|
int signal_queue[MAX_QUEUE_SIZE];
|
|
/**/
|
|
sigset_t signal_mask_queue[MAX_QUEUE_SIZE];
|
|
|
|
/* This is only used on machines that don't understand signal sets. *
|
|
* On SYSV machines this will represent the signals that are blocked *
|
|
* (held) using sighold. On machines which can't block signals at *
|
|
* all, we will simulate this by ignoring them and remembering them *
|
|
* in this variable. */
|
|
#if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS)
|
|
static sigset_t blocked_set;
|
|
#endif
|
|
|
|
#ifdef POSIX_SIGNALS
|
|
# define signal_jmp_buf sigjmp_buf
|
|
# define signal_setjmp(b) sigsetjmp((b),1)
|
|
# define signal_longjmp(b,n) siglongjmp((b),(n))
|
|
#else
|
|
# define signal_jmp_buf jmp_buf
|
|
# define signal_setjmp(b) setjmp(b)
|
|
# define signal_longjmp(b,n) longjmp((b),(n))
|
|
#endif
|
|
|
|
#ifdef NO_SIGNAL_BLOCKING
|
|
# define signal_process(sig) signal_ignore(sig)
|
|
# define signal_reset(sig) install_handler(sig)
|
|
#else
|
|
# define signal_process(sig) ;
|
|
# define signal_reset(sig) ;
|
|
#endif
|
|
|
|
/* Install signal handler for given signal. *
|
|
* If possible, we want to make sure that interrupted *
|
|
* system calls are not restarted. */
|
|
|
|
/**/
|
|
void
|
|
install_handler(int sig)
|
|
{
|
|
#ifdef POSIX_SIGNALS
|
|
struct sigaction act;
|
|
|
|
act.sa_handler = (SIGNAL_HANDTYPE) handler;
|
|
sigemptyset(&act.sa_mask); /* only block sig while in handler */
|
|
act.sa_flags = 0;
|
|
# ifdef SA_INTERRUPT /* SunOS 4.x */
|
|
if (interact)
|
|
act.sa_flags |= SA_INTERRUPT; /* make sure system calls are not restarted */
|
|
# endif
|
|
sigaction(sig, &act, (struct sigaction *)NULL);
|
|
#else
|
|
# ifdef BSD_SIGNALS
|
|
struct sigvec vec;
|
|
|
|
vec.sv_handler = (SIGNAL_HANDTYPE) handler;
|
|
vec.sv_mask = sigmask(sig); /* mask out this signal while in handler */
|
|
# ifdef SV_INTERRUPT
|
|
vec.sv_flags = SV_INTERRUPT; /* make sure system calls are not restarted */
|
|
# endif
|
|
sigvec(sig, &vec, (struct sigvec *)NULL);
|
|
# else
|
|
# ifdef SYSV_SIGNALS
|
|
/* we want sigset rather than signal because it will *
|
|
* block sig while in handler. signal usually doesn't */
|
|
sigset(sig, handler);
|
|
# else /* NO_SIGNAL_BLOCKING (bummer) */
|
|
signal(sig, handler);
|
|
|
|
# endif /* SYSV_SIGNALS */
|
|
# endif /* BSD_SIGNALS */
|
|
#endif /* POSIX_SIGNALS */
|
|
}
|
|
|
|
/* enable ^C interrupts */
|
|
|
|
/**/
|
|
void
|
|
intr(void)
|
|
{
|
|
if (interact)
|
|
install_handler(SIGINT);
|
|
}
|
|
|
|
#if 0
|
|
/* disable ^C interrupts */
|
|
|
|
/**/
|
|
void
|
|
nointr(void)
|
|
{
|
|
if (interact)
|
|
signal_ignore(SIGINT);
|
|
}
|
|
#endif
|
|
|
|
/* temporarily block ^C interrupts */
|
|
|
|
/**/
|
|
void
|
|
holdintr(void)
|
|
{
|
|
if (interact)
|
|
signal_block(signal_mask(SIGINT));
|
|
}
|
|
|
|
/* release ^C interrupts */
|
|
|
|
/**/
|
|
void
|
|
noholdintr(void)
|
|
{
|
|
if (interact)
|
|
signal_unblock(signal_mask(SIGINT));
|
|
}
|
|
|
|
/* create a signal mask containing *
|
|
* only the given signal */
|
|
|
|
/**/
|
|
sigset_t
|
|
signal_mask(int sig)
|
|
{
|
|
sigset_t set;
|
|
|
|
sigemptyset(&set);
|
|
if (sig)
|
|
sigaddset(&set, sig);
|
|
return set;
|
|
}
|
|
|
|
/* Block the signals in the given signal *
|
|
* set. Return the old signal set. */
|
|
|
|
/**/
|
|
sigset_t
|
|
signal_block(sigset_t set)
|
|
{
|
|
sigset_t oset;
|
|
|
|
#ifdef POSIX_SIGNALS
|
|
sigprocmask(SIG_BLOCK, &set, &oset);
|
|
#else
|
|
# ifdef BSD_SIGNALS
|
|
oset = sigblock(set);
|
|
# else
|
|
# ifdef SYSV_SIGNALS
|
|
int i;
|
|
|
|
oset = blocked_set;
|
|
for (i = 1; i <= NSIG; ++i) {
|
|
if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
|
|
sigaddset(&blocked_set, i);
|
|
sighold(i);
|
|
}
|
|
}
|
|
# else /* NO_SIGNAL_BLOCKING */
|
|
/* We will just ignore signals if the system doesn't have *
|
|
* the ability to block them. */
|
|
int i;
|
|
|
|
oset = blocked_set;
|
|
for (i = 1; i <= NSIG; ++i) {
|
|
if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
|
|
sigaddset(&blocked_set, i);
|
|
signal_ignore(i);
|
|
}
|
|
}
|
|
# endif /* SYSV_SIGNALS */
|
|
# endif /* BSD_SIGNALS */
|
|
#endif /* POSIX_SIGNALS */
|
|
|
|
return oset;
|
|
}
|
|
|
|
/* Unblock the signals in the given signal *
|
|
* set. Return the old signal set. */
|
|
|
|
/**/
|
|
sigset_t
|
|
signal_unblock(sigset_t set)
|
|
{
|
|
sigset_t oset;
|
|
|
|
#ifdef POSIX_SIGNALS
|
|
sigprocmask(SIG_UNBLOCK, &set, &oset);
|
|
#else
|
|
# ifdef BSD_SIGNALS
|
|
sigfillset(&oset);
|
|
oset = sigsetmask(oset);
|
|
sigsetmask(oset & ~set);
|
|
# else
|
|
# ifdef SYSV_SIGNALS
|
|
int i;
|
|
|
|
oset = blocked_set;
|
|
for (i = 1; i <= NSIG; ++i) {
|
|
if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
|
|
sigdelset(&blocked_set, i);
|
|
sigrelse(i);
|
|
}
|
|
}
|
|
# else /* NO_SIGNAL_BLOCKING */
|
|
/* On systems that can't block signals, we are just ignoring them. So *
|
|
* to unblock signals, we just reenable the signal handler for them. */
|
|
int i;
|
|
|
|
oset = blocked_set;
|
|
for (i = 1; i <= NSIG; ++i) {
|
|
if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
|
|
sigdelset(&blocked_set, i);
|
|
install_handler(i);
|
|
}
|
|
}
|
|
# endif /* SYSV_SIGNALS */
|
|
# endif /* BSD_SIGNALS */
|
|
#endif /* POSIX_SIGNALS */
|
|
|
|
return oset;
|
|
}
|
|
|
|
/* set the process signal mask to *
|
|
* be the given signal mask */
|
|
|
|
/**/
|
|
sigset_t
|
|
signal_setmask(sigset_t set)
|
|
{
|
|
sigset_t oset;
|
|
|
|
#ifdef POSIX_SIGNALS
|
|
sigprocmask(SIG_SETMASK, &set, &oset);
|
|
#else
|
|
# ifdef BSD_SIGNALS
|
|
oset = sigsetmask(set);
|
|
# else
|
|
# ifdef SYSV_SIGNALS
|
|
int i;
|
|
|
|
oset = blocked_set;
|
|
for (i = 1; i <= NSIG; ++i) {
|
|
if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
|
|
sigaddset(&blocked_set, i);
|
|
sighold(i);
|
|
} else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
|
|
sigdelset(&blocked_set, i);
|
|
sigrelse(i);
|
|
}
|
|
}
|
|
# else /* NO_SIGNAL_BLOCKING */
|
|
int i;
|
|
|
|
oset = blocked_set;
|
|
for (i = 1; i < NSIG; ++i) {
|
|
if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
|
|
sigaddset(&blocked_set, i);
|
|
signal_ignore(i);
|
|
} else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
|
|
sigdelset(&blocked_set, i);
|
|
install_handler(i);
|
|
}
|
|
}
|
|
# endif /* SYSV_SIGNALS */
|
|
# endif /* BSD_SIGNALS */
|
|
#endif /* POSIX_SIGNALS */
|
|
|
|
return oset;
|
|
}
|
|
|
|
#if defined(NO_SIGNAL_BLOCKING)
|
|
static int suspend_longjmp = 0;
|
|
static signal_jmp_buf suspend_jmp_buf;
|
|
#endif
|
|
|
|
/**/
|
|
int
|
|
signal_suspend(int sig, int sig2)
|
|
{
|
|
int ret;
|
|
|
|
#ifdef POSIX_SIGNALS
|
|
sigset_t set;
|
|
|
|
sigfillset(&set);
|
|
sigdelset(&set, sig);
|
|
sigdelset(&set, SIGHUP); /* still don't know why we add this? */
|
|
if (sig2)
|
|
sigdelset(&set, sig2);
|
|
ret = sigsuspend(&set);
|
|
#else
|
|
# ifdef BSD_SIGNALS
|
|
sigset_t set;
|
|
|
|
sigfillset(&set);
|
|
sigdelset(&set, sig);
|
|
if (sig2)
|
|
sigdelset(&set, sig2);
|
|
ret = sigpause(set);
|
|
# else
|
|
# ifdef SYSV_SIGNALS
|
|
ret = sigpause(sig);
|
|
|
|
# else /* NO_SIGNAL_BLOCKING */
|
|
/* need to use signal_longjmp to make this race-free *
|
|
* between the child_unblock() and pause() */
|
|
if (signal_setjmp(suspend_jmp_buf) == 0) {
|
|
suspend_longjmp = 1; /* we want to signal_longjmp after catching signal */
|
|
child_unblock(); /* do we need to unblock sig2 as well? */
|
|
ret = pause();
|
|
}
|
|
suspend_longjmp = 0; /* turn off using signal_longjmp since we are past *
|
|
* the pause() function. */
|
|
# endif /* SYSV_SIGNALS */
|
|
# endif /* BSD_SIGNALS */
|
|
#endif /* POSIX_SIGNALS */
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* What flavor of waitpid/wait3/wait shall we use? */
|
|
|
|
#ifdef HAVE_WAITPID
|
|
# define WAIT(pid, statusp, options) waitpid(pid, statusp, options)
|
|
#else
|
|
# ifdef HAVE_WAIT3
|
|
# define WAIT(pid, statusp, options) wait3((void *) statusp, options, NULL)
|
|
# else
|
|
# define WAIT(pid, statusp, options) wait(statusp)
|
|
# endif
|
|
#endif
|
|
|
|
/* the signal handler */
|
|
|
|
/**/
|
|
RETSIGTYPE
|
|
handler(int sig)
|
|
{
|
|
sigset_t newmask, oldmask;
|
|
|
|
#if defined(NO_SIGNAL_BLOCKING)
|
|
int do_jump;
|
|
signal_jmp_buf jump_to;
|
|
#endif
|
|
|
|
signal_process(sig);
|
|
|
|
sigfillset(&newmask);
|
|
oldmask = signal_block(newmask); /* Block all signals temporarily */
|
|
|
|
#if defined(NO_SIGNAL_BLOCKING)
|
|
do_jump = suspend_longjmp; /* do we need to longjmp to signal_suspend */
|
|
suspend_longjmp = 0; /* In case a SIGCHLD somehow arrives */
|
|
|
|
if (sig == SIGCHLD) { /* Traps can cause nested child_suspend() */
|
|
if (do_jump)
|
|
jump_to = suspend_jmp_buf; /* Copy suspend_jmp_buf */
|
|
}
|
|
#endif
|
|
|
|
if (queueing_enabled) { /* Are we queueing signals now? */
|
|
int temp_rear = ++queue_rear % MAX_QUEUE_SIZE;
|
|
|
|
DPUTS(temp_rear == queue_front, "BUG: signal queue full");
|
|
if (temp_rear != queue_front) { /* Make sure it's not full (extremely unlikely) */
|
|
queue_rear = temp_rear; /* ok, not full, so add to queue */
|
|
signal_queue[queue_rear] = sig; /* save signal caught */
|
|
signal_mask_queue[queue_rear] = oldmask; /* save current signal mask */
|
|
}
|
|
signal_reset(sig);
|
|
return;
|
|
}
|
|
|
|
signal_setmask(oldmask); /* Reset signal mask, signal traps ok now */
|
|
|
|
switch (sig) {
|
|
case SIGCHLD:
|
|
|
|
/* keep WAITING until no more child processes to reap */
|
|
for (;;)
|
|
cont: {
|
|
int old_errno = errno; /* save the errno, since WAIT may change it */
|
|
int status;
|
|
Job jn;
|
|
Process pn;
|
|
pid_t pid;
|
|
pid_t *procsubpid = &cmdoutpid;
|
|
int *procsubval = &cmdoutval;
|
|
struct execstack *es = exstack;
|
|
|
|
pid = WAIT(-1, &status, WNOHANG|WUNTRACED); /* reap the child process */
|
|
|
|
if (!pid) /* no more children to reap */
|
|
break;
|
|
|
|
/* check if child returned was from process substitution */
|
|
for (;;) {
|
|
if (pid == *procsubpid) {
|
|
*procsubpid = 0;
|
|
if (WIFSIGNALED(status))
|
|
*procsubval = (0200 | WTERMSIG(status));
|
|
else
|
|
*procsubval = WEXITSTATUS(status);
|
|
times(&shtms);
|
|
goto cont;
|
|
}
|
|
if (!es)
|
|
break;
|
|
procsubpid = &es->cmdoutpid;
|
|
procsubval = &es->cmdoutval;
|
|
es = es->next;
|
|
}
|
|
|
|
/* check for WAIT error */
|
|
if (pid == -1) {
|
|
if (errno != ECHILD)
|
|
zerr("wait failed: %e", NULL, errno);
|
|
errno = old_errno; /* WAIT changed errno, so restore the original */
|
|
break;
|
|
}
|
|
|
|
/* Find the process and job containing this pid and update it. */
|
|
if (findproc(pid, &jn, &pn)) {
|
|
update_process(pn, status);
|
|
update_job(jn);
|
|
} else {
|
|
/* If not found, update the shell record of time spent by
|
|
* children in sub processes anyway: otherwise, this
|
|
* will get added on to the next found process that terminates.
|
|
*/
|
|
times(&shtms);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SIGHUP:
|
|
if (sigtrapped[SIGHUP])
|
|
dotrap(SIGHUP);
|
|
else {
|
|
stopmsg = 1;
|
|
zexit(SIGHUP, 1);
|
|
}
|
|
break;
|
|
|
|
case SIGINT:
|
|
if (sigtrapped[SIGINT])
|
|
dotrap(SIGINT);
|
|
else {
|
|
if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
|
|
isset(INTERACTIVE) && noerrexit < 0)
|
|
zexit(SIGINT, 1);
|
|
if (list_pipe || chline || simple_pline) {
|
|
breaks = loops;
|
|
errflag = 1;
|
|
inerrflush();
|
|
}
|
|
}
|
|
break;
|
|
|
|
#ifdef SIGWINCH
|
|
case SIGWINCH:
|
|
adjustwinsize(); /* check window size and adjust */
|
|
if (sigtrapped[SIGWINCH])
|
|
dotrap(SIGWINCH);
|
|
break;
|
|
#endif
|
|
|
|
case SIGALRM:
|
|
if (sigtrapped[SIGALRM]) {
|
|
int tmout;
|
|
dotrap(SIGALRM);
|
|
if ((tmout = getiparam("TMOUT")))
|
|
alarm(tmout); /* reset the alarm */
|
|
} else {
|
|
int idle = ttyidlegetfn(NULL);
|
|
int tmout = getiparam("TMOUT");
|
|
if (idle >= 0 && idle < tmout)
|
|
alarm(tmout - idle);
|
|
else {
|
|
errflag = noerrs = 0;
|
|
zerr("timeout", NULL, 0);
|
|
errflag = 0;
|
|
stopmsg = 1;
|
|
zexit(SIGALRM, 1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dotrap(sig);
|
|
break;
|
|
} /* end of switch(sig) */
|
|
|
|
signal_reset(sig);
|
|
|
|
/* This is used to make signal_suspend() race-free */
|
|
#if defined(NO_SIGNAL_BLOCKING)
|
|
if (do_jump)
|
|
signal_longjmp(jump_to, 1);
|
|
#endif
|
|
|
|
} /* handler */
|
|
|
|
|
|
/* SIGHUP any jobs left running */
|
|
|
|
/**/
|
|
void
|
|
killrunjobs(int from_signal)
|
|
{
|
|
int i, killed = 0;
|
|
|
|
if (unset(HUP))
|
|
return;
|
|
for (i = 1; i < MAXJOB; i++)
|
|
if ((from_signal || i != thisjob) && (jobtab[i].stat & STAT_LOCKED) &&
|
|
!(jobtab[i].stat & STAT_NOPRINT) &&
|
|
!(jobtab[i].stat & STAT_STOPPED)) {
|
|
if (killpg(jobtab[i].gleader, SIGHUP) != -1)
|
|
killed++;
|
|
}
|
|
if (killed)
|
|
zerr("warning: %d jobs SIGHUPed", NULL, killed);
|
|
}
|
|
|
|
|
|
/* send a signal to a job (simply involves kill if monitoring is on) */
|
|
|
|
/**/
|
|
int
|
|
killjb(Job jn, int sig)
|
|
{
|
|
Process pn;
|
|
int err = 0;
|
|
|
|
if (jobbing) {
|
|
if (jn->stat & STAT_SUPERJOB) {
|
|
if (sig == SIGCONT) {
|
|
for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
|
|
kill(pn->pid, sig);
|
|
|
|
for (pn = jn->procs; pn->next; pn = pn->next)
|
|
err = kill(pn->pid, sig);
|
|
|
|
return err;
|
|
}
|
|
|
|
killpg(jobtab[jn->other].gleader, sig);
|
|
return killpg(jn->gleader, sig);
|
|
}
|
|
else
|
|
return (killpg(jn->gleader, sig));
|
|
}
|
|
for (pn = jn->procs; pn; pn = pn->next)
|
|
if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH)
|
|
return -1;
|
|
return err;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
settrap(int sig, List l)
|
|
{
|
|
if (sig == -1)
|
|
return 1;
|
|
if (jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN)) {
|
|
zerr("can't trap SIG%s in interactive shells", sigs[sig], 0);
|
|
return 1;
|
|
}
|
|
if (sigfuncs[sig])
|
|
unsettrap(sig);
|
|
sigfuncs[sig] = l;
|
|
if (!l) {
|
|
sigtrapped[sig] = ZSIG_IGNORED;
|
|
if (sig && sig <= SIGCOUNT &&
|
|
#ifdef SIGWINCH
|
|
sig != SIGWINCH &&
|
|
#endif
|
|
sig != SIGCHLD)
|
|
signal_ignore(sig);
|
|
} else {
|
|
sigtrapped[sig] = ZSIG_TRAPPED;
|
|
if (sig && sig <= SIGCOUNT &&
|
|
#ifdef SIGWINCH
|
|
sig != SIGWINCH &&
|
|
#endif
|
|
sig != SIGCHLD)
|
|
install_handler(sig);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
void
|
|
unsettrap(int sig)
|
|
{
|
|
int trapped;
|
|
|
|
if (sig == -1 || !(trapped = sigtrapped[sig]) ||
|
|
(jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN))) {
|
|
return;
|
|
}
|
|
sigtrapped[sig] = 0;
|
|
if (sig == SIGINT && interact) {
|
|
/* PWS 1995/05/16: added test for interactive, also noholdintr() *
|
|
* as subshells ignoring SIGINT have it blocked from delivery */
|
|
intr();
|
|
noholdintr();
|
|
} else if (sig == SIGHUP)
|
|
install_handler(sig);
|
|
else if (sig && sig <= SIGCOUNT &&
|
|
#ifdef SIGWINCH
|
|
sig != SIGWINCH &&
|
|
#endif
|
|
sig != SIGCHLD)
|
|
signal_default(sig);
|
|
if (trapped & ZSIG_FUNC) {
|
|
char func[20];
|
|
HashNode hn;
|
|
|
|
sprintf(func, "TRAP%s", sigs[sig]);
|
|
if ((hn = shfunctab->removenode(shfunctab, func)))
|
|
shfunctab->freenode(hn);
|
|
} else if (sigfuncs[sig]) {
|
|
freestruct(sigfuncs[sig]);
|
|
sigfuncs[sig] = NULL;
|
|
}
|
|
}
|
|
|
|
/* Execute a trap function for a given signal, possibly
|
|
* with non-standard sigtrapped & sigfuncs values
|
|
*/
|
|
|
|
/**/
|
|
void
|
|
dotrapargs(int sig, int *sigtr, void *sigfn)
|
|
{
|
|
LinkList args;
|
|
char *name, num[4];
|
|
int trapret = 0;
|
|
int obreaks = breaks;
|
|
|
|
/* if signal is being ignored or the trap function *
|
|
* is NULL, then return *
|
|
* *
|
|
* Also return if errflag is set. In fact, the code in the *
|
|
* function will test for this, but this way we keep status flags *
|
|
* intact without working too hard. Special cases (e.g. calling *
|
|
* a trap for SIGINT after the error flag was set) are handled *
|
|
* by the calling code. (PWS 1995/06/08). */
|
|
if ((*sigtr & ZSIG_IGNORED) || !sigfn || errflag)
|
|
return;
|
|
|
|
*sigtr |= ZSIG_IGNORED;
|
|
|
|
lexsave();
|
|
execsave();
|
|
breaks = 0;
|
|
if (*sigtr & ZSIG_FUNC) {
|
|
PERMALLOC {
|
|
args = newlinklist();
|
|
name = (char *) zalloc(5 + strlen(sigs[sig]));
|
|
sprintf(name, "TRAP%s", sigs[sig]);
|
|
addlinknode(args, name);
|
|
sprintf(num, "%d", sig);
|
|
addlinknode(args, num);
|
|
} LASTALLOC;
|
|
trapreturn = -1;
|
|
doshfunc(sigfn, args, 0, 1);
|
|
freelinklist(args, (FreeFunc) NULL);
|
|
zsfree(name);
|
|
} else HEAPALLOC {
|
|
execlist(dupstruct(sigfn), 1, 0);
|
|
} LASTALLOC;
|
|
if (trapreturn > 0)
|
|
trapret = trapreturn;
|
|
else if (errflag)
|
|
trapret = 1;
|
|
execrestore();
|
|
lexrestore();
|
|
|
|
if (trapret > 0) {
|
|
breaks = loops;
|
|
errflag = 1;
|
|
} else {
|
|
breaks += obreaks;
|
|
if (breaks > loops)
|
|
breaks = loops;
|
|
}
|
|
|
|
if (*sigtr != ZSIG_IGNORED)
|
|
*sigtr &= ~ZSIG_IGNORED;
|
|
}
|
|
|
|
/* Standard call to execute a trap for a given signal */
|
|
|
|
/**/
|
|
void
|
|
dotrap(int sig)
|
|
{
|
|
dotrapargs(sig, sigtrapped+sig, sigfuncs[sig]);
|
|
}
|