1 /* trap.c -- Not the trap command, but useful functions for manipulating
2 those objects. The trap command is in builtins/trap.def. */
4 /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
24 #if defined (HAVE_UNISTD_H)
28 #include "bashtypes.h"
37 #include "input.h" /* for save_token_state, restore_token_state */
39 #include "builtins/common.h"
45 /* Flags which describe the current handling state of a signal. */
46 #define SIG_INHERITED 0x0 /* Value inherited from parent. */
47 #define SIG_TRAPPED 0x1 /* Currently trapped. */
48 #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
49 #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
50 #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
51 #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
52 #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
53 #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
55 /* An array of such flags, one for each signal, describing what the
56 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
58 static int sigmodes[NSIG+1];
60 static void change_signal (), restore_signal ();
62 /* Variables used here but defined in other files. */
63 extern int interactive_shell, interactive;
64 extern int interrupt_immediately;
65 extern int last_command_exit_value;
66 extern int line_number;
68 /* The list of things to do originally, before we started trapping. */
69 SigHandler *original_signals[NSIG];
71 /* For each signal, a slot for a string, which is a command to be
72 executed when that signal is recieved. The slot can also contain
73 DEFAULT_SIG, which means do whatever you were going to do before
74 you were so rudely interrupted, or IGNORE_SIG, which says ignore
76 char *trap_list[NSIG+1];
78 /* A bitmap of signals received for which we have trap handlers. */
79 int pending_traps[NSIG];
81 /* Set to the number of the signal we're running the trap for + 1.
82 Used in execute_cmd.c and builtins/common.c to clean up when
83 parse_and_execute does not return normally after executing the
84 trap command (e.g., when `return' is executed in the trap command). */
87 /* The value of line_number when the trap started executing, since
88 parse_and_execute resets it to 1 and the trap command might want
92 /* A value which can never be the target of a trap handler. */
93 #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
100 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = (char *)NULL;
101 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = SIG_INHERITED;
102 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
104 for (i = 1; i < NSIG; i++)
106 pending_traps[i] = 0;
107 trap_list[i] = (char *)DEFAULT_SIG;
108 sigmodes[i] = SIG_INHERITED;
109 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
112 /* Show which signals are treated specially by the shell. */
113 #if defined (SIGCHLD)
114 original_signals[SIGCHLD] =
115 (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
116 set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
117 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
120 original_signals[SIGINT] =
121 (SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
122 set_signal_handler (SIGINT, original_signals[SIGINT]);
123 sigmodes[SIGINT] |= SIG_SPECIAL;
125 #if defined (__BEOS__)
126 /* BeOS sets SIGINT to SIG_IGN! */
127 original_signals[SIGINT] = SIG_DFL;
130 original_signals[SIGQUIT] =
131 (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
132 set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
133 sigmodes[SIGQUIT] |= SIG_SPECIAL;
137 original_signals[SIGTERM] =
138 (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
139 set_signal_handler (SIGTERM, original_signals[SIGTERM]);
140 sigmodes[SIGTERM] |= SIG_SPECIAL;
144 #ifdef INCLUDE_UNUSED
145 /* Return a printable representation of the trap handler for SIG. */
147 trap_handler_string (sig)
150 if (trap_list[sig] == (char *)DEFAULT_SIG)
151 return "DEFAULT_SIG";
152 else if (trap_list[sig] == (char *)IGNORE_SIG)
154 else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
155 return "IMPOSSIBLE_TRAP_HANDLER";
156 else if (trap_list[sig])
157 return trap_list[sig];
163 /* Return the print name of this signal. */
170 /* on cygwin32, signal_names[sig] could be null */
171 ret = (sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig];
173 ret = "unrecognized signal number";
177 /* Turn a string into a signal number, or a number into
178 a signal number. If STRING is "2", "SIGINT", or "INT",
179 then (int)2 is returned. Return NO_SIG if STRING doesn't
180 contain a valid signal descriptor. */
182 decode_signal (string)
187 if (legal_number (string, &sig))
188 return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG);
190 /* A leading `SIG' may be omitted. */
191 for (sig = 0; sig <= NSIG; sig++)
193 if (signal_names[sig] == 0 || signal_names[sig][0] == '\0')
195 if (strcasecmp (string, signal_names[sig]) == 0 ||
196 (STREQN (signal_names[sig], "SIG", 3) &&
197 strcasecmp (string, &(signal_names[sig])[3]) == 0))
204 /* Non-zero when we catch a trapped signal. */
205 static int catch_flag;
211 int old_exit_value, *token_state;
213 if (catch_flag == 0) /* simple optimization */
218 /* Preserve $? when running trap. */
219 old_exit_value = last_command_exit_value;
221 for (sig = 1; sig < NSIG; sig++)
223 /* XXX this could be made into a counter by using
224 while (pending_traps[sig]--) instead of the if statement. */
225 if (pending_traps[sig])
227 #if defined (HAVE_POSIX_SIGNALS)
233 sigaddset (&set, sig);
234 sigprocmask (SIG_BLOCK, &set, &oset);
236 # if defined (HAVE_BSD_SIGNALS)
237 int oldmask = sigblock (sigmask (sig));
239 #endif /* HAVE_POSIX_SIGNALS */
243 run_interrupt_trap ();
246 else if (trap_list[sig] == (char *)DEFAULT_SIG ||
247 trap_list[sig] == (char *)IGNORE_SIG ||
248 trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
250 /* This is possible due to a race condition. Say a bash
251 process has SIGTERM trapped. A subshell is spawned
252 using { list; } & and the parent does something and kills
253 the subshell with SIGTERM. It's possible for the subshell
254 to set pending_traps[SIGTERM] to 1 before the code in
255 execute_cmd.c eventually calls restore_original_signals
256 to reset the SIGTERM signal handler in the subshell. The
257 next time run_pending_traps is called, pending_traps[SIGTERM]
258 will be 1, but the trap handler in trap_list[SIGTERM] will
259 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
260 Unless we catch this, the subshell will dump core when
261 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
263 internal_warning ("run_pending_traps: bad value in trap_list[%d]: 0x%x",
264 sig, (int)trap_list[sig]);
265 if (trap_list[sig] == (char *)DEFAULT_SIG)
267 internal_warning ("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself", sig, signal_name (sig));
268 kill (getpid (), sig);
273 token_state = save_token_state ();
274 parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST);
275 restore_token_state (token_state);
279 pending_traps[sig] = 0;
281 #if defined (HAVE_POSIX_SIGNALS)
282 sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
284 # if defined (HAVE_BSD_SIGNALS)
285 sigsetmask (oldmask);
287 #endif /* POSIX_VERSION */
291 last_command_exit_value = old_exit_value;
301 (trap_list[sig] == (char *)DEFAULT_SIG) ||
302 (trap_list[sig] == (char *)IGNORE_SIG))
303 programming_error ("trap_handler: bad signal %d", sig);
307 #if defined (MUST_REINSTALL_SIGHANDLERS)
308 set_signal_handler (sig, trap_handler);
309 #endif /* MUST_REINSTALL_SIGHANDLERS */
312 pending_traps[sig]++;
314 if (interrupt_immediately)
315 run_pending_traps ();
323 #if defined (JOB_CONTROL) && defined (SIGCHLD)
325 #ifdef INCLUDE_UNUSED
326 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
328 set_sigchld_trap (command_string)
329 char *command_string;
331 set_signal (SIGCHLD, command_string);
335 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
336 SIGCHLD trap handler is DEFAULT_SIG. */
338 maybe_set_sigchld_trap (command_string)
339 char *command_string;
341 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
342 set_signal (SIGCHLD, command_string);
344 #endif /* JOB_CONTROL && SIGCHLD */
347 set_debug_trap (command)
350 set_signal (DEBUG_TRAP, command);
353 #ifdef INCLUDE_UNUSED
355 set_sigint_trap (command)
358 set_signal (SIGINT, command);
362 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
363 things, like waiting for command substitution or executing commands
364 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
366 set_sigint_handler ()
368 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
369 return ((SigHandler *)SIG_IGN);
371 else if (sigmodes[SIGINT] & SIG_IGNORED)
372 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
374 else if (sigmodes[SIGINT] & SIG_TRAPPED)
375 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
377 /* The signal is not trapped, so set the handler to the shell's special
378 interrupt handler. */
379 else if (interactive) /* XXX - was interactive_shell */
380 return (set_signal_handler (SIGINT, sigint_sighandler));
382 return (set_signal_handler (SIGINT, termination_unwind_protect));
385 /* Return the correct handler for signal SIG according to the values in
388 trap_to_sighandler (sig)
391 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
393 else if (sigmodes[sig] & SIG_TRAPPED)
394 return (trap_handler);
399 /* Set SIG to call STRING as a command. */
401 set_signal (sig, string)
405 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
407 change_signal (sig, savestring (string));
408 if (sig == EXIT_TRAP && interactive == 0)
409 initialize_terminating_signals ();
413 /* A signal ignored on entry to the shell cannot be trapped or reset, but
414 no error is reported when attempting to do so. -- Posix.2 */
415 if (sigmodes[sig] & SIG_HARD_IGNORE)
418 /* Make sure we have original_signals[sig] if the signal has not yet
420 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
422 /* If we aren't sure of the original value, check it. */
423 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
425 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL);
426 set_signal_handler (sig, original_signals[sig]);
429 /* Signals ignored on entry to the shell cannot be trapped or reset. */
430 if (original_signals[sig] == SIG_IGN)
432 sigmodes[sig] |= SIG_HARD_IGNORE;
437 /* Only change the system signal handler if SIG_NO_TRAP is not set.
438 The trap command string is changed in either case. The shell signal
439 handlers for SIGINT and SIGCHLD run the user specified traps in an
440 environment in which it is safe to do so. */
441 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
443 set_signal_handler (sig, SIG_IGN);
444 change_signal (sig, savestring (string));
445 set_signal_handler (sig, trap_handler);
448 change_signal (sig, savestring (string));
452 free_trap_command (sig)
455 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
456 (trap_list[sig] != (char *)IGNORE_SIG) &&
457 (trap_list[sig] != (char *)DEFAULT_SIG) &&
458 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
459 free (trap_list[sig]);
462 /* If SIG has a string assigned to it, get rid of it. Then give it
465 change_signal (sig, value)
469 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
470 free_trap_command (sig);
471 trap_list[sig] = value;
473 sigmodes[sig] |= SIG_TRAPPED;
474 if (value == (char *)IGNORE_SIG)
475 sigmodes[sig] |= SIG_IGNORED;
477 sigmodes[sig] &= ~SIG_IGNORED;
478 if (sigmodes[sig] & SIG_INPROGRESS)
479 sigmodes[sig] |= SIG_CHANGED;
482 #define GET_ORIGINAL_SIGNAL(sig) \
483 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
484 get_original_signal (sig)
487 get_original_signal (sig)
490 /* If we aren't sure the of the original value, then get it. */
491 if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
493 original_signals[sig] =
494 (SigHandler *) set_signal_handler (sig, SIG_DFL);
495 set_signal_handler (sig, original_signals[sig]);
497 /* Signals ignored on entry to the shell cannot be trapped. */
498 if (original_signals[sig] == SIG_IGN)
499 sigmodes[sig] |= SIG_HARD_IGNORE;
503 /* Restore the default action for SIG; i.e., the action the shell
504 would have taken before you used the trap command. This is called
505 from trap_builtin (), which takes care to restore the handlers for
506 the signals the shell treats specially. */
508 restore_default_signal (sig)
511 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
513 if ((sig != DEBUG_TRAP) || (sigmodes[sig] & SIG_INPROGRESS) == 0)
514 free_trap_command (sig);
515 trap_list[sig] = (char *)NULL;
516 sigmodes[sig] &= ~SIG_TRAPPED;
517 if (sigmodes[sig] & SIG_INPROGRESS)
518 sigmodes[sig] |= SIG_CHANGED;
522 GET_ORIGINAL_SIGNAL (sig);
524 /* A signal ignored on entry to the shell cannot be trapped or reset, but
525 no error is reported when attempting to do so. Thanks Posix.2. */
526 if (sigmodes[sig] & SIG_HARD_IGNORE)
529 /* If we aren't trapping this signal, don't bother doing anything else. */
530 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
533 /* Only change the signal handler for SIG if it allows it. */
534 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
535 set_signal_handler (sig, original_signals[sig]);
537 /* Change the trap command in either case. */
538 change_signal (sig, (char *)DEFAULT_SIG);
540 /* Mark the signal as no longer trapped. */
541 sigmodes[sig] &= ~SIG_TRAPPED;
544 /* Make this signal be ignored. */
549 if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0))
551 change_signal (sig, (char *)IGNORE_SIG);
555 GET_ORIGINAL_SIGNAL (sig);
557 /* A signal ignored on entry to the shell cannot be trapped or reset.
558 No error is reported when the user attempts to do so. */
559 if (sigmodes[sig] & SIG_HARD_IGNORE)
562 /* If already trapped and ignored, no change necessary. */
563 if (sigmodes[sig] & SIG_IGNORED)
566 /* Only change the signal handler for SIG if it allows it. */
567 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
568 set_signal_handler (sig, SIG_IGN);
570 /* Change the trap command in either case. */
571 change_signal (sig, (char *)IGNORE_SIG);
574 /* Handle the calling of "trap 0". The only sticky situation is when
575 the command to be executed includes an "exit". This is why we have
576 to provide our own place for top_level to jump to. */
581 int code, old_exit_value;
583 old_exit_value = last_command_exit_value;
585 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
586 currently running in the trap handler (call to exit in the list of
587 commands given to trap 0). */
588 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
589 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
591 trap_command = savestring (trap_list[EXIT_TRAP]);
592 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
593 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
595 code = setjmp (top_level);
600 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST);
602 else if (code == EXITPROG)
603 return (last_command_exit_value);
605 return (old_exit_value);
608 return (old_exit_value);
612 run_trap_cleanup (sig)
615 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
618 /* Run a trap command for SIG. SIG is one of the signals the shell treats
621 _run_trap_internal (sig, tag)
625 char *trap_command, *old_trap;
626 int old_exit_value, old_line_number, *token_state;
628 /* Run the trap only if SIG is trapped and not ignored, and we are not
629 currently executing in the trap handler. */
630 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
631 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
632 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
634 old_trap = trap_list[sig];
635 sigmodes[sig] |= SIG_INPROGRESS;
636 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
637 trap_command = savestring (old_trap);
639 running_trap = sig + 1;
640 old_exit_value = last_command_exit_value;
641 /* Need to copy the value of line_number because parse_and_execute
642 resets it to 1, and the trap command might want it. */
643 trap_line_number = line_number;
645 token_state = save_token_state ();
646 parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST);
647 restore_token_state (token_state);
650 last_command_exit_value = old_exit_value;
653 sigmodes[sig] &= ~SIG_INPROGRESS;
655 if (sigmodes[sig] & SIG_CHANGED)
658 sigmodes[sig] &= ~SIG_CHANGED;
666 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)
667 _run_trap_internal (DEBUG_TRAP, "debug trap");
670 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
671 declared here to localize the trap functions. */
673 run_interrupt_trap ()
675 _run_trap_internal (SIGINT, "interrupt trap");
678 #ifdef INCLUDE_UNUSED
679 /* Free all the allocated strings in the list of traps and reset the trap
680 values to the default. */
686 for (i = 0; i < NSIG+1; i++)
688 free_trap_command (i);
689 trap_list[i] = (char *)DEFAULT_SIG;
690 sigmodes[i] &= ~SIG_TRAPPED;
692 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL;
696 /* Reset the handler for SIG to the original value. */
701 set_signal_handler (sig, original_signals[sig]);
704 /* Set the handler signal SIG to the original and free any trap
705 command associated with it. */
710 set_signal_handler (sig, original_signals[sig]);
711 change_signal (sig, (char *)DEFAULT_SIG);
712 sigmodes[sig] &= ~SIG_TRAPPED;
716 reset_or_restore_signal_handlers (reset)
721 /* Take care of the exit trap first */
722 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
724 free_trap_command (EXIT_TRAP);
725 trap_list[EXIT_TRAP] = (char *)NULL;
726 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
728 for (i = 1; i < NSIG; i++)
730 if (sigmodes[i] & SIG_TRAPPED)
732 if (trap_list[i] == (char *)IGNORE_SIG)
733 set_signal_handler (i, SIG_IGN);
737 else if (sigmodes[i] & SIG_SPECIAL)
743 reset_signal_handlers ()
745 reset_or_restore_signal_handlers (reset_signal);
748 /* Reset all trapped signals to their original values. Signals set to be
749 ignored with trap '' SIGNAL should be ignored, so we make sure that they
750 are. Called by child processes after they are forked. */
752 restore_original_signals ()
754 reset_or_restore_signal_handlers (restore_signal);
757 /* If a trap handler exists for signal SIG, then call it; otherwise just
760 maybe_call_trap_handler (sig)
763 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
764 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
769 run_interrupt_trap ();
788 signal_is_trapped (sig)
791 return (sigmodes[sig] & SIG_TRAPPED);
795 signal_is_special (sig)
798 return (sigmodes[sig] & SIG_SPECIAL);
802 signal_is_ignored (sig)
805 return (sigmodes[sig] & SIG_IGNORED);
809 set_signal_ignored (sig)
812 sigmodes[sig] |= SIG_HARD_IGNORE;
813 original_signals[sig] = SIG_IGN;