1/* sig.c - interface for shell signal handlers and signal initialization. */ 2 3/* Copyright (C) 1994-2006 Free Software Foundation, Inc. 4 5 This file is part of GNU Bash, the Bourne Again SHell. 6 7 Bash is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 2, or (at your option) any later 10 version. 11 12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 You should have received a copy of the GNU General Public License along 18 with Bash; see the file COPYING. If not, write to the Free Software 19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 20 21#include "config.h" 22 23#include "bashtypes.h" 24 25#if defined (HAVE_UNISTD_H) 26# ifdef _MINIX 27# include <sys/types.h> 28# endif 29# include <unistd.h> 30#endif 31 32#include <stdio.h> 33#include <signal.h> 34 35#include "bashintl.h" 36 37#include "shell.h" 38#if defined (JOB_CONTROL) 39#include "jobs.h" 40#endif /* JOB_CONTROL */ 41#include "siglist.h" 42#include "sig.h" 43#include "trap.h" 44 45#include "builtins/common.h" 46 47#if defined (READLINE) 48# include "bashline.h" 49#endif 50 51#if defined (HISTORY) 52# include "bashhist.h" 53#endif 54 55extern int last_command_exit_value; 56extern int last_command_exit_signal; 57extern int return_catch_flag; 58extern int loop_level, continuing, breaking; 59extern int parse_and_execute_level, shell_initialized; 60 61/* Non-zero after SIGINT. */ 62volatile int interrupt_state = 0; 63 64/* Non-zero after SIGWINCH */ 65volatile int sigwinch_received = 0; 66 67/* Set to the value of any terminating signal received. */ 68volatile int terminating_signal = 0; 69 70/* The environment at the top-level R-E loop. We use this in 71 the case of error return. */ 72procenv_t top_level; 73 74#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) 75/* The signal masks that this shell runs with. */ 76sigset_t top_level_mask; 77#endif /* JOB_CONTROL */ 78 79/* When non-zero, we throw_to_top_level (). */ 80int interrupt_immediately = 0; 81 82/* When non-zero, we call the terminating signal handler immediately. */ 83int terminate_immediately = 0; 84 85#if defined (SIGWINCH) 86static SigHandler *old_winch = (SigHandler *)SIG_DFL; 87#endif 88 89static void initialize_shell_signals __P((void)); 90 91void 92initialize_signals (reinit) 93 int reinit; 94{ 95 initialize_shell_signals (); 96 initialize_job_signals (); 97#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) 98 if (reinit == 0) 99 initialize_siglist (); 100#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */ 101} 102 103/* A structure describing a signal that terminates the shell if not 104 caught. The orig_handler member is present so children can reset 105 these signals back to their original handlers. */ 106struct termsig { 107 int signum; 108 SigHandler *orig_handler; 109 int orig_flags; 110}; 111 112#define NULL_HANDLER (SigHandler *)SIG_DFL 113 114/* The list of signals that would terminate the shell if not caught. 115 We catch them, but just so that we can write the history file, 116 and so forth. */ 117static struct termsig terminating_signals[] = { 118#ifdef SIGHUP 119{ SIGHUP, NULL_HANDLER, 0 }, 120#endif 121 122#ifdef SIGINT 123{ SIGINT, NULL_HANDLER, 0 }, 124#endif 125 126#ifdef SIGILL 127{ SIGILL, NULL_HANDLER, 0 }, 128#endif 129 130#ifdef SIGTRAP 131{ SIGTRAP, NULL_HANDLER, 0 }, 132#endif 133 134#ifdef SIGIOT 135{ SIGIOT, NULL_HANDLER, 0 }, 136#endif 137 138#ifdef SIGDANGER 139{ SIGDANGER, NULL_HANDLER, 0 }, 140#endif 141 142#ifdef SIGEMT 143{ SIGEMT, NULL_HANDLER, 0 }, 144#endif 145 146#ifdef SIGFPE 147{ SIGFPE, NULL_HANDLER, 0 }, 148#endif 149 150#ifdef SIGBUS 151{ SIGBUS, NULL_HANDLER, 0 }, 152#endif 153 154#ifdef SIGSEGV 155{ SIGSEGV, NULL_HANDLER, 0 }, 156#endif 157 158#ifdef SIGSYS 159{ SIGSYS, NULL_HANDLER, 0 }, 160#endif 161 162#ifdef SIGPIPE 163{ SIGPIPE, NULL_HANDLER, 0 }, 164#endif 165 166#ifdef SIGALRM 167{ SIGALRM, NULL_HANDLER, 0 }, 168#endif 169 170#ifdef SIGTERM 171{ SIGTERM, NULL_HANDLER, 0 }, 172#endif 173 174#ifdef SIGXCPU 175{ SIGXCPU, NULL_HANDLER, 0 }, 176#endif 177 178#ifdef SIGXFSZ 179{ SIGXFSZ, NULL_HANDLER, 0 }, 180#endif 181 182#ifdef SIGVTALRM 183{ SIGVTALRM, NULL_HANDLER, 0 }, 184#endif 185 186#if 0 187#ifdef SIGPROF 188{ SIGPROF, NULL_HANDLER, 0 }, 189#endif 190#endif 191 192#ifdef SIGLOST 193{ SIGLOST, NULL_HANDLER, 0 }, 194#endif 195 196#ifdef SIGUSR1 197{ SIGUSR1, NULL_HANDLER, 0 }, 198#endif 199 200#ifdef SIGUSR2 201{ SIGUSR2, NULL_HANDLER, 0 }, 202#endif 203}; 204 205#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig)) 206 207#define XSIG(x) (terminating_signals[x].signum) 208#define XHANDLER(x) (terminating_signals[x].orig_handler) 209#define XSAFLAGS(x) (terminating_signals[x].orig_flags) 210 211static int termsigs_initialized = 0; 212 213/* Initialize signals that will terminate the shell to do some 214 unwind protection. For non-interactive shells, we only call 215 this when a trap is defined for EXIT (0). */ 216void 217initialize_terminating_signals () 218{ 219 register int i; 220#if defined (HAVE_POSIX_SIGNALS) 221 struct sigaction act, oact; 222#endif 223 224 if (termsigs_initialized) 225 return; 226 227 /* The following code is to avoid an expensive call to 228 set_signal_handler () for each terminating_signals. Fortunately, 229 this is possible in Posix. Unfortunately, we have to call signal () 230 on non-Posix systems for each signal in terminating_signals. */ 231#if defined (HAVE_POSIX_SIGNALS) 232 act.sa_handler = termsig_sighandler; 233 act.sa_flags = 0; 234 sigemptyset (&act.sa_mask); 235 sigemptyset (&oact.sa_mask); 236 for (i = 0; i < TERMSIGS_LENGTH; i++) 237 sigaddset (&act.sa_mask, XSIG (i)); 238 for (i = 0; i < TERMSIGS_LENGTH; i++) 239 { 240 /* If we've already trapped it, don't do anything. */ 241 if (signal_is_trapped (XSIG (i))) 242 continue; 243 244 sigaction (XSIG (i), &act, &oact); 245 XHANDLER(i) = oact.sa_handler; 246 XSAFLAGS(i) = oact.sa_flags; 247 /* Don't do anything with signals that are ignored at shell entry 248 if the shell is not interactive. */ 249 if (!interactive_shell && XHANDLER (i) == SIG_IGN) 250 { 251 sigaction (XSIG (i), &oact, &act); 252 set_signal_ignored (XSIG (i)); 253 } 254#if defined (SIGPROF) && !defined (_MINIX) 255 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) 256 sigaction (XSIG (i), &oact, (struct sigaction *)NULL); 257#endif /* SIGPROF && !_MINIX */ 258 } 259 260#else /* !HAVE_POSIX_SIGNALS */ 261 262 for (i = 0; i < TERMSIGS_LENGTH; i++) 263 { 264 /* If we've already trapped it, don't do anything. */ 265 if (signal_is_trapped (XSIG (i))) 266 continue; 267 268 XHANDLER(i) = signal (XSIG (i), termsig_sighandler); 269 XSAFLAGS(i) = 0; 270 /* Don't do anything with signals that are ignored at shell entry 271 if the shell is not interactive. */ 272 if (!interactive_shell && XHANDLER (i) == SIG_IGN) 273 { 274 signal (XSIG (i), SIG_IGN); 275 set_signal_ignored (XSIG (i)); 276 } 277#ifdef SIGPROF 278 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) 279 signal (XSIG (i), XHANDLER (i)); 280#endif 281 } 282 283#endif /* !HAVE_POSIX_SIGNALS */ 284 285 termsigs_initialized = 1; 286} 287 288static void 289initialize_shell_signals () 290{ 291 if (interactive) 292 initialize_terminating_signals (); 293 294#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) 295 /* All shells use the signal mask they inherit, and pass it along 296 to child processes. Children will never block SIGCHLD, though. */ 297 sigemptyset (&top_level_mask); 298 sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask); 299# if defined (SIGCHLD) 300 sigdelset (&top_level_mask, SIGCHLD); 301# endif 302#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */ 303 304 /* And, some signals that are specifically ignored by the shell. */ 305 set_signal_handler (SIGQUIT, SIG_IGN); 306 307 if (interactive) 308 { 309 set_signal_handler (SIGINT, sigint_sighandler); 310 set_signal_handler (SIGTERM, SIG_IGN); 311 set_sigwinch_handler (); 312 } 313} 314 315void 316reset_terminating_signals () 317{ 318 register int i; 319#if defined (HAVE_POSIX_SIGNALS) 320 struct sigaction act; 321#endif 322 323 if (termsigs_initialized == 0) 324 return; 325 326#if defined (HAVE_POSIX_SIGNALS) 327 act.sa_flags = 0; 328 sigemptyset (&act.sa_mask); 329 for (i = 0; i < TERMSIGS_LENGTH; i++) 330 { 331 /* Skip a signal if it's trapped or handled specially, because the 332 trap code will restore the correct value. */ 333 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) 334 continue; 335 336 act.sa_handler = XHANDLER (i); 337 act.sa_flags = XSAFLAGS (i); 338 sigaction (XSIG (i), &act, (struct sigaction *) NULL); 339 } 340#else /* !HAVE_POSIX_SIGNALS */ 341 for (i = 0; i < TERMSIGS_LENGTH; i++) 342 { 343 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) 344 continue; 345 346 signal (XSIG (i), XHANDLER (i)); 347 } 348#endif /* !HAVE_POSIX_SIGNALS */ 349} 350#undef XSIG 351#undef XHANDLER 352 353/* Run some of the cleanups that should be performed when we run 354 jump_to_top_level from a builtin command context. XXX - might want to 355 also call reset_parser here. */ 356void 357top_level_cleanup () 358{ 359 /* Clean up string parser environment. */ 360 while (parse_and_execute_level) 361 parse_and_execute_cleanup (); 362 363#if defined (PROCESS_SUBSTITUTION) 364 unlink_fifo_list (); 365#endif /* PROCESS_SUBSTITUTION */ 366 367 run_unwind_protects (); 368 loop_level = continuing = breaking = 0; 369 return_catch_flag = 0; 370} 371 372/* What to do when we've been interrupted, and it is safe to handle it. */ 373void 374throw_to_top_level () 375{ 376 int print_newline = 0; 377 378 if (interrupt_state) 379 { 380 print_newline = 1; 381 DELINTERRUPT; 382 } 383 384 if (interrupt_state) 385 return; 386 387 last_command_exit_signal = (last_command_exit_value > 128) ? 388 (last_command_exit_value - 128) : 0; 389 last_command_exit_value |= 128; 390 391 /* Run any traps set on SIGINT. */ 392 run_interrupt_trap (); 393 394 /* Cleanup string parser environment. */ 395 while (parse_and_execute_level) 396 parse_and_execute_cleanup (); 397 398#if defined (JOB_CONTROL) 399 give_terminal_to (shell_pgrp, 0); 400#endif /* JOB_CONTROL */ 401 402#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) 403 /* This should not be necessary on systems using sigsetjmp/siglongjmp. */ 404 sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); 405#endif 406 407 reset_parser (); 408 409#if defined (READLINE) 410 if (interactive) 411 bashline_reinitialize (); 412#endif /* READLINE */ 413 414#if defined (PROCESS_SUBSTITUTION) 415 unlink_fifo_list (); 416#endif /* PROCESS_SUBSTITUTION */ 417 418 run_unwind_protects (); 419 loop_level = continuing = breaking = 0; 420 return_catch_flag = 0; 421 422 if (interactive && print_newline) 423 { 424 fflush (stdout); 425 fprintf (stderr, "\n"); 426 fflush (stderr); 427 } 428 429 /* An interrupted `wait' command in a script does not exit the script. */ 430 if (interactive || (interactive_shell && !shell_initialized) || 431 (print_newline && signal_is_trapped (SIGINT))) 432 jump_to_top_level (DISCARD); 433 else 434 jump_to_top_level (EXITPROG); 435} 436 437/* This is just here to isolate the longjmp calls. */ 438void 439jump_to_top_level (value) 440 int value; 441{ 442 longjmp (top_level, value); 443} 444 445sighandler 446termsig_sighandler (sig) 447 int sig; 448{ 449 terminating_signal = sig; 450 451 if (terminate_immediately) 452 { 453 terminate_immediately = 0; 454 termsig_handler (sig); 455 } 456 457 SIGRETURN (0); 458} 459 460void 461termsig_handler (sig) 462 int sig; 463{ 464 static int handling_termsig = 0; 465 466 /* Simple semaphore to keep this function from being executed multiple 467 times. Since we no longer are running as a signal handler, we don't 468 block multiple occurrences of the terminating signals while running. */ 469 if (handling_termsig) 470 return; 471 handling_termsig = 1; 472 terminating_signal = 0; /* keep macro from re-testing true. */ 473 474 /* I don't believe this condition ever tests true. */ 475 if (sig == SIGINT && signal_is_trapped (SIGINT)) 476 run_interrupt_trap (); 477 478#if defined (HISTORY) 479 if (interactive_shell && sig != SIGABRT) 480 maybe_save_shell_history (); 481#endif /* HISTORY */ 482 483#if defined (JOB_CONTROL) 484 if (interactive && sig == SIGHUP) 485 hangup_all_jobs (); 486 end_job_control (); 487#endif /* JOB_CONTROL */ 488 489#if defined (PROCESS_SUBSTITUTION) 490 unlink_fifo_list (); 491#endif /* PROCESS_SUBSTITUTION */ 492 493 run_exit_trap (); 494 set_signal_handler (sig, SIG_DFL); 495 kill (getpid (), sig); 496} 497 498/* What we really do when SIGINT occurs. */ 499sighandler 500sigint_sighandler (sig) 501 int sig; 502{ 503#if defined (MUST_REINSTALL_SIGHANDLERS) 504 signal (sig, sigint_sighandler); 505#endif 506 507 /* interrupt_state needs to be set for the stack of interrupts to work 508 right. Should it be set unconditionally? */ 509 if (interrupt_state == 0) 510 ADDINTERRUPT; 511 512 if (interrupt_immediately) 513 { 514 interrupt_immediately = 0; 515 throw_to_top_level (); 516 } 517 518 SIGRETURN (0); 519} 520 521#if defined (SIGWINCH) 522sighandler 523sigwinch_sighandler (sig) 524 int sig; 525{ 526#if defined (MUST_REINSTALL_SIGHANDLERS) 527 set_signal_handler (SIGWINCH, sigwinch_sighandler); 528#endif /* MUST_REINSTALL_SIGHANDLERS */ 529 sigwinch_received = 1; 530 SIGRETURN (0); 531} 532#endif /* SIGWINCH */ 533 534void 535set_sigwinch_handler () 536{ 537#if defined (SIGWINCH) 538 old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); 539#endif 540} 541 542void 543unset_sigwinch_handler () 544{ 545#if defined (SIGWINCH) 546 set_signal_handler (SIGWINCH, old_winch); 547#endif 548} 549 550/* Signal functions used by the rest of the code. */ 551#if !defined (HAVE_POSIX_SIGNALS) 552 553#if defined (JOB_CONTROL) 554/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ 555sigprocmask (operation, newset, oldset) 556 int operation, *newset, *oldset; 557{ 558 int old, new; 559 560 if (newset) 561 new = *newset; 562 else 563 new = 0; 564 565 switch (operation) 566 { 567 case SIG_BLOCK: 568 old = sigblock (new); 569 break; 570 571 case SIG_SETMASK: 572 sigsetmask (new); 573 break; 574 575 default: 576 internal_error (_("sigprocmask: %d: invalid operation"), operation); 577 } 578 579 if (oldset) 580 *oldset = old; 581} 582#endif /* JOB_CONTROL */ 583 584#else 585 586#if !defined (SA_INTERRUPT) 587# define SA_INTERRUPT 0 588#endif 589 590#if !defined (SA_RESTART) 591# define SA_RESTART 0 592#endif 593 594SigHandler * 595set_signal_handler (sig, handler) 596 int sig; 597 SigHandler *handler; 598{ 599 struct sigaction act, oact; 600 601 act.sa_handler = handler; 602 act.sa_flags = 0; 603#if 0 604 if (sig == SIGALRM) 605 act.sa_flags |= SA_INTERRUPT; /* XXX */ 606 else 607 act.sa_flags |= SA_RESTART; /* XXX */ 608#endif 609 sigemptyset (&act.sa_mask); 610 sigemptyset (&oact.sa_mask); 611 sigaction (sig, &act, &oact); 612 return (oact.sa_handler); 613} 614#endif /* HAVE_POSIX_SIGNALS */ 615