/*****************************************************************************

  POPular -- A POP3 server and proxy for large mail systems

  $Id: sig.c,v 1.6 2002/09/15 12:27:16 sqrt Exp $

  http://www.remote.org/jochen/mail/popular/

******************************************************************************

  Copyright (C) 1999-2002  Jochen Topf <jochen@remote.org>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  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 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

*****************************************************************************/

#if HAVE_CONFIG_H
# include <config.h>
#endif

#include "popular.h"
#include "sig.h"


static volatile int signal_remember[SIGNAL_MAX];


/*****************************************************************************

  signal_handler()

  The signal handler just saves the information which signal occurred into
  an array.

*****************************************************************************/
void
signal_handler(int signum)
{
  if (signum < SIGNAL_MAX) signal_remember[signum] = 1;
}


/*****************************************************************************

  signal_set()

*****************************************************************************/
void
signal_set(signal_handler_t what, int signum, int flags)
{
  struct sigaction sigAction;
  memset(&sigAction, 0, sizeof(sigAction));
  sigemptyset(&sigAction.sa_mask);

  switch (what) {
    case sigIgnore:
      sigAction.sa_handler = SIG_IGN;
      sigAction.sa_flags = 0;
      break;
    case sigDefault:
      sigAction.sa_handler = SIG_DFL;
      sigAction.sa_flags = 0;
      break;
    case sigHandler:
      sigAction.sa_handler = signal_handler;
      sigAction.sa_flags = SA_RESTART | flags;
      break;
  }

  if (sigaction(signum, &sigAction, (struct sigaction *)0) != 0) {
    /* XLOG-DOC:BUG:014a:sigaction_failed
     * A sigaction () system call failed. This should never happen. */
    xlog_printf(xlog_bug, 0x014a, "sigaction_failed signal=%d", signum);
  }
}


/*****************************************************************************

  signal_init(int c)

  Setup standard signal handling for servers.

  c=1: Call signal handler if child dies

*****************************************************************************/
void
signal_init(int c)
{
  int i;
  for (i=0; i < SIGNAL_MAX; i++) signal_remember[i] = 0;

  signal_set(sigIgnore,  SIGPIPE, 0);
  if (c) {
    signal_set(sigHandler, SIGCHLD, SA_NOCLDSTOP);
  } else {
    signal_set(sigDefault, SIGCHLD, 0);
  }
  signal_set(sigHandler, SIGHUP,  0);
  signal_set(sigHandler, SIGTERM, 0);
  signal_set(sigHandler, SIGINT,  0);
  signal_set(sigHandler, SIGQUIT, 0);
  signal_set(sigHandler, SIGUSR1, 0);
  signal_set(sigHandler, SIGUSR2, 0);
}


/*****************************************************************************

  signal_init_child()

  Setup standard signal handling for children of servers.

*****************************************************************************/
void
signal_init_child()
{
  int i;

  signal_set(sigIgnore,  SIGPIPE, 0);
  signal_set(sigDefault, SIGCHLD, 0);
  signal_set(sigDefault, SIGHUP,  0);
  signal_set(sigDefault, SIGTERM, 0);
  signal_set(sigDefault, SIGINT,  0);
  signal_set(sigDefault, SIGQUIT, 0);
  signal_set(sigDefault, SIGUSR1, 0);
  signal_set(sigDefault, SIGUSR2, 0);

  if (signal_remember[SIGTERM] || signal_remember[SIGINT]) {
    /* XLOG-DOC:INF:0133:got_term_signal
     * The child got a TERM or INT signal and will shut down. This signal
     * was either delivered to the parent between the last check for signals
     * and the fork, or it was delivered to the child before the child
     * could change its signal handling to the default behaviour. In any
     * case, calling exit immediately is the right thing to do here. */
    xlog_printf(xlog_inf, 0x0133, "got_term_signal");
    exit(0);
  }
  for (i=0; i < SIGNAL_MAX; i++) signal_remember[i] = 0;
}


/*****************************************************************************

  signal_came()

  Return 1 if the specified signal arrived, 0 otherwise.

*****************************************************************************/
int
signal_came(int signum)
{
  if (signum < SIGNAL_MAX) {
    int ret = signal_remember[signum];
    signal_remember[signum] = 0;
    return ret;
  }
  return 0;
}


/*****************************************************************************

  signal_next()

  Return the next signal, that was caught. If there was no signal, return 0.

*****************************************************************************/
int
signal_next()
{
  int n;

  for (n=1; n < SIGNAL_MAX; n++) {
    if (signal_remember[n]) {
      signal_remember[n] = 0;
      return n;
    }
  }

  return 0;
}


/** THE END *****************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1