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-2023 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
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
24 #if defined (HAVE_UNISTD_H)
28 #include "bashtypes.h"
41 #include "execute_cmd.h"
44 #include "input.h" /* for save_token_state, restore_token_state */
48 #include "builtins/common.h"
49 #include "builtins/builtext.h"
51 #if defined (READLINE)
52 # include <readline/readline.h>
53 # include "bashline.h"
60 /* Flags which describe the current handling state of a signal. */
61 #define SIG_INHERITED 0x0 /* Value inherited from parent. */
62 #define SIG_TRAPPED 0x1 /* Currently trapped. */
63 #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
64 #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
65 #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
66 #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
67 #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
68 #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
69 #define SIG_ASYNCSIG 0x80 /* The signal is ignored because it's in an asynchronous command. */
71 #define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
73 /* An array of such flags, one for each signal, describing what the
74 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
76 static int sigmodes
[BASH_NSIG
];
78 static void free_trap_command (int);
79 static void change_signal (int, char *);
81 static int _run_trap_internal (int, char *);
83 static void free_trap_string (int);
84 static void reset_signal (int);
85 static void restore_signal (int);
86 static void reset_or_restore_signal_handlers (sh_resetsig_func_t
*);
87 static void reinit_trap (int);
89 static void trap_if_untrapped (int, const char *);
91 /* Variables used here but defined in other files. */
93 extern volatile int from_return_trap
;
94 extern int waiting_for_child
;
96 extern WORD_LIST
*subst_assign_varlist
;
98 /* The list of things to do originally, before we started trapping. */
99 SigHandler
*original_signals
[NSIG
];
101 /* For each signal, a slot for a string, which is a command to be
102 executed when that signal is received. The slot can also contain
103 DEFAULT_SIG, which means do whatever you were going to do before
104 you were so rudely interrupted, or IGNORE_SIG, which says ignore
106 char *trap_list
[BASH_NSIG
];
108 /* A bitmap of signals received for which we have trap handlers. */
109 int pending_traps
[NSIG
];
111 /* Set to the number of the signal we're running the trap for + 1.
112 Used in execute_cmd.c and builtins/common.c to clean up when
113 parse_and_execute does not return normally after executing the
114 trap command (e.g., when `return' is executed in the trap command). */
117 /* The execution context (function/source execution level) when we began
118 running this trap command. This is used to determine whether we have
119 executed any shell functions or sourced files from the trap action, and
120 determines where `return' without arguments gets its return status. */
121 int trap_return_context
;
123 /* Set to last_command_exit_value before running a trap. */
124 int trap_saved_exit_value
;
126 /* The (trapped) signal received while executing in the `wait' builtin */
127 int wait_signal_received
;
129 int trapped_signal_received
;
131 /* Set to 1 to suppress the effect of `set v' in the DEBUG trap. */
132 int suppress_debug_trap_verbose
= 0;
134 #define GETORIGSIG(sig) \
136 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
137 set_signal_handler (sig, original_signals[sig]); \
138 if (original_signals[sig] == SIG_IGN) \
139 sigmodes[sig] |= SIG_HARD_IGNORE; \
142 #define SETORIGSIG(sig,handler) \
144 original_signals[sig] = handler; \
145 if (original_signals[sig] == SIG_IGN) \
146 sigmodes[sig] |= SIG_HARD_IGNORE; \
149 #define GET_ORIGINAL_SIGNAL(sig) \
150 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
154 initialize_traps (void)
158 initialize_signames();
160 trap_list
[EXIT_TRAP
] = trap_list
[DEBUG_TRAP
] = trap_list
[ERROR_TRAP
] = trap_list
[RETURN_TRAP
] = (char *)NULL
;
161 sigmodes
[EXIT_TRAP
] = sigmodes
[DEBUG_TRAP
] = sigmodes
[ERROR_TRAP
] = sigmodes
[RETURN_TRAP
] = SIG_INHERITED
;
162 original_signals
[EXIT_TRAP
] = IMPOSSIBLE_TRAP_HANDLER
;
164 for (i
= 1; i
< NSIG
; i
++)
166 pending_traps
[i
] = 0;
167 trap_list
[i
] = (char *)DEFAULT_SIG
;
168 sigmodes
[i
] = SIG_INHERITED
; /* XXX - only set, not used */
169 original_signals
[i
] = IMPOSSIBLE_TRAP_HANDLER
;
172 /* Show which signals are treated specially by the shell. */
173 #if defined (SIGCHLD)
174 GETORIGSIG (SIGCHLD
);
175 sigmodes
[SIGCHLD
] |= (SIG_SPECIAL
| SIG_NO_TRAP
);
179 sigmodes
[SIGINT
] |= SIG_SPECIAL
;
181 #if defined (__BEOS__)
182 /* BeOS sets SIGINT to SIG_IGN! */
183 original_signals
[SIGINT
] = SIG_DFL
;
184 sigmodes
[SIGINT
] &= ~SIG_HARD_IGNORE
;
187 GETORIGSIG (SIGQUIT
);
188 sigmodes
[SIGQUIT
] |= SIG_SPECIAL
;
192 GETORIGSIG (SIGTERM
);
193 sigmodes
[SIGTERM
] |= SIG_SPECIAL
;
196 get_original_tty_job_signals ();
200 /* Return a printable representation of the trap handler for SIG. */
202 trap_handler_string (int sig
)
204 if (trap_list
[sig
] == (char *)DEFAULT_SIG
)
205 return "DEFAULT_SIG";
206 else if (trap_list
[sig
] == (char *)IGNORE_SIG
)
208 else if (trap_list
[sig
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
209 return "IMPOSSIBLE_TRAP_HANDLER";
210 else if (trap_list
[sig
])
211 return trap_list
[sig
];
217 /* Return the print name of this signal. */
219 signal_name (int sig
)
223 /* on cygwin32, signal_names[sig] could be null */
224 ret
= (sig
>= BASH_NSIG
|| sig
< 0 || signal_names
[sig
] == NULL
)
225 ? _("invalid signal number")
231 /* Turn a string into a signal number, or a number into
232 a signal number. If STRING is "2", "SIGINT", or "INT",
233 then (int)2 is returned. Return NO_SIG if STRING doesn't
234 contain a valid signal descriptor. */
236 decode_signal (const char *string
, int flags
)
241 if (valid_number (string
, &sig
))
242 return ((sig
>= 0 && sig
< NSIG
) ? (int)sig
: NO_SIG
);
244 #if defined (SIGRTMIN) && defined (SIGRTMAX)
245 if (STREQN (string
, "SIGRTMIN+", 9) || ((flags
& DSIG_NOCASE
) && strncasecmp (string
, "SIGRTMIN+", 9) == 0))
247 if (valid_number (string
+9, &sig
) && sig
>= 0 && sig
<= SIGRTMAX
- SIGRTMIN
)
248 return (SIGRTMIN
+ sig
);
252 else if (STREQN (string
, "RTMIN+", 6) || ((flags
& DSIG_NOCASE
) && strncasecmp (string
, "RTMIN+", 6) == 0))
254 if (valid_number (string
+6, &sig
) && sig
>= 0 && sig
<= SIGRTMAX
- SIGRTMIN
)
255 return (SIGRTMIN
+ sig
);
259 #endif /* SIGRTMIN && SIGRTMAX */
261 /* A leading `SIG' may be omitted. */
262 for (sig
= 0; sig
< BASH_NSIG
; sig
++)
264 name
= signal_names
[sig
];
265 if (name
== 0 || name
[0] == '\0')
268 /* Check name without the SIG prefix first case sensitively or
269 insensitively depending on whether flags includes DSIG_NOCASE */
270 if (STREQN (name
, "SIG", 3))
274 if ((flags
& DSIG_NOCASE
) && strcasecmp (string
, name
) == 0)
276 else if ((flags
& DSIG_NOCASE
) == 0 && strcmp (string
, name
) == 0)
278 /* If we can't use the `SIG' prefix to match, punt on this
280 else if ((flags
& DSIG_SIGPREFIX
) == 0)
284 /* Check name with SIG prefix case sensitively or insensitively
285 depending on whether flags includes DSIG_NOCASE */
286 name
= signal_names
[sig
];
287 if ((flags
& DSIG_NOCASE
) && strcasecmp (string
, name
) == 0)
289 else if ((flags
& DSIG_NOCASE
) == 0 && strcmp (string
, name
) == 0)
297 save_bash_trapsig (void)
301 if (ret
= get_string_value ("BASH_TRAPSIG"))
302 ret
= savestring (ret
);
307 set_bash_trapsig (int sig
)
309 bind_var_to_int ("BASH_TRAPSIG", sig
, 0);
313 restore_bash_trapsig (char *oldval
)
316 unbind_variable_noref ("BASH_TRAPSIG");
319 bind_variable ("BASH_TRAPSIG", oldval
, 0);
324 /* Non-zero when we catch a trapped signal. */
325 static int catch_flag
;
328 run_pending_traps (void)
332 volatile int old_exit_value
, old_running
, old_context
;
333 WORD_LIST
*save_subst_varlist
;
334 HASH_TABLE
*save_tempenv
;
335 sh_parser_state_t pstate
;
336 volatile int save_return_catch_flag
, function_code
;
337 procenv_t save_return_catch
;
338 char *trap_command
, *old_trap
;
340 #if defined (ARRAY_VARS)
344 if (catch_flag
== 0) /* simple optimization */
347 if (running_trap
> 0)
349 internal_debug ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap
-1);
350 #if defined (SIGWINCH)
351 if (running_trap
== SIGWINCH
+1 && pending_traps
[SIGWINCH
])
352 return; /* no recursive SIGWINCH trap invocations */
354 /* could check for running the trap handler for the same signal here
355 (running_trap == sig+1) */
356 if (evalnest_max
> 0 && evalnest
> evalnest_max
)
358 internal_error (_("trap handler: maximum trap handler level exceeded (%d)"), evalnest_max
);
360 jump_to_top_level (DISCARD
);
364 catch_flag
= trapped_signal_received
= 0;
366 /* Preserve $? when running trap. */
367 trap_saved_exit_value
= old_exit_value
= last_command_exit_value
;
368 #if defined (ARRAY_VARS)
369 ps
= save_pipestatus_array ();
371 old_running
= running_trap
;
372 old_context
= trap_return_context
;
373 old_trapsig
= save_bash_trapsig ();
375 for (sig
= 1; sig
< NSIG
; sig
++)
377 /* XXX this could be made into a counter by using
378 while (pending_traps[sig]--) instead of the if statement. */
379 if (pending_traps
[sig
])
381 /* XXX - set last_command_exit_value = trap_saved_exit_value here? */
382 running_trap
= sig
+ 1;
383 trap_return_context
= funcnest
+ sourcenest
;
385 set_bash_trapsig (sig
);
389 pending_traps
[sig
] = 0; /* XXX */
390 /* We don't modify evalnest here, since run_interrupt_trap() calls
391 _run_trap_internal, which does. */
392 run_interrupt_trap (0);
393 CLRINTERRUPT
; /* interrupts don't stack */
395 #if defined (JOB_CONTROL) && defined (SIGCHLD)
396 else if (sig
== SIGCHLD
&&
397 trap_list
[SIGCHLD
] != (char *)IMPOSSIBLE_TRAP_HANDLER
&&
398 (sigmodes
[SIGCHLD
] & SIG_INPROGRESS
) == 0)
400 sigmodes
[SIGCHLD
] |= SIG_INPROGRESS
;
401 /* We modify evalnest here even though run_sigchld_trap can run
402 the trap action more than once */
404 x
= pending_traps
[sig
];
405 pending_traps
[sig
] = 0;
406 run_sigchld_trap (x
); /* use as counter */
409 sigmodes
[SIGCHLD
] &= ~SIG_INPROGRESS
;
410 /* continue here rather than reset pending_traps[SIGCHLD] below in
411 case there are recursive calls to run_pending_traps and children
412 have been reaped while run_sigchld_trap was running. */
415 else if (sig
== SIGCHLD
&&
416 trap_list
[SIGCHLD
] == (char *)IMPOSSIBLE_TRAP_HANDLER
&&
417 (sigmodes
[SIGCHLD
] & SIG_INPROGRESS
) != 0)
419 /* This can happen when run_pending_traps is called while
420 running a SIGCHLD trap handler. */
422 /* want to leave pending_traps[SIGCHLD] alone here */
425 else if (sig
== SIGCHLD
&& (sigmodes
[SIGCHLD
] & SIG_INPROGRESS
))
427 /* whoops -- print warning? */
428 running_trap
= 0; /* XXX */
429 /* want to leave pending_traps[SIGCHLD] alone here */
433 else if (trap_list
[sig
] == (char *)DEFAULT_SIG
||
434 trap_list
[sig
] == (char *)IGNORE_SIG
||
435 trap_list
[sig
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
437 /* This is possible due to a race condition. Say a bash
438 process has SIGTERM trapped. A subshell is spawned
439 using { list; } & and the parent does something and kills
440 the subshell with SIGTERM. It's possible for the subshell
441 to set pending_traps[SIGTERM] to 1 before the code in
442 execute_cmd.c eventually calls restore_original_signals
443 to reset the SIGTERM signal handler in the subshell. The
444 next time run_pending_traps is called, pending_traps[SIGTERM]
445 will be 1, but the trap handler in trap_list[SIGTERM] will
446 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
447 Unless we catch this, the subshell will dump core when
448 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
450 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
451 sig
, trap_list
[sig
]);
452 if (trap_list
[sig
] == (char *)DEFAULT_SIG
)
454 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig
, signal_name (sig
));
455 kill (getpid (), sig
);
460 /* XXX - why not set SIG_INPROGRESS, clear SIG_CHANGED here? */
461 old_trap
= trap_list
[sig
];
462 trap_command
= savestring (old_trap
);
464 save_parser_state (&pstate
);
465 save_subst_varlist
= subst_assign_varlist
;
466 subst_assign_varlist
= 0;
467 save_tempenv
= temporary_env
;
468 temporary_env
= 0; /* traps should not run with temporary env */
470 #if defined (JOB_CONTROL)
471 save_pipeline (1); /* XXX only provides one save level */
473 /* XXX - set pending_traps[sig] = 0 here? */
474 pending_traps
[sig
] = 0;
478 save_return_catch_flag
= return_catch_flag
;
479 if (return_catch_flag
)
481 COPY_PROCENV (return_catch
, save_return_catch
);
482 function_code
= setjmp_nosigs (return_catch
);
485 if (function_code
== 0)
486 /* XXX is x always last_command_exit_value? */
487 x
= parse_and_execute (trap_command
, "trap", SEVAL_NONINT
|SEVAL_NOHIST
|SEVAL_RESETLINE
|SEVAL_NOOPTIMIZE
);
490 parse_and_execute_cleanup (sig
+ 1); /* XXX - could use -1 */
491 x
= return_catch_value
;
495 #if defined (JOB_CONTROL)
496 restore_pipeline (1);
499 subst_assign_varlist
= save_subst_varlist
;
500 restore_parser_state (&pstate
);
501 temporary_env
= save_tempenv
;
503 if (save_return_catch_flag
)
505 return_catch_flag
= save_return_catch_flag
;
506 return_catch_value
= x
;
507 COPY_PROCENV (save_return_catch
, return_catch
);
510 running_trap
= old_running
; /* XXX */
511 trap_return_context
= old_context
;
512 restore_bash_trapsig (old_trapsig
);
513 /* caller will set last_command_exit_value */
514 sh_longjmp (return_catch
, 1);
519 pending_traps
[sig
] = 0; /* XXX - move before evalstring? */
520 running_trap
= old_running
;
521 trap_return_context
= old_context
;
525 #if defined (ARRAY_VARS)
526 restore_pipestatus_array (ps
);
528 restore_bash_trapsig (old_trapsig
);
529 last_command_exit_value
= old_exit_value
;
532 /* Set the private state variables noting that we received a signal SIG
533 for which we have a trap set. */
535 set_trap_state (int sig
)
538 pending_traps
[sig
]++;
539 trapped_signal_received
= sig
;
543 trap_handler (int sig
)
547 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
549 internal_debug ("trap_handler: signal %d: signal not trapped", sig
);
553 /* This means we're in a subshell, but have not yet reset the handler for
554 trapped signals. We're not supposed to execute the trap in this situation;
555 we should restore the original signal and resend the signal to ourselves
556 to preserve the Posix "signal traps that are not being ignored shall be
557 set to the default action" semantics. */
558 if ((subshell_environment
& SUBSHELL_IGNTRAP
) && trap_list
[sig
] != (char *)IGNORE_SIG
)
563 if (original_signals
[sig
] == IMPOSSIBLE_TRAP_HANDLER
)
564 original_signals
[sig
] = SIG_DFL
;
566 restore_signal (sig
);
568 /* Make sure we let the signal we just caught through */
570 sigprocmask (SIG_SETMASK
, (sigset_t
*)NULL
, &mask
);
571 sigdelset (&mask
, sig
);
572 sigprocmask (SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
574 kill (getpid (), sig
);
580 (trap_list
[sig
] == (char *)DEFAULT_SIG
) ||
581 (trap_list
[sig
] == (char *)IGNORE_SIG
))
582 programming_error (_("trap_handler: bad signal %d"), sig
);
586 #if defined (MUST_REINSTALL_SIGHANDLERS)
587 # if defined (JOB_CONTROL) && defined (SIGCHLD)
589 # endif /* JOB_CONTROL && SIGCHLD */
590 set_signal_handler (sig
, trap_handler
);
591 #endif /* MUST_REINSTALL_SIGHANDLERS */
593 set_trap_state (sig
);
595 if (this_shell_builtin
&& (this_shell_builtin
== wait_builtin
))
597 wait_signal_received
= sig
;
598 if (waiting_for_child
&& wait_intr_flag
)
599 sh_longjmp (wait_intr_buf
, 1);
602 #if defined (READLINE)
603 /* Set the event hook so readline will call it after the signal handlers
604 finish executing, so if this interrupted character input we can get
606 if (RL_ISSTATE (RL_STATE_SIGHANDLER
))
607 bashline_set_event_hook ();
617 next_pending_trap (int start
)
621 for (i
= start
; i
< NSIG
; i
++)
622 if (pending_traps
[i
])
628 first_pending_trap (void)
630 return (next_pending_trap (1));
633 /* Return > 0 if any of the "real" signals (not fake signals like EXIT) are
636 any_signals_trapped (void)
640 for (i
= 1; i
< NSIG
; i
++)
641 if ((sigmodes
[i
] & SIG_TRAPPED
) && (sigmodes
[i
] & SIG_IGNORED
) == 0)
647 clear_pending_traps (void)
651 for (i
= 1; i
< NSIG
; i
++)
652 pending_traps
[i
] = 0;
658 /* Add any other shell timeouts here */
659 check_read_timeout (); /* set by the read builtin */
663 /* Convenience functions the rest of the shell can use */
665 check_signals_and_traps (void)
669 run_pending_traps ();
672 #if defined (JOB_CONTROL) && defined (SIGCHLD)
674 #ifdef INCLUDE_UNUSED
675 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
677 set_sigchld_trap (const char *command_string
)
679 set_signal (SIGCHLD
, command_string
);
683 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
684 is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
685 to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
686 reset the disposition to the default and not have the original signal
687 accidentally restored, undoing the user's command. */
689 uw_maybe_set_sigchld_trap (void *command_string
)
691 if ((sigmodes
[SIGCHLD
] & SIG_TRAPPED
) == 0 && trap_list
[SIGCHLD
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
692 set_signal (SIGCHLD
, (const char *)command_string
);
695 /* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
696 as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
697 or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
699 set_impossible_sigchld_trap (void)
701 restore_default_signal (SIGCHLD
);
702 change_signal (SIGCHLD
, (char *)IMPOSSIBLE_TRAP_HANDLER
);
703 sigmodes
[SIGCHLD
] &= ~SIG_TRAPPED
; /* uw_maybe_set_sigchld_trap checks this */
706 /* Act as if we received SIGCHLD NCHILD times and increment
707 pending_traps[SIGCHLD] by that amount. This allows us to still run the
708 SIGCHLD trap once for each exited child. */
710 queue_sigchld_trap (int nchild
)
715 pending_traps
[SIGCHLD
] += nchild
;
716 trapped_signal_received
= SIGCHLD
;
719 #endif /* JOB_CONTROL && SIGCHLD */
721 /* Set a trap for SIG only if SIG is not already trapped. */
723 trap_if_untrapped (int sig
, const char *command
)
725 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
726 set_signal (sig
, command
);
730 set_debug_trap (const char *command
)
732 set_signal (DEBUG_TRAP
, command
);
735 /* Separate function to call when functions and sourced files want to restore
736 the original version of the DEBUG trap before returning. Unless the -T
737 option is set, source and shell function execution save the old debug trap
738 and unset the trap. If the function or sourced file changes the DEBUG trap,
739 SIG_TRAPPED will be set and we don't bother restoring the original trap string.
740 This is used by both functions and the source builtin. */
742 uw_maybe_set_debug_trap (void *command
)
744 trap_if_untrapped (DEBUG_TRAP
, command
);
748 set_error_trap (const char *command
)
750 set_signal (ERROR_TRAP
, command
);
754 uw_set_error_trap (void *command
)
756 set_error_trap (command
);
760 uw_maybe_set_error_trap (void *command
)
762 trap_if_untrapped (ERROR_TRAP
, command
);
766 set_return_trap (const char *command
)
768 set_signal (RETURN_TRAP
, command
);
772 uw_maybe_set_return_trap (void *command
)
774 trap_if_untrapped (RETURN_TRAP
, command
);
777 #ifdef INCLUDE_UNUSED
779 set_sigint_trap (const char *command
)
781 set_signal (SIGINT
, command
);
785 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
786 things, like waiting for command substitution or executing commands
787 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
789 set_sigint_handler (void)
791 if (sigmodes
[SIGINT
] & SIG_HARD_IGNORE
)
792 return ((SigHandler
*)SIG_IGN
);
794 else if (sigmodes
[SIGINT
] & SIG_IGNORED
)
795 return ((SigHandler
*)set_signal_handler (SIGINT
, SIG_IGN
)); /* XXX */
797 else if (sigmodes
[SIGINT
] & SIG_TRAPPED
)
798 return ((SigHandler
*)set_signal_handler (SIGINT
, trap_handler
));
800 /* The signal is not trapped, so set the handler to the shell's special
801 interrupt handler. Make sure this agrees with code in sig.c and
803 else if (interactive
) /* XXX - was interactive_shell */
804 return (set_signal_handler (SIGINT
, sigint_sighandler
));
806 return (set_signal_handler (SIGINT
, termsig_sighandler
));
809 /* Return the correct handler for signal SIG according to the values in
812 trap_to_sighandler (int sig
)
814 if (sigmodes
[sig
] & (SIG_IGNORED
|SIG_HARD_IGNORE
))
816 else if (sigmodes
[sig
] & SIG_TRAPPED
)
817 return (trap_handler
);
822 /* Set SIG to call STRING as a command. */
824 set_signal (int sig
, const char *string
)
828 if (SPECIAL_TRAP (sig
))
830 change_signal (sig
, savestring (string
));
831 if (sig
== EXIT_TRAP
&& interactive
== 0)
832 initialize_terminating_signals ();
836 /* A signal ignored on entry to the shell cannot be trapped or reset, but
837 no error is reported when attempting to do so. -- Posix.2 */
838 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
841 /* Make sure we have original_signals[sig] if the signal has not yet
843 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
845 /* If we aren't sure of the original value, check it. */
846 if (original_signals
[sig
] == IMPOSSIBLE_TRAP_HANDLER
)
848 if (original_signals
[sig
] == SIG_IGN
&& (sigmodes
[sig
] & SIG_ASYNCSIG
) == 0)
852 /* Only change the system signal handler if SIG_NO_TRAP is not set.
853 The trap command string is changed in either case. The shell signal
854 handlers for SIGINT and SIGCHLD run the user specified traps in an
855 environment in which it is safe to do so. */
856 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
858 BLOCK_SIGNAL (sig
, set
, oset
);
859 change_signal (sig
, savestring (string
));
860 set_signal_handler (sig
, trap_handler
);
861 UNBLOCK_SIGNAL (oset
);
864 change_signal (sig
, savestring (string
));
868 free_trap_command (int sig
)
870 if ((sigmodes
[sig
] & SIG_TRAPPED
) && trap_list
[sig
] &&
871 (trap_list
[sig
] != (char *)IGNORE_SIG
) &&
872 (trap_list
[sig
] != (char *)DEFAULT_SIG
) &&
873 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
))
874 free (trap_list
[sig
]);
877 /* If SIG has a string assigned to it, get rid of it. Then give it
880 change_signal (int sig
, char *value
)
882 if ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
883 free_trap_command (sig
);
884 trap_list
[sig
] = value
;
886 sigmodes
[sig
] |= SIG_TRAPPED
;
887 if (value
== (char *)IGNORE_SIG
)
888 sigmodes
[sig
] |= SIG_IGNORED
;
890 sigmodes
[sig
] &= ~SIG_IGNORED
;
891 if (sigmodes
[sig
] & SIG_INPROGRESS
)
892 sigmodes
[sig
] |= SIG_CHANGED
;
896 get_original_signal (int sig
)
898 /* If we aren't sure the of the original value, then get it. */
899 if (sig
> 0 && sig
< NSIG
&& original_signals
[sig
] == (SigHandler
*)IMPOSSIBLE_TRAP_HANDLER
)
904 get_all_original_signals (void)
908 for (i
= 1; i
< NSIG
; i
++)
909 GET_ORIGINAL_SIGNAL (i
);
913 set_original_signal (int sig
, SigHandler
*handler
)
915 if (sig
> 0 && sig
< NSIG
&& original_signals
[sig
] == (SigHandler
*)IMPOSSIBLE_TRAP_HANDLER
)
916 SETORIGSIG (sig
, handler
);
919 /* Restore the default action for SIG; i.e., the action the shell
920 would have taken before you used the trap command. This is called
921 from trap_builtin (), which takes care to restore the handlers for
922 the signals the shell treats specially. */
924 restore_default_signal (int sig
)
926 if (SPECIAL_TRAP (sig
))
928 if ((sig
!= DEBUG_TRAP
&& sig
!= ERROR_TRAP
&& sig
!= RETURN_TRAP
) ||
929 (sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
930 free_trap_command (sig
);
931 trap_list
[sig
] = (char *)NULL
;
932 sigmodes
[sig
] &= ~SIG_TRAPPED
;
933 if (sigmodes
[sig
] & SIG_INPROGRESS
)
934 sigmodes
[sig
] |= SIG_CHANGED
;
938 GET_ORIGINAL_SIGNAL (sig
);
940 /* A signal ignored on entry to the shell cannot be trapped or reset, but
941 no error is reported when attempting to do so. Thanks Posix.2. */
942 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
945 /* Even if the signal is not trapped, POSIX interp 751 requires that we
946 allow `trap - SIGINT' to reset the signal disposition for SIGINT to
948 if ((sigmodes
[sig
] & (SIG_TRAPPED
|SIG_ASYNCSIG
|SIG_NO_TRAP
)) == SIG_ASYNCSIG
)
950 original_signals
[sig
] = SIG_DFL
; /* XXX */
951 set_signal_handler (sig
, SIG_DFL
);
952 change_signal (sig
, (char *)DEFAULT_SIG
);
956 /* If we aren't trapping this signal, don't bother doing anything else. */
957 /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
958 sentinel to determine whether or not disposition is reset to the default
959 while the trap handler is executing. */
960 if (((sigmodes
[sig
] & SIG_TRAPPED
) == 0) &&
961 (sig
!= SIGCHLD
|| (sigmodes
[sig
] & SIG_INPROGRESS
) == 0 || trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
))
964 /* Only change the signal handler for SIG if it allows it. */
965 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
966 set_signal_handler (sig
, original_signals
[sig
]);
968 /* Change the trap command in either case. */
969 change_signal (sig
, (char *)DEFAULT_SIG
);
971 /* Mark the signal as no longer trapped. */
972 sigmodes
[sig
] &= ~SIG_TRAPPED
;
975 /* Make this signal be ignored. */
977 ignore_signal (int sig
)
979 if (SPECIAL_TRAP (sig
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
981 change_signal (sig
, (char *)IGNORE_SIG
);
985 GET_ORIGINAL_SIGNAL (sig
);
987 /* A signal ignored on entry to the shell cannot be trapped or reset.
988 No error is reported when the user attempts to do so. */
989 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
992 /* If already trapped and ignored, no change necessary. */
993 if (sigmodes
[sig
] & SIG_IGNORED
)
995 sigmodes
[sig
] |= SIG_TRAPPED
; /* just make sure */
996 /* XXX - turn off SIG_ASYNCSIG here? */
1000 /* Only change the signal handler for SIG if it allows it. */
1001 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
1002 set_signal_handler (sig
, SIG_IGN
);
1004 /* Change the trap command in either case. */
1005 change_signal (sig
, (char *)IGNORE_SIG
);
1008 /* Handle the calling of "trap 0". The only sticky situation is when
1009 the command to be executed includes an "exit". This is why we have
1010 to provide our own place for top_level to jump to. */
1012 run_exit_trap (void)
1016 int code
, function_code
, retval
;
1017 #if defined (ARRAY_VARS)
1021 trap_saved_exit_value
= last_command_exit_value
;
1022 #if defined (ARRAY_VARS)
1023 ps
= save_pipestatus_array ();
1027 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
1028 currently running in the trap handler (call to exit in the list of
1029 commands given to trap 0). */
1030 if ((sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
) &&
1031 (sigmodes
[EXIT_TRAP
] & (SIG_IGNORED
|SIG_INPROGRESS
)) == 0)
1033 trap_command
= savestring (trap_list
[EXIT_TRAP
]);
1034 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
;
1035 sigmodes
[EXIT_TRAP
] |= SIG_INPROGRESS
;
1037 retval
= trap_saved_exit_value
;
1039 trap_return_context
= funcnest
+ sourcenest
;
1041 old_trapsig
= save_bash_trapsig ();
1042 set_bash_trapsig (EXIT_TRAP
);
1044 code
= setjmp_nosigs (top_level
);
1046 /* If we're in a function, make sure return longjmps come here, too. */
1047 if (return_catch_flag
)
1048 function_code
= setjmp_nosigs (return_catch
);
1050 if (code
== 0 && function_code
== 0)
1053 parse_and_execute (trap_command
, "exit trap", SEVAL_NONINT
|SEVAL_NOHIST
|SEVAL_RESETLINE
|SEVAL_NOOPTIMIZE
);
1055 else if (code
== ERREXIT
)
1056 retval
= last_command_exit_value
;
1057 else if (code
== EXITPROG
|| code
== EXITBLTIN
)
1058 retval
= last_command_exit_value
;
1059 else if (function_code
!= 0)
1060 retval
= return_catch_value
;
1062 retval
= trap_saved_exit_value
;
1065 #if defined (ARRAY_VARS)
1068 restore_bash_trapsig (old_trapsig
);
1073 #if defined (ARRAY_VARS)
1074 restore_pipestatus_array (ps
);
1076 return (trap_saved_exit_value
);
1080 run_trap_cleanup (int sig
)
1082 /* XXX - should we clean up trap_list[sig] == IMPOSSIBLE_TRAP_HANDLER? */
1083 sigmodes
[sig
] &= ~(SIG_INPROGRESS
|SIG_CHANGED
);
1086 #define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
1088 /* Run a trap command for SIG. SIG is one of the signals the shell treats
1089 specially. Returns the exit status of the executed trap command list. */
1091 _run_trap_internal (int sig
, char *tag
)
1093 char *trap_command
, *old_trap
;
1095 int trap_exit_value
;
1096 volatile int save_return_catch_flag
, function_code
;
1097 int old_modes
, old_running
, old_int
, old_context
;
1099 procenv_t save_return_catch
;
1100 WORD_LIST
*save_subst_varlist
;
1101 HASH_TABLE
*save_tempenv
;
1102 sh_parser_state_t pstate
;
1103 #if defined (ARRAY_VARS)
1107 old_modes
= old_running
= old_context
= -1;
1109 trap_exit_value
= 0;
1110 trap_saved_exit_value
= last_command_exit_value
;
1111 /* Run the trap only if SIG is trapped and not ignored, and we are not
1112 currently executing in the trap handler. */
1113 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0) &&
1114 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
) &&
1116 /* Uncomment this to allow some special signals to recursively execute
1118 (RECURSIVE_SIG (sig
) || (sigmodes
[sig
] & SIG_INPROGRESS
) == 0))
1120 ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0))
1123 old_trap
= trap_list
[sig
];
1124 old_modes
= sigmodes
[sig
];
1125 old_running
= running_trap
;
1126 old_context
= trap_return_context
;
1128 sigmodes
[sig
] |= SIG_INPROGRESS
;
1129 sigmodes
[sig
] &= ~SIG_CHANGED
; /* just to be sure */
1130 trap_command
= savestring (old_trap
);
1132 old_trapsig
= save_bash_trapsig ();
1133 set_bash_trapsig (sig
);
1135 running_trap
= sig
+ 1;
1136 trap_return_context
= funcnest
+ sourcenest
;
1138 old_int
= interrupt_state
; /* temporarily suppress pending interrupts */
1141 #if defined (ARRAY_VARS)
1142 ps
= save_pipestatus_array ();
1145 save_parser_state (&pstate
);
1146 save_subst_varlist
= subst_assign_varlist
;
1147 subst_assign_varlist
= 0;
1148 save_tempenv
= temporary_env
;
1149 temporary_env
= 0; /* traps should not run with temporary env */
1151 /* Will be restored by restore_parser_state */
1152 if (shell_eof_token
)
1154 reset_parser (); /* resets parser-private state */
1155 shell_eof_token
= 0;
1158 #if defined (JOB_CONTROL)
1159 if (sig
!= DEBUG_TRAP
) /* run_debug_trap does this */
1160 save_pipeline (1); /* XXX only provides one save level */
1163 /* XXX - set pending_traps[sig] = 0 here? */
1166 /* If we're in a function, make sure return longjmps come here, too. */
1168 save_return_catch_flag
= return_catch_flag
;
1169 if (return_catch_flag
)
1171 COPY_PROCENV (return_catch
, save_return_catch
);
1172 function_code
= setjmp_nosigs (return_catch
);
1175 flags
= SEVAL_NONINT
|SEVAL_NOHIST
|SEVAL_NOOPTIMIZE
;
1176 if (sig
!= DEBUG_TRAP
&& sig
!= RETURN_TRAP
&& sig
!= ERROR_TRAP
)
1177 flags
|= SEVAL_RESETLINE
;
1178 if (function_code
== 0)
1180 parse_and_execute (trap_command
, tag
, flags
);
1181 trap_exit_value
= last_command_exit_value
;
1184 trap_exit_value
= return_catch_value
;
1187 #if defined (JOB_CONTROL)
1188 if (sig
!= DEBUG_TRAP
) /* run_debug_trap does this */
1189 restore_pipeline (1);
1192 subst_assign_varlist
= save_subst_varlist
;
1193 restore_parser_state (&pstate
);
1195 #if defined (ARRAY_VARS)
1196 restore_pipestatus_array (ps
);
1199 temporary_env
= save_tempenv
;
1201 if ((old_modes
& SIG_INPROGRESS
) == 0)
1202 sigmodes
[sig
] &= ~SIG_INPROGRESS
;
1204 restore_bash_trapsig (old_trapsig
);
1206 running_trap
= old_running
;
1207 interrupt_state
= old_int
;
1208 trap_return_context
= old_context
;
1210 if (sigmodes
[sig
] & SIG_CHANGED
)
1213 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
1214 the places where they can be changed using unwind-protects. For
1215 example, look at execute_cmd.c:execute_function(). */
1216 if (SPECIAL_TRAP (sig
) == 0)
1219 sigmodes
[sig
] &= ~SIG_CHANGED
;
1221 CHECK_TERMSIG
; /* some pathological conditions lead here */
1224 if (save_return_catch_flag
)
1226 return_catch_flag
= save_return_catch_flag
;
1227 return_catch_value
= trap_exit_value
;
1228 COPY_PROCENV (save_return_catch
, return_catch
);
1232 from_return_trap
= sig
== RETURN_TRAP
;
1234 sh_longjmp (return_catch
, 1);
1239 return trap_exit_value
;
1243 run_debug_trap (void)
1245 int trap_exit_value
, old_verbose
;
1247 #if defined (PGRP_PIPE)
1251 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
1252 trap_exit_value
= 0;
1253 if ((sigmodes
[DEBUG_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[DEBUG_TRAP
] & SIG_IGNORED
) == 0) && ((sigmodes
[DEBUG_TRAP
] & SIG_INPROGRESS
) == 0))
1255 #if defined (JOB_CONTROL)
1256 save_pgrp
= pipeline_pgrp
;
1259 # if defined (PGRP_PIPE)
1260 save_pgrp_pipe (save_pipe
, 1);
1262 stop_making_children ();
1265 old_verbose
= echo_input_at_read
;
1266 echo_input_at_read
= suppress_debug_trap_verbose
? 0 : echo_input_at_read
;
1268 trap_exit_value
= _run_trap_internal (DEBUG_TRAP
, "debug trap");
1270 echo_input_at_read
= old_verbose
;
1272 #if defined (JOB_CONTROL)
1273 pipeline_pgrp
= save_pgrp
;
1274 restore_pipeline (1);
1275 # if defined (PGRP_PIPE)
1277 restore_pgrp_pipe (save_pipe
);
1279 if (pipeline_pgrp
> 0 && ((subshell_environment
& (SUBSHELL_ASYNC
|SUBSHELL_PIPE
)) == 0))
1280 give_terminal_to (pipeline_pgrp
, 1);
1282 notify_and_cleanup ();
1285 #if defined (DEBUGGER)
1286 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
1287 a function or sourced script, we force a `return'. */
1288 if (debugging_mode
&& trap_exit_value
== 2 && return_catch_flag
)
1290 return_catch_value
= trap_exit_value
;
1291 sh_longjmp (return_catch
, 1);
1295 return trap_exit_value
;
1299 run_error_trap (void)
1301 if ((sigmodes
[ERROR_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[ERROR_TRAP
] & SIG_IGNORED
) == 0) && (sigmodes
[ERROR_TRAP
] & SIG_INPROGRESS
) == 0)
1302 _run_trap_internal (ERROR_TRAP
, "error trap");
1306 run_return_trap (void)
1311 if ((sigmodes
[DEBUG_TRAP
] & SIG_TRAPPED
) && (sigmodes
[DEBUG_TRAP
] & SIG_INPROGRESS
))
1315 if ((sigmodes
[RETURN_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[RETURN_TRAP
] & SIG_IGNORED
) == 0) && (sigmodes
[RETURN_TRAP
] & SIG_INPROGRESS
) == 0)
1317 old_exit_value
= last_command_exit_value
;
1318 _run_trap_internal (RETURN_TRAP
, "return trap");
1319 last_command_exit_value
= old_exit_value
;
1323 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
1324 declared here to localize the trap functions. */
1325 /* WILL_THROW indicates whether we're run from throw_to_top_level */
1327 run_interrupt_trap (int will_throw
)
1329 if (will_throw
&& running_trap
> 0)
1330 run_trap_cleanup (running_trap
- 1);
1331 pending_traps
[SIGINT
] = 0; /* run_pending_traps does this */
1333 _run_trap_internal (SIGINT
, "interrupt trap");
1336 /* Free all the allocated strings in the list of traps and reset the trap
1337 values to the default. Intended to be called from subshells that want
1338 to complete work done by reset_signal_handlers upon execution of a
1339 subsequent `trap' command that changes a signal's disposition. We need
1340 to make sure that we duplicate the behavior of
1341 reset_or_restore_signal_handlers and not change the disposition of signals
1342 that are set to be ignored. */
1344 free_trap_strings (void)
1348 for (i
= 0; i
< NSIG
; i
++)
1350 if (trap_list
[i
] != (char *)IGNORE_SIG
)
1351 free_trap_string (i
);
1353 for (i
= NSIG
; i
< BASH_NSIG
; i
++)
1355 /* Don't free the trap string if the subshell inherited the trap */
1356 if ((sigmodes
[i
] & SIG_TRAPPED
) == 0)
1358 free_trap_string (i
);
1359 trap_list
[i
] = (char *)NULL
;
1364 /* Free a trap command string associated with SIG without changing signal
1365 disposition. Intended to be called from free_trap_strings() */
1367 free_trap_string (int sig
)
1369 change_signal (sig
, (char *)DEFAULT_SIG
);
1370 sigmodes
[sig
] &= ~SIG_TRAPPED
; /* XXX - SIG_INPROGRESS? */
1373 /* Reset the handler for SIG to the original value but leave the trap string
1376 reset_signal (int sig
)
1379 /* If we have a trapped signal that was previously ignored because it was
1380 SIGINT or SIGQUIT in an asynchronous list, then we need to restore the
1381 default signal and not the (artificial) SIG_IGN. We know that the signal
1382 was not ignored at shell invocation because you can't trap it if
1383 SIG_HARD_IGNORE is set. */
1384 if ((sigmodes
[sig
] & SIG_ASYNCSIG
) && signal_is_trapped (sig
) && original_signals
[sig
] == SIG_IGN
)
1385 original_signals
[sig
] = SIG_DFL
;
1387 set_signal_handler (sig
, original_signals
[sig
]);
1388 sigmodes
[sig
] &= ~SIG_TRAPPED
; /* XXX - SIG_INPROGRESS? */
1391 /* Set the handler signal SIG to the original and free any trap
1392 command associated with it. */
1394 restore_signal (int sig
)
1397 /* If we have a trapped signal that was previously ignored because it was
1398 SIGINT or SIGQUIT in an asynchronous list, then we need to restore the
1399 default signal and not the (artificial) SIG_IGN. We know that the signal
1400 was not ignored at shell invocation because you can't trap it if
1401 SIG_HARD_IGNORE is set. */
1402 if ((sigmodes
[sig
] & SIG_ASYNCSIG
) && signal_is_trapped (sig
) && original_signals
[sig
] == SIG_IGN
)
1403 original_signals
[sig
] = SIG_DFL
;
1405 set_signal_handler (sig
, original_signals
[sig
]);
1406 change_signal (sig
, (char *)DEFAULT_SIG
);
1407 sigmodes
[sig
] &= ~SIG_TRAPPED
;
1411 reset_or_restore_signal_handlers (sh_resetsig_func_t
*reset
)
1415 /* Take care of the exit trap first */
1416 if (sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
)
1418 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
; /* XXX - SIG_INPROGRESS? */
1419 if (reset
!= reset_signal
)
1421 free_trap_command (EXIT_TRAP
);
1422 trap_list
[EXIT_TRAP
] = (char *)NULL
;
1426 for (i
= 1; i
< NSIG
; i
++)
1428 if (sigmodes
[i
] & SIG_TRAPPED
)
1430 if (trap_list
[i
] == (char *)IGNORE_SIG
)
1431 set_signal_handler (i
, SIG_IGN
);
1435 else if (sigmodes
[i
] & SIG_SPECIAL
)
1437 pending_traps
[i
] = 0; /* XXX */
1440 /* Command substitution and other child processes don't inherit the
1441 debug, error, or return traps. If we're in the debugger, and the
1442 `functrace' or `errtrace' options have been set, then let command
1443 substitutions inherit them. Let command substitution inherit the
1444 RETURN trap if we're in the debugger and tracing functions. */
1445 if (function_trace_mode
== 0)
1447 sigmodes
[DEBUG_TRAP
] &= ~SIG_TRAPPED
;
1448 sigmodes
[RETURN_TRAP
] &= ~SIG_TRAPPED
;
1450 if (error_trace_mode
== 0)
1451 sigmodes
[ERROR_TRAP
] &= ~SIG_TRAPPED
;
1454 /* Reset trapped signals to their original values, but don't free the
1455 trap strings. Called by the command substitution code and other places
1456 that create a "subshell environment". */
1458 reset_signal_handlers (void)
1460 reset_or_restore_signal_handlers (reset_signal
);
1463 /* Reset all trapped signals to their original values. Signals set to be
1464 ignored with trap '' SIGNAL should be ignored, so we make sure that they
1465 are. Called by child processes after they are forked. */
1467 restore_original_signals (void)
1469 reset_or_restore_signal_handlers (restore_signal
);
1472 /* Change the flags associated with signal SIG without changing the trap
1473 string. The string is TRAP_LIST[SIG] if we need it. */
1475 reinit_trap (int sig
)
1477 sigmodes
[sig
] |= SIG_TRAPPED
;
1478 if (trap_list
[sig
] == (char *)IGNORE_SIG
)
1479 sigmodes
[sig
] |= SIG_IGNORED
;
1481 sigmodes
[sig
] &= ~SIG_IGNORED
;
1482 if (sigmodes
[sig
] & SIG_INPROGRESS
)
1483 sigmodes
[sig
] |= SIG_CHANGED
;
1486 /* Undo the effects of reset_signal_handlers(), which unsets the traps but
1487 leaves the trap strings in place. This understands how reset_signal_handlers
1490 restore_traps (void)
1495 /* Take care of the exit trap first. If TRAP_LIST[0] is non-null, the trap
1497 trapstr
= trap_list
[EXIT_TRAP
];
1499 reinit_trap (EXIT_TRAP
);
1501 /* Then DEBUG, RETURN, and ERROR. TRAP_LIST[N] == 0 if these signals are
1502 not trapped. This knows what reset_signal_handlers does for these traps */
1503 trapstr
= trap_list
[DEBUG_TRAP
];
1504 if (trapstr
&& function_trace_mode
== 0)
1505 reinit_trap (DEBUG_TRAP
);
1506 trapstr
= trap_list
[RETURN_TRAP
];
1507 if (trapstr
&& function_trace_mode
== 0)
1508 reinit_trap (RETURN_TRAP
);
1509 trapstr
= trap_list
[ERROR_TRAP
];
1510 if (trapstr
&& error_trace_mode
== 0)
1511 reinit_trap (ERROR_TRAP
);
1513 /* And finally all the `real' signals. reset_signal_handlers just changes the
1514 signal handler for these signals, leaving the trap value in place. We
1515 intuit what to do based on that value. We assume that signals marked as
1516 SIG_SPECIAL are reinitialized by initialize_signals (), so we don't
1517 change the signal handler unless the signal is supposed to be ignored. */
1518 for (i
= 1; i
< NSIG
; i
++)
1520 trapstr
= trap_list
[i
];
1521 if (sigmodes
[i
] & SIG_SPECIAL
)
1523 if (trapstr
&& trapstr
!= (char *)DEFAULT_SIG
)
1525 if (trapstr
== (char *)IGNORE_SIG
&& (sigmodes
[i
] & SIG_NO_TRAP
) == 0)
1526 set_signal_handler (i
, SIG_IGN
);
1528 else if (trapstr
== (char *)IGNORE_SIG
)
1531 if ((sigmodes
[i
] & SIG_NO_TRAP
) == 0)
1532 set_signal_handler (i
, SIG_IGN
);
1534 else if (trapstr
!= (char *)DEFAULT_SIG
)
1535 /* set_signal duplicates the string argument before freeing it. */
1536 set_signal (i
, trapstr
);
1538 pending_traps
[i
] = 0; /* XXX */
1542 /* If a trap handler exists for signal SIG, then call it; otherwise just
1543 return failure. Returns 1 if it called the trap handler. */
1545 maybe_call_trap_handler (int sig
)
1547 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1548 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
1553 run_interrupt_trap (0);
1575 signal_is_trapped (int sig
)
1577 return (sigmodes
[sig
] & SIG_TRAPPED
);
1581 signal_is_pending (int sig
)
1583 return (pending_traps
[sig
]);
1587 signal_is_special (int sig
)
1589 return (sigmodes
[sig
] & SIG_SPECIAL
);
1593 signal_is_ignored (int sig
)
1595 return (sigmodes
[sig
] & SIG_IGNORED
);
1599 signal_is_hard_ignored (int sig
)
1601 return (sigmodes
[sig
] & SIG_HARD_IGNORE
);
1605 set_signal_hard_ignored (int sig
)
1607 sigmodes
[sig
] |= SIG_HARD_IGNORE
;
1608 original_signals
[sig
] = SIG_IGN
;
1612 set_signal_ignored (int sig
)
1614 original_signals
[sig
] = SIG_IGN
;
1618 set_signal_async_ignored (int sig
)
1620 original_signals
[sig
] = SIG_IGN
;
1621 sigmodes
[sig
] |= SIG_ASYNCSIG
|SIG_IGNORED
;
1625 signal_is_async_ignored (int sig
)
1627 return (sigmodes
[sig
] & SIG_ASYNCSIG
);
1631 signal_in_progress (int sig
)
1633 return (sigmodes
[sig
] & SIG_INPROGRESS
);
1638 block_trapped_signals (sigset_t
*maskp
, sigset_t
*omaskp
)
1642 sigemptyset (maskp
);
1643 for (i
= 1; i
< NSIG
; i
++)
1644 if (sigmodes
[i
] & SIG_TRAPPED
)
1645 sigaddset (maskp
, i
);
1646 return (sigprocmask (SIG_BLOCK
, maskp
, omaskp
));
1650 unblock_trapped_signals (sigset_t
*maskp
)
1652 return (sigprocmask (SIG_SETMASK
, maskp
, 0));