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-2006 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"
40 #include "input.h" /* for save_token_state, restore_token_state */
43 #include "builtins/common.h"
44 #include "builtins/builtext.h"
50 /* Flags which describe the current handling state of a signal. */
51 #define SIG_INHERITED 0x0 /* Value inherited from parent. */
52 #define SIG_TRAPPED 0x1 /* Currently trapped. */
53 #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
54 #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
55 #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
56 #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
57 #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
58 #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
60 #define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
62 /* An array of such flags, one for each signal, describing what the
63 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
65 static int sigmodes
[BASH_NSIG
];
67 static void free_trap_command
__P((int));
68 static void change_signal
__P((int, char *));
70 static void get_original_signal
__P((int));
72 static int _run_trap_internal
__P((int, char *));
74 static void reset_signal
__P((int));
75 static void restore_signal
__P((int));
76 static void reset_or_restore_signal_handlers
__P((sh_resetsig_func_t
*));
78 /* Variables used here but defined in other files. */
79 extern int last_command_exit_value
;
80 extern int line_number
;
82 extern char *this_command_name
;
83 extern sh_builtin_func_t
*this_shell_builtin
;
84 extern procenv_t wait_intr_buf
;
85 extern int return_catch_flag
, return_catch_value
;
86 extern int subshell_level
;
88 /* The list of things to do originally, before we started trapping. */
89 SigHandler
*original_signals
[NSIG
];
91 /* For each signal, a slot for a string, which is a command to be
92 executed when that signal is recieved. The slot can also contain
93 DEFAULT_SIG, which means do whatever you were going to do before
94 you were so rudely interrupted, or IGNORE_SIG, which says ignore
96 char *trap_list
[BASH_NSIG
];
98 /* A bitmap of signals received for which we have trap handlers. */
99 int pending_traps
[NSIG
];
101 /* Set to the number of the signal we're running the trap for + 1.
102 Used in execute_cmd.c and builtins/common.c to clean up when
103 parse_and_execute does not return normally after executing the
104 trap command (e.g., when `return' is executed in the trap command). */
107 /* Set to last_command_exit_value before running a trap. */
108 int trap_saved_exit_value
;
110 /* The (trapped) signal received while executing in the `wait' builtin */
111 int wait_signal_received
;
113 /* A value which can never be the target of a trap handler. */
114 #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
116 #define GETORIGSIG(sig) \
118 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
119 set_signal_handler (sig, original_signals[sig]); \
120 if (original_signals[sig] == SIG_IGN) \
121 sigmodes[sig] |= SIG_HARD_IGNORE; \
124 #define GET_ORIGINAL_SIGNAL(sig) \
125 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
133 initialize_signames();
135 trap_list
[EXIT_TRAP
] = trap_list
[DEBUG_TRAP
] = trap_list
[ERROR_TRAP
] = trap_list
[RETURN_TRAP
] = (char *)NULL
;
136 sigmodes
[EXIT_TRAP
] = sigmodes
[DEBUG_TRAP
] = sigmodes
[ERROR_TRAP
] = sigmodes
[RETURN_TRAP
] = SIG_INHERITED
;
137 original_signals
[EXIT_TRAP
] = IMPOSSIBLE_TRAP_HANDLER
;
139 for (i
= 1; i
< NSIG
; i
++)
141 pending_traps
[i
] = 0;
142 trap_list
[i
] = (char *)DEFAULT_SIG
;
143 sigmodes
[i
] = SIG_INHERITED
;
144 original_signals
[i
] = IMPOSSIBLE_TRAP_HANDLER
;
147 /* Show which signals are treated specially by the shell. */
148 #if defined (SIGCHLD)
149 GETORIGSIG (SIGCHLD
);
150 sigmodes
[SIGCHLD
] |= (SIG_SPECIAL
| SIG_NO_TRAP
);
154 sigmodes
[SIGINT
] |= SIG_SPECIAL
;
156 #if defined (__BEOS__)
157 /* BeOS sets SIGINT to SIG_IGN! */
158 original_signals
[SIGINT
] = SIG_DFL
;
159 sigmodes
[SIGINT
] &= ~SIG_HARD_IGNORE
;
162 GETORIGSIG (SIGQUIT
);
163 sigmodes
[SIGQUIT
] |= SIG_SPECIAL
;
167 GETORIGSIG (SIGTERM
);
168 sigmodes
[SIGTERM
] |= SIG_SPECIAL
;
172 #ifdef INCLUDE_UNUSED
173 /* Return a printable representation of the trap handler for SIG. */
175 trap_handler_string (sig
)
178 if (trap_list
[sig
] == (char *)DEFAULT_SIG
)
179 return "DEFAULT_SIG";
180 else if (trap_list
[sig
] == (char *)IGNORE_SIG
)
182 else if (trap_list
[sig
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
183 return "IMPOSSIBLE_TRAP_HANDLER";
184 else if (trap_list
[sig
])
185 return trap_list
[sig
];
191 /* Return the print name of this signal. */
198 /* on cygwin32, signal_names[sig] could be null */
199 ret
= (sig
>= BASH_NSIG
|| sig
< 0 || signal_names
[sig
] == NULL
)
200 ? _("invalid signal number")
206 /* Turn a string into a signal number, or a number into
207 a signal number. If STRING is "2", "SIGINT", or "INT",
208 then (int)2 is returned. Return NO_SIG if STRING doesn't
209 contain a valid signal descriptor. */
211 decode_signal (string
, flags
)
218 if (legal_number (string
, &sig
))
219 return ((sig
>= 0 && sig
< NSIG
) ? (int)sig
: NO_SIG
);
221 /* A leading `SIG' may be omitted. */
222 for (sig
= 0; sig
< BASH_NSIG
; sig
++)
224 name
= signal_names
[sig
];
225 if (name
== 0 || name
[0] == '\0')
228 /* Check name without the SIG prefix first case sensitivly or
229 insensitively depending on whether flags includes DSIG_NOCASE */
230 if (STREQN (name
, "SIG", 3))
234 if ((flags
& DSIG_NOCASE
) && strcasecmp (string
, name
) == 0)
236 else if ((flags
& DSIG_NOCASE
) == 0 && strcmp (string
, name
) == 0)
238 /* If we can't use the `SIG' prefix to match, punt on this
240 else if ((flags
& DSIG_SIGPREFIX
) == 0)
244 /* Check name with SIG prefix case sensitively or insensitively
245 depending on whether flags includes DSIG_NOCASE */
246 name
= signal_names
[sig
];
247 if ((flags
& DSIG_NOCASE
) && strcasecmp (string
, name
) == 0)
249 else if ((flags
& DSIG_NOCASE
) == 0 && strcmp (string
, name
) == 0)
256 /* Non-zero when we catch a trapped signal. */
257 static int catch_flag
;
263 int old_exit_value
, *token_state
;
265 if (catch_flag
== 0) /* simple optimization */
270 /* Preserve $? when running trap. */
271 old_exit_value
= last_command_exit_value
;
273 for (sig
= 1; sig
< NSIG
; sig
++)
275 /* XXX this could be made into a counter by using
276 while (pending_traps[sig]--) instead of the if statement. */
277 if (pending_traps
[sig
])
279 #if defined (HAVE_POSIX_SIGNALS)
285 sigaddset (&set
, sig
);
286 sigprocmask (SIG_BLOCK
, &set
, &oset
);
288 # if defined (HAVE_BSD_SIGNALS)
289 int oldmask
= sigblock (sigmask (sig
));
291 #endif /* HAVE_POSIX_SIGNALS */
295 run_interrupt_trap ();
298 else if (trap_list
[sig
] == (char *)DEFAULT_SIG
||
299 trap_list
[sig
] == (char *)IGNORE_SIG
||
300 trap_list
[sig
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
302 /* This is possible due to a race condition. Say a bash
303 process has SIGTERM trapped. A subshell is spawned
304 using { list; } & and the parent does something and kills
305 the subshell with SIGTERM. It's possible for the subshell
306 to set pending_traps[SIGTERM] to 1 before the code in
307 execute_cmd.c eventually calls restore_original_signals
308 to reset the SIGTERM signal handler in the subshell. The
309 next time run_pending_traps is called, pending_traps[SIGTERM]
310 will be 1, but the trap handler in trap_list[SIGTERM] will
311 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
312 Unless we catch this, the subshell will dump core when
313 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
315 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
316 sig
, trap_list
[sig
]);
317 if (trap_list
[sig
] == (char *)DEFAULT_SIG
)
319 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig
, signal_name (sig
));
320 kill (getpid (), sig
);
325 token_state
= save_token_state ();
326 parse_and_execute (savestring (trap_list
[sig
]), "trap", SEVAL_NONINT
|SEVAL_NOHIST
);
327 restore_token_state (token_state
);
331 pending_traps
[sig
] = 0;
333 #if defined (HAVE_POSIX_SIGNALS)
334 sigprocmask (SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
336 # if defined (HAVE_BSD_SIGNALS)
337 sigsetmask (oldmask
);
339 #endif /* POSIX_VERSION */
343 last_command_exit_value
= old_exit_value
;
353 (trap_list
[sig
] == (char *)DEFAULT_SIG
) ||
354 (trap_list
[sig
] == (char *)IGNORE_SIG
))
355 programming_error (_("trap_handler: bad signal %d"), sig
);
359 #if defined (MUST_REINSTALL_SIGHANDLERS)
360 set_signal_handler (sig
, trap_handler
);
361 #endif /* MUST_REINSTALL_SIGHANDLERS */
364 pending_traps
[sig
]++;
366 if (interrupt_immediately
&& this_shell_builtin
&& (this_shell_builtin
== wait_builtin
))
368 wait_signal_received
= sig
;
369 longjmp (wait_intr_buf
, 1);
372 if (interrupt_immediately
)
373 run_pending_traps ();
381 #if defined (JOB_CONTROL) && defined (SIGCHLD)
383 #ifdef INCLUDE_UNUSED
384 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
386 set_sigchld_trap (command_string
)
387 char *command_string
;
389 set_signal (SIGCHLD
, command_string
);
393 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
394 is not already trapped. */
396 maybe_set_sigchld_trap (command_string
)
397 char *command_string
;
399 if ((sigmodes
[SIGCHLD
] & SIG_TRAPPED
) == 0)
400 set_signal (SIGCHLD
, command_string
);
402 #endif /* JOB_CONTROL && SIGCHLD */
405 set_debug_trap (command
)
408 set_signal (DEBUG_TRAP
, command
);
412 set_error_trap (command
)
415 set_signal (ERROR_TRAP
, command
);
419 set_return_trap (command
)
422 set_signal (RETURN_TRAP
, command
);
425 #ifdef INCLUDE_UNUSED
427 set_sigint_trap (command
)
430 set_signal (SIGINT
, command
);
434 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
435 things, like waiting for command substitution or executing commands
436 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
438 set_sigint_handler ()
440 if (sigmodes
[SIGINT
] & SIG_HARD_IGNORE
)
441 return ((SigHandler
*)SIG_IGN
);
443 else if (sigmodes
[SIGINT
] & SIG_IGNORED
)
444 return ((SigHandler
*)set_signal_handler (SIGINT
, SIG_IGN
)); /* XXX */
446 else if (sigmodes
[SIGINT
] & SIG_TRAPPED
)
447 return ((SigHandler
*)set_signal_handler (SIGINT
, trap_handler
));
449 /* The signal is not trapped, so set the handler to the shell's special
450 interrupt handler. */
451 else if (interactive
) /* XXX - was interactive_shell */
452 return (set_signal_handler (SIGINT
, sigint_sighandler
));
454 return (set_signal_handler (SIGINT
, termsig_sighandler
));
457 /* Return the correct handler for signal SIG according to the values in
460 trap_to_sighandler (sig
)
463 if (sigmodes
[sig
] & (SIG_IGNORED
|SIG_HARD_IGNORE
))
465 else if (sigmodes
[sig
] & SIG_TRAPPED
)
466 return (trap_handler
);
471 /* Set SIG to call STRING as a command. */
473 set_signal (sig
, string
)
477 if (SPECIAL_TRAP (sig
))
479 change_signal (sig
, savestring (string
));
480 if (sig
== EXIT_TRAP
&& interactive
== 0)
481 initialize_terminating_signals ();
485 /* A signal ignored on entry to the shell cannot be trapped or reset, but
486 no error is reported when attempting to do so. -- Posix.2 */
487 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
490 /* Make sure we have original_signals[sig] if the signal has not yet
492 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
494 /* If we aren't sure of the original value, check it. */
495 if (original_signals
[sig
] == IMPOSSIBLE_TRAP_HANDLER
)
497 if (original_signals
[sig
] == SIG_IGN
)
501 /* Only change the system signal handler if SIG_NO_TRAP is not set.
502 The trap command string is changed in either case. The shell signal
503 handlers for SIGINT and SIGCHLD run the user specified traps in an
504 environment in which it is safe to do so. */
505 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
507 set_signal_handler (sig
, SIG_IGN
);
508 change_signal (sig
, savestring (string
));
509 set_signal_handler (sig
, trap_handler
);
512 change_signal (sig
, savestring (string
));
516 free_trap_command (sig
)
519 if ((sigmodes
[sig
] & SIG_TRAPPED
) && trap_list
[sig
] &&
520 (trap_list
[sig
] != (char *)IGNORE_SIG
) &&
521 (trap_list
[sig
] != (char *)DEFAULT_SIG
) &&
522 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
))
523 free (trap_list
[sig
]);
526 /* If SIG has a string assigned to it, get rid of it. Then give it
529 change_signal (sig
, value
)
533 if ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
534 free_trap_command (sig
);
535 trap_list
[sig
] = value
;
537 sigmodes
[sig
] |= SIG_TRAPPED
;
538 if (value
== (char *)IGNORE_SIG
)
539 sigmodes
[sig
] |= SIG_IGNORED
;
541 sigmodes
[sig
] &= ~SIG_IGNORED
;
542 if (sigmodes
[sig
] & SIG_INPROGRESS
)
543 sigmodes
[sig
] |= SIG_CHANGED
;
547 get_original_signal (sig
)
550 /* If we aren't sure the of the original value, then get it. */
551 if (original_signals
[sig
] == (SigHandler
*)IMPOSSIBLE_TRAP_HANDLER
)
555 /* Restore the default action for SIG; i.e., the action the shell
556 would have taken before you used the trap command. This is called
557 from trap_builtin (), which takes care to restore the handlers for
558 the signals the shell treats specially. */
560 restore_default_signal (sig
)
563 if (SPECIAL_TRAP (sig
))
565 if ((sig
!= DEBUG_TRAP
&& sig
!= ERROR_TRAP
&& sig
!= RETURN_TRAP
) ||
566 (sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
567 free_trap_command (sig
);
568 trap_list
[sig
] = (char *)NULL
;
569 sigmodes
[sig
] &= ~SIG_TRAPPED
;
570 if (sigmodes
[sig
] & SIG_INPROGRESS
)
571 sigmodes
[sig
] |= SIG_CHANGED
;
575 GET_ORIGINAL_SIGNAL (sig
);
577 /* A signal ignored on entry to the shell cannot be trapped or reset, but
578 no error is reported when attempting to do so. Thanks Posix.2. */
579 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
582 /* If we aren't trapping this signal, don't bother doing anything else. */
583 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
586 /* Only change the signal handler for SIG if it allows it. */
587 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
588 set_signal_handler (sig
, original_signals
[sig
]);
590 /* Change the trap command in either case. */
591 change_signal (sig
, (char *)DEFAULT_SIG
);
593 /* Mark the signal as no longer trapped. */
594 sigmodes
[sig
] &= ~SIG_TRAPPED
;
597 /* Make this signal be ignored. */
602 if (SPECIAL_TRAP (sig
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
604 change_signal (sig
, (char *)IGNORE_SIG
);
608 GET_ORIGINAL_SIGNAL (sig
);
610 /* A signal ignored on entry to the shell cannot be trapped or reset.
611 No error is reported when the user attempts to do so. */
612 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
615 /* If already trapped and ignored, no change necessary. */
616 if (sigmodes
[sig
] & SIG_IGNORED
)
619 /* Only change the signal handler for SIG if it allows it. */
620 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
621 set_signal_handler (sig
, SIG_IGN
);
623 /* Change the trap command in either case. */
624 change_signal (sig
, (char *)IGNORE_SIG
);
627 /* Handle the calling of "trap 0". The only sticky situation is when
628 the command to be executed includes an "exit". This is why we have
629 to provide our own place for top_level to jump to. */
634 int code
, function_code
, retval
;
636 trap_saved_exit_value
= last_command_exit_value
;
639 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
640 currently running in the trap handler (call to exit in the list of
641 commands given to trap 0). */
642 if ((sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
) &&
643 (sigmodes
[EXIT_TRAP
] & (SIG_IGNORED
|SIG_INPROGRESS
)) == 0)
645 trap_command
= savestring (trap_list
[EXIT_TRAP
]);
646 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
;
647 sigmodes
[EXIT_TRAP
] |= SIG_INPROGRESS
;
649 retval
= trap_saved_exit_value
;
652 code
= setjmp (top_level
);
654 /* If we're in a function, make sure return longjmps come here, too. */
655 if (return_catch_flag
)
656 function_code
= setjmp (return_catch
);
658 if (code
== 0 && function_code
== 0)
661 parse_and_execute (trap_command
, "exit trap", SEVAL_NONINT
|SEVAL_NOHIST
);
663 else if (code
== ERREXIT
)
664 retval
= last_command_exit_value
;
665 else if (code
== EXITPROG
)
666 retval
= last_command_exit_value
;
667 else if (function_code
!= 0)
668 retval
= return_catch_value
;
670 retval
= trap_saved_exit_value
;
676 return (trap_saved_exit_value
);
680 run_trap_cleanup (sig
)
683 sigmodes
[sig
] &= ~(SIG_INPROGRESS
|SIG_CHANGED
);
686 /* Run a trap command for SIG. SIG is one of the signals the shell treats
687 specially. Returns the exit status of the executed trap command list. */
689 _run_trap_internal (sig
, tag
)
693 char *trap_command
, *old_trap
;
694 int trap_exit_value
, *token_state
;
695 int save_return_catch_flag
, function_code
;
696 procenv_t save_return_catch
;
698 trap_exit_value
= function_code
= 0;
699 /* Run the trap only if SIG is trapped and not ignored, and we are not
700 currently executing in the trap handler. */
701 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0) &&
702 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
) &&
703 ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0))
705 old_trap
= trap_list
[sig
];
706 sigmodes
[sig
] |= SIG_INPROGRESS
;
707 sigmodes
[sig
] &= ~SIG_CHANGED
; /* just to be sure */
708 trap_command
= savestring (old_trap
);
710 running_trap
= sig
+ 1;
711 trap_saved_exit_value
= last_command_exit_value
;
713 token_state
= save_token_state ();
715 /* If we're in a function, make sure return longjmps come here, too. */
716 save_return_catch_flag
= return_catch_flag
;
717 if (return_catch_flag
)
719 COPY_PROCENV (return_catch
, save_return_catch
);
720 function_code
= setjmp (return_catch
);
723 if (function_code
== 0)
724 parse_and_execute (trap_command
, tag
, SEVAL_NONINT
|SEVAL_NOHIST
);
726 restore_token_state (token_state
);
729 trap_exit_value
= last_command_exit_value
;
730 last_command_exit_value
= trap_saved_exit_value
;
733 sigmodes
[sig
] &= ~SIG_INPROGRESS
;
735 if (sigmodes
[sig
] & SIG_CHANGED
)
738 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
739 the places where they can be changed using unwind-protects. For
740 example, look at execute_cmd.c:execute_function(). */
741 if (SPECIAL_TRAP (sig
) == 0)
744 sigmodes
[sig
] &= ~SIG_CHANGED
;
747 if (save_return_catch_flag
)
749 return_catch_flag
= save_return_catch_flag
;
750 return_catch_value
= trap_exit_value
;
751 COPY_PROCENV (save_return_catch
, return_catch
);
753 longjmp (return_catch
, 1);
757 return trap_exit_value
;
765 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
767 if ((sigmodes
[DEBUG_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[DEBUG_TRAP
] & SIG_IGNORED
) == 0) && ((sigmodes
[DEBUG_TRAP
] & SIG_INPROGRESS
) == 0))
769 trap_exit_value
= _run_trap_internal (DEBUG_TRAP
, "debug trap");
771 #if defined (DEBUGGER)
772 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
773 a function or sourced script, we force a `return'. */
774 if (debugging_mode
&& trap_exit_value
== 2 && return_catch_flag
)
776 return_catch_value
= trap_exit_value
;
777 longjmp (return_catch
, 1);
781 return trap_exit_value
;
787 if ((sigmodes
[ERROR_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[ERROR_TRAP
] & SIG_IGNORED
) == 0) && (sigmodes
[ERROR_TRAP
] & SIG_INPROGRESS
) == 0)
788 _run_trap_internal (ERROR_TRAP
, "error trap");
797 if ((sigmodes
[DEBUG_TRAP
] & SIG_TRAPPED
) && (sigmodes
[DEBUG_TRAP
] & SIG_INPROGRESS
))
801 if ((sigmodes
[RETURN_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[RETURN_TRAP
] & SIG_IGNORED
) == 0) && (sigmodes
[RETURN_TRAP
] & SIG_INPROGRESS
) == 0)
803 old_exit_value
= last_command_exit_value
;
804 _run_trap_internal (RETURN_TRAP
, "return trap");
805 last_command_exit_value
= old_exit_value
;
809 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
810 declared here to localize the trap functions. */
812 run_interrupt_trap ()
814 _run_trap_internal (SIGINT
, "interrupt trap");
817 #ifdef INCLUDE_UNUSED
818 /* Free all the allocated strings in the list of traps and reset the trap
819 values to the default. */
825 for (i
= 0; i
< BASH_NSIG
; i
++)
827 free_trap_command (i
);
828 trap_list
[i
] = (char *)DEFAULT_SIG
;
829 sigmodes
[i
] &= ~SIG_TRAPPED
;
831 trap_list
[DEBUG_TRAP
] = trap_list
[EXIT_TRAP
] = trap_list
[ERROR_TRAP
] = trap_list
[RETURN_TRAP
] = (char *)NULL
;
835 /* Reset the handler for SIG to the original value. */
840 set_signal_handler (sig
, original_signals
[sig
]);
841 sigmodes
[sig
] &= ~SIG_TRAPPED
;
844 /* Set the handler signal SIG to the original and free any trap
845 command associated with it. */
850 set_signal_handler (sig
, original_signals
[sig
]);
851 change_signal (sig
, (char *)DEFAULT_SIG
);
852 sigmodes
[sig
] &= ~SIG_TRAPPED
;
856 reset_or_restore_signal_handlers (reset
)
857 sh_resetsig_func_t
*reset
;
861 /* Take care of the exit trap first */
862 if (sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
)
864 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
;
865 if (reset
!= reset_signal
)
867 free_trap_command (EXIT_TRAP
);
868 trap_list
[EXIT_TRAP
] = (char *)NULL
;
872 for (i
= 1; i
< NSIG
; i
++)
874 if (sigmodes
[i
] & SIG_TRAPPED
)
876 if (trap_list
[i
] == (char *)IGNORE_SIG
)
877 set_signal_handler (i
, SIG_IGN
);
881 else if (sigmodes
[i
] & SIG_SPECIAL
)
885 /* Command substitution and other child processes don't inherit the
886 debug, error, or return traps. If we're in the debugger, and the
887 `functrace' or `errtrace' options have been set, then let command
888 substitutions inherit them. Let command substitution inherit the
889 RETURN trap if we're in the debugger and tracing functions. */
890 if (function_trace_mode
== 0)
892 sigmodes
[DEBUG_TRAP
] &= ~SIG_TRAPPED
;
893 sigmodes
[RETURN_TRAP
] &= ~SIG_TRAPPED
;
895 if (error_trace_mode
== 0)
896 sigmodes
[ERROR_TRAP
] &= ~SIG_TRAPPED
;
899 /* Reset trapped signals to their original values, but don't free the
900 trap strings. Called by the command substitution code. */
902 reset_signal_handlers ()
904 reset_or_restore_signal_handlers (reset_signal
);
907 /* Reset all trapped signals to their original values. Signals set to be
908 ignored with trap '' SIGNAL should be ignored, so we make sure that they
909 are. Called by child processes after they are forked. */
911 restore_original_signals ()
913 reset_or_restore_signal_handlers (restore_signal
);
916 /* If a trap handler exists for signal SIG, then call it; otherwise just
919 maybe_call_trap_handler (sig
)
922 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
923 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
928 run_interrupt_trap ();
950 signal_is_trapped (sig
)
953 return (sigmodes
[sig
] & SIG_TRAPPED
);
957 signal_is_special (sig
)
960 return (sigmodes
[sig
] & SIG_SPECIAL
);
964 signal_is_ignored (sig
)
967 return (sigmodes
[sig
] & SIG_IGNORED
);
971 set_signal_ignored (sig
)
974 sigmodes
[sig
] |= SIG_HARD_IGNORE
;
975 original_signals
[sig
] = SIG_IGN
;
979 signal_in_progress (sig
)
982 return (sigmodes
[sig
] & SIG_INPROGRESS
);