1N/A/*
1N/A * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
1N/A * All rights reserved.
1N/A *
1N/A * By using this file, you agree to the terms and conditions set
1N/A * forth in the LICENSE file which can be found at the top level of
1N/A * the sendmail distribution.
1N/A */
1N/A
1N/A#pragma ident "%Z%%M% %I% %E% SMI"
1N/A
1N/A#include <sm/gen.h>
1N/ASM_RCSID("@(#)$Id: signal.c,v 1.17 2005/06/14 23:07:20 ca Exp $")
1N/A
1N/A#if SM_CONF_SETITIMER
1N/A# include <sm/time.h>
1N/A#endif /* SM_CONF_SETITIMER */
1N/A#include <errno.h>
1N/A#include <stdlib.h>
1N/A#include <time.h>
1N/A#include <unistd.h>
1N/A#include <sm/clock.h>
1N/A#include <sm/signal.h>
1N/A#include <signal.h>
1N/A#include <sm/string.h>
1N/A
1N/Aunsigned int volatile InCriticalSection; /* >0 if inside critical section */
1N/Aint volatile PendingSignal; /* pending signal to resend */
1N/A
1N/A/*
1N/A** SM_SIGNAL -- set a signal handler
1N/A**
1N/A** This is essentially old BSD "signal(3)".
1N/A**
1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1N/A** DOING.
1N/A*/
1N/A
1N/Asigfunc_t
1N/Asm_signal(sig, handler)
1N/A int sig;
1N/A sigfunc_t handler;
1N/A{
1N/A# if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
1N/A struct sigaction n, o;
1N/A# endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
1N/A
1N/A /*
1N/A ** First, try for modern signal calls
1N/A ** and restartable syscalls
1N/A */
1N/A
1N/A# ifdef SA_RESTART
1N/A (void) memset(&n, '\0', sizeof n);
1N/A# if USE_SA_SIGACTION
1N/A n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
1N/A n.sa_flags = SA_RESTART|SA_SIGINFO;
1N/A# else /* USE_SA_SIGACTION */
1N/A n.sa_handler = handler;
1N/A n.sa_flags = SA_RESTART;
1N/A# endif /* USE_SA_SIGACTION */
1N/A if (sigaction(sig, &n, &o) < 0)
1N/A return SIG_ERR;
1N/A return o.sa_handler;
1N/A# else /* SA_RESTART */
1N/A
1N/A /*
1N/A ** Else check for SYS5SIGNALS or
1N/A ** BSD4_3 signals
1N/A */
1N/A
1N/A# if defined(SYS5SIGNALS) || defined(BSD4_3)
1N/A# ifdef BSD4_3
1N/A return signal(sig, handler);
1N/A# else /* BSD4_3 */
1N/A return sigset(sig, handler);
1N/A# endif /* BSD4_3 */
1N/A# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
1N/A
1N/A /*
1N/A ** Finally, if nothing else is available,
1N/A ** go for a default
1N/A */
1N/A
1N/A (void) memset(&n, '\0', sizeof n);
1N/A n.sa_handler = handler;
1N/A if (sigaction(sig, &n, &o) < 0)
1N/A return SIG_ERR;
1N/A return o.sa_handler;
1N/A# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
1N/A# endif /* SA_RESTART */
1N/A}
1N/A/*
1N/A** SM_BLOCKSIGNAL -- hold a signal to prevent delivery
1N/A**
1N/A** Parameters:
1N/A** sig -- the signal to block.
1N/A**
1N/A** Returns:
1N/A** 1 signal was previously blocked
1N/A** 0 signal was not previously blocked
1N/A** -1 on failure.
1N/A*/
1N/A
1N/Aint
1N/Asm_blocksignal(sig)
1N/A int sig;
1N/A{
1N/A# ifdef BSD4_3
1N/A# ifndef sigmask
1N/A# define sigmask(s) (1 << ((s) - 1))
1N/A# endif /* ! sigmask */
1N/A return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
1N/A# else /* BSD4_3 */
1N/A# ifdef ALTOS_SYSTEM_V
1N/A sigfunc_t handler;
1N/A
1N/A handler = sigset(sig, SIG_HOLD);
1N/A if (handler == SIG_ERR)
1N/A return -1;
1N/A else
1N/A return handler == SIG_HOLD;
1N/A# else /* ALTOS_SYSTEM_V */
1N/A sigset_t sset, oset;
1N/A
1N/A (void) sigemptyset(&sset);
1N/A (void) sigaddset(&sset, sig);
1N/A if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
1N/A return -1;
1N/A else
1N/A return sigismember(&oset, sig);
1N/A# endif /* ALTOS_SYSTEM_V */
1N/A# endif /* BSD4_3 */
1N/A}
1N/A/*
1N/A** SM_RELEASESIGNAL -- release a held signal
1N/A**
1N/A** Parameters:
1N/A** sig -- the signal to release.
1N/A**
1N/A** Returns:
1N/A** 1 signal was previously blocked
1N/A** 0 signal was not previously blocked
1N/A** -1 on failure.
1N/A*/
1N/A
1N/Aint
1N/Asm_releasesignal(sig)
1N/A int sig;
1N/A{
1N/A# ifdef BSD4_3
1N/A return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
1N/A# else /* BSD4_3 */
1N/A# ifdef ALTOS_SYSTEM_V
1N/A sigfunc_t handler;
1N/A
1N/A handler = sigset(sig, SIG_HOLD);
1N/A if (sigrelse(sig) < 0)
1N/A return -1;
1N/A else
1N/A return handler == SIG_HOLD;
1N/A# else /* ALTOS_SYSTEM_V */
1N/A sigset_t sset, oset;
1N/A
1N/A (void) sigemptyset(&sset);
1N/A (void) sigaddset(&sset, sig);
1N/A if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
1N/A return -1;
1N/A else
1N/A return sigismember(&oset, sig);
1N/A# endif /* ALTOS_SYSTEM_V */
1N/A# endif /* BSD4_3 */
1N/A}
1N/A/*
1N/A** PEND_SIGNAL -- Add a signal to the pending signal list
1N/A**
1N/A** Parameters:
1N/A** sig -- signal to add
1N/A**
1N/A** Returns:
1N/A** none.
1N/A**
1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1N/A** DOING.
1N/A*/
1N/A
1N/Avoid
1N/Apend_signal(sig)
1N/A int sig;
1N/A{
1N/A int sigbit;
1N/A int save_errno = errno;
1N/A#if SM_CONF_SETITIMER
1N/A struct itimerval clr;
1N/A#endif /* SM_CONF_SETITIMER */
1N/A
1N/A /*
1N/A ** Don't want to interrupt something critical, hence delay
1N/A ** the alarm for one second. Hopefully, by then we
1N/A ** will be out of the critical section. If not, then
1N/A ** we will just delay again. The events to be run will
1N/A ** still all be run, maybe just a little bit late.
1N/A */
1N/A
1N/A switch (sig)
1N/A {
1N/A case SIGHUP:
1N/A sigbit = PEND_SIGHUP;
1N/A break;
1N/A
1N/A case SIGINT:
1N/A sigbit = PEND_SIGINT;
1N/A break;
1N/A
1N/A case SIGTERM:
1N/A sigbit = PEND_SIGTERM;
1N/A break;
1N/A
1N/A case SIGUSR1:
1N/A sigbit = PEND_SIGUSR1;
1N/A break;
1N/A
1N/A case SIGALRM:
1N/A /* don't have to pend these */
1N/A sigbit = 0;
1N/A break;
1N/A
1N/A default:
1N/A /* If we get here, we are in trouble */
1N/A abort();
1N/A
1N/A /* NOTREACHED */
1N/A /* shut up stupid compiler warning on HP-UX 11 */
1N/A sigbit = 0;
1N/A break;
1N/A }
1N/A
1N/A if (sigbit != 0)
1N/A PendingSignal |= sigbit;
1N/A (void) sm_signal(SIGALRM, sm_tick);
1N/A#if SM_CONF_SETITIMER
1N/A clr.it_interval.tv_sec = 0;
1N/A clr.it_interval.tv_usec = 0;
1N/A clr.it_value.tv_sec = 1;
1N/A clr.it_value.tv_usec = 0;
1N/A (void) setitimer(ITIMER_REAL, &clr, NULL);
1N/A#else /* SM_CONF_SETITIMER */
1N/A (void) alarm(1);
1N/A#endif /* SM_CONF_SETITIMER */
1N/A errno = save_errno;
1N/A}
1N/A/*
1N/A** SM_ALLSIGNALS -- act on all signals
1N/A**
1N/A** Parameters:
1N/A** block -- whether to block or release all signals.
1N/A**
1N/A** Returns:
1N/A** none.
1N/A*/
1N/A
1N/Avoid
1N/Asm_allsignals(block)
1N/A bool block;
1N/A{
1N/A# ifdef BSD4_3
1N/A# ifndef sigmask
1N/A# define sigmask(s) (1 << ((s) - 1))
1N/A# endif /* ! sigmask */
1N/A if (block)
1N/A {
1N/A int mask = 0;
1N/A
1N/A mask |= sigmask(SIGALRM);
1N/A mask |= sigmask(SIGCHLD);
1N/A mask |= sigmask(SIGHUP);
1N/A mask |= sigmask(SIGINT);
1N/A mask |= sigmask(SIGTERM);
1N/A mask |= sigmask(SIGUSR1);
1N/A
1N/A (void) sigblock(mask);
1N/A }
1N/A else
1N/A sigsetmask(0);
1N/A# else /* BSD4_3 */
1N/A# ifdef ALTOS_SYSTEM_V
1N/A if (block)
1N/A {
1N/A (void) sigset(SIGALRM, SIG_HOLD);
1N/A (void) sigset(SIGCHLD, SIG_HOLD);
1N/A (void) sigset(SIGHUP, SIG_HOLD);
1N/A (void) sigset(SIGINT, SIG_HOLD);
1N/A (void) sigset(SIGTERM, SIG_HOLD);
1N/A (void) sigset(SIGUSR1, SIG_HOLD);
1N/A }
1N/A else
1N/A {
1N/A (void) sigset(SIGALRM, SIG_DFL);
1N/A (void) sigset(SIGCHLD, SIG_DFL);
1N/A (void) sigset(SIGHUP, SIG_DFL);
1N/A (void) sigset(SIGINT, SIG_DFL);
1N/A (void) sigset(SIGTERM, SIG_DFL);
1N/A (void) sigset(SIGUSR1, SIG_DFL);
1N/A }
1N/A# else /* ALTOS_SYSTEM_V */
1N/A sigset_t sset;
1N/A
1N/A (void) sigemptyset(&sset);
1N/A (void) sigaddset(&sset, SIGALRM);
1N/A (void) sigaddset(&sset, SIGCHLD);
1N/A (void) sigaddset(&sset, SIGHUP);
1N/A (void) sigaddset(&sset, SIGINT);
1N/A (void) sigaddset(&sset, SIGTERM);
1N/A (void) sigaddset(&sset, SIGUSR1);
1N/A (void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
1N/A# endif /* ALTOS_SYSTEM_V */
1N/A# endif /* BSD4_3 */
1N/A}
1N/A/*
1N/A** SM_SIGNAL_NOOP -- A signal no-op function
1N/A**
1N/A** Parameters:
1N/A** sig -- signal received
1N/A**
1N/A** Returns:
1N/A** SIGFUNC_RETURN
1N/A*/
1N/A
1N/A/* ARGSUSED */
1N/ASIGFUNC_DECL
1N/Asm_signal_noop(sig)
1N/A int sig;
1N/A{
1N/A int save_errno = errno;
1N/A
1N/A FIX_SYSV_SIGNAL(sig, sm_signal_noop);
1N/A errno = save_errno;
1N/A return SIGFUNC_RETURN;
1N/A}
1N/A