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.17 2005/06/14 23:07:20 ca Exp $") 14 15 #if SM_CONF_SETITIMER 16 # include <sm/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