1/*
2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 */
9
10#include <sm/gen.h>
11SM_RCSID("@(#)$Id: signal.c,v 1.17 2005/06/14 23:07:20 ca Exp $")
12
13#if SM_CONF_SETITIMER
14# include <sm/time.h>
15#endif /* SM_CONF_SETITIMER */
16#include <errno.h>
17#include <stdlib.h>
18#include <time.h>
19#include <unistd.h>
20#include <sm/clock.h>
21#include <sm/signal.h>
22#include <signal.h>
23#include <sm/string.h>
24
25unsigned int	volatile InCriticalSection; /* >0 if inside critical section */
26int		volatile PendingSignal;	/* pending signal to resend */
27
28/*
29**  SM_SIGNAL -- set a signal handler
30**
31**	This is essentially old BSD "signal(3)".
32**
33**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
34**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
35**		DOING.
36*/
37
38sigfunc_t
39sm_signal(sig, handler)
40	int sig;
41	sigfunc_t handler;
42{
43# if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
44	struct sigaction n, o;
45# endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
46
47	/*
48	**  First, try for modern signal calls
49	**  and restartable syscalls
50	*/
51
52# ifdef SA_RESTART
53	(void) memset(&n, '\0', sizeof n);
54#  if USE_SA_SIGACTION
55	n.sa_sigaction = (void(*)(int, siginfo_t *, void *))(uintptr_t) handler;
56	n.sa_flags = SA_RESTART|SA_SIGINFO;
57#  else /* USE_SA_SIGACTION */
58	n.sa_handler = handler;
59	n.sa_flags = SA_RESTART;
60#  endif /* USE_SA_SIGACTION */
61	if (sigaction(sig, &n, &o) < 0)
62		return SIG_ERR;
63	return o.sa_handler;
64# else /* SA_RESTART */
65
66	/*
67	**  Else check for SYS5SIGNALS or
68	**  BSD4_3 signals
69	*/
70
71#  if defined(SYS5SIGNALS) || defined(BSD4_3)
72#   ifdef BSD4_3
73	return signal(sig, handler);
74#   else /* BSD4_3 */
75	return sigset(sig, handler);
76#   endif /* BSD4_3 */
77#  else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
78
79	/*
80	**  Finally, if nothing else is available,
81	**  go for a default
82	*/
83
84	(void) memset(&n, '\0', sizeof n);
85	n.sa_handler = handler;
86	if (sigaction(sig, &n, &o) < 0)
87		return SIG_ERR;
88	return o.sa_handler;
89#  endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
90# endif /* SA_RESTART */
91}
92/*
93**  SM_BLOCKSIGNAL -- hold a signal to prevent delivery
94**
95**	Parameters:
96**		sig -- the signal to block.
97**
98**	Returns:
99**		1 signal was previously blocked
100**		0 signal was not previously blocked
101**		-1 on failure.
102*/
103
104int
105sm_blocksignal(sig)
106	int sig;
107{
108# ifdef BSD4_3
109#  ifndef sigmask
110#   define sigmask(s)	(1 << ((s) - 1))
111#  endif /* ! sigmask */
112	return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
113# else /* BSD4_3 */
114#  ifdef ALTOS_SYSTEM_V
115	sigfunc_t handler;
116
117	handler = sigset(sig, SIG_HOLD);
118	if (handler == SIG_ERR)
119		return -1;
120	else
121		return handler == SIG_HOLD;
122#  else /* ALTOS_SYSTEM_V */
123	sigset_t sset, oset;
124
125	(void) sigemptyset(&sset);
126	(void) sigaddset(&sset, sig);
127	if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
128		return -1;
129	else
130		return sigismember(&oset, sig);
131#  endif /* ALTOS_SYSTEM_V */
132# endif /* BSD4_3 */
133}
134/*
135**  SM_RELEASESIGNAL -- release a held signal
136**
137**	Parameters:
138**		sig -- the signal to release.
139**
140**	Returns:
141**		1 signal was previously blocked
142**		0 signal was not previously blocked
143**		-1 on failure.
144*/
145
146int
147sm_releasesignal(sig)
148	int sig;
149{
150# ifdef BSD4_3
151	return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
152# else /* BSD4_3 */
153#  ifdef ALTOS_SYSTEM_V
154	sigfunc_t handler;
155
156	handler = sigset(sig, SIG_HOLD);
157	if (sigrelse(sig) < 0)
158		return -1;
159	else
160		return handler == SIG_HOLD;
161#  else /* ALTOS_SYSTEM_V */
162	sigset_t sset, oset;
163
164	(void) sigemptyset(&sset);
165	(void) sigaddset(&sset, sig);
166	if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
167		return -1;
168	else
169		return sigismember(&oset, sig);
170#  endif /* ALTOS_SYSTEM_V */
171# endif /* BSD4_3 */
172}
173/*
174**  PEND_SIGNAL -- Add a signal to the pending signal list
175**
176**	Parameters:
177**		sig -- signal to add
178**
179**	Returns:
180**		none.
181**
182**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
183**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
184**		DOING.
185*/
186
187void
188pend_signal(sig)
189	int sig;
190{
191	int sigbit;
192	int save_errno = errno;
193#if SM_CONF_SETITIMER
194	struct itimerval clr;
195#endif /* SM_CONF_SETITIMER */
196
197	/*
198	**  Don't want to interrupt something critical, hence delay
199	**  the alarm for one second.  Hopefully, by then we
200	**  will be out of the critical section.  If not, then
201	**  we will just delay again.  The events to be run will
202	**  still all be run, maybe just a little bit late.
203	*/
204
205	switch (sig)
206	{
207	  case SIGHUP:
208		sigbit = PEND_SIGHUP;
209		break;
210
211	  case SIGINT:
212		sigbit = PEND_SIGINT;
213		break;
214
215	  case SIGTERM:
216		sigbit = PEND_SIGTERM;
217		break;
218
219	  case SIGUSR1:
220		sigbit = PEND_SIGUSR1;
221		break;
222
223	  case SIGALRM:
224		/* don't have to pend these */
225		sigbit = 0;
226		break;
227
228	  default:
229		/* If we get here, we are in trouble */
230		abort();
231
232		/* NOTREACHED */
233		/* shut up stupid compiler warning on HP-UX 11 */
234		sigbit = 0;
235		break;
236	}
237
238	if (sigbit != 0)
239		PendingSignal |= sigbit;
240	(void) sm_signal(SIGALRM, sm_tick);
241#if SM_CONF_SETITIMER
242	clr.it_interval.tv_sec = 0;
243	clr.it_interval.tv_usec = 0;
244	clr.it_value.tv_sec = 1;
245	clr.it_value.tv_usec = 0;
246	(void) setitimer(ITIMER_REAL, &clr, NULL);
247#else /* SM_CONF_SETITIMER */
248	(void) alarm(1);
249#endif /* SM_CONF_SETITIMER */
250	errno = save_errno;
251}
252/*
253**  SM_ALLSIGNALS -- act on all signals
254**
255**	Parameters:
256**		block -- whether to block or release all signals.
257**
258**	Returns:
259**		none.
260*/
261
262void
263sm_allsignals(block)
264	bool block;
265{
266# ifdef BSD4_3
267#  ifndef sigmask
268#   define sigmask(s)	(1 << ((s) - 1))
269#  endif /* ! sigmask */
270	if (block)
271	{
272		int mask = 0;
273
274		mask |= sigmask(SIGALRM);
275		mask |= sigmask(SIGCHLD);
276		mask |= sigmask(SIGHUP);
277		mask |= sigmask(SIGINT);
278		mask |= sigmask(SIGTERM);
279		mask |= sigmask(SIGUSR1);
280
281		(void) sigblock(mask);
282	}
283	else
284		sigsetmask(0);
285# else /* BSD4_3 */
286#  ifdef ALTOS_SYSTEM_V
287	if (block)
288	{
289		(void) sigset(SIGALRM, SIG_HOLD);
290		(void) sigset(SIGCHLD, SIG_HOLD);
291		(void) sigset(SIGHUP, SIG_HOLD);
292		(void) sigset(SIGINT, SIG_HOLD);
293		(void) sigset(SIGTERM, SIG_HOLD);
294		(void) sigset(SIGUSR1, SIG_HOLD);
295	}
296	else
297	{
298		(void) sigset(SIGALRM, SIG_DFL);
299		(void) sigset(SIGCHLD, SIG_DFL);
300		(void) sigset(SIGHUP, SIG_DFL);
301		(void) sigset(SIGINT, SIG_DFL);
302		(void) sigset(SIGTERM, SIG_DFL);
303		(void) sigset(SIGUSR1, SIG_DFL);
304	}
305#  else /* ALTOS_SYSTEM_V */
306	sigset_t sset;
307
308	(void) sigemptyset(&sset);
309	(void) sigaddset(&sset, SIGALRM);
310	(void) sigaddset(&sset, SIGCHLD);
311	(void) sigaddset(&sset, SIGHUP);
312	(void) sigaddset(&sset, SIGINT);
313	(void) sigaddset(&sset, SIGTERM);
314	(void) sigaddset(&sset, SIGUSR1);
315	(void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
316#  endif /* ALTOS_SYSTEM_V */
317# endif /* BSD4_3 */
318}
319/*
320**  SM_SIGNAL_NOOP -- A signal no-op function
321**
322**	Parameters:
323**		sig -- signal received
324**
325**	Returns:
326**		SIGFUNC_RETURN
327*/
328
329/* ARGSUSED */
330SIGFUNC_DECL
331sm_signal_noop(sig)
332	int sig;
333{
334	int save_errno = errno;
335
336	FIX_SYSV_SIGNAL(sig, sm_signal_noop);
337	errno = save_errno;
338	return SIGFUNC_RETURN;
339}
340
341