/*
* Copyright (c) 2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: stthreadssignal.c,v 1.4 2005/01/18 00:08:31 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/types.h"
#include "sm/signal.h"
#include "statethreads/st.h"
/*
** Generic signal handler for statethreads application.
** This module requires a signal pipe (see below) over which it will
** send single characters that indicate which signal has been received
** (see signal.h).
** The application can read from the pipe and act accordingly.
** The advantage of this approach is that the signal handler code is
** small and "async signal safe", while the code that acts on the
** data read from the pipe doesn't have to be and hence can use logging etc.
*/
/*
** Signal pipe, provided by application.
** Fixme: should this be local/static and the installation function returns
** a pointer to the read part??
*/
extern st_netfd_t Sig_pipe[2];
/*
** Callback function if write(2) fails and context for it.
** The context doesn't seem to be necessary, it can be a global in the
** application itself (as there is only one "global" callback function and
** context).
*/
static sm_sigwrfail_F sigwrfailcb = NULL;
static void *sigwrfailctx = NULL;
/*
** ST_SIGNAL -- install a single signal handler
**
** Parameters:
** sig -- signal number
** handler -- handler for signal
**
** Returns:
** nothing.
*/
static void
st_signal(int sig, sm_sighandler_F handler)
{
struct sigaction sa;
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(sig, &sa, NULL);
}
/*
** ST_SIGHANDLER -- Signal handler; send signal number via pipe
**
** Parameters:
** signo -- signal number
**
** Returns:
** nothing
*/
static void
st_sighandler(int signo)
{
int err, fd;
char sig;
err = errno;
fd = st_netfd_fileno(Sig_pipe[SM_WR_SIG_PIPE]);
sig = '\0';
switch (signo)
{
case SIGHUP:
sig = SM_SIG_HUP;
break;
case SIGINT:
sig = SM_SIG_INT;
break;
case SIGALRM:
sig = SM_SIG_ALRM;
break;
case SIGCHLD:
sig = SM_SIG_CHLD;
break;
case SIGTERM:
sig = SM_SIG_TERM;
break;
case SIGUSR1:
sig = SM_SIG_USR1;
break;
case SIGUSR2:
sig = SM_SIG_USR2;
break;
case SIGPIPE:
sig = SM_SIG_PIPE;
break;
default:
sig = SM_SIG_UNKNOWN;
break;
}
/* write() is async-safe */
if (write(fd, &sig, sizeof(char)) != sizeof(char))
{
if (sigwrfailcb != NULL)
sigwrfailcb(errno, sigwrfailctx);
}
errno = err;
}
/*
** ST_INSTALL_SIGHANDLERS -- install signal handlers
**
** Parameters:
** signalset -- set of signals to handle
** sigwrfail -- function to invoke when write() in signal handler
** fails
** ctx -- context for sigwrfail
**
** Returns:
** usual error code
*/
sm_ret_T
st_install_sighandlers(uint signalset, sm_sigwrfail_F sigwrfail, void *ctx)
{
sigset_t mask;
int p[2];
/* Create signal pipe */
if (pipe(p) < 0)
return sm_error_perm(SM_EM_STR, errno);
/*
set close-on-exec flag?
fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0
fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)
*/
if ((Sig_pipe[SM_RD_SIG_PIPE] = st_netfd_open(p[SM_RD_SIG_PIPE]))
== NULL)
return sm_error_perm(SM_EM_STTHR, errno);
if ((Sig_pipe[SM_WR_SIG_PIPE] = st_netfd_open(p[SM_WR_SIG_PIPE]))
== NULL)
return sm_error_perm(SM_EM_STTHR, errno);
sigemptyset(&mask);
/* Install signal handlers */
if (SM_IS_FLAG(signalset, SM_HDL_SIG_HUP))
{
st_signal(SIGHUP, st_sighandler);
sigaddset(&mask, SIGHUP);
}
if (SM_IS_FLAG(signalset, SM_HDL_SIG_INT))
{
st_signal(SIGINT, st_sighandler);
sigaddset(&mask, SIGINT);
}
if (SM_IS_FLAG(signalset, SM_HDL_SIG_ALRM))
{
st_signal(SIGALRM, st_sighandler);
sigaddset(&mask, SIGALRM);
}
if (SM_IS_FLAG(signalset, SM_HDL_SIG_CHLD))
{
st_signal(SIGCHLD, st_sighandler);
sigaddset(&mask, SIGCHLD);
}
if (SM_IS_FLAG(signalset, SM_HDL_SIG_TERM))
{
st_signal(SIGTERM, st_sighandler);
sigaddset(&mask, SIGTERM);
}
if (SM_IS_FLAG(signalset, SM_HDL_SIG_USR1))
{
st_signal(SIGUSR1, st_sighandler);
sigaddset(&mask, SIGUSR1);
}
if (SM_IS_FLAG(signalset, SM_HDL_SIG_USR2))
{
st_signal(SIGUSR2, st_sighandler);
sigaddset(&mask, SIGUSR2);
}
if (SM_IS_FLAG(signalset, SM_HDL_SIG_PIPE))
{
st_signal(SIGPIPE, st_sighandler);
sigaddset(&mask, SIGPIPE);
}
sigprocmask(SIG_UNBLOCK, &mask, NULL);
sigwrfailcb = sigwrfail;
sigwrfailctx = ctx;
return SM_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1