/*
   <p>Signal handling functions.</p>

   <kbd>
   <b>environ - C programming support functions</b><br>
   Copyright (C) 2005  Martin C Gregorie
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the Lesser GNU General Public License.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the Lesser GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   </kbd>
  
   <p>Contact Martin Gregorie at <i>martin@gregorie.org</i></p>
*/

#include <stdio.h>
#include <signal.h>

#define __USE_GNU
#include <string.h>

#include <environ.h>

/*
   globals
*/
static int signaled = 0;
static int debug    = 0;

/*
   Signal handler used to trap shutdowns.
   This is designed for use with programs using <i>poll()</i>
   for asynchronous i/o and to detect signals. It is installed
   as the signal handler for all signals by <i>set_sigtraps()</i>.
   When a signal is detected it stores the signal internally before
   <i>poll()</i> exits with a return value of -1 and <i>errno</i> set to
   EINTR. When this occurs <i>get_sigtrap_type()</i> is used to retrieve
   the signal type before taking the appropriate action.

   <b>See also:</b> <i>set_sigtrap_debug(), set_sigtraps(),
   get_sigtrap_type(), get_sigtrap_name()</i>.
*/
static void sighandler(int sig)
{
   signaled = sig;
}   

/*
   Set the signal handling debug level. Level 1 traces calls on all
   signal trap functions except <i>sighandler()</i>, which is never traced,
   and <i>get_sigtrap_type()</i> and <i>get_sigtrap_name()</i>, which are
   traced at debug level 2.

   <b>See also:</b> <i>sighandler(), set_sigtraps(),
   get_sigtrap_type(), get_sigtrap_name()</i>.
*/
void set_sigtrap_debug(int d)
{
   if (d < 0)
      d = 0;
      
   debug = d;

   if (debug)
      logmsg("set_trap_debug(%d)", debug);
}

/*
   Sets up signal trap handling by installing <i>sighandler()</i>
   as the signal handler for SIGHUP, SIGINT, SIGQUIT, SIGTERM,
   SIGPOLL, SIGUSR1 and SIGUSR2. It returns zero on success
   and the signal type that caused an error if one ocurred.

   <b>See also:</b> <i>sighandler(), set_sigtrap_debug(),
   get_sigtrap_type(), get_sigtrap_name()</i>.
*/
int set_sigtraps()
{
   int r = 0;
   
   if (signal(SIGHUP, sighandler) == SIG_ERR)
      r = SIGHUP;
   else
   if (signal(SIGINT, sighandler) == SIG_ERR)
      r = SIGINT;
   else
   if (signal(SIGQUIT, sighandler) == SIG_ERR)
      r = SIGQUIT;
   else
   if (signal(SIGTERM, sighandler) == SIG_ERR)
      r = SIGTERM;
   else
   if (signal(SIGPOLL, sighandler) == SIG_ERR)
      r = SIGPOLL;
   else
   if (signal(SIGUSR1, sighandler) == SIG_ERR)
      r = SIGPOLL;
   else
   if (signal(SIGUSR2, sighandler) == SIG_ERR)
      r = SIGPOLL;

   if (debug)
   {
      if (r)
         logmsg("'%s' = set_sigtraps()", get_sigtrap_name(r));
      else
         logmsg("%d = set_sigtraps()", r);
   }
   
   return r;
}

/*
   Retrieves the last signal type trapped by <i>sighandler()</i>.
   It is used in conjunction with <i>poll()</i>. When a signal is
   detected <i>poll()</i> exits with a return value of -1 and
   <i>errno</i> set to EINTR. When this occurs
   <i>get_sigtrap_type()</i> is used to retrieve the signal type
   before taking the appropriate action.

   It returns the type of signal that caused <i>poll()</i> to exit.
 
   <b>See also:</b> <i>sighandler(), set_sigtrap_debug(), set_sigtraps(),
   get_sigtrap_name()</i>.
*/
int get_sigtrap_type()
{
   return signaled;

   if (debug > 1)
      logmsg("%d = get_sigtrap_type()", signaled);
}

/*
   Translate a signal type into a string. This function is
   intended for diagnostic and debugging use. It returns a pointer
   to a string containing the name of the signal type <u>e</u>.

   <b>See also:</b> <i>sighandler(), set_sigtrap_debug(), set_sigtraps(),
   get_sigtrap_type()</i>.
*/
char *get_sigtrap_name(int e)
{
   static char *s;
   static char buff[40];

   s = strsignal(e);
   if (s == NULL)
   {
      snprintf(buff, 40, "signal %d trapped", e);
      s = buff;
   }

   if (debug > 1)
      logmsg("%s = get_sigtrap_name(%d)", s, signaled);

   return s;
}


