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