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> 11 SM_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 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 /* 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 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 /* ! 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 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 /* 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 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 /* ! 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 */ 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