xref: /freebsd/contrib/sendmail/libsm/signal.c (revision 4530e0c3e78d0616367d37273d6c1f47f627839b)
1 /*
2  * Copyright (c) 2000-2001 Proofpoint, 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>
11 SM_RCSID("@(#)$Id: signal.c,v 1.18 2013-11-22 20:51:43 ca Exp $")
12 
13 #if SM_CONF_SETITIMER
14 # include <sm/time.h>
15 #endif
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 
25 unsigned int	volatile InCriticalSection; /* >0 if inside critical section */
26 int		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 
38 sigfunc_t
39 sm_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
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 *)) handler;
56 	n.sa_flags = SA_RESTART|SA_SIGINFO;
57 # else
58 	n.sa_handler = handler;
59 	n.sa_flags = SA_RESTART;
60 # endif
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
75 	return sigset(sig, handler);
76 #  endif
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 
104 int
105 sm_blocksignal(sig)
106 	int sig;
107 {
108 #ifdef BSD4_3
109 # ifndef sigmask
110 #  define sigmask(s)	(1 << ((s) - 1))
111 # endif
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 
146 int
147 sm_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 
187 void
188 pend_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
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 
262 void
263 sm_allsignals(block)
264 	bool block;
265 {
266 #ifdef BSD4_3
267 # ifndef sigmask
268 #  define sigmask(s)	(1 << ((s) - 1))
269 # endif
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 */
330 SIGFUNC_DECL
331 sm_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