1 /* trap.c -- Not the trap command, but useful functions for manipulating
2 those objects. The trap command is in builtins/trap.def. */
4 /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
24 #if defined (HAVE_UNISTD_H)
28 #include "bashtypes.h"
37 #include "builtins/common.h"
39 /* Flags which describe the current handling state of a signal. */
40 #define SIG_INHERITED 0x0 /* Value inherited from parent. */
41 #define SIG_TRAPPED 0x1 /* Currently trapped. */
42 #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
43 #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
44 #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
45 #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
46 #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
47 #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
49 /* An array of such flags, one for each signal, describing what the
50 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
52 static int sigmodes[NSIG+1];
54 static void change_signal (), restore_signal ();
56 /* Variables used here but defined in other files. */
57 extern int interactive_shell, interactive;
58 extern int interrupt_immediately;
59 extern int last_command_exit_value;
60 extern int line_number;
62 /* The list of things to do originally, before we started trapping. */
63 SigHandler *original_signals[NSIG];
65 /* For each signal, a slot for a string, which is a command to be
66 executed when that signal is recieved. The slot can also contain
67 DEFAULT_SIG, which means do whatever you were going to do before
68 you were so rudely interrupted, or IGNORE_SIG, which says ignore
70 char *trap_list[NSIG+1];
72 /* A bitmap of signals received for which we have trap handlers. */
73 int pending_traps[NSIG];
75 /* Set to the number of the signal we're running the trap for + 1.
76 Used in execute_cmd.c and builtins/common.c to clean up when
77 parse_and_execute does not return normally after executing the
78 trap command (e.g., when `return' is executed in the trap command). */
81 /* The value of line_number when the trap started executing, since
82 parse_and_execute resets it to 1 and the trap command might want
86 /* A value which can never be the target of a trap handler. */
87 #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
94 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = (char *)NULL;
95 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = SIG_INHERITED;
96 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
98 for (i = 1; i < NSIG; i++)
100 pending_traps[i] = 0;
101 trap_list[i] = (char *)DEFAULT_SIG;
102 sigmodes[i] = SIG_INHERITED;
103 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
106 /* Show which signals are treated specially by the shell. */
107 #if defined (SIGCHLD)
108 original_signals[SIGCHLD] =
109 (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
110 set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
111 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
114 original_signals[SIGINT] =
115 (SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
116 set_signal_handler (SIGINT, original_signals[SIGINT]);
117 sigmodes[SIGINT] |= SIG_SPECIAL;
119 original_signals[SIGQUIT] =
120 (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
121 set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
122 sigmodes[SIGQUIT] |= SIG_SPECIAL;
126 original_signals[SIGTERM] =
127 (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
128 set_signal_handler (SIGTERM, original_signals[SIGTERM]);
129 sigmodes[SIGTERM] |= SIG_SPECIAL;
133 /* Return the print name of this signal. */
140 /* on cygwin32, signal_names[sig] could be null */
141 ret = (sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig];
143 ret = "unrecognized signal number";
147 /* Turn a string into a signal number, or a number into
148 a signal number. If STRING is "2", "SIGINT", or "INT",
149 then (int)2 is returned. Return NO_SIG if STRING doesn't
150 contain a valid signal descriptor. */
152 decode_signal (string)
157 if (legal_number (string, &sig))
158 return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG);
160 /* A leading `SIG' may be omitted. */
161 for (sig = 0; sig <= NSIG; sig++)
162 if (strcasecmp (string, signal_names[sig]) == 0 ||
163 (STREQN (signal_names[sig], "SIG", 3) &&
164 strcasecmp (string, &(signal_names[sig])[3]) == 0))
170 /* Non-zero when we catch a trapped signal. */
171 static int catch_flag;
179 if (catch_flag == 0) /* simple optimization */
184 /* Preserve $? when running trap. */
185 old_exit_value = last_command_exit_value;
187 for (sig = 1; sig < NSIG; sig++)
189 /* XXX this could be made into a counter by using
190 while (pending_traps[sig]--) instead of the if statement. */
191 if (pending_traps[sig])
193 #if defined (HAVE_POSIX_SIGNALS)
199 sigaddset (&set, sig);
200 sigprocmask (SIG_BLOCK, &set, &oset);
202 # if defined (HAVE_BSD_SIGNALS)
203 int oldmask = sigblock (sigmask (sig));
205 #endif /* HAVE_POSIX_SIGNALS */
209 run_interrupt_trap ();
213 parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST);
215 pending_traps[sig] = 0;
217 #if defined (HAVE_POSIX_SIGNALS)
218 sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
220 # if defined (HAVE_BSD_SIGNALS)
221 sigsetmask (oldmask);
223 #endif /* POSIX_VERSION */
227 last_command_exit_value = old_exit_value;
235 (trap_list[sig] == (char *)DEFAULT_SIG) ||
236 (trap_list[sig] == (char *)IGNORE_SIG))
237 programming_error ("trap_handler: bad signal %d", sig);
240 #if defined (MUST_REINSTALL_SIGHANDLERS)
241 set_signal_handler (sig, trap_handler);
242 #endif /* MUST_REINSTALL_SIGHANDLERS */
245 pending_traps[sig]++;
247 if (interrupt_immediately)
248 run_pending_traps ();
254 #if defined (JOB_CONTROL) && defined (SIGCHLD)
256 #ifdef INCLUDE_UNUSED
257 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
259 set_sigchld_trap (command_string)
260 char *command_string;
262 set_signal (SIGCHLD, command_string);
266 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
267 SIGCHLD trap handler is DEFAULT_SIG. */
269 maybe_set_sigchld_trap (command_string)
270 char *command_string;
272 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
273 set_signal (SIGCHLD, command_string);
275 #endif /* JOB_CONTROL && SIGCHLD */
278 set_debug_trap (command)
281 set_signal (DEBUG_TRAP, command);
284 #ifdef INCLUDE_UNUSED
286 set_sigint_trap (command)
289 set_signal (SIGINT, command);
293 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
294 things, like waiting for command substitution or executing commands
295 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
297 set_sigint_handler ()
299 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
300 return ((SigHandler *)SIG_IGN);
302 else if (sigmodes[SIGINT] & SIG_IGNORED)
303 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
305 else if (sigmodes[SIGINT] & SIG_TRAPPED)
306 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
308 /* The signal is not trapped, so set the handler to the shell's special
309 interrupt handler. */
310 else if (interactive) /* XXX - was interactive_shell */
311 return (set_signal_handler (SIGINT, sigint_sighandler));
313 return (set_signal_handler (SIGINT, termination_unwind_protect));
316 /* Return the correct handler for signal SIG according to the values in
319 trap_to_sighandler (sig)
322 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
324 else if (sigmodes[sig] & SIG_TRAPPED)
325 return (trap_handler);
330 /* Set SIG to call STRING as a command. */
332 set_signal (sig, string)
336 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
338 change_signal (sig, savestring (string));
339 if (sig == EXIT_TRAP && interactive == 0)
340 initialize_terminating_signals ();
344 /* A signal ignored on entry to the shell cannot be trapped or reset, but
345 no error is reported when attempting to do so. -- Posix.2 */
346 if (sigmodes[sig] & SIG_HARD_IGNORE)
349 /* Make sure we have original_signals[sig] if the signal has not yet
351 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
353 /* If we aren't sure of the original value, check it. */
354 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
356 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL);
357 set_signal_handler (sig, original_signals[sig]);
360 /* Signals ignored on entry to the shell cannot be trapped or reset. */
361 if (original_signals[sig] == SIG_IGN)
363 sigmodes[sig] |= SIG_HARD_IGNORE;
368 /* Only change the system signal handler if SIG_NO_TRAP is not set.
369 The trap command string is changed in either case. The shell signal
370 handlers for SIGINT and SIGCHLD run the user specified traps in an
371 environment in which it is safe to do so. */
372 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
374 set_signal_handler (sig, SIG_IGN);
375 change_signal (sig, savestring (string));
376 set_signal_handler (sig, trap_handler);
379 change_signal (sig, savestring (string));
383 free_trap_command (sig)
386 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
387 (trap_list[sig] != (char *)IGNORE_SIG) &&
388 (trap_list[sig] != (char *)DEFAULT_SIG) &&
389 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
390 free (trap_list[sig]);
393 /* If SIG has a string assigned to it, get rid of it. Then give it
396 change_signal (sig, value)
400 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
401 free_trap_command (sig);
402 trap_list[sig] = value;
404 sigmodes[sig] |= SIG_TRAPPED;
405 if (value == (char *)IGNORE_SIG)
406 sigmodes[sig] |= SIG_IGNORED;
408 sigmodes[sig] &= ~SIG_IGNORED;
409 if (sigmodes[sig] & SIG_INPROGRESS)
410 sigmodes[sig] |= SIG_CHANGED;
413 #define GET_ORIGINAL_SIGNAL(sig) \
414 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
415 get_original_signal (sig)
418 get_original_signal (sig)
421 /* If we aren't sure the of the original value, then get it. */
422 if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
424 original_signals[sig] =
425 (SigHandler *) set_signal_handler (sig, SIG_DFL);
426 set_signal_handler (sig, original_signals[sig]);
428 /* Signals ignored on entry to the shell cannot be trapped. */
429 if (original_signals[sig] == SIG_IGN)
430 sigmodes[sig] |= SIG_HARD_IGNORE;
434 /* Restore the default action for SIG; i.e., the action the shell
435 would have taken before you used the trap command. This is called
436 from trap_builtin (), which takes care to restore the handlers for
437 the signals the shell treats specially. */
439 restore_default_signal (sig)
442 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
444 if ((sig != DEBUG_TRAP) || (sigmodes[sig] & SIG_INPROGRESS) == 0)
445 free_trap_command (sig);
446 trap_list[sig] = (char *)NULL;
447 sigmodes[sig] &= ~SIG_TRAPPED;
448 if (sigmodes[sig] & SIG_INPROGRESS)
449 sigmodes[sig] |= SIG_CHANGED;
453 GET_ORIGINAL_SIGNAL (sig);
455 /* A signal ignored on entry to the shell cannot be trapped or reset, but
456 no error is reported when attempting to do so. Thanks Posix.2. */
457 if (sigmodes[sig] & SIG_HARD_IGNORE)
460 /* If we aren't trapping this signal, don't bother doing anything else. */
461 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
464 /* Only change the signal handler for SIG if it allows it. */
465 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
466 set_signal_handler (sig, original_signals[sig]);
468 /* Change the trap command in either case. */
469 change_signal (sig, (char *)DEFAULT_SIG);
471 /* Mark the signal as no longer trapped. */
472 sigmodes[sig] &= ~SIG_TRAPPED;
475 /* Make this signal be ignored. */
480 if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0))
482 change_signal (sig, (char *)IGNORE_SIG);
486 GET_ORIGINAL_SIGNAL (sig);
488 /* A signal ignored on entry to the shell cannot be trapped or reset.
489 No error is reported when the user attempts to do so. */
490 if (sigmodes[sig] & SIG_HARD_IGNORE)
493 /* If already trapped and ignored, no change necessary. */
494 if (sigmodes[sig] & SIG_IGNORED)
497 /* Only change the signal handler for SIG if it allows it. */
498 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
499 set_signal_handler (sig, SIG_IGN);
501 /* Change the trap command in either case. */
502 change_signal (sig, (char *)IGNORE_SIG);
505 /* Handle the calling of "trap 0". The only sticky situation is when
506 the command to be executed includes an "exit". This is why we have
507 to provide our own place for top_level to jump to. */
512 int code, old_exit_value;
514 old_exit_value = last_command_exit_value;
516 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
517 currently running in the trap handler (call to exit in the list of
518 commands given to trap 0). */
519 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
520 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
522 trap_command = savestring (trap_list[EXIT_TRAP]);
523 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
524 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
526 code = setjmp (top_level);
531 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST);
533 else if (code == EXITPROG)
534 return (last_command_exit_value);
536 return (old_exit_value);
539 return (old_exit_value);
543 run_trap_cleanup (sig)
546 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
549 /* Run a trap command for SIG. SIG is one of the signals the shell treats
552 _run_trap_internal (sig, tag)
556 char *trap_command, *old_trap;
557 int old_exit_value, old_line_number;
559 /* Run the trap only if SIG is trapped and not ignored, and we are not
560 currently executing in the trap handler. */
561 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
562 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
563 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
565 old_trap = trap_list[sig];
566 sigmodes[sig] |= SIG_INPROGRESS;
567 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
568 trap_command = savestring (old_trap);
570 running_trap = sig + 1;
571 old_exit_value = last_command_exit_value;
572 /* Need to copy the value of line_number because parse_and_execute
573 resets it to 1, and the trap command might want it. */
574 trap_line_number = line_number;
575 parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST);
576 last_command_exit_value = old_exit_value;
579 sigmodes[sig] &= ~SIG_INPROGRESS;
581 if (sigmodes[sig] & SIG_CHANGED)
584 sigmodes[sig] &= ~SIG_CHANGED;
592 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)
593 _run_trap_internal (DEBUG_TRAP, "debug trap");
596 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
597 declared here to localize the trap functions. */
599 run_interrupt_trap ()
601 _run_trap_internal (SIGINT, "interrupt trap");
604 #ifdef INCLUDE_UNUSED
605 /* Free all the allocated strings in the list of traps and reset the trap
606 values to the default. */
612 for (i = 0; i < NSIG+1; i++)
614 free_trap_command (i);
615 trap_list[i] = (char *)DEFAULT_SIG;
616 sigmodes[i] &= ~SIG_TRAPPED;
618 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL;
622 /* Reset the handler for SIG to the original value. */
627 set_signal_handler (sig, original_signals[sig]);
630 /* Set the handler signal SIG to the original and free any trap
631 command associated with it. */
636 set_signal_handler (sig, original_signals[sig]);
637 change_signal (sig, (char *)DEFAULT_SIG);
638 sigmodes[sig] &= ~SIG_TRAPPED;
642 reset_or_restore_signal_handlers (reset)
647 /* Take care of the exit trap first */
648 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
650 free_trap_command (EXIT_TRAP);
651 trap_list[EXIT_TRAP] = (char *)NULL;
652 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
654 for (i = 1; i < NSIG; i++)
656 if (sigmodes[i] & SIG_TRAPPED)
658 if (trap_list[i] == (char *)IGNORE_SIG)
659 set_signal_handler (i, SIG_IGN);
663 else if (sigmodes[i] & SIG_SPECIAL)
669 reset_signal_handlers ()
671 reset_or_restore_signal_handlers (reset_signal);
674 /* Reset all trapped signals to their original values. Signals set to be
675 ignored with trap '' SIGNAL should be ignored, so we make sure that they
676 are. Called by child processes after they are forked. */
678 restore_original_signals ()
680 reset_or_restore_signal_handlers (restore_signal);
683 /* If a trap handler exists for signal SIG, then call it; otherwise just
686 maybe_call_trap_handler (sig)
689 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
690 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
695 run_interrupt_trap ();
714 signal_is_trapped (sig)
717 return (sigmodes[sig] & SIG_TRAPPED);
721 signal_is_special (sig)
724 return (sigmodes[sig] & SIG_SPECIAL);
728 signal_is_ignored (sig)
731 return (sigmodes[sig] & SIG_IGNORED);
735 set_signal_ignored (sig)
738 sigmodes[sig] |= SIG_HARD_IGNORE;
739 original_signals[sig] = SIG_IGN;