|
|
researchv10 Norman
#ident "@(#)sigretro.c 1.3 'attmail mail(1) command'"
#ident "@(#)mailx:sigretro.c 1.6.1.1"
/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)mailx:sigretro.c 1.6"
/*
* mailx -- a modified version of a University of California at Berkeley
* mail program
*/
/*
* This code is only compiled in if SIG_HOLD is not defined!
*
* Retrofit new signal interface to old signal primitives.
* Supported routines:
* sigsys(sig, func)
* sigset(sig, func)
* sighold(sig)
* sigrelse(sig)
* sigignore(sig)
* sigpause(sig)
* Also,
* sigchild()
* to set all held signals to ignored signals in the
* child process after fork(2)
*/
#include <rcv.h> /* find out if we're in USG -- adb */
#include <signal.h>
#ifndef USG
# include <errno.h>
extern int errno;
typedef void (*sigtype)();
#ifndef SIG_HOLD /* adb */
#define SIG_HOLD ((sigtype) 2)
#endif
#ifndef SIG_ERR
# define SIG_ERR ((sigtype) -1)
#endif
sigtype sigdisp(), sighold(), sigignore();
void _Sigtramp();
/*
* The following helps us keep the extended signal semantics together.
* We remember for each signal the address of the function we're
* supposed to call. s_func is SIG_DFL / SIG_IGN if appropriate.
*/
static struct sigtable {
sigtype s_func; /* What to call */
int s_flag; /* Signal flags; see below */
} sigtable[NSIG + 1];
/*
* Signal flag values.
*/
#define SHELD 1 /* Signal is being held */
#define SDEFER 2 /* Signal occured while held */
#define SSET 4 /* s_func is believable */
#define SPAUSE 8 /* are pausing, waiting for sig */
jmp_buf _pause; /* For doing sigpause() */
/*
* Approximate sigsys() system call
* This is almost useless since one only calls sigsys()
* in the child of a fork(). If you have vfork(), you have new signals
* anyway. The real sigsys() does all the stuff needed to support
* the real sigset() library. We don't bother here, assuming that
* you are either ignoring or defaulting a signal in the child.
*/
sigtype
sigsys(sig, func)
sigtype func;
{
sigtype old;
old = sigdisp(sig);
signal(sig, func);
return(old);
}
/*
* Set the (permanent) disposition of a signal.
* If the signal is subsequently (or even now) held,
* the action you set here can be enabled using sigrelse().
*/
sigtype
sigset(sig, func)
sigtype func;
{
sigtype old;
if (sig < 1 || sig > NSIG) {
errno = EINVAL;
return(SIG_ERR);
}
old = sigdisp(sig);
/*
* Does anyone actually call sigset with SIG_HOLD!?
*/
if (func == (void (*)())SIG_HOLD) { /* adb */
sighold(sig);
return(old);
}
sigtable[sig].s_flag |= SSET;
sigtable[sig].s_func = func;
if (func == (void (*)())SIG_DFL) { /* adb */
/*
* If signal has been held, must retain
* the catch so that we can note occurrance
* of signal.
*/
if ((sigtable[sig].s_flag & SHELD) == 0)
signal(sig, SIG_DFL);
else
signal(sig, _Sigtramp);
return(old);
}
if (func == (void (*)())SIG_IGN) { /* adb */
/*
* Clear pending signal
*/
signal(sig, SIG_IGN);
sigtable[sig].s_flag &= ~SDEFER;
return(old);
}
signal(sig, _Sigtramp);
return(old);
}
/*
* Hold a signal.
* This CAN be tricky if the signal's disposition is SIG_DFL.
* In that case, we still catch the signal so we can note it
*/
sigtype
sighold(sig)
{
sigtype old;
if (sig < 1 || sig > NSIG) {
errno = EINVAL;
return(SIG_ERR);
}
old = sigdisp(sig);
if (sigtable[sig].s_flag & SHELD)
return(old);
/*
* When the default action is required, we have to
* set up to catch the signal to note signal's occurrance.
*/
if (old == (void (*)())SIG_DFL) { /* adb */
sigtable[sig].s_flag |= SSET;
signal(sig, _Sigtramp);
}
sigtable[sig].s_flag |= SHELD;
return(old);
}
/*
* Release a signal
* If the signal occurred while we had it held, cause the signal.
*/
sigtype
sigrelse(sig)
{
sigtype old;
if (sig < 1 || sig > NSIG) {
errno = EINVAL;
return(SIG_ERR);
}
old = sigdisp(sig);
if ((sigtable[sig].s_flag & SHELD) == 0)
return(old);
sigtable[sig].s_flag &= ~SHELD;
if (sigtable[sig].s_flag & SDEFER)
_Sigtramp(sig);
/*
* If disposition was the default, then we can unset the
* catch to _Sigtramp() and let the system do the work.
*/
if (sigtable[sig].s_func == (void (*)())SIG_DFL) /* adb */
signal(sig, SIG_DFL);
return(old);
}
/*
* Ignore a signal.
*/
sigtype
sigignore(sig)
{
return(sigset(sig, SIG_IGN));
}
/*
* Pause, waiting for sig to occur.
* We assume LUSER called us with the signal held.
* When we got the signal, mark the signal as having
* occurred. It will actually cause something when
* the signal is released.
*/
sigpause(sig)
{
if (sig < 1 || sig > NSIG) {
errno = EINVAL;
return;
}
sigtable[sig].s_flag |= SHELD|SPAUSE;
if (setjmp(_pause) == 0)
pause();
sigtable[sig].s_flag &= ~SPAUSE;
sigtable[sig].s_flag |= SDEFER;
}
/*
* In the child process after fork(2), set the disposition of all held
* signals to SIG_IGN. This is a new procedure not in the real sigset()
* package, provided for retrofitting purposes.
*/
void
sigchild()
{
register int i;
for (i = 1; i <= NSIG; i++)
if (sigtable[i].s_flag & SHELD)
signal(i, SIG_IGN);
}
/*
* Return the current disposition of a signal
* If we have not set this signal before, we have to
* ask the system
*/
sigtype
sigdisp(sig)
{
sigtype old;
if (sig < 1 || sig > NSIG) {
errno = EINVAL;
return(SIG_ERR);
}
/*
* If we have no knowledge of this signal,
* ask the system, then save the result for later.
*/
if ((sigtable[sig].s_flag & SSET) == 0) {
old = (void (*)())signal(sig, SIG_IGN); /* adb */
sigtable[sig].s_func = old;
sigtable[sig].s_flag |= SSET;
signal(sig, old);
return(old);
}
/*
* If we have set this signal before, then sigset()
* will have been careful to leave something meaningful
* in s_func.
*/
return(sigtable[sig].s_func);
}
/*
* The following routine gets called for any signal
* that is to be trapped to a user function.
*/
void
_Sigtramp(sig)
{
sigtype old;
if (sig < 1 || sig > NSIG) {
errno = EINVAL;
return;
}
top:
old = (void (*)())signal(sig, SIG_IGN); /* adb */
/*
* If signal being paused on, wakeup sigpause()
*/
if (sigtable[sig].s_flag & SPAUSE)
longjmp(_pause, 1);
/*
* If signal is being held, mark its table entry
* so we can trigger it when signal is released.
* Then just return.
*/
if (sigtable[sig].s_flag & SHELD) {
sigtable[sig].s_flag |= SDEFER;
signal(sig, _Sigtramp);
return;
}
/*
* If the signal is being ignored, just return.
* This would make SIGCONT more normal, but of course
* any system with SIGCONT also has the new signal pkg, so...
*/
if (sigtable[sig].s_func == (void (*)())SIG_IGN) /* adb */
return;
/*
* If the signal is SIG_DFL, then we probably got here
* by holding the signal, having it happen, then releasing
* the signal.
*/
if (sigtable[sig].s_func == (void (*)())SIG_DFL) { /* adb */
signal(sig, SIG_DFL);
kill(getpid(), sig);
/* Will we get back here? */
return;
}
/*
* Looks like we should just cause the signal...
* We hold the signal for the duration of the user's
* code with the signal re-enabled. If the signal
* happens again while in user code, we will recursively
* trap here and mark that we had another occurance
* and return to the user's trap code. When we return
* from there, we can cause the signal again.
*/
sigtable[sig].s_flag &= ~SDEFER;
sigtable[sig].s_flag |= SHELD;
signal(sig, _Sigtramp);
(*sigtable[sig].s_func)(sig);
/*
* If the signal re-occurred while in the user's routine,
* just go try it again...
*/
sigtable[sig].s_flag &= ~SHELD;
if (sigtable[sig].s_flag & SDEFER)
goto top;
}
#else
/*
* In the child process after fork(2), set the disposition of all held
* signals to SIG_IGN. This is a new procedure not in the real sigset()
* package, provided for retrofitting purposes. With the real sigset()
* package, this function is unnecessary.
*/
void sigchild() {}
#endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.