1 /* $NetBSD: sig.c,v 1.1 2009/04/10 13:08:25 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.1 2009/04/10 13:08:25 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 } sigqueue = { NULL, &sigqueue.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 sigqueue. 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 *sigqueue.qe_last = e; 120 sigqueue.qe_last = &e->qe_next; 121 } 122 } 123 124 /* 125 * Check the sigqueue 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 = sigqueue.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 sigqueue.qe_first = e->qe_next; 148 if (sigqueue.qe_first == NULL) 149 sigqueue.qe_last = &sigqueue.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_signal(int signo, sig_t handler) 166 { 167 sig_t old_handler; 168 sigset_t nset; 169 sigset_t oset; 170 171 assert(signo > 0 && signo < NSIG); 172 173 (void)sigemptyset(&nset); 174 (void)sigaddset(&nset, signo); 175 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 176 177 old_handler = sigarray[signo]; 178 sigarray[signo] = handler; 179 180 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 181 182 return old_handler; 183 } 184 185 static void 186 do_default_handler(int signo, int flags) 187 { 188 struct sigaction nsa; 189 struct sigaction osa; 190 sigset_t nset; 191 sigset_t oset; 192 int save_errno; 193 194 save_errno = errno; 195 (void)sigemptyset(&nsa.sa_mask); 196 nsa.sa_flags = flags; 197 nsa.sa_handler = SIG_DFL; 198 (void)sigaction(signo, &nsa, &osa); 199 200 (void)sigemptyset(&nset); 201 (void)sigaddset(&nset, signo); 202 (void)sigprocmask(SIG_UNBLOCK, &nset, &oset); 203 204 (void)kill(0, signo); 205 206 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 207 (void)sigaction(signo, &osa, NULL); 208 errno = save_errno; 209 } 210 211 /* 212 * Our generic signal handler. 213 */ 214 static void 215 sig_handler(int signo) 216 { 217 sigset_t nset; 218 sigset_t oset; 219 220 (void)sigfillset(&nset); 221 (void)sigprocmask(SIG_SETMASK, &nset, &oset); 222 223 assert (signo > 0 && signo < NSIG); /* Should be guaranteed. */ 224 225 sig_post(signo); 226 227 switch (signo) { 228 case SIGCONT: 229 assert(/*CONSTCOND*/ 0); /* We should not be seeing these. */ 230 do_default_handler(signo, 0); 231 break; 232 233 case SIGTSTP: 234 case SIGTTIN: 235 case SIGTTOU: 236 do_default_handler(signo, 0); 237 break; 238 239 case SIGINT: 240 case SIGHUP: 241 case SIGQUIT: 242 case SIGPIPE: 243 default: 244 if (sigarray[signo] == SIG_DFL) 245 do_default_handler(signo, SA_RESTART); 246 break; 247 } 248 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 249 } 250 251 /* 252 * Setup the signal handlers. 253 */ 254 PUBLIC void 255 sig_setup(void) 256 { 257 sigset_t nset; 258 sigset_t oset; 259 struct sigaction sa; 260 struct sigaction osa; 261 262 /* Block all signals while setting things. */ 263 (void)sigfillset(&nset); 264 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 265 266 /* 267 * Flow Control - SIGTSTP, SIGTTIN, SIGTTOU, SIGCONT: 268 * 269 * We grab SIGTSTP, SIGTTIN, and SIGTTOU so that we post the 270 * signals before suspending so that they are available when 271 * we resume. If we were to use SIGCONT instead, they will 272 * not get posted until SIGCONT is unblocked, even though the 273 * process has resumed. 274 * 275 * NOTE: We default these to SA_RESTART here, but we need to 276 * change this in certain cases, e.g., when reading from a 277 * tty. 278 */ 279 (void)sigemptyset(&sa.sa_mask); 280 sa.sa_flags = SA_RESTART; 281 sa.sa_handler = sig_handler; 282 (void)sigaction(SIGTSTP, &sa, NULL); 283 (void)sigaction(SIGTTIN, &sa, NULL); 284 (void)sigaction(SIGTTOU, &sa, NULL); 285 286 /* 287 * SIGHUP, SIGINT, and SIGQUIT: 288 * 289 * SIGHUP and SIGINT are trapped unless they are being 290 * ignored. 291 * 292 * Currently, we let the default handler deal with SIGQUIT. 293 */ 294 (void)sigemptyset(&sa.sa_mask); 295 sa.sa_flags = 0; 296 sa.sa_handler = sig_handler; 297 298 if (sigaction(SIGHUP, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN) 299 (void)signal(SIGHUP, SIG_IGN); 300 301 if (sigaction(SIGINT, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN) 302 (void)signal(SIGINT, SIG_IGN); 303 #if 0 304 if (signal(SIGQUIT, SIG_DFL) == SIG_IGN) 305 (void)signal(SIGQUIT, SIG_IGN); 306 #endif 307 /* 308 * SIGCHLD and SIGPIPE: 309 * 310 * SIGCHLD is setup early in main. The handler lives in 311 * popen.c as it uses internals of that module. 312 * 313 * SIGPIPE is grabbed here. It is only used in 314 * lex.c:setup_piping(), cmd1.c:type1(), and cmd1.c:pipecmd(). 315 */ 316 (void)sigemptyset(&sa.sa_mask); 317 sa.sa_flags = 0; 318 sa.sa_handler = sig_handler; 319 (void)sigaction(SIGPIPE, &sa, NULL); 320 321 /* 322 * Make sure our structures are initialized. 323 * XXX: This should be unnecessary. 324 */ 325 (void)memset(sigarray, 0, sizeof(sigarray)); 326 SIGQUEUE_INIT(&sigqueue); 327 328 /* Restore the signal mask. */ 329 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 330 } 331 332 static struct { /* data shared by sig_hold() and sig_release() */ 333 int depth; /* depth of sig_hold() */ 334 sigset_t oset; /* old signal mask saved by sig_hold() */ 335 } hold; 336 337 /* 338 * Hold signals SIGHUP, SIGINT, and SIGQUIT. 339 */ 340 PUBLIC void 341 sig_hold(void) 342 { 343 sigset_t nset; 344 345 if (hold.depth++ == 0) { 346 (void)sigemptyset(&nset); 347 (void)sigaddset(&nset, SIGHUP); 348 (void)sigaddset(&nset, SIGINT); 349 (void)sigaddset(&nset, SIGQUIT); 350 (void)sigprocmask(SIG_BLOCK, &nset, &hold.oset); 351 } 352 } 353 354 /* 355 * Release signals SIGHUP, SIGINT, and SIGQUIT. 356 */ 357 PUBLIC void 358 sig_release(void) 359 { 360 361 if (--hold.depth == 0) 362 (void)sigprocmask(SIG_SETMASK, &hold.oset, NULL); 363 } 364 365 /* 366 * Unblock and ignore a signal. 367 */ 368 PUBLIC int 369 sig_ignore(int sig, struct sigaction *osa, sigset_t *oset) 370 { 371 struct sigaction act; 372 sigset_t nset; 373 int error; 374 375 (void)sigemptyset(&act.sa_mask); 376 act.sa_flags = SA_RESTART; 377 act.sa_handler = SIG_IGN; 378 error = sigaction(sig, &act, osa); 379 380 if (error != -1) { 381 (void)sigemptyset(&nset); 382 (void)sigaddset(&nset, sig); 383 (void)sigprocmask(SIG_UNBLOCK, &nset, oset); 384 } else if (oset != NULL) 385 (void)sigprocmask(SIG_UNBLOCK, NULL, oset); 386 387 return error; 388 } 389 390 /* 391 * Restore a signal and the current signal mask. 392 */ 393 PUBLIC int 394 sig_restore(int sig, struct sigaction *osa, sigset_t *oset) 395 { 396 int error; 397 398 error = 0; 399 if (oset) 400 error = sigprocmask(SIG_SETMASK, oset, NULL); 401 if (osa) 402 error = sigaction(sig, osa, NULL); 403 404 return error; 405 } 406 407 /* 408 * Change the current flags and (optionally) return the old sigaction 409 * structure so we can restore things later. This is used to turn 410 * SA_RESTART on or off. 411 */ 412 PUBLIC int 413 sig_setflags(int signo, int flags, struct sigaction *osa) 414 { 415 struct sigaction sa; 416 417 if (sigaction(signo, NULL, &sa) == -1) 418 return -1; 419 if (osa) 420 *osa = sa; 421 sa.sa_flags = flags; 422 return sigaction(signo, &sa, NULL); 423 } 424 425