1 /* $NetBSD: sig.c,v 1.3 2012/06/12 19:03:26 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: sig.c,v 1.3 2012/06/12 19:03:26 christos Exp $"); 35 #endif /* not lint */ 36 37 #include <assert.h> 38 #include <util.h> 39 #include <sys/queue.h> 40 41 #include "rcv.h" 42 #include "extern.h" 43 #include "sig.h" 44 45 /* 46 * Mail -- a mail program 47 * 48 * Signal routines. 49 */ 50 51 static sig_t sigarray[NSIG]; 52 53 typedef struct q_entry_s { 54 int qe_signo; 55 sig_t qe_handler; 56 struct q_entry_s *qe_next; 57 } q_entry_t; 58 59 static struct { 60 q_entry_t *qe_first; 61 q_entry_t **qe_last; 62 } sigq = { NULL, &sigq.qe_first }; 63 #define SIGQUEUE_INIT(p) do {\ 64 (p)->qe_first = NULL;\ 65 (p)->qe_last = &((p)->qe_first);\ 66 } while (/*CONSTCOND*/ 0) 67 68 /* 69 * The routines alloc_entry() and free_entry() manage the queue 70 * elements. 71 * 72 * Currently, they just assign one element per signo from a fix array 73 * as we don't support POSIX signal queues. We leave them as this may 74 * change in the future and the modifications will be isolated. 75 */ 76 static q_entry_t * 77 alloc_entry(int signo) 78 { 79 static q_entry_t entries[NSIG]; 80 q_entry_t *e; 81 82 /* 83 * We currently only post one signal per signal number, so 84 * there is no need to make this complicated. 85 */ 86 e = &entries[signo]; 87 if (e->qe_signo != 0) 88 return NULL; 89 90 e->qe_signo = signo; 91 e->qe_handler = sigarray[signo]; 92 e->qe_next = NULL; 93 94 return e; 95 } 96 97 static void 98 free_entry(q_entry_t *e) 99 { 100 101 e->qe_signo = 0; 102 e->qe_handler = NULL; 103 e->qe_next = NULL; 104 } 105 106 /* 107 * Attempt to post a signal to the sigq. 108 */ 109 static void 110 sig_post(int signo) 111 { 112 q_entry_t *e; 113 114 if (sigarray[signo] == SIG_DFL || sigarray[signo] == SIG_IGN) 115 return; 116 117 e = alloc_entry(signo); 118 if (e != NULL) { 119 *sigq.qe_last = e; 120 sigq.qe_last = &e->qe_next; 121 } 122 } 123 124 /* 125 * Check the sigq for any pending signals. If any are found, 126 * preform the required actions and remove them from the queue. 127 */ 128 PUBLIC void 129 sig_check(void) 130 { 131 q_entry_t *e; 132 sigset_t nset; 133 sigset_t oset; 134 void (*handler)(int); 135 int signo; 136 137 (void)sigfillset(&nset); 138 (void)sigprocmask(SIG_SETMASK, &nset, &oset); 139 140 while ((e = sigq.qe_first) != NULL) { 141 signo = e->qe_signo; 142 handler = e->qe_handler; 143 144 /* 145 * Remove the entry from the queue and free it. 146 */ 147 sigq.qe_first = e->qe_next; 148 if (sigq.qe_first == NULL) 149 sigq.qe_last = &sigq.qe_first; 150 free_entry(e); 151 152 if (handler == SIG_DFL || handler == SIG_IGN) { 153 assert(/*CONSTCOND*/ 0); /* These should not get posted. */ 154 } 155 else { 156 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 157 handler(signo); 158 (void)sigprocmask(SIG_SETMASK, &nset, NULL); 159 } 160 } 161 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 162 } 163 164 PUBLIC sig_t 165 sig_current(int signo) 166 { 167 assert(signo > 0 && signo < NSIG); 168 return sigarray[signo]; 169 } 170 171 PUBLIC sig_t 172 sig_signal(int signo, sig_t handler) 173 { 174 sig_t old_handler; 175 sigset_t nset; 176 sigset_t oset; 177 178 assert(signo > 0 && signo < NSIG); 179 180 (void)sigemptyset(&nset); 181 (void)sigaddset(&nset, signo); 182 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 183 184 old_handler = sigarray[signo]; 185 sigarray[signo] = handler; 186 187 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 188 189 return old_handler; 190 } 191 192 static void 193 do_default_handler(int signo, int flags) 194 { 195 struct sigaction nsa; 196 struct sigaction osa; 197 sigset_t nset; 198 sigset_t oset; 199 int save_errno; 200 201 save_errno = errno; 202 (void)sigemptyset(&nsa.sa_mask); 203 nsa.sa_flags = flags; 204 nsa.sa_handler = SIG_DFL; 205 (void)sigaction(signo, &nsa, &osa); 206 207 (void)sigemptyset(&nset); 208 (void)sigaddset(&nset, signo); 209 (void)sigprocmask(SIG_UNBLOCK, &nset, &oset); 210 211 (void)kill(0, signo); 212 213 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 214 (void)sigaction(signo, &osa, NULL); 215 errno = save_errno; 216 } 217 218 /* 219 * Our generic signal handler. 220 */ 221 static void 222 sig_handler(int signo) 223 { 224 sigset_t nset; 225 sigset_t oset; 226 227 (void)sigfillset(&nset); 228 (void)sigprocmask(SIG_SETMASK, &nset, &oset); 229 230 assert (signo > 0 && signo < NSIG); /* Should be guaranteed. */ 231 232 sig_post(signo); 233 234 switch (signo) { 235 case SIGCONT: 236 assert(/*CONSTCOND*/ 0); /* We should not be seeing these. */ 237 do_default_handler(signo, 0); 238 break; 239 240 case SIGTSTP: 241 case SIGTTIN: 242 case SIGTTOU: 243 do_default_handler(signo, 0); 244 break; 245 246 case SIGINT: 247 case SIGHUP: 248 case SIGQUIT: 249 case SIGPIPE: 250 default: 251 if (sigarray[signo] == SIG_DFL) 252 do_default_handler(signo, SA_RESTART); 253 break; 254 } 255 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 256 } 257 258 /* 259 * Setup the signal handlers. 260 */ 261 PUBLIC void 262 sig_setup(void) 263 { 264 sigset_t nset; 265 sigset_t oset; 266 struct sigaction sa; 267 struct sigaction osa; 268 269 /* Block all signals while setting things. */ 270 (void)sigfillset(&nset); 271 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 272 273 /* 274 * Flow Control - SIGTSTP, SIGTTIN, SIGTTOU, SIGCONT: 275 * 276 * We grab SIGTSTP, SIGTTIN, and SIGTTOU so that we post the 277 * signals before suspending so that they are available when 278 * we resume. If we were to use SIGCONT instead, they will 279 * not get posted until SIGCONT is unblocked, even though the 280 * process has resumed. 281 * 282 * NOTE: We default these to SA_RESTART here, but we need to 283 * change this in certain cases, e.g., when reading from a 284 * tty. 285 */ 286 (void)sigemptyset(&sa.sa_mask); 287 sa.sa_flags = SA_RESTART; 288 sa.sa_handler = sig_handler; 289 (void)sigaction(SIGTSTP, &sa, NULL); 290 (void)sigaction(SIGTTIN, &sa, NULL); 291 (void)sigaction(SIGTTOU, &sa, NULL); 292 293 /* 294 * SIGHUP, SIGINT, and SIGQUIT: 295 * 296 * SIGHUP and SIGINT are trapped unless they are being 297 * ignored. 298 * 299 * Currently, we let the default handler deal with SIGQUIT. 300 */ 301 (void)sigemptyset(&sa.sa_mask); 302 sa.sa_flags = 0; 303 sa.sa_handler = sig_handler; 304 305 if (sigaction(SIGHUP, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN) 306 (void)signal(SIGHUP, SIG_IGN); 307 308 if (sigaction(SIGINT, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN) 309 (void)signal(SIGINT, SIG_IGN); 310 #if 0 311 if (signal(SIGQUIT, SIG_DFL) == SIG_IGN) 312 (void)signal(SIGQUIT, SIG_IGN); 313 #endif 314 /* 315 * SIGCHLD and SIGPIPE: 316 * 317 * SIGCHLD is setup early in main. The handler lives in 318 * popen.c as it uses internals of that module. 319 * 320 * SIGPIPE is grabbed here. It is only used in 321 * lex.c:setup_piping(), cmd1.c:type1(), and cmd1.c:pipecmd(). 322 */ 323 (void)sigemptyset(&sa.sa_mask); 324 sa.sa_flags = 0; 325 sa.sa_handler = sig_handler; 326 (void)sigaction(SIGPIPE, &sa, NULL); 327 328 /* 329 * Make sure our structures are initialized. 330 * XXX: This should be unnecessary. 331 */ 332 (void)memset(sigarray, 0, sizeof(sigarray)); 333 SIGQUEUE_INIT(&sigq); 334 335 /* Restore the signal mask. */ 336 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 337 } 338 339 static struct { /* data shared by sig_hold() and sig_release() */ 340 int depth; /* depth of sig_hold() */ 341 sigset_t oset; /* old signal mask saved by sig_hold() */ 342 } hold; 343 344 /* 345 * Hold signals SIGHUP, SIGINT, and SIGQUIT. 346 */ 347 PUBLIC void 348 sig_hold(void) 349 { 350 sigset_t nset; 351 352 if (hold.depth++ == 0) { 353 (void)sigemptyset(&nset); 354 (void)sigaddset(&nset, SIGHUP); 355 (void)sigaddset(&nset, SIGINT); 356 (void)sigaddset(&nset, SIGQUIT); 357 (void)sigprocmask(SIG_BLOCK, &nset, &hold.oset); 358 } 359 } 360 361 /* 362 * Release signals SIGHUP, SIGINT, and SIGQUIT. 363 */ 364 PUBLIC void 365 sig_release(void) 366 { 367 368 if (--hold.depth == 0) 369 (void)sigprocmask(SIG_SETMASK, &hold.oset, NULL); 370 } 371 372 /* 373 * Unblock and ignore a signal. 374 */ 375 PUBLIC int 376 sig_ignore(int sig, struct sigaction *osa, sigset_t *oset) 377 { 378 struct sigaction act; 379 sigset_t nset; 380 int error; 381 382 (void)sigemptyset(&act.sa_mask); 383 act.sa_flags = SA_RESTART; 384 act.sa_handler = SIG_IGN; 385 error = sigaction(sig, &act, osa); 386 387 if (error != -1) { 388 (void)sigemptyset(&nset); 389 (void)sigaddset(&nset, sig); 390 (void)sigprocmask(SIG_UNBLOCK, &nset, oset); 391 } else if (oset != NULL) 392 (void)sigprocmask(SIG_UNBLOCK, NULL, oset); 393 394 return error; 395 } 396 397 /* 398 * Restore a signal and the current signal mask. 399 */ 400 PUBLIC int 401 sig_restore(int sig, struct sigaction *osa, sigset_t *oset) 402 { 403 int error; 404 405 error = 0; 406 if (oset) 407 error = sigprocmask(SIG_SETMASK, oset, NULL); 408 if (osa) 409 error = sigaction(sig, osa, NULL); 410 411 return error; 412 } 413 414 /* 415 * Change the current flags and (optionally) return the old sigaction 416 * structure so we can restore things later. This is used to turn 417 * SA_RESTART on or off. 418 */ 419 PUBLIC int 420 sig_setflags(int signo, int flags, struct sigaction *osa) 421 { 422 struct sigaction sa; 423 424 if (sigaction(signo, NULL, &sa) == -1) 425 return -1; 426 if (osa) 427 *osa = sa; 428 sa.sa_flags = flags; 429 return sigaction(signo, &sa, NULL); 430 } 431 432