pennmush/game/data/
pennmush/game/log/
pennmush/game/save/
pennmush/game/txt/evt/
pennmush/game/txt/nws/
pennmush/os2/
pennmush/po/
pennmush/win32/msvc.net/
pennmush/win32/msvc6/
/**
 * \file sig.c
 *
 * \brief Signal handling routines for PennMUSH.
 *
 *
 */

#include "config.h"
#include <signal.h>
#include "conf.h"
#include "externs.h"
#include "confmagic.h"

#ifndef HAS_SIGPROCMASK
static Sigfunc saved_handlers[NSIG];
#endif

/** Our own version of signal().
 * We're going to rewrite the signal() function in terms of
 * sigaction, where available, to ensure consistent semantics.
 * We want signal handlers to remain installed, and we want
 * signals (except SIGALRM) to restart system calls which they
 * interrupt. This is how bsd signals work, and what we'd like.
 * This function is essentially example 10.12 from Stevens'
 * _Advanced Programming in the Unix Environment_.
 * \param signo signal number.
 * \param func signal handler function to install.
 * \return former signal handler for signo.
 */
Sigfunc
install_sig_handler(int signo, Sigfunc func)
{
#ifdef HAS_SIGACTION
  struct sigaction act, oact;
  act.sa_handler = func;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
#ifdef SA_RESTART
  act.sa_flags |= SA_RESTART;
#endif
  if (sigaction(signo, &act, &oact) < 0)
    return SIG_ERR;
  return oact.sa_handler;
#else				/* No sigaction, drat. */
  return signal(signo, func);
#endif
}

/** Reinstall a signal handler.
 * \param signo the signal number.
 * \param func signal handler function to reload.
 */
void
reload_sig_handler(int signo __attribute__ ((__unused__)),
		   Sigfunc func __attribute__ ((__unused__)))
{
#if !(defined(HAS_SIGACTION) || defined(SIGNALS_KEPT))
  signal(signo, func);
#endif
}

/** Set a signal to be ignored.
 * \param signo signal number to ignore.
 */
void
ignore_signal(int signo)
{
#ifdef HAS_SIGACTION
  struct sigaction act;
  act.sa_handler = SIG_IGN;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  sigaction(signo, &act, NULL);
#else				/* No sigaction, drat. */
  signal(signo, SIG_IGN);
#endif
}

/** Set a signal to block.
 * These don't really work right without sigprocmask(), but we try.
 * \param signo signal number to block.
 */
void
block_a_signal(int signo)
{
#ifdef HAS_SIGPROCMASK
  sigset_t mask;
  sigemptyset(&mask);
  sigaddset(&mask, signo);
  sigprocmask(SIG_BLOCK, &mask, NULL);
#else
  if (signo > 0 && signo < NSIG)
    saved_handlers[signo] = signal(signo, SIG_IGN);
#endif
}

/** Unblock a signal.
 * These don't really work right without sigprocmask(), but we try.
 * \param signo signal number to unblock.
 */
void
unblock_a_signal(int signo)
{
#ifdef HAS_SIGPROCMASK
  sigset_t mask;
  if (signo >= 0 && signo < NSIG) {
    sigemptyset(&mask);
    sigaddset(&mask, signo);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
  }
#else
  if (signo >= 0 && signo < NSIG)
    signal(signo, saved_handlers[signo]);
#endif
}

/** Block all signals.
 */
void
block_signals(void)
{
#ifdef HAS_SIGPROCMASK
  sigset_t mask;
  sigfillset(&mask);
  sigprocmask(SIG_BLOCK, &mask, NULL);
#else
  int i;
  for (i = 0; i < NSIG; i++)
    signal(i, SIG_IGN);
#endif
}