192 lines
4.8 KiB
C
192 lines
4.8 KiB
C
/*++
|
|
/* NAME
|
|
/* master_sig 3
|
|
/* SUMMARY
|
|
/* Postfix master - signal processing
|
|
/* SYNOPSIS
|
|
/* #include "master.h"
|
|
/*
|
|
/* int master_gotsighup;
|
|
/* int master_gotsigchld;
|
|
/*
|
|
/* int master_sigsetup()
|
|
/* DESCRIPTION
|
|
/* This module implements the master process signal handling interface.
|
|
/*
|
|
/* master_gotsighup (master_gotsigchld) is set to SIGHUP (SIGCHLD)
|
|
/* when the process receives a hangup (child death) signal.
|
|
/*
|
|
/* master_sigsetup() enables processing of hangup and child death signals.
|
|
/* Receipt of SIGINT, SIGQUIT, SIGSEGV, SIGILL, or SIGTERM
|
|
/* is interpreted as a request for termination. Child processes are
|
|
/* notified of the master\'s demise by sending them a SIGTERM signal.
|
|
/* DIAGNOSTICS
|
|
/* BUGS
|
|
/* Need a way to register cleanup actions.
|
|
/* SEE ALSO
|
|
/* LICENSE
|
|
/* .ad
|
|
/* .fi
|
|
/* The Secure Mailer license must be distributed with this software.
|
|
/* AUTHOR(S)
|
|
/* Wietse Venema
|
|
/* IBM T.J. Watson Research
|
|
/* P.O. Box 704
|
|
/* Yorktown Heights, NY 10598, USA
|
|
/*--*/
|
|
|
|
/* System libraries. */
|
|
|
|
#include <sys_defs.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
/* Utility library. */
|
|
|
|
#include <msg.h>
|
|
#include <posix_signals.h>
|
|
|
|
/* Application-specific. */
|
|
|
|
#include "master.h"
|
|
|
|
#ifdef USE_SIG_RETURN
|
|
#include <sys/syscall.h>
|
|
#endif
|
|
|
|
/* Local stuff. */
|
|
|
|
int master_gotsigchld;
|
|
int master_gotsighup;
|
|
|
|
/* master_sighup - register arrival of hangup signal */
|
|
|
|
static void master_sighup(int sig)
|
|
{
|
|
|
|
/*
|
|
* WARNING WARNING WARNING.
|
|
*
|
|
* This code runs at unpredictable moments, as a signal handler. Don't put
|
|
* any code here other than for setting a global flag.
|
|
*/
|
|
master_gotsighup = sig;
|
|
}
|
|
|
|
/* master_sigchld - register arrival of child death signal */
|
|
|
|
#ifdef USE_SIG_RETURN
|
|
|
|
static void master_sigchld(int sig, int code, struct sigcontext * scp)
|
|
{
|
|
|
|
/*
|
|
* WARNING WARNING WARNING.
|
|
*
|
|
* This code runs at unpredictable moments, as a signal handler. Don't put
|
|
* any code here other than for setting a global flag, or code that is
|
|
* intended to be run within a signal handler.
|
|
*/
|
|
master_gotsigchld = sig;
|
|
if (scp != NULL && scp->sc_syscall == SYS_select) {
|
|
scp->sc_syscall_action = SIG_RETURN;
|
|
#ifndef SA_RESTART
|
|
} else if (scp != NULL) {
|
|
scp->sc_syscall_action = SIG_RESTART;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
static void master_sigchld(int sig)
|
|
{
|
|
|
|
/*
|
|
* WARNING WARNING WARNING.
|
|
*
|
|
* This code runs at unpredictable moments, as a signal handler. Don't put
|
|
* any code here other than for setting a global flag.
|
|
*/
|
|
master_gotsigchld = sig;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* master_sigdeath - die, women and children first */
|
|
|
|
static void master_sigdeath(int sig)
|
|
{
|
|
char *myname = "master_sigsetup";
|
|
struct sigaction action;
|
|
pid_t pid = getpid();
|
|
|
|
/*
|
|
* XXX We're running from a signal handler, and really should not call
|
|
* any msg() routines at all, but it would be even worse to silently
|
|
* terminate without informing the sysadmin.
|
|
*/
|
|
msg_info("terminating on signal %d", sig);
|
|
|
|
/*
|
|
* Terminate all processes in our process group, except ourselves.
|
|
*/
|
|
sigemptyset(&action.sa_mask);
|
|
action.sa_flags = 0;
|
|
action.sa_handler = SIG_IGN;
|
|
if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0)
|
|
msg_fatal("%s: sigaction: %m", myname);
|
|
if (kill(-pid, SIGTERM) < 0)
|
|
msg_fatal("%s: kill process group: %m", myname);
|
|
|
|
/*
|
|
* Deliver the signal to ourselves and clean up. XXX We're running as a
|
|
* signal handler and really should not be doing complicated things...
|
|
*/
|
|
sigemptyset(&action.sa_mask);
|
|
action.sa_flags = 0;
|
|
action.sa_handler = SIG_DFL;
|
|
if (sigaction(sig, &action, (struct sigaction *) 0) < 0)
|
|
msg_fatal("%s: sigaction: %m", myname);
|
|
if (kill(pid, sig) < 0)
|
|
msg_fatal("%s: kill myself: %m", myname);
|
|
}
|
|
|
|
/* master_sigsetup - set up signal handlers */
|
|
|
|
void master_sigsetup(void)
|
|
{
|
|
char *myname = "master_sigsetup";
|
|
struct sigaction action;
|
|
static int sigs[] = {
|
|
SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM,
|
|
};
|
|
unsigned i;
|
|
|
|
sigemptyset(&action.sa_mask);
|
|
action.sa_flags = 0;
|
|
|
|
/*
|
|
* Prepare to kill our children when we receive any of the above signals.
|
|
*/
|
|
action.sa_handler = master_sigdeath;
|
|
for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
|
|
if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0)
|
|
msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]);
|
|
|
|
/*
|
|
* Intercept SIGHUP (re-read config file) and SIGCHLD (child exit).
|
|
*/
|
|
#ifdef SA_RESTART
|
|
action.sa_flags |= SA_RESTART;
|
|
#endif
|
|
action.sa_handler = master_sighup;
|
|
if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0)
|
|
msg_fatal("%s: sigaction(%d): %m", myname, SIGHUP);
|
|
|
|
action.sa_flags |= SA_NOCLDSTOP;
|
|
action.sa_handler = master_sigchld;
|
|
if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0)
|
|
msg_fatal("%s: sigaction(%d): %m", myname, SIGCHLD);
|
|
}
|