xref: /freebsd/contrib/sendmail/libsm/signal.c (revision 2fb4f839f3fc72ce2bab12f9ba4760f97f73e97f)
140266059SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers.
340266059SGregory Neil Shapiro  *      All rights reserved.
440266059SGregory Neil Shapiro  *
540266059SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
640266059SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
740266059SGregory Neil Shapiro  * the sendmail distribution.
840266059SGregory Neil Shapiro  */
940266059SGregory Neil Shapiro 
1040266059SGregory Neil Shapiro #include <sm/gen.h>
114313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: signal.c,v 1.18 2013-11-22 20:51:43 ca Exp $")
1240266059SGregory Neil Shapiro 
1340266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
144e4196cbSGregory Neil Shapiro # include <sm/time.h>
15*5b0945b5SGregory Neil Shapiro #endif
1640266059SGregory Neil Shapiro #include <errno.h>
1740266059SGregory Neil Shapiro #include <stdlib.h>
1840266059SGregory Neil Shapiro #include <time.h>
1940266059SGregory Neil Shapiro #include <unistd.h>
2040266059SGregory Neil Shapiro #include <sm/clock.h>
2140266059SGregory Neil Shapiro #include <sm/signal.h>
2240266059SGregory Neil Shapiro #include <signal.h>
2340266059SGregory Neil Shapiro #include <sm/string.h>
2440266059SGregory Neil Shapiro 
2540266059SGregory Neil Shapiro unsigned int	volatile InCriticalSection; /* >0 if inside critical section */
2640266059SGregory Neil Shapiro int		volatile PendingSignal;	/* pending signal to resend */
2740266059SGregory Neil Shapiro 
2840266059SGregory Neil Shapiro /*
2940266059SGregory Neil Shapiro **  SM_SIGNAL -- set a signal handler
3040266059SGregory Neil Shapiro **
3140266059SGregory Neil Shapiro **	This is essentially old BSD "signal(3)".
3240266059SGregory Neil Shapiro **
3340266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3440266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3540266059SGregory Neil Shapiro **		DOING.
3640266059SGregory Neil Shapiro */
3740266059SGregory Neil Shapiro 
3840266059SGregory Neil Shapiro sigfunc_t
sm_signal(sig,handler)3940266059SGregory Neil Shapiro sm_signal(sig, handler)
4040266059SGregory Neil Shapiro 	int sig;
4140266059SGregory Neil Shapiro 	sigfunc_t handler;
4240266059SGregory Neil Shapiro {
4340266059SGregory Neil Shapiro #if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
4440266059SGregory Neil Shapiro 	struct sigaction n, o;
45*5b0945b5SGregory Neil Shapiro #endif
4640266059SGregory Neil Shapiro 
4740266059SGregory Neil Shapiro 	/*
4840266059SGregory Neil Shapiro 	**  First, try for modern signal calls
4940266059SGregory Neil Shapiro 	**  and restartable syscalls
5040266059SGregory Neil Shapiro 	*/
5140266059SGregory Neil Shapiro 
5240266059SGregory Neil Shapiro #ifdef SA_RESTART
5340266059SGregory Neil Shapiro 	(void) memset(&n, '\0', sizeof n);
5440266059SGregory Neil Shapiro # if USE_SA_SIGACTION
5540266059SGregory Neil Shapiro 	n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
5640266059SGregory Neil Shapiro 	n.sa_flags = SA_RESTART|SA_SIGINFO;
57*5b0945b5SGregory Neil Shapiro # else
5840266059SGregory Neil Shapiro 	n.sa_handler = handler;
5940266059SGregory Neil Shapiro 	n.sa_flags = SA_RESTART;
60*5b0945b5SGregory Neil Shapiro # endif
6140266059SGregory Neil Shapiro 	if (sigaction(sig, &n, &o) < 0)
6240266059SGregory Neil Shapiro 		return SIG_ERR;
6340266059SGregory Neil Shapiro 	return o.sa_handler;
6440266059SGregory Neil Shapiro #else /* SA_RESTART */
6540266059SGregory Neil Shapiro 
6640266059SGregory Neil Shapiro 	/*
6740266059SGregory Neil Shapiro 	**  Else check for SYS5SIGNALS or
6840266059SGregory Neil Shapiro 	**  BSD4_3 signals
6940266059SGregory Neil Shapiro 	*/
7040266059SGregory Neil Shapiro 
7140266059SGregory Neil Shapiro # if defined(SYS5SIGNALS) || defined(BSD4_3)
7240266059SGregory Neil Shapiro #  ifdef BSD4_3
7340266059SGregory Neil Shapiro 	return signal(sig, handler);
74*5b0945b5SGregory Neil Shapiro #  else
7540266059SGregory Neil Shapiro 	return sigset(sig, handler);
76*5b0945b5SGregory Neil Shapiro #  endif
7740266059SGregory Neil Shapiro # else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
7840266059SGregory Neil Shapiro 
7940266059SGregory Neil Shapiro 	/*
8040266059SGregory Neil Shapiro 	**  Finally, if nothing else is available,
8140266059SGregory Neil Shapiro 	**  go for a default
8240266059SGregory Neil Shapiro 	*/
8340266059SGregory Neil Shapiro 
8440266059SGregory Neil Shapiro 	(void) memset(&n, '\0', sizeof n);
8540266059SGregory Neil Shapiro 	n.sa_handler = handler;
8640266059SGregory Neil Shapiro 	if (sigaction(sig, &n, &o) < 0)
8740266059SGregory Neil Shapiro 		return SIG_ERR;
8840266059SGregory Neil Shapiro 	return o.sa_handler;
8940266059SGregory Neil Shapiro # endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
9040266059SGregory Neil Shapiro #endif /* SA_RESTART */
9140266059SGregory Neil Shapiro }
9240266059SGregory Neil Shapiro /*
9340266059SGregory Neil Shapiro **  SM_BLOCKSIGNAL -- hold a signal to prevent delivery
9440266059SGregory Neil Shapiro **
9540266059SGregory Neil Shapiro **	Parameters:
9640266059SGregory Neil Shapiro **		sig -- the signal to block.
9740266059SGregory Neil Shapiro **
9840266059SGregory Neil Shapiro **	Returns:
9940266059SGregory Neil Shapiro **		1 signal was previously blocked
10040266059SGregory Neil Shapiro **		0 signal was not previously blocked
10140266059SGregory Neil Shapiro **		-1 on failure.
10240266059SGregory Neil Shapiro */
10340266059SGregory Neil Shapiro 
10440266059SGregory Neil Shapiro int
sm_blocksignal(sig)10540266059SGregory Neil Shapiro sm_blocksignal(sig)
10640266059SGregory Neil Shapiro 	int sig;
10740266059SGregory Neil Shapiro {
10840266059SGregory Neil Shapiro #ifdef BSD4_3
10940266059SGregory Neil Shapiro # ifndef sigmask
11040266059SGregory Neil Shapiro #  define sigmask(s)	(1 << ((s) - 1))
111*5b0945b5SGregory Neil Shapiro # endif
11240266059SGregory Neil Shapiro 	return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
11340266059SGregory Neil Shapiro #else /* BSD4_3 */
11440266059SGregory Neil Shapiro # ifdef ALTOS_SYSTEM_V
11540266059SGregory Neil Shapiro 	sigfunc_t handler;
11640266059SGregory Neil Shapiro 
11740266059SGregory Neil Shapiro 	handler = sigset(sig, SIG_HOLD);
11840266059SGregory Neil Shapiro 	if (handler == SIG_ERR)
11940266059SGregory Neil Shapiro 		return -1;
12040266059SGregory Neil Shapiro 	else
12140266059SGregory Neil Shapiro 		return handler == SIG_HOLD;
12240266059SGregory Neil Shapiro # else /* ALTOS_SYSTEM_V */
12340266059SGregory Neil Shapiro 	sigset_t sset, oset;
12440266059SGregory Neil Shapiro 
12540266059SGregory Neil Shapiro 	(void) sigemptyset(&sset);
12640266059SGregory Neil Shapiro 	(void) sigaddset(&sset, sig);
12740266059SGregory Neil Shapiro 	if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
12840266059SGregory Neil Shapiro 		return -1;
12940266059SGregory Neil Shapiro 	else
13040266059SGregory Neil Shapiro 		return sigismember(&oset, sig);
13140266059SGregory Neil Shapiro # endif /* ALTOS_SYSTEM_V */
13240266059SGregory Neil Shapiro #endif /* BSD4_3 */
13340266059SGregory Neil Shapiro }
13440266059SGregory Neil Shapiro /*
13540266059SGregory Neil Shapiro **  SM_RELEASESIGNAL -- release a held signal
13640266059SGregory Neil Shapiro **
13740266059SGregory Neil Shapiro **	Parameters:
13840266059SGregory Neil Shapiro **		sig -- the signal to release.
13940266059SGregory Neil Shapiro **
14040266059SGregory Neil Shapiro **	Returns:
14140266059SGregory Neil Shapiro **		1 signal was previously blocked
14240266059SGregory Neil Shapiro **		0 signal was not previously blocked
14340266059SGregory Neil Shapiro **		-1 on failure.
14440266059SGregory Neil Shapiro */
14540266059SGregory Neil Shapiro 
14640266059SGregory Neil Shapiro int
sm_releasesignal(sig)14740266059SGregory Neil Shapiro sm_releasesignal(sig)
14840266059SGregory Neil Shapiro 	int sig;
14940266059SGregory Neil Shapiro {
15040266059SGregory Neil Shapiro #ifdef BSD4_3
15140266059SGregory Neil Shapiro 	return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
15240266059SGregory Neil Shapiro #else /* BSD4_3 */
15340266059SGregory Neil Shapiro # ifdef ALTOS_SYSTEM_V
15440266059SGregory Neil Shapiro 	sigfunc_t handler;
15540266059SGregory Neil Shapiro 
15640266059SGregory Neil Shapiro 	handler = sigset(sig, SIG_HOLD);
15740266059SGregory Neil Shapiro 	if (sigrelse(sig) < 0)
15840266059SGregory Neil Shapiro 		return -1;
15940266059SGregory Neil Shapiro 	else
16040266059SGregory Neil Shapiro 		return handler == SIG_HOLD;
16140266059SGregory Neil Shapiro # else /* ALTOS_SYSTEM_V */
16240266059SGregory Neil Shapiro 	sigset_t sset, oset;
16340266059SGregory Neil Shapiro 
16440266059SGregory Neil Shapiro 	(void) sigemptyset(&sset);
16540266059SGregory Neil Shapiro 	(void) sigaddset(&sset, sig);
16640266059SGregory Neil Shapiro 	if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
16740266059SGregory Neil Shapiro 		return -1;
16840266059SGregory Neil Shapiro 	else
16940266059SGregory Neil Shapiro 		return sigismember(&oset, sig);
17040266059SGregory Neil Shapiro # endif /* ALTOS_SYSTEM_V */
17140266059SGregory Neil Shapiro #endif /* BSD4_3 */
17240266059SGregory Neil Shapiro }
17340266059SGregory Neil Shapiro /*
17440266059SGregory Neil Shapiro **  PEND_SIGNAL -- Add a signal to the pending signal list
17540266059SGregory Neil Shapiro **
17640266059SGregory Neil Shapiro **	Parameters:
17740266059SGregory Neil Shapiro **		sig -- signal to add
17840266059SGregory Neil Shapiro **
17940266059SGregory Neil Shapiro **	Returns:
18040266059SGregory Neil Shapiro **		none.
18140266059SGregory Neil Shapiro **
18240266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
18340266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
18440266059SGregory Neil Shapiro **		DOING.
18540266059SGregory Neil Shapiro */
18640266059SGregory Neil Shapiro 
18740266059SGregory Neil Shapiro void
pend_signal(sig)18840266059SGregory Neil Shapiro pend_signal(sig)
18940266059SGregory Neil Shapiro 	int sig;
19040266059SGregory Neil Shapiro {
19140266059SGregory Neil Shapiro 	int sigbit;
19240266059SGregory Neil Shapiro 	int save_errno = errno;
19340266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
19440266059SGregory Neil Shapiro 	struct itimerval clr;
195*5b0945b5SGregory Neil Shapiro #endif
19640266059SGregory Neil Shapiro 
19740266059SGregory Neil Shapiro 	/*
19840266059SGregory Neil Shapiro 	**  Don't want to interrupt something critical, hence delay
19940266059SGregory Neil Shapiro 	**  the alarm for one second.  Hopefully, by then we
20040266059SGregory Neil Shapiro 	**  will be out of the critical section.  If not, then
20140266059SGregory Neil Shapiro 	**  we will just delay again.  The events to be run will
20240266059SGregory Neil Shapiro 	**  still all be run, maybe just a little bit late.
20340266059SGregory Neil Shapiro 	*/
20440266059SGregory Neil Shapiro 
20540266059SGregory Neil Shapiro 	switch (sig)
20640266059SGregory Neil Shapiro 	{
20740266059SGregory Neil Shapiro 	  case SIGHUP:
20840266059SGregory Neil Shapiro 		sigbit = PEND_SIGHUP;
20940266059SGregory Neil Shapiro 		break;
21040266059SGregory Neil Shapiro 
21140266059SGregory Neil Shapiro 	  case SIGINT:
21240266059SGregory Neil Shapiro 		sigbit = PEND_SIGINT;
21340266059SGregory Neil Shapiro 		break;
21440266059SGregory Neil Shapiro 
21540266059SGregory Neil Shapiro 	  case SIGTERM:
21640266059SGregory Neil Shapiro 		sigbit = PEND_SIGTERM;
21740266059SGregory Neil Shapiro 		break;
21840266059SGregory Neil Shapiro 
21940266059SGregory Neil Shapiro 	  case SIGUSR1:
22040266059SGregory Neil Shapiro 		sigbit = PEND_SIGUSR1;
22140266059SGregory Neil Shapiro 		break;
22240266059SGregory Neil Shapiro 
22340266059SGregory Neil Shapiro 	  case SIGALRM:
22440266059SGregory Neil Shapiro 		/* don't have to pend these */
22540266059SGregory Neil Shapiro 		sigbit = 0;
22640266059SGregory Neil Shapiro 		break;
22740266059SGregory Neil Shapiro 
22840266059SGregory Neil Shapiro 	  default:
22940266059SGregory Neil Shapiro 		/* If we get here, we are in trouble */
23040266059SGregory Neil Shapiro 		abort();
23140266059SGregory Neil Shapiro 
23240266059SGregory Neil Shapiro 		/* NOTREACHED */
23340266059SGregory Neil Shapiro 		/* shut up stupid compiler warning on HP-UX 11 */
23440266059SGregory Neil Shapiro 		sigbit = 0;
23540266059SGregory Neil Shapiro 		break;
23640266059SGregory Neil Shapiro 	}
23740266059SGregory Neil Shapiro 
23840266059SGregory Neil Shapiro 	if (sigbit != 0)
23940266059SGregory Neil Shapiro 		PendingSignal |= sigbit;
24040266059SGregory Neil Shapiro 	(void) sm_signal(SIGALRM, sm_tick);
24140266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
24240266059SGregory Neil Shapiro 	clr.it_interval.tv_sec = 0;
24340266059SGregory Neil Shapiro 	clr.it_interval.tv_usec = 0;
24440266059SGregory Neil Shapiro 	clr.it_value.tv_sec = 1;
24540266059SGregory Neil Shapiro 	clr.it_value.tv_usec = 0;
24640266059SGregory Neil Shapiro 	(void) setitimer(ITIMER_REAL, &clr, NULL);
24740266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
24840266059SGregory Neil Shapiro 	(void) alarm(1);
24940266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
25040266059SGregory Neil Shapiro 	errno = save_errno;
25140266059SGregory Neil Shapiro }
25240266059SGregory Neil Shapiro /*
25340266059SGregory Neil Shapiro **  SM_ALLSIGNALS -- act on all signals
25440266059SGregory Neil Shapiro **
25540266059SGregory Neil Shapiro **	Parameters:
25640266059SGregory Neil Shapiro **		block -- whether to block or release all signals.
25740266059SGregory Neil Shapiro **
25840266059SGregory Neil Shapiro **	Returns:
25940266059SGregory Neil Shapiro **		none.
26040266059SGregory Neil Shapiro */
26140266059SGregory Neil Shapiro 
26240266059SGregory Neil Shapiro void
sm_allsignals(block)26340266059SGregory Neil Shapiro sm_allsignals(block)
26440266059SGregory Neil Shapiro 	bool block;
26540266059SGregory Neil Shapiro {
26640266059SGregory Neil Shapiro #ifdef BSD4_3
26740266059SGregory Neil Shapiro # ifndef sigmask
26840266059SGregory Neil Shapiro #  define sigmask(s)	(1 << ((s) - 1))
269*5b0945b5SGregory Neil Shapiro # endif
27040266059SGregory Neil Shapiro 	if (block)
27140266059SGregory Neil Shapiro 	{
27240266059SGregory Neil Shapiro 		int mask = 0;
27340266059SGregory Neil Shapiro 
27440266059SGregory Neil Shapiro 		mask |= sigmask(SIGALRM);
27540266059SGregory Neil Shapiro 		mask |= sigmask(SIGCHLD);
27640266059SGregory Neil Shapiro 		mask |= sigmask(SIGHUP);
27740266059SGregory Neil Shapiro 		mask |= sigmask(SIGINT);
27840266059SGregory Neil Shapiro 		mask |= sigmask(SIGTERM);
27940266059SGregory Neil Shapiro 		mask |= sigmask(SIGUSR1);
28040266059SGregory Neil Shapiro 
28140266059SGregory Neil Shapiro 		(void) sigblock(mask);
28240266059SGregory Neil Shapiro 	}
28340266059SGregory Neil Shapiro 	else
28440266059SGregory Neil Shapiro 		sigsetmask(0);
28540266059SGregory Neil Shapiro #else /* BSD4_3 */
28640266059SGregory Neil Shapiro # ifdef ALTOS_SYSTEM_V
28740266059SGregory Neil Shapiro 	if (block)
28840266059SGregory Neil Shapiro 	{
28940266059SGregory Neil Shapiro 		(void) sigset(SIGALRM, SIG_HOLD);
29040266059SGregory Neil Shapiro 		(void) sigset(SIGCHLD, SIG_HOLD);
29140266059SGregory Neil Shapiro 		(void) sigset(SIGHUP, SIG_HOLD);
29240266059SGregory Neil Shapiro 		(void) sigset(SIGINT, SIG_HOLD);
29340266059SGregory Neil Shapiro 		(void) sigset(SIGTERM, SIG_HOLD);
29440266059SGregory Neil Shapiro 		(void) sigset(SIGUSR1, SIG_HOLD);
29540266059SGregory Neil Shapiro 	}
29640266059SGregory Neil Shapiro 	else
29740266059SGregory Neil Shapiro 	{
29840266059SGregory Neil Shapiro 		(void) sigset(SIGALRM, SIG_DFL);
29940266059SGregory Neil Shapiro 		(void) sigset(SIGCHLD, SIG_DFL);
30040266059SGregory Neil Shapiro 		(void) sigset(SIGHUP, SIG_DFL);
30140266059SGregory Neil Shapiro 		(void) sigset(SIGINT, SIG_DFL);
30240266059SGregory Neil Shapiro 		(void) sigset(SIGTERM, SIG_DFL);
30340266059SGregory Neil Shapiro 		(void) sigset(SIGUSR1, SIG_DFL);
30440266059SGregory Neil Shapiro 	}
30540266059SGregory Neil Shapiro # else /* ALTOS_SYSTEM_V */
30640266059SGregory Neil Shapiro 	sigset_t sset;
30740266059SGregory Neil Shapiro 
30840266059SGregory Neil Shapiro 	(void) sigemptyset(&sset);
30940266059SGregory Neil Shapiro 	(void) sigaddset(&sset, SIGALRM);
31040266059SGregory Neil Shapiro 	(void) sigaddset(&sset, SIGCHLD);
31140266059SGregory Neil Shapiro 	(void) sigaddset(&sset, SIGHUP);
31240266059SGregory Neil Shapiro 	(void) sigaddset(&sset, SIGINT);
31340266059SGregory Neil Shapiro 	(void) sigaddset(&sset, SIGTERM);
31440266059SGregory Neil Shapiro 	(void) sigaddset(&sset, SIGUSR1);
31540266059SGregory Neil Shapiro 	(void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
31640266059SGregory Neil Shapiro # endif /* ALTOS_SYSTEM_V */
31740266059SGregory Neil Shapiro #endif /* BSD4_3 */
31840266059SGregory Neil Shapiro }
31940266059SGregory Neil Shapiro /*
32040266059SGregory Neil Shapiro **  SM_SIGNAL_NOOP -- A signal no-op function
32140266059SGregory Neil Shapiro **
32240266059SGregory Neil Shapiro **	Parameters:
32340266059SGregory Neil Shapiro **		sig -- signal received
32440266059SGregory Neil Shapiro **
32540266059SGregory Neil Shapiro **	Returns:
32640266059SGregory Neil Shapiro **		SIGFUNC_RETURN
32740266059SGregory Neil Shapiro */
32840266059SGregory Neil Shapiro 
32940266059SGregory Neil Shapiro /* ARGSUSED */
33040266059SGregory Neil Shapiro SIGFUNC_DECL
sm_signal_noop(sig)33140266059SGregory Neil Shapiro sm_signal_noop(sig)
33240266059SGregory Neil Shapiro 	int sig;
33340266059SGregory Neil Shapiro {
33440266059SGregory Neil Shapiro 	int save_errno = errno;
33540266059SGregory Neil Shapiro 
33640266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sm_signal_noop);
33740266059SGregory Neil Shapiro 	errno = save_errno;
33840266059SGregory Neil Shapiro 	return SIGFUNC_RETURN;
33940266059SGregory Neil Shapiro }
34040266059SGregory Neil Shapiro 
341