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-2020 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. */
70 #define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
72 /* An array of such flags, one for each signal, describing what the
73 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
75 static int sigmodes
[BASH_NSIG
];
77 static void free_trap_command (int);
78 static void change_signal (int, char *);
80 static int _run_trap_internal (int, char *);
82 static void free_trap_string (int);
83 static void reset_signal (int);
84 static void restore_signal (int);
85 static void reset_or_restore_signal_handlers (sh_resetsig_func_t
*);
87 static void trap_if_untrapped (int, char *);
89 /* Variables used here but defined in other files. */
90 extern procenv_t alrmbuf
;
92 extern volatile int from_return_trap
;
93 extern int waiting_for_child
;
95 extern WORD_LIST
*subst_assign_varlist
;
97 /* The list of things to do originally, before we started trapping. */
98 SigHandler
*original_signals
[NSIG
];
100 /* For each signal, a slot for a string, which is a command to be
101 executed when that signal is received. The slot can also contain
102 DEFAULT_SIG, which means do whatever you were going to do before
103 you were so rudely interrupted, or IGNORE_SIG, which says ignore
105 char *trap_list
[BASH_NSIG
];
107 /* A bitmap of signals received for which we have trap handlers. */
108 int pending_traps
[NSIG
];
110 /* Set to the number of the signal we're running the trap for + 1.
111 Used in execute_cmd.c and builtins/common.c to clean up when
112 parse_and_execute does not return normally after executing the
113 trap command (e.g., when `return' is executed in the trap command). */
116 /* Set to last_command_exit_value before running a trap. */
117 int trap_saved_exit_value
;
119 /* The (trapped) signal received while executing in the `wait' builtin */
120 int wait_signal_received
;
122 int trapped_signal_received
;
124 /* Set to 1 to suppress the effect of `set v' in the DEBUG trap. */
125 int suppress_debug_trap_verbose
= 0;
127 #define GETORIGSIG(sig) \
129 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
130 set_signal_handler (sig, original_signals[sig]); \
131 if (original_signals[sig] == SIG_IGN) \
132 sigmodes[sig] |= SIG_HARD_IGNORE; \
135 #define SETORIGSIG(sig,handler) \
137 original_signals[sig] = handler; \
138 if (original_signals[sig] == SIG_IGN) \
139 sigmodes[sig] |= SIG_HARD_IGNORE; \
142 #define GET_ORIGINAL_SIGNAL(sig) \
143 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
151 initialize_signames();
153 trap_list
[EXIT_TRAP
] = trap_list
[DEBUG_TRAP
] = trap_list
[ERROR_TRAP
] = trap_list
[RETURN_TRAP
] = (char *)NULL
;
154 sigmodes
[EXIT_TRAP
] = sigmodes
[DEBUG_TRAP
] = sigmodes
[ERROR_TRAP
] = sigmodes
[RETURN_TRAP
] = SIG_INHERITED
;
155 original_signals
[EXIT_TRAP
] = IMPOSSIBLE_TRAP_HANDLER
;
157 for (i
= 1; i
< NSIG
; i
++)
159 pending_traps
[i
] = 0;
160 trap_list
[i
] = (char *)DEFAULT_SIG
;
161 sigmodes
[i
] = SIG_INHERITED
; /* XXX - only set, not used */
162 original_signals
[i
] = IMPOSSIBLE_TRAP_HANDLER
;
165 /* Show which signals are treated specially by the shell. */
166 #if defined (SIGCHLD)
167 GETORIGSIG (SIGCHLD
);
168 sigmodes
[SIGCHLD
] |= (SIG_SPECIAL
| SIG_NO_TRAP
);
172 sigmodes
[SIGINT
] |= SIG_SPECIAL
;
174 #if defined (__BEOS__)
175 /* BeOS sets SIGINT to SIG_IGN! */
176 original_signals
[SIGINT
] = SIG_DFL
;
177 sigmodes
[SIGINT
] &= ~SIG_HARD_IGNORE
;
180 GETORIGSIG (SIGQUIT
);
181 sigmodes
[SIGQUIT
] |= SIG_SPECIAL
;
185 GETORIGSIG (SIGTERM
);
186 sigmodes
[SIGTERM
] |= SIG_SPECIAL
;
189 get_original_tty_job_signals ();
193 /* Return a printable representation of the trap handler for SIG. */
195 trap_handler_string (sig
)
198 if (trap_list
[sig
] == (char *)DEFAULT_SIG
)
199 return "DEFAULT_SIG";
200 else if (trap_list
[sig
] == (char *)IGNORE_SIG
)
202 else if (trap_list
[sig
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
203 return "IMPOSSIBLE_TRAP_HANDLER";
204 else if (trap_list
[sig
])
205 return trap_list
[sig
];
211 /* Return the print name of this signal. */
218 /* on cygwin32, signal_names[sig] could be null */
219 ret
= (sig
>= BASH_NSIG
|| sig
< 0 || signal_names
[sig
] == NULL
)
220 ? _("invalid signal number")
226 /* Turn a string into a signal number, or a number into
227 a signal number. If STRING is "2", "SIGINT", or "INT",
228 then (int)2 is returned. Return NO_SIG if STRING doesn't
229 contain a valid signal descriptor. */
231 decode_signal (string
, flags
)
238 if (legal_number (string
, &sig
))
239 return ((sig
>= 0 && sig
< NSIG
) ? (int)sig
: NO_SIG
);
241 #if defined (SIGRTMIN) && defined (SIGRTMAX)
242 if (STREQN (string
, "SIGRTMIN+", 9) || ((flags
& DSIG_NOCASE
) && strncasecmp (string
, "SIGRTMIN+", 9) == 0))
244 if (legal_number (string
+9, &sig
) && sig
>= 0 && sig
<= SIGRTMAX
- SIGRTMIN
)
245 return (SIGRTMIN
+ sig
);
249 else if (STREQN (string
, "RTMIN+", 6) || ((flags
& DSIG_NOCASE
) && strncasecmp (string
, "RTMIN+", 6) == 0))
251 if (legal_number (string
+6, &sig
) && sig
>= 0 && sig
<= SIGRTMAX
- SIGRTMIN
)
252 return (SIGRTMIN
+ sig
);
256 #endif /* SIGRTMIN && SIGRTMAX */
258 /* A leading `SIG' may be omitted. */
259 for (sig
= 0; sig
< BASH_NSIG
; sig
++)
261 name
= signal_names
[sig
];
262 if (name
== 0 || name
[0] == '\0')
265 /* Check name without the SIG prefix first case sensitively or
266 insensitively depending on whether flags includes DSIG_NOCASE */
267 if (STREQN (name
, "SIG", 3))
271 if ((flags
& DSIG_NOCASE
) && strcasecmp (string
, name
) == 0)
273 else if ((flags
& DSIG_NOCASE
) == 0 && strcmp (string
, name
) == 0)
275 /* If we can't use the `SIG' prefix to match, punt on this
277 else if ((flags
& DSIG_SIGPREFIX
) == 0)
281 /* Check name with SIG prefix case sensitively or insensitively
282 depending on whether flags includes DSIG_NOCASE */
283 name
= signal_names
[sig
];
284 if ((flags
& DSIG_NOCASE
) && strcasecmp (string
, name
) == 0)
286 else if ((flags
& DSIG_NOCASE
) == 0 && strcmp (string
, name
) == 0)
293 /* Non-zero when we catch a trapped signal. */
294 static int catch_flag
;
300 int old_exit_value
, x
;
302 WORD_LIST
*save_subst_varlist
;
303 HASH_TABLE
*save_tempenv
;
304 sh_parser_state_t pstate
;
305 #if defined (ARRAY_VARS)
309 if (catch_flag
== 0) /* simple optimization */
312 if (running_trap
> 0)
315 internal_warning ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap
-1);
317 #if defined (SIGWINCH)
318 if (running_trap
== SIGWINCH
+1 && pending_traps
[SIGWINCH
])
319 return; /* no recursive SIGWINCH trap invocations */
321 /* could check for running the trap handler for the same signal here
322 (running_trap == sig+1) */
323 if (evalnest_max
> 0 && evalnest
> evalnest_max
)
325 internal_error (_("trap handler: maximum trap handler level exceeded (%d)"), evalnest_max
);
327 jump_to_top_level (DISCARD
);
331 catch_flag
= trapped_signal_received
= 0;
333 /* Preserve $? when running trap. */
334 trap_saved_exit_value
= old_exit_value
= last_command_exit_value
;
335 #if defined (ARRAY_VARS)
336 ps
= save_pipestatus_array ();
338 old_running
= running_trap
;
340 for (sig
= 1; sig
< NSIG
; sig
++)
342 /* XXX this could be made into a counter by using
343 while (pending_traps[sig]--) instead of the if statement. */
344 if (pending_traps
[sig
])
346 if (running_trap
== sig
+1)
349 running_trap
= sig
+ 1;
353 pending_traps
[sig
] = 0; /* XXX */
354 /* We don't modify evalnest here, since run_interrupt_trap() calls
355 _run_trap_internal, which does. */
356 run_interrupt_trap (0);
357 CLRINTERRUPT
; /* interrupts don't stack */
359 #if defined (JOB_CONTROL) && defined (SIGCHLD)
360 else if (sig
== SIGCHLD
&&
361 trap_list
[SIGCHLD
] != (char *)IMPOSSIBLE_TRAP_HANDLER
&&
362 (sigmodes
[SIGCHLD
] & SIG_INPROGRESS
) == 0)
364 sigmodes
[SIGCHLD
] |= SIG_INPROGRESS
;
365 /* We modify evalnest here even though run_sigchld_trap can run
366 the trap action more than once */
368 x
= pending_traps
[sig
];
369 pending_traps
[sig
] = 0;
370 run_sigchld_trap (x
); /* use as counter */
373 sigmodes
[SIGCHLD
] &= ~SIG_INPROGRESS
;
374 /* continue here rather than reset pending_traps[SIGCHLD] below in
375 case there are recursive calls to run_pending_traps and children
376 have been reaped while run_sigchld_trap was running. */
379 else if (sig
== SIGCHLD
&&
380 trap_list
[SIGCHLD
] == (char *)IMPOSSIBLE_TRAP_HANDLER
&&
381 (sigmodes
[SIGCHLD
] & SIG_INPROGRESS
) != 0)
383 /* This can happen when run_pending_traps is called while
384 running a SIGCHLD trap handler. */
386 /* want to leave pending_traps[SIGCHLD] alone here */
389 else if (sig
== SIGCHLD
&& (sigmodes
[SIGCHLD
] & SIG_INPROGRESS
))
391 /* whoops -- print warning? */
392 running_trap
= 0; /* XXX */
393 /* want to leave pending_traps[SIGCHLD] alone here */
397 else if (trap_list
[sig
] == (char *)DEFAULT_SIG
||
398 trap_list
[sig
] == (char *)IGNORE_SIG
||
399 trap_list
[sig
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
401 /* This is possible due to a race condition. Say a bash
402 process has SIGTERM trapped. A subshell is spawned
403 using { list; } & and the parent does something and kills
404 the subshell with SIGTERM. It's possible for the subshell
405 to set pending_traps[SIGTERM] to 1 before the code in
406 execute_cmd.c eventually calls restore_original_signals
407 to reset the SIGTERM signal handler in the subshell. The
408 next time run_pending_traps is called, pending_traps[SIGTERM]
409 will be 1, but the trap handler in trap_list[SIGTERM] will
410 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
411 Unless we catch this, the subshell will dump core when
412 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
414 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
415 sig
, trap_list
[sig
]);
416 if (trap_list
[sig
] == (char *)DEFAULT_SIG
)
418 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig
, signal_name (sig
));
419 kill (getpid (), sig
);
424 /* XXX - should we use save_parser_state/restore_parser_state? */
425 save_parser_state (&pstate
);
426 save_subst_varlist
= subst_assign_varlist
;
427 subst_assign_varlist
= 0;
428 save_tempenv
= temporary_env
;
429 temporary_env
= 0; /* traps should not run with temporary env */
431 #if defined (JOB_CONTROL)
432 save_pipeline (1); /* XXX only provides one save level */
434 /* XXX - set pending_traps[sig] = 0 here? */
435 pending_traps
[sig
] = 0;
437 evalstring (savestring (trap_list
[sig
]), "trap", SEVAL_NONINT
|SEVAL_NOHIST
|SEVAL_RESETLINE
);
439 #if defined (JOB_CONTROL)
440 restore_pipeline (1);
443 subst_assign_varlist
= save_subst_varlist
;
444 restore_parser_state (&pstate
);
445 temporary_env
= save_tempenv
;
448 pending_traps
[sig
] = 0; /* XXX - move before evalstring? */
449 running_trap
= old_running
;
453 #if defined (ARRAY_VARS)
454 restore_pipestatus_array (ps
);
456 last_command_exit_value
= old_exit_value
;
459 /* Set the private state variables noting that we received a signal SIG
460 for which we have a trap set. */
466 pending_traps
[sig
]++;
467 trapped_signal_received
= sig
;
476 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
479 internal_warning ("trap_handler: signal %d: signal not trapped", sig
);
484 /* This means we're in a subshell, but have not yet reset the handler for
485 trapped signals. We're not supposed to execute the trap in this situation;
486 we should restore the original signal and resend the signal to ourselves
487 to preserve the Posix "signal traps that are not being ignored shall be
488 set to the default action" semantics. */
489 if ((subshell_environment
& SUBSHELL_IGNTRAP
) && trap_list
[sig
] != (char *)IGNORE_SIG
)
494 if (original_signals
[sig
] == IMPOSSIBLE_TRAP_HANDLER
)
495 original_signals
[sig
] = SIG_DFL
;
497 restore_signal (sig
);
499 /* Make sure we let the signal we just caught through */
501 sigprocmask (SIG_SETMASK
, (sigset_t
*)NULL
, &mask
);
502 sigdelset (&mask
, sig
);
503 sigprocmask (SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
505 kill (getpid (), sig
);
511 (trap_list
[sig
] == (char *)DEFAULT_SIG
) ||
512 (trap_list
[sig
] == (char *)IGNORE_SIG
))
513 programming_error (_("trap_handler: bad signal %d"), sig
);
517 #if defined (MUST_REINSTALL_SIGHANDLERS)
518 # if defined (JOB_CONTROL) && defined (SIGCHLD)
520 # endif /* JOB_CONTROL && SIGCHLD */
521 set_signal_handler (sig
, trap_handler
);
522 #endif /* MUST_REINSTALL_SIGHANDLERS */
524 set_trap_state (sig
);
526 if (this_shell_builtin
&& (this_shell_builtin
== wait_builtin
))
528 wait_signal_received
= sig
;
529 if (waiting_for_child
&& wait_intr_flag
)
530 sh_longjmp (wait_intr_buf
, 1);
533 #if defined (READLINE)
534 /* Set the event hook so readline will call it after the signal handlers
535 finish executing, so if this interrupted character input we can get
537 if (RL_ISSTATE (RL_STATE_SIGHANDLER
))
538 bashline_set_event_hook ();
548 next_pending_trap (start
)
553 for (i
= start
; i
< NSIG
; i
++)
554 if (pending_traps
[i
])
560 first_pending_trap ()
562 return (next_pending_trap (1));
565 /* Return > 0 if any of the "real" signals (not fake signals like EXIT) are
568 any_signals_trapped ()
572 for (i
= 1; i
< NSIG
; i
++)
573 if (sigmodes
[i
] & SIG_TRAPPED
)
579 clear_pending_traps ()
583 for (i
= 1; i
< NSIG
; i
++)
584 pending_traps
[i
] = 0;
590 CHECK_ALRM
; /* set by the read builtin */
594 /* Convenience functions the rest of the shell can use */
596 check_signals_and_traps ()
600 run_pending_traps ();
603 #if defined (JOB_CONTROL) && defined (SIGCHLD)
605 #ifdef INCLUDE_UNUSED
606 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
608 set_sigchld_trap (command_string
)
609 char *command_string
;
611 set_signal (SIGCHLD
, command_string
);
615 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
616 is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
617 to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
618 reset the disposition to the default and not have the original signal
619 accidentally restored, undoing the user's command. */
621 maybe_set_sigchld_trap (command_string
)
622 char *command_string
;
624 if ((sigmodes
[SIGCHLD
] & SIG_TRAPPED
) == 0 && trap_list
[SIGCHLD
] == (char *)IMPOSSIBLE_TRAP_HANDLER
)
625 set_signal (SIGCHLD
, command_string
);
628 /* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
629 as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
630 or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
632 set_impossible_sigchld_trap ()
634 restore_default_signal (SIGCHLD
);
635 change_signal (SIGCHLD
, (char *)IMPOSSIBLE_TRAP_HANDLER
);
636 sigmodes
[SIGCHLD
] &= ~SIG_TRAPPED
; /* maybe_set_sigchld_trap checks this */
639 /* Act as if we received SIGCHLD NCHILD times and increment
640 pending_traps[SIGCHLD] by that amount. This allows us to still run the
641 SIGCHLD trap once for each exited child. */
643 queue_sigchld_trap (nchild
)
649 pending_traps
[SIGCHLD
] += nchild
;
650 trapped_signal_received
= SIGCHLD
;
653 #endif /* JOB_CONTROL && SIGCHLD */
655 /* Set a trap for SIG only if SIG is not already trapped. */
657 trap_if_untrapped (sig
, command
)
661 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
662 set_signal (sig
, command
);
666 set_debug_trap (command
)
669 set_signal (DEBUG_TRAP
, command
);
672 /* Separate function to call when functions and sourced files want to restore
673 the original version of the DEBUG trap before returning. Unless the -T
674 option is set, source and shell function execution save the old debug trap
675 and unset the trap. If the function or sourced file changes the DEBUG trap,
676 SIG_TRAPPED will be set and we don't bother restoring the original trap string.
677 This is used by both functions and the source builtin. */
679 maybe_set_debug_trap (command
)
682 trap_if_untrapped (DEBUG_TRAP
, command
);
686 set_error_trap (command
)
689 set_signal (ERROR_TRAP
, command
);
693 maybe_set_error_trap (command
)
696 trap_if_untrapped (ERROR_TRAP
, command
);
700 set_return_trap (command
)
703 set_signal (RETURN_TRAP
, command
);
707 maybe_set_return_trap (command
)
710 trap_if_untrapped (RETURN_TRAP
, command
);
713 #ifdef INCLUDE_UNUSED
715 set_sigint_trap (command
)
718 set_signal (SIGINT
, command
);
722 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
723 things, like waiting for command substitution or executing commands
724 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
726 set_sigint_handler ()
728 if (sigmodes
[SIGINT
] & SIG_HARD_IGNORE
)
729 return ((SigHandler
*)SIG_IGN
);
731 else if (sigmodes
[SIGINT
] & SIG_IGNORED
)
732 return ((SigHandler
*)set_signal_handler (SIGINT
, SIG_IGN
)); /* XXX */
734 else if (sigmodes
[SIGINT
] & SIG_TRAPPED
)
735 return ((SigHandler
*)set_signal_handler (SIGINT
, trap_handler
));
737 /* The signal is not trapped, so set the handler to the shell's special
738 interrupt handler. */
739 else if (interactive
) /* XXX - was interactive_shell */
740 return (set_signal_handler (SIGINT
, sigint_sighandler
));
742 return (set_signal_handler (SIGINT
, termsig_sighandler
));
745 /* Return the correct handler for signal SIG according to the values in
748 trap_to_sighandler (sig
)
751 if (sigmodes
[sig
] & (SIG_IGNORED
|SIG_HARD_IGNORE
))
753 else if (sigmodes
[sig
] & SIG_TRAPPED
)
754 return (trap_handler
);
759 /* Set SIG to call STRING as a command. */
761 set_signal (sig
, string
)
767 if (SPECIAL_TRAP (sig
))
769 change_signal (sig
, savestring (string
));
770 if (sig
== EXIT_TRAP
&& interactive
== 0)
771 initialize_terminating_signals ();
775 /* A signal ignored on entry to the shell cannot be trapped or reset, but
776 no error is reported when attempting to do so. -- Posix.2 */
777 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
780 /* Make sure we have original_signals[sig] if the signal has not yet
782 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
784 /* If we aren't sure of the original value, check it. */
785 if (original_signals
[sig
] == IMPOSSIBLE_TRAP_HANDLER
)
787 if (original_signals
[sig
] == SIG_IGN
)
791 /* Only change the system signal handler if SIG_NO_TRAP is not set.
792 The trap command string is changed in either case. The shell signal
793 handlers for SIGINT and SIGCHLD run the user specified traps in an
794 environment in which it is safe to do so. */
795 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
797 BLOCK_SIGNAL (sig
, set
, oset
);
798 change_signal (sig
, savestring (string
));
799 set_signal_handler (sig
, trap_handler
);
800 UNBLOCK_SIGNAL (oset
);
803 change_signal (sig
, savestring (string
));
807 free_trap_command (sig
)
810 if ((sigmodes
[sig
] & SIG_TRAPPED
) && trap_list
[sig
] &&
811 (trap_list
[sig
] != (char *)IGNORE_SIG
) &&
812 (trap_list
[sig
] != (char *)DEFAULT_SIG
) &&
813 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
))
814 free (trap_list
[sig
]);
817 /* If SIG has a string assigned to it, get rid of it. Then give it
820 change_signal (sig
, value
)
824 if ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
825 free_trap_command (sig
);
826 trap_list
[sig
] = value
;
828 sigmodes
[sig
] |= SIG_TRAPPED
;
829 if (value
== (char *)IGNORE_SIG
)
830 sigmodes
[sig
] |= SIG_IGNORED
;
832 sigmodes
[sig
] &= ~SIG_IGNORED
;
833 if (sigmodes
[sig
] & SIG_INPROGRESS
)
834 sigmodes
[sig
] |= SIG_CHANGED
;
838 get_original_signal (sig
)
841 /* If we aren't sure the of the original value, then get it. */
842 if (sig
> 0 && sig
< NSIG
&& original_signals
[sig
] == (SigHandler
*)IMPOSSIBLE_TRAP_HANDLER
)
847 get_all_original_signals ()
851 for (i
= 1; i
< NSIG
; i
++)
852 GET_ORIGINAL_SIGNAL (i
);
856 set_original_signal (sig
, handler
)
860 if (sig
> 0 && sig
< NSIG
&& original_signals
[sig
] == (SigHandler
*)IMPOSSIBLE_TRAP_HANDLER
)
861 SETORIGSIG (sig
, handler
);
864 /* Restore the default action for SIG; i.e., the action the shell
865 would have taken before you used the trap command. This is called
866 from trap_builtin (), which takes care to restore the handlers for
867 the signals the shell treats specially. */
869 restore_default_signal (sig
)
872 if (SPECIAL_TRAP (sig
))
874 if ((sig
!= DEBUG_TRAP
&& sig
!= ERROR_TRAP
&& sig
!= RETURN_TRAP
) ||
875 (sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
876 free_trap_command (sig
);
877 trap_list
[sig
] = (char *)NULL
;
878 sigmodes
[sig
] &= ~SIG_TRAPPED
;
879 if (sigmodes
[sig
] & SIG_INPROGRESS
)
880 sigmodes
[sig
] |= SIG_CHANGED
;
884 GET_ORIGINAL_SIGNAL (sig
);
886 /* A signal ignored on entry to the shell cannot be trapped or reset, but
887 no error is reported when attempting to do so. Thanks Posix.2. */
888 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
891 /* If we aren't trapping this signal, don't bother doing anything else. */
892 /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
893 sentinel to determine whether or not disposition is reset to the default
894 while the trap handler is executing. */
895 if (((sigmodes
[sig
] & SIG_TRAPPED
) == 0) &&
896 (sig
!= SIGCHLD
|| (sigmodes
[sig
] & SIG_INPROGRESS
) == 0 || trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
))
899 /* Only change the signal handler for SIG if it allows it. */
900 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
901 set_signal_handler (sig
, original_signals
[sig
]);
903 /* Change the trap command in either case. */
904 change_signal (sig
, (char *)DEFAULT_SIG
);
906 /* Mark the signal as no longer trapped. */
907 sigmodes
[sig
] &= ~SIG_TRAPPED
;
910 /* Make this signal be ignored. */
915 if (SPECIAL_TRAP (sig
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
917 change_signal (sig
, (char *)IGNORE_SIG
);
921 GET_ORIGINAL_SIGNAL (sig
);
923 /* A signal ignored on entry to the shell cannot be trapped or reset.
924 No error is reported when the user attempts to do so. */
925 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
928 /* If already trapped and ignored, no change necessary. */
929 if (sigmodes
[sig
] & SIG_IGNORED
)
932 /* Only change the signal handler for SIG if it allows it. */
933 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
934 set_signal_handler (sig
, SIG_IGN
);
936 /* Change the trap command in either case. */
937 change_signal (sig
, (char *)IGNORE_SIG
);
940 /* Handle the calling of "trap 0". The only sticky situation is when
941 the command to be executed includes an "exit". This is why we have
942 to provide our own place for top_level to jump to. */
947 int code
, function_code
, retval
;
948 #if defined (ARRAY_VARS)
952 trap_saved_exit_value
= last_command_exit_value
;
953 #if defined (ARRAY_VARS)
954 ps
= save_pipestatus_array ();
958 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
959 currently running in the trap handler (call to exit in the list of
960 commands given to trap 0). */
961 if ((sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
) &&
962 (sigmodes
[EXIT_TRAP
] & (SIG_IGNORED
|SIG_INPROGRESS
)) == 0)
964 trap_command
= savestring (trap_list
[EXIT_TRAP
]);
965 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
;
966 sigmodes
[EXIT_TRAP
] |= SIG_INPROGRESS
;
968 retval
= trap_saved_exit_value
;
971 code
= setjmp_nosigs (top_level
);
973 /* If we're in a function, make sure return longjmps come here, too. */
974 if (return_catch_flag
)
975 function_code
= setjmp_nosigs (return_catch
);
977 if (code
== 0 && function_code
== 0)
980 parse_and_execute (trap_command
, "exit trap", SEVAL_NONINT
|SEVAL_NOHIST
|SEVAL_RESETLINE
);
982 else if (code
== ERREXIT
)
983 retval
= last_command_exit_value
;
984 else if (code
== EXITPROG
)
985 retval
= last_command_exit_value
;
986 else if (function_code
!= 0)
987 retval
= return_catch_value
;
989 retval
= trap_saved_exit_value
;
992 #if defined (ARRAY_VARS)
999 #if defined (ARRAY_VARS)
1000 restore_pipestatus_array (ps
);
1002 return (trap_saved_exit_value
);
1006 run_trap_cleanup (sig
)
1009 /* XXX - should we clean up trap_list[sig] == IMPOSSIBLE_TRAP_HANDLER? */
1010 sigmodes
[sig
] &= ~(SIG_INPROGRESS
|SIG_CHANGED
);
1013 #define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
1015 /* Run a trap command for SIG. SIG is one of the signals the shell treats
1016 specially. Returns the exit status of the executed trap command list. */
1018 _run_trap_internal (sig
, tag
)
1022 char *trap_command
, *old_trap
;
1023 int trap_exit_value
;
1024 volatile int save_return_catch_flag
, function_code
;
1025 int old_modes
, old_running
, old_int
;
1027 procenv_t save_return_catch
;
1028 WORD_LIST
*save_subst_varlist
;
1029 HASH_TABLE
*save_tempenv
;
1030 sh_parser_state_t pstate
;
1031 #if defined (ARRAY_VARS)
1035 old_modes
= old_running
= -1;
1037 trap_exit_value
= function_code
= 0;
1038 trap_saved_exit_value
= last_command_exit_value
;
1039 /* Run the trap only if SIG is trapped and not ignored, and we are not
1040 currently executing in the trap handler. */
1041 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0) &&
1042 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
) &&
1044 /* Uncomment this to allow some special signals to recursively execute
1046 (RECURSIVE_SIG (sig
) || (sigmodes
[sig
] & SIG_INPROGRESS
) == 0))
1048 ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0))
1051 old_trap
= trap_list
[sig
];
1052 old_modes
= sigmodes
[sig
];
1053 old_running
= running_trap
;
1055 sigmodes
[sig
] |= SIG_INPROGRESS
;
1056 sigmodes
[sig
] &= ~SIG_CHANGED
; /* just to be sure */
1057 trap_command
= savestring (old_trap
);
1059 running_trap
= sig
+ 1;
1061 old_int
= interrupt_state
; /* temporarily suppress pending interrupts */
1064 #if defined (ARRAY_VARS)
1065 ps
= save_pipestatus_array ();
1068 save_parser_state (&pstate
);
1069 save_subst_varlist
= subst_assign_varlist
;
1070 subst_assign_varlist
= 0;
1071 save_tempenv
= temporary_env
;
1072 temporary_env
= 0; /* traps should not run with temporary env */
1074 #if defined (JOB_CONTROL)
1075 if (sig
!= DEBUG_TRAP
) /* run_debug_trap does this */
1076 save_pipeline (1); /* XXX only provides one save level */
1079 /* If we're in a function, make sure return longjmps come here, too. */
1080 save_return_catch_flag
= return_catch_flag
;
1081 if (return_catch_flag
)
1083 COPY_PROCENV (return_catch
, save_return_catch
);
1084 function_code
= setjmp_nosigs (return_catch
);
1087 flags
= SEVAL_NONINT
|SEVAL_NOHIST
;
1088 if (sig
!= DEBUG_TRAP
&& sig
!= RETURN_TRAP
&& sig
!= ERROR_TRAP
)
1089 flags
|= SEVAL_RESETLINE
;
1091 if (function_code
== 0)
1093 parse_and_execute (trap_command
, tag
, flags
);
1094 trap_exit_value
= last_command_exit_value
;
1097 trap_exit_value
= return_catch_value
;
1100 #if defined (JOB_CONTROL)
1101 if (sig
!= DEBUG_TRAP
) /* run_debug_trap does this */
1102 restore_pipeline (1);
1105 subst_assign_varlist
= save_subst_varlist
;
1106 restore_parser_state (&pstate
);
1108 #if defined (ARRAY_VARS)
1109 restore_pipestatus_array (ps
);
1112 temporary_env
= save_tempenv
;
1114 if ((old_modes
& SIG_INPROGRESS
) == 0)
1115 sigmodes
[sig
] &= ~SIG_INPROGRESS
;
1117 running_trap
= old_running
;
1118 interrupt_state
= old_int
;
1120 if (sigmodes
[sig
] & SIG_CHANGED
)
1123 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
1124 the places where they can be changed using unwind-protects. For
1125 example, look at execute_cmd.c:execute_function(). */
1126 if (SPECIAL_TRAP (sig
) == 0)
1129 sigmodes
[sig
] &= ~SIG_CHANGED
;
1131 CHECK_TERMSIG
; /* some pathological conditions lead here */
1134 if (save_return_catch_flag
)
1136 return_catch_flag
= save_return_catch_flag
;
1137 return_catch_value
= trap_exit_value
;
1138 COPY_PROCENV (save_return_catch
, return_catch
);
1142 from_return_trap
= sig
== RETURN_TRAP
;
1144 sh_longjmp (return_catch
, 1);
1149 return trap_exit_value
;
1155 int trap_exit_value
, old_verbose
;
1157 #if defined (PGRP_PIPE)
1161 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
1162 trap_exit_value
= 0;
1163 if ((sigmodes
[DEBUG_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[DEBUG_TRAP
] & SIG_IGNORED
) == 0) && ((sigmodes
[DEBUG_TRAP
] & SIG_INPROGRESS
) == 0))
1165 #if defined (JOB_CONTROL)
1166 save_pgrp
= pipeline_pgrp
;
1169 # if defined (PGRP_PIPE)
1170 save_pgrp_pipe (save_pipe
, 1);
1172 stop_making_children ();
1175 old_verbose
= echo_input_at_read
;
1176 echo_input_at_read
= suppress_debug_trap_verbose
? 0 : echo_input_at_read
;
1178 trap_exit_value
= _run_trap_internal (DEBUG_TRAP
, "debug trap");
1180 echo_input_at_read
= old_verbose
;
1182 #if defined (JOB_CONTROL)
1183 pipeline_pgrp
= save_pgrp
;
1184 restore_pipeline (1);
1185 # if defined (PGRP_PIPE)
1187 restore_pgrp_pipe (save_pipe
);
1189 if (pipeline_pgrp
> 0 && ((subshell_environment
& (SUBSHELL_ASYNC
|SUBSHELL_PIPE
)) == 0))
1190 give_terminal_to (pipeline_pgrp
, 1);
1192 notify_and_cleanup ();
1195 #if defined (DEBUGGER)
1196 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
1197 a function or sourced script, we force a `return'. */
1198 if (debugging_mode
&& trap_exit_value
== 2 && return_catch_flag
)
1200 return_catch_value
= trap_exit_value
;
1201 sh_longjmp (return_catch
, 1);
1205 return trap_exit_value
;
1211 if ((sigmodes
[ERROR_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[ERROR_TRAP
] & SIG_IGNORED
) == 0) && (sigmodes
[ERROR_TRAP
] & SIG_INPROGRESS
) == 0)
1212 _run_trap_internal (ERROR_TRAP
, "error trap");
1221 if ((sigmodes
[DEBUG_TRAP
] & SIG_TRAPPED
) && (sigmodes
[DEBUG_TRAP
] & SIG_INPROGRESS
))
1225 if ((sigmodes
[RETURN_TRAP
] & SIG_TRAPPED
) && ((sigmodes
[RETURN_TRAP
] & SIG_IGNORED
) == 0) && (sigmodes
[RETURN_TRAP
] & SIG_INPROGRESS
) == 0)
1227 old_exit_value
= last_command_exit_value
;
1228 _run_trap_internal (RETURN_TRAP
, "return trap");
1229 last_command_exit_value
= old_exit_value
;
1233 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
1234 declared here to localize the trap functions. */
1236 run_interrupt_trap (will_throw
)
1237 int will_throw
; /* from throw_to_top_level? */
1239 if (will_throw
&& running_trap
> 0)
1240 run_trap_cleanup (running_trap
- 1);
1241 pending_traps
[SIGINT
] = 0; /* run_pending_traps does this */
1243 _run_trap_internal (SIGINT
, "interrupt trap");
1246 /* Free all the allocated strings in the list of traps and reset the trap
1247 values to the default. Intended to be called from subshells that want
1248 to complete work done by reset_signal_handlers upon execution of a
1249 subsequent `trap' command that changes a signal's disposition. We need
1250 to make sure that we duplicate the behavior of
1251 reset_or_restore_signal_handlers and not change the disposition of signals
1252 that are set to be ignored. */
1254 free_trap_strings ()
1258 for (i
= 0; i
< NSIG
; i
++)
1260 if (trap_list
[i
] != (char *)IGNORE_SIG
)
1261 free_trap_string (i
);
1263 for (i
= NSIG
; i
< BASH_NSIG
; i
++)
1265 /* Don't free the trap string if the subshell inherited the trap */
1266 if ((sigmodes
[i
] & SIG_TRAPPED
) == 0)
1268 free_trap_string (i
);
1269 trap_list
[i
] = (char *)NULL
;
1274 /* Free a trap command string associated with SIG without changing signal
1275 disposition. Intended to be called from free_trap_strings() */
1277 free_trap_string (sig
)
1280 change_signal (sig
, (char *)DEFAULT_SIG
);
1281 sigmodes
[sig
] &= ~SIG_TRAPPED
; /* XXX - SIG_INPROGRESS? */
1284 /* Reset the handler for SIG to the original value but leave the trap string
1290 set_signal_handler (sig
, original_signals
[sig
]);
1291 sigmodes
[sig
] &= ~SIG_TRAPPED
; /* XXX - SIG_INPROGRESS? */
1294 /* Set the handler signal SIG to the original and free any trap
1295 command associated with it. */
1297 restore_signal (sig
)
1300 set_signal_handler (sig
, original_signals
[sig
]);
1301 change_signal (sig
, (char *)DEFAULT_SIG
);
1302 sigmodes
[sig
] &= ~SIG_TRAPPED
;
1306 reset_or_restore_signal_handlers (reset
)
1307 sh_resetsig_func_t
*reset
;
1311 /* Take care of the exit trap first */
1312 if (sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
)
1314 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
; /* XXX - SIG_INPROGRESS? */
1315 if (reset
!= reset_signal
)
1317 free_trap_command (EXIT_TRAP
);
1318 trap_list
[EXIT_TRAP
] = (char *)NULL
;
1322 for (i
= 1; i
< NSIG
; i
++)
1324 if (sigmodes
[i
] & SIG_TRAPPED
)
1326 if (trap_list
[i
] == (char *)IGNORE_SIG
)
1327 set_signal_handler (i
, SIG_IGN
);
1331 else if (sigmodes
[i
] & SIG_SPECIAL
)
1333 pending_traps
[i
] = 0; /* XXX */
1336 /* Command substitution and other child processes don't inherit the
1337 debug, error, or return traps. If we're in the debugger, and the
1338 `functrace' or `errtrace' options have been set, then let command
1339 substitutions inherit them. Let command substitution inherit the
1340 RETURN trap if we're in the debugger and tracing functions. */
1341 if (function_trace_mode
== 0)
1343 sigmodes
[DEBUG_TRAP
] &= ~SIG_TRAPPED
;
1344 sigmodes
[RETURN_TRAP
] &= ~SIG_TRAPPED
;
1346 if (error_trace_mode
== 0)
1347 sigmodes
[ERROR_TRAP
] &= ~SIG_TRAPPED
;
1350 /* Reset trapped signals to their original values, but don't free the
1351 trap strings. Called by the command substitution code and other places
1352 that create a "subshell environment". */
1354 reset_signal_handlers ()
1356 reset_or_restore_signal_handlers (reset_signal
);
1359 /* Reset all trapped signals to their original values. Signals set to be
1360 ignored with trap '' SIGNAL should be ignored, so we make sure that they
1361 are. Called by child processes after they are forked. */
1363 restore_original_signals ()
1365 reset_or_restore_signal_handlers (restore_signal
);
1368 /* If a trap handler exists for signal SIG, then call it; otherwise just
1369 return failure. Returns 1 if it called the trap handler. */
1371 maybe_call_trap_handler (sig
)
1374 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1375 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
1380 run_interrupt_trap (0);
1402 signal_is_trapped (sig
)
1405 return (sigmodes
[sig
] & SIG_TRAPPED
);
1409 signal_is_pending (sig
)
1412 return (pending_traps
[sig
]);
1416 signal_is_special (sig
)
1419 return (sigmodes
[sig
] & SIG_SPECIAL
);
1423 signal_is_ignored (sig
)
1426 return (sigmodes
[sig
] & SIG_IGNORED
);
1430 signal_is_hard_ignored (sig
)
1433 return (sigmodes
[sig
] & SIG_HARD_IGNORE
);
1437 set_signal_hard_ignored (sig
)
1440 sigmodes
[sig
] |= SIG_HARD_IGNORE
;
1441 original_signals
[sig
] = SIG_IGN
;
1445 set_signal_ignored (sig
)
1448 original_signals
[sig
] = SIG_IGN
;
1452 signal_in_progress (sig
)
1455 return (sigmodes
[sig
] & SIG_INPROGRESS
);
1458 #if 0 /* TAG: bash-5.2 */
1460 block_trapped_signals (maskp
, omaskp
)
1466 sigemptyset (maskp
);
1467 for (i
= 1; i
< NSIG
; i
++)
1468 if (sigmodes
[i
] & SIG_TRAPPED
)
1469 sigaddset (maskp
, i
);
1470 return (sigprocmask (SIG_BLOCK
, maskp
, omaskp
));
1474 unblock_trapped_signals (maskp
)
1477 return (sigprocmask (SIG_SETMASK
, maskp
, 0));