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 >
C/C++ Source or Header  |  2003-08-12  |  7KB  |  327 lines

  1. /*
  2.     signals.c
  3.  
  4.     Copyright (c) 2002,2003 Thomas J Pinkl <tom@pinkl.com>
  5.  
  6.     Signal handlers.  Uses reliable signals.
  7.  
  8.     Version 1.00    11/30/2001
  9.     Version 1.01    02/07/2002        Special treatment of SIGCLD (for SCO OSR5). 
  10.                                     We don't rearm the signal handler until 
  11.                                     we've reaped the child's termination status.
  12. */
  13.  
  14. #include "telnetcpcd.h"
  15. #ifndef SA_RESTART                /* SCO 3.2v4.x doesn't have this */
  16. #define SA_RESTART 0
  17. #endif
  18.  
  19. #ifdef __linux__
  20. #undef REARMSIGS
  21. #else
  22. #define REARMSIGS
  23. #endif
  24.  
  25. static int alarmsw = 0;
  26.  
  27. /*
  28.     install signal handlers for SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGCLD
  29.     SIGUSR1, SIGUSR2, and SIGPIPE.
  30.  
  31.     returns nothing.
  32. */
  33. void install_signal_handlers(void)
  34. {
  35.     struct sigaction act;
  36.  
  37.     act.sa_handler = record_parent_signal;    /* function to handle all signals */
  38.  
  39.     /* we NEED signals to interrupt system calls, so don't specify SA_RESTART */
  40.     sigemptyset(&act.sa_mask);            /* required before sigaction() */
  41.     act.sa_flags = 0;                    /* no SA_RESTART */
  42.     sigaction(SIGTERM,&act,NULL);
  43.     sigaction(SIGINT,&act,NULL);
  44.     sigaction(SIGQUIT,&act,NULL);
  45.     sigaction(SIGHUP,&act,NULL);
  46.     sigaction(SIGCLD,&act,NULL);
  47.     sigaction(SIGUSR1,&act,NULL);
  48.     sigaction(SIGUSR2,&act,NULL);
  49.     sigaction(SIGPIPE,&act,NULL);
  50.     
  51.     syslog(LOG_INFO,"installed signal handlers");
  52. }
  53.  
  54. /*
  55.     this is our generic signal handling function.  it gets called for 
  56.     any signal we care to handle and simply sets the global signo 
  57.     variable to the signal number. 
  58.  
  59.     it's then up to code elsewhere in the system to check signo and 
  60.     act accordingly.
  61. */
  62. void record_parent_signal(int sig)
  63. {
  64.     extern int signo;                    /* what signal did we receive? */
  65. #ifdef REARMSIGS
  66.     struct sigaction act;
  67. #endif
  68.  
  69.     signo = sig;                        /* save signal number in global var */
  70.  
  71. #ifdef REARMSIGS
  72.     if (signo != SIGCLD) {
  73.         act.sa_handler = record_parent_signal;
  74.         sigemptyset(&act.sa_mask);
  75.         act.sa_flags = 0;                /* no SA_RESTART */
  76.         sigaction(sig,&act,NULL);
  77.     }
  78. #endif
  79. }
  80.  
  81. /*
  82.     this function is called from within concurrent_server() whenever 
  83.     the accept() call returns an error and our global signo variable 
  84.     is non-zero.
  85. */
  86. void parent_sighandler(int sig)
  87. {
  88.     extern int signo;
  89. #ifdef REARMSIGS
  90.     struct sigaction act;
  91. #endif
  92.  
  93.     switch (sig) {
  94.     case SIGTERM:
  95.     case SIGINT:
  96.     case SIGQUIT:
  97.         sigterm(sig);                    /* does not return */
  98.         break;
  99.     case SIGHUP:
  100.         sighup(sig);                    /* re-read config file */
  101.         break;
  102.     case SIGCLD:
  103.         sigchild(sig);                    /* child process died */
  104. #ifdef REARMSIGS
  105.         act.sa_handler = record_parent_signal;
  106.         sigemptyset(&act.sa_mask);
  107.         act.sa_flags = 0;                /* no SA_RESTART */
  108.         sigaction(sig,&act,NULL);
  109. #endif
  110.         break;
  111.     case SIGPIPE:
  112.         sigpipe(sig);
  113.         break;
  114.     case SIGUSR1:
  115.         sigusr1(sig);                    /* increment debug level */
  116.         break;
  117.     case SIGUSR2:
  118.         sigusr2(sig);                    /* decrement debug level */
  119.         break;
  120.     }
  121.     signo = 0;                            /* clear pending signal; very important! */
  122. }
  123.  
  124. /*
  125.     clear signal handlers 
  126. */
  127. void clear_signal_handlers(void)
  128. {
  129.     struct sigaction act;
  130.  
  131.     /*
  132.         set default action for all signals
  133.     */
  134.     act.sa_handler = SIG_DFL;
  135.     sigemptyset(&act.sa_mask);
  136.     act.sa_flags = 0;
  137.     sigaction(SIGHUP,&act,NULL);
  138.     sigaction(SIGTERM,&act,NULL);
  139.     sigaction(SIGINT,&act,NULL);
  140.     sigaction(SIGQUIT,&act,NULL);
  141.     sigaction(SIGCLD,&act,NULL);
  142.     sigaction(SIGPIPE,&act,NULL);
  143.     sigaction(SIGUSR1,&act,NULL);
  144.     sigaction(SIGUSR2,&act,NULL);
  145.     sigaction(SIGALRM,&act,NULL);
  146. }
  147.  
  148. /*
  149.     handle SIGTERM, SIGINT, and SIGQUIT.  calls the clean up 
  150.     routine, then it terminates the current process by sending 
  151.     itself SIGTERM.
  152.  
  153.     returns nothing.
  154. */
  155. void sigterm(int sig)
  156. {
  157.     struct sigaction act;
  158.  
  159.     /* log this at the ERR level to be sure it reaches the log */
  160.     syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
  161.  
  162.     telnetcpcd_cleanup();                /* close everything */
  163.  
  164.     act.sa_handler = SIG_DFL;            /* default signal handler */
  165.     sigemptyset(&act.sa_mask);            /* required before sigaction() */
  166.     act.sa_flags = 0;                    /* signal is fatal, so no SA_RESTART */
  167.     sigaction(SIGTERM,&act,NULL);
  168.  
  169.     /* and now we die ... */
  170.     kill(0,SIGTERM);                    /* send our process group the terminate signal */
  171. }
  172.  
  173. /*
  174.     handle the SIGHUP signal.  this has the effect of re-reading 
  175.     the configuration file.
  176.  
  177.     returns nothing.
  178. */
  179. void sighup(int sig)
  180. {
  181.     /* log this at the ERR level to be sure it reaches the log */
  182.     syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
  183.  
  184.     telnetcpcd_cleanup();                /* close everything */
  185.     telnetcpcd_init();                    /* open everything */
  186. }
  187.  
  188. /*
  189.     handle the SIGCLD signal.  we collect the child process's 
  190.     termination status and log it.  
  191.  
  192.     returns nothing.
  193. */
  194. void sigchild(int sig)
  195. {
  196.     pid_t pid;                            /* pid of child */
  197.     int status;                            /* child's termination status */
  198.  
  199.     /* log this at the ERR level to be sure it reaches the log */
  200.     syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
  201.  
  202.     while (1) {
  203.         pid = wait_child((pid_t) -1,&status);    /* get pid and child's status */
  204.         if (pid == -1) {
  205.             if (errno == EINTR) {        /* wait() interrupted by a signal */
  206.                 continue;                /* wait() again */
  207.             } else {                    /* errno == ECHILD, no more children */
  208.                 break;
  209.             }
  210.         } else if (pid == (pid_t) 0) {    /* no status available */
  211.             break;
  212.         } else {                        /* got pid and status */
  213.             ;                            /* nothing to do */
  214.         }
  215.     }
  216. }
  217.  
  218. /*
  219.     handle the SIGPIPE signal.  we don't really do anything except 
  220.     to log the fact that it occurred.
  221.  
  222.     returns nothing.
  223. */
  224. void sigpipe(int sig)
  225. {
  226.     /* log this at the ERR level to be sure it reaches the log */
  227.     syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
  228. }
  229.  
  230. /*
  231.     sigusr1() and sigusr2() provide a means for us to change 
  232.     the debug level on the fly.  
  233. */
  234.  
  235. /*
  236.     handle SIGUSR2.  decrement the debug level.
  237. */
  238. void sigusr2(int sig)
  239. {
  240.     int level;
  241.  
  242.     /*
  243.         decrement the debug level
  244.     */
  245.     level = get_debug_level();
  246.     if (level > DBG_LV0) {
  247.         --level;
  248.         set_debug_level(level);
  249.     }
  250.     
  251.     /* log this at the LOG_ERR level to be sure it reaches the log */
  252.     syslog(LOG_ERR,"Received %s signal.  Debug level now %d.",signame(sig),level);
  253. }
  254.  
  255. /*
  256.     handle SIGUSR1.  increment the debug level.
  257. */
  258. void sigusr1(int sig)
  259. {
  260.     int level;
  261.  
  262.     /*
  263.         increment the debug level
  264.     */
  265.     level = get_debug_level();
  266.     if (level < DBG_LV9) {
  267.         ++level;
  268.         set_debug_level(level);
  269.     }
  270.     
  271.     /* log this at the LOG_ERR level to be sure it reaches the log */
  272.     syslog(LOG_ERR,"Received %s signal.  Debug level now %d.",signame(sig),level);
  273. }
  274.  
  275. /*
  276.     handle the SIGALRM signal.  it just sets a flag indicating 
  277.     that we've received the signal.
  278.  
  279.     returns nothing.
  280. */
  281. void sigalarm(int sig)
  282. {
  283.     alarmsw++;
  284. }
  285.  
  286. /*
  287.     returns 0 if SIGALRM has not occurred, non-zero if it has.
  288. */
  289. int alarm_occurred(void)
  290. {
  291.     return(alarmsw);
  292. }
  293.  
  294. /*
  295.     install a signal handler for SIGALRM and set an alarm to go 
  296.     off per the seconds argument.
  297.  
  298.     returns the value returned by alarm()
  299. */
  300. unsigned int set_alarm(int seconds)
  301. {
  302.     struct sigaction act;
  303.  
  304.     alarmsw = 0;
  305.     act.sa_handler = sigalarm;            /* function to handle signal */
  306.     sigemptyset(&act.sa_mask);            /* required before sigaction() */
  307.     act.sa_flags = SA_RESTART;
  308.     sigaction(SIGALRM,&act,NULL);
  309.     return(alarm(seconds));
  310. }
  311.  
  312. /*
  313.     cancel a pending alarm.
  314.  
  315.     returns the value returned by alarm()
  316. */
  317. unsigned int cancel_alarm(int seconds)
  318. {
  319.     struct sigaction act;
  320.  
  321.     act.sa_handler = SIG_DFL;
  322.     sigemptyset(&act.sa_mask);            /* required before sigaction() */
  323.     act.sa_flags = 0;
  324.     sigaction(SIGALRM,&act,NULL);
  325.     return(alarm(seconds));
  326. }
  327.