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. */
26 #include "bashtypes.h"
29 #if defined (HAVE_STRING_H)
31 #else /* !HAVE_STRING_H */
33 #endif /* !HAVE_STRING_H */
35 #if defined (HAVE_UNISTD_H)
41 #include "builtins/common.h"
43 /* Flags which describe the current handling state of a signal. */
44 #define SIG_INHERITED 0x0 /* Value inherited from parent. */
45 #define SIG_TRAPPED 0x1 /* Currently trapped. */
46 #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
47 #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
48 #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
49 #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
50 #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
51 #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
53 /* An array of such flags, one for each signal, describing what the
54 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
56 static int sigmodes[NSIG+1];
58 static void change_signal (), restore_signal ();
60 /* Variables used here but defined in other files. */
61 extern int interactive_shell, interactive;
62 extern int interrupt_immediately;
63 extern int last_command_exit_value;
65 /* The list of things to do originally, before we started trapping. */
66 SigHandler *original_signals[NSIG];
68 /* For each signal, a slot for a string, which is a command to be
69 executed when that signal is recieved. The slot can also contain
70 DEFAULT_SIG, which means do whatever you were going to do before
71 you were so rudely interrupted, or IGNORE_SIG, which says ignore
73 char *trap_list[NSIG+1];
75 /* A bitmap of signals received for which we have trap handlers. */
76 int pending_traps[NSIG];
78 /* Set to the number of the signal we're running the trap for + 1.
79 Used in execute_cmd.c and builtins/common.c to clean up when
80 parse_and_execute does not return normally after executing the
81 trap command (e.g., when `return' is executed in the trap command). */
84 /* A value which can never be the target of a trap handler. */
85 #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
92 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = (char *)NULL;
93 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = SIG_INHERITED;
94 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
96 for (i = 1; i < NSIG; i++)
99 trap_list[i] = (char *)DEFAULT_SIG;
100 sigmodes[i] = SIG_INHERITED;
101 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
104 /* Show which signals are treated specially by the shell. */
105 #if defined (SIGCHLD)
106 original_signals[SIGCHLD] =
107 (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
108 set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
109 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
112 original_signals[SIGINT] =
113 (SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
114 set_signal_handler (SIGINT, original_signals[SIGINT]);
115 sigmodes[SIGINT] |= SIG_SPECIAL;
117 original_signals[SIGQUIT] =
118 (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
119 set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
120 sigmodes[SIGQUIT] |= SIG_SPECIAL;
124 original_signals[SIGTERM] =
125 (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
126 set_signal_handler (SIGTERM, original_signals[SIGTERM]);
127 sigmodes[SIGTERM] |= SIG_SPECIAL;
131 /* Return the print name of this signal. */
136 return ((sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]);
139 /* Turn a string into a signal number, or a number into
140 a signal number. If STRING is "2", "SIGINT", or "INT",
141 then (int)2 is returned. Return NO_SIG if STRING doesn't
142 contain a valid signal descriptor. */
144 decode_signal (string)
149 if (legal_number (string, &sig))
150 return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG);
152 for (sig = 0; sig <= NSIG; sig++)
153 if (strcasecmp (string, signal_names[sig]) == 0 ||
154 strcasecmp (string, &(signal_names[sig])[3]) == 0)
160 /* Non-zero when we catch a trapped signal. */
161 static int catch_flag;
169 if (catch_flag == 0) /* simple optimization */
174 /* Preserve $? when running trap. */
175 old_exit_value = last_command_exit_value;
177 for (sig = 1; sig < NSIG; sig++)
179 /* XXX this could be made into a counter by using
180 while (pending_traps[sig]--) instead of the if statement. */
181 if (pending_traps[sig])
183 #if defined (HAVE_POSIX_SIGNALS)
189 sigaddset (&set, sig);
190 sigprocmask (SIG_BLOCK, &set, &oset);
192 # if defined (HAVE_BSD_SIGNALS)
193 int oldmask = sigblock (sigmask (sig));
195 #endif /* HAVE_POSIX_SIGNALS */
199 run_interrupt_trap ();
203 parse_and_execute (savestring (trap_list[sig]), "trap", 0);
205 pending_traps[sig] = 0;
207 #if defined (HAVE_POSIX_SIGNALS)
208 sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
210 # if defined (HAVE_BSD_SIGNALS)
211 sigsetmask (oldmask);
213 #endif /* POSIX_VERSION */
217 last_command_exit_value = old_exit_value;
225 (trap_list[sig] == (char *)DEFAULT_SIG) ||
226 (trap_list[sig] == (char *)IGNORE_SIG))
227 programming_error ("trap_handler: bad signal %d", sig);
230 #if defined (MUST_REINSTALL_SIGHANDLERS)
231 set_signal_handler (sig, trap_handler);
232 #endif /* MUST_REINSTALL_SIGHANDLERS */
235 pending_traps[sig]++;
237 if (interrupt_immediately)
238 run_pending_traps ();
244 #if defined (JOB_CONTROL) && defined (SIGCHLD)
245 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
247 set_sigchld_trap (command_string)
248 char *command_string;
250 set_signal (SIGCHLD, command_string);
253 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
254 SIGCHLD trap handler is DEFAULT_SIG. */
256 maybe_set_sigchld_trap (command_string)
257 char *command_string;
259 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
260 set_signal (SIGCHLD, command_string);
262 #endif /* JOB_CONTROL && SIGCHLD */
265 set_debug_trap (command)
268 set_signal (DEBUG_TRAP, command);
272 set_sigint_trap (command)
275 set_signal (SIGINT, command);
278 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
279 things, like waiting for command substitution or executing commands
280 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
282 set_sigint_handler ()
284 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
285 return ((SigHandler *)SIG_IGN);
287 else if (sigmodes[SIGINT] & SIG_IGNORED)
288 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
290 else if (sigmodes[SIGINT] & SIG_TRAPPED)
291 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
293 /* The signal is not trapped, so set the handler to the shell's special
294 interrupt handler. */
295 else if (interactive) /* XXX - was interactive_shell */
296 return (set_signal_handler (SIGINT, sigint_sighandler));
298 return (set_signal_handler (SIGINT, termination_unwind_protect));
301 /* Set SIG to call STRING as a command. */
303 set_signal (sig, string)
307 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
309 change_signal (sig, savestring (string));
313 /* A signal ignored on entry to the shell cannot be trapped or reset, but
314 no error is reported when attempting to do so. -- Posix.2 */
315 if (sigmodes[sig] & SIG_HARD_IGNORE)
318 /* Make sure we have original_signals[sig] if the signal has not yet
320 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
322 /* If we aren't sure of the original value, check it. */
323 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
325 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL);
326 set_signal_handler (sig, original_signals[sig]);
329 /* Signals ignored on entry to the shell cannot be trapped or reset. */
330 if (original_signals[sig] == SIG_IGN)
332 sigmodes[sig] |= SIG_HARD_IGNORE;
337 /* Only change the system signal handler if SIG_NO_TRAP is not set.
338 The trap command string is changed in either case. The shell signal
339 handlers for SIGINT and SIGCHLD run the user specified traps in an
340 environment in which it is safe to do so. */
341 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
343 set_signal_handler (sig, SIG_IGN);
344 change_signal (sig, savestring (string));
345 set_signal_handler (sig, trap_handler);
348 change_signal (sig, savestring (string));
352 free_trap_command (sig)
355 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
356 (trap_list[sig] != (char *)IGNORE_SIG) &&
357 (trap_list[sig] != (char *)DEFAULT_SIG) &&
358 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
359 free (trap_list[sig]);
362 /* If SIG has a string assigned to it, get rid of it. Then give it
365 change_signal (sig, value)
369 free_trap_command (sig);
370 trap_list[sig] = value;
372 sigmodes[sig] |= SIG_TRAPPED;
373 if (value == (char *)IGNORE_SIG)
374 sigmodes[sig] |= SIG_IGNORED;
376 sigmodes[sig] &= ~SIG_IGNORED;
377 if (sigmodes[sig] & SIG_INPROGRESS)
378 sigmodes[sig] |= SIG_CHANGED;
381 #define GET_ORIGINAL_SIGNAL(sig) \
382 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
383 get_original_signal (sig)
386 get_original_signal (sig)
389 /* If we aren't sure the of the original value, then get it. */
390 if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
392 original_signals[sig] =
393 (SigHandler *) set_signal_handler (sig, SIG_DFL);
394 set_signal_handler (sig, original_signals[sig]);
396 /* Signals ignored on entry to the shell cannot be trapped. */
397 if (original_signals[sig] == SIG_IGN)
398 sigmodes[sig] |= SIG_HARD_IGNORE;
402 /* Restore the default action for SIG; i.e., the action the shell
403 would have taken before you used the trap command. This is called
404 from trap_builtin (), which takes care to restore the handlers for
405 the signals the shell treats specially. */
407 restore_default_signal (sig)
410 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
412 free_trap_command (sig);
413 trap_list[sig] = (char *)NULL;
414 sigmodes[sig] &= ~SIG_TRAPPED;
418 GET_ORIGINAL_SIGNAL (sig);
420 /* A signal ignored on entry to the shell cannot be trapped or reset, but
421 no error is reported when attempting to do so. Thanks Posix.2. */
422 if (sigmodes[sig] & SIG_HARD_IGNORE)
425 /* If we aren't trapping this signal, don't bother doing anything else. */
426 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
429 /* Only change the signal handler for SIG if it allows it. */
430 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
431 set_signal_handler (sig, original_signals[sig]);
433 /* Change the trap command in either case. */
434 change_signal (sig, (char *)DEFAULT_SIG);
436 /* Mark the signal as no longer trapped. */
437 sigmodes[sig] &= ~SIG_TRAPPED;
440 /* Make this signal be ignored. */
445 if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0))
447 change_signal (sig, (char *)IGNORE_SIG);
451 GET_ORIGINAL_SIGNAL (sig);
453 /* A signal ignored on entry to the shell cannot be trapped or reset.
454 No error is reported when the user attempts to do so. */
455 if (sigmodes[sig] & SIG_HARD_IGNORE)
458 /* If already trapped and ignored, no change necessary. */
459 if (sigmodes[sig] & SIG_IGNORED)
462 /* Only change the signal handler for SIG if it allows it. */
463 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
464 set_signal_handler (sig, SIG_IGN);
466 /* Change the trap command in either case. */
467 change_signal (sig, (char *)IGNORE_SIG);
470 /* Handle the calling of "trap 0". The only sticky situation is when
471 the command to be executed includes an "exit". This is why we have
472 to provide our own place for top_level to jump to. */
477 int code, old_exit_value;
479 old_exit_value = last_command_exit_value;
481 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
482 currently running in the trap handler (call to exit in the list of
483 commands given to trap 0). */
484 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
485 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
487 trap_command = savestring (trap_list[EXIT_TRAP]);
488 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
489 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
491 code = setjmp (top_level);
494 parse_and_execute (trap_command, "exit trap", 0);
495 else if (code == EXITPROG)
496 return (last_command_exit_value);
498 return (old_exit_value);
501 return (old_exit_value);
505 run_trap_cleanup (sig)
508 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
511 /* Run a trap command for SIG. SIG is one of the signals the shell treats
514 _run_trap_internal (sig, tag)
518 char *trap_command, *old_trap;
521 /* Run the trap only if SIG is trapped and not ignored, and we are not
522 currently executing in the trap handler. */
523 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
524 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
525 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
527 old_trap = trap_list[sig];
528 sigmodes[sig] |= SIG_INPROGRESS;
529 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
530 trap_command = savestring (old_trap);
532 running_trap = sig + 1;
533 old_exit_value = last_command_exit_value;
534 parse_and_execute (trap_command, tag, 0);
535 last_command_exit_value = old_exit_value;
538 sigmodes[sig] &= ~SIG_INPROGRESS;
540 if (sigmodes[sig] & SIG_CHANGED)
543 sigmodes[sig] &= ~SIG_CHANGED;
551 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)
552 _run_trap_internal (DEBUG_TRAP, "debug trap");
555 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
556 declared here to localize the trap functions. */
558 run_interrupt_trap ()
560 _run_trap_internal (SIGINT, "interrupt trap");
563 /* Free all the allocated strings in the list of traps and reset the trap
564 values to the default. */
570 for (i = 0; i < NSIG+1; i++)
572 free_trap_command (i);
573 trap_list[i] = (char *)DEFAULT_SIG;
574 sigmodes[i] &= ~SIG_TRAPPED;
576 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL;
579 /* Reset the handler for SIG to the original value. */
584 set_signal_handler (sig, original_signals[sig]);
587 /* Set the handler signal SIG to the original and free any trap
588 command associated with it. */
593 set_signal_handler (sig, original_signals[sig]);
594 change_signal (sig, (char *)DEFAULT_SIG);
595 sigmodes[sig] &= ~SIG_TRAPPED;
599 reset_or_restore_signal_handlers (reset)
604 /* Take care of the exit trap first */
605 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
607 free_trap_command (EXIT_TRAP);
608 trap_list[EXIT_TRAP] = (char *)NULL;
609 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
611 for (i = 1; i < NSIG; i++)
613 if (sigmodes[i] & SIG_TRAPPED)
615 if (trap_list[i] == (char *)IGNORE_SIG)
616 set_signal_handler (i, SIG_IGN);
620 else if (sigmodes[i] & SIG_SPECIAL)
626 reset_signal_handlers ()
628 reset_or_restore_signal_handlers (reset_signal);
631 /* Reset all trapped signals to their original values. Signals set to be
632 ignored with trap '' SIGNAL should be ignored, so we make sure that they
633 are. Called by child processes after they are forked. */
635 restore_original_signals ()
637 reset_or_restore_signal_handlers (restore_signal);
640 /* If a trap handler exists for signal SIG, then call it; otherwise just
643 maybe_call_trap_handler (sig)
646 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
647 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
652 run_interrupt_trap ();
671 signal_is_trapped (sig)
674 return (sigmodes[sig] & SIG_TRAPPED);
678 signal_is_special (sig)
681 return (sigmodes[sig] & SIG_SPECIAL);
685 signal_is_ignored (sig)
688 return (sigmodes[sig] & SIG_IGNORED);
692 set_signal_ignored (sig)
695 sigmodes[sig] |= SIG_HARD_IGNORE;
696 original_signals[sig] = SIG_IGN;