home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
sredird
/
telnetcpcd-1.09.tar.gz
/
telnetcpcd-1.09.tar
/
signals.c
< prev
next >
Wrap
C/C++ Source or Header
|
2003-08-12
|
7KB
|
327 lines
/*
signals.c
Copyright (c) 2002,2003 Thomas J Pinkl <tom@pinkl.com>
Signal handlers. Uses reliable signals.
Version 1.00 11/30/2001
Version 1.01 02/07/2002 Special treatment of SIGCLD (for SCO OSR5).
We don't rearm the signal handler until
we've reaped the child's termination status.
*/
#include "telnetcpcd.h"
#ifndef SA_RESTART /* SCO 3.2v4.x doesn't have this */
#define SA_RESTART 0
#endif
#ifdef __linux__
#undef REARMSIGS
#else
#define REARMSIGS
#endif
static int alarmsw = 0;
/*
install signal handlers for SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGCLD
SIGUSR1, SIGUSR2, and SIGPIPE.
returns nothing.
*/
void install_signal_handlers(void)
{
struct sigaction act;
act.sa_handler = record_parent_signal; /* function to handle all signals */
/* we NEED signals to interrupt system calls, so don't specify SA_RESTART */
sigemptyset(&act.sa_mask); /* required before sigaction() */
act.sa_flags = 0; /* no SA_RESTART */
sigaction(SIGTERM,&act,NULL);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGHUP,&act,NULL);
sigaction(SIGCLD,&act,NULL);
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGUSR2,&act,NULL);
sigaction(SIGPIPE,&act,NULL);
syslog(LOG_INFO,"installed signal handlers");
}
/*
this is our generic signal handling function. it gets called for
any signal we care to handle and simply sets the global signo
variable to the signal number.
it's then up to code elsewhere in the system to check signo and
act accordingly.
*/
void record_parent_signal(int sig)
{
extern int signo; /* what signal did we receive? */
#ifdef REARMSIGS
struct sigaction act;
#endif
signo = sig; /* save signal number in global var */
#ifdef REARMSIGS
if (signo != SIGCLD) {
act.sa_handler = record_parent_signal;
sigemptyset(&act.sa_mask);
act.sa_flags = 0; /* no SA_RESTART */
sigaction(sig,&act,NULL);
}
#endif
}
/*
this function is called from within concurrent_server() whenever
the accept() call returns an error and our global signo variable
is non-zero.
*/
void parent_sighandler(int sig)
{
extern int signo;
#ifdef REARMSIGS
struct sigaction act;
#endif
switch (sig) {
case SIGTERM:
case SIGINT:
case SIGQUIT:
sigterm(sig); /* does not return */
break;
case SIGHUP:
sighup(sig); /* re-read config file */
break;
case SIGCLD:
sigchild(sig); /* child process died */
#ifdef REARMSIGS
act.sa_handler = record_parent_signal;
sigemptyset(&act.sa_mask);
act.sa_flags = 0; /* no SA_RESTART */
sigaction(sig,&act,NULL);
#endif
break;
case SIGPIPE:
sigpipe(sig);
break;
case SIGUSR1:
sigusr1(sig); /* increment debug level */
break;
case SIGUSR2:
sigusr2(sig); /* decrement debug level */
break;
}
signo = 0; /* clear pending signal; very important! */
}
/*
clear signal handlers
*/
void clear_signal_handlers(void)
{
struct sigaction act;
/*
set default action for all signals
*/
act.sa_handler = SIG_DFL;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGHUP,&act,NULL);
sigaction(SIGTERM,&act,NULL);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGCLD,&act,NULL);
sigaction(SIGPIPE,&act,NULL);
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGUSR2,&act,NULL);
sigaction(SIGALRM,&act,NULL);
}
/*
handle SIGTERM, SIGINT, and SIGQUIT. calls the clean up
routine, then it terminates the current process by sending
itself SIGTERM.
returns nothing.
*/
void sigterm(int sig)
{
struct sigaction act;
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
telnetcpcd_cleanup(); /* close everything */
act.sa_handler = SIG_DFL; /* default signal handler */
sigemptyset(&act.sa_mask); /* required before sigaction() */
act.sa_flags = 0; /* signal is fatal, so no SA_RESTART */
sigaction(SIGTERM,&act,NULL);
/* and now we die ... */
kill(0,SIGTERM); /* send our process group the terminate signal */
}
/*
handle the SIGHUP signal. this has the effect of re-reading
the configuration file.
returns nothing.
*/
void sighup(int sig)
{
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
telnetcpcd_cleanup(); /* close everything */
telnetcpcd_init(); /* open everything */
}
/*
handle the SIGCLD signal. we collect the child process's
termination status and log it.
returns nothing.
*/
void sigchild(int sig)
{
pid_t pid; /* pid of child */
int status; /* child's termination status */
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
while (1) {
pid = wait_child((pid_t) -1,&status); /* get pid and child's status */
if (pid == -1) {
if (errno == EINTR) { /* wait() interrupted by a signal */
continue; /* wait() again */
} else { /* errno == ECHILD, no more children */
break;
}
} else if (pid == (pid_t) 0) { /* no status available */
break;
} else { /* got pid and status */
; /* nothing to do */
}
}
}
/*
handle the SIGPIPE signal. we don't really do anything except
to log the fact that it occurred.
returns nothing.
*/
void sigpipe(int sig)
{
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
}
/*
sigusr1() and sigusr2() provide a means for us to change
the debug level on the fly.
*/
/*
handle SIGUSR2. decrement the debug level.
*/
void sigusr2(int sig)
{
int level;
/*
decrement the debug level
*/
level = get_debug_level();
if (level > DBG_LV0) {
--level;
set_debug_level(level);
}
/* log this at the LOG_ERR level to be sure it reaches the log */
syslog(LOG_ERR,"Received %s signal. Debug level now %d.",signame(sig),level);
}
/*
handle SIGUSR1. increment the debug level.
*/
void sigusr1(int sig)
{
int level;
/*
increment the debug level
*/
level = get_debug_level();
if (level < DBG_LV9) {
++level;
set_debug_level(level);
}
/* log this at the LOG_ERR level to be sure it reaches the log */
syslog(LOG_ERR,"Received %s signal. Debug level now %d.",signame(sig),level);
}
/*
handle the SIGALRM signal. it just sets a flag indicating
that we've received the signal.
returns nothing.
*/
void sigalarm(int sig)
{
alarmsw++;
}
/*
returns 0 if SIGALRM has not occurred, non-zero if it has.
*/
int alarm_occurred(void)
{
return(alarmsw);
}
/*
install a signal handler for SIGALRM and set an alarm to go
off per the seconds argument.
returns the value returned by alarm()
*/
unsigned int set_alarm(int seconds)
{
struct sigaction act;
alarmsw = 0;
act.sa_handler = sigalarm; /* function to handle signal */
sigemptyset(&act.sa_mask); /* required before sigaction() */
act.sa_flags = SA_RESTART;
sigaction(SIGALRM,&act,NULL);
return(alarm(seconds));
}
/*
cancel a pending alarm.
returns the value returned by alarm()
*/
unsigned int cancel_alarm(int seconds)
{
struct sigaction act;
act.sa_handler = SIG_DFL;
sigemptyset(&act.sa_mask); /* required before sigaction() */
act.sa_flags = 0;
sigaction(SIGALRM,&act,NULL);
return(alarm(seconds));
}