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 #if defined (HAVE_UNISTD_H)
30 #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. */
138 return ((sig
> NSIG
|| sig
< 0) ? "bad signal number" : signal_names
[sig
]);
141 /* Turn a string into a signal number, or a number into
142 a signal number. If STRING is "2", "SIGINT", or "INT",
143 then (int)2 is returned. Return NO_SIG if STRING doesn't
144 contain a valid signal descriptor. */
146 decode_signal (string
)
151 if (legal_number (string
, &sig
))
152 return ((sig
>= 0 && sig
<= NSIG
) ? (int)sig
: NO_SIG
);
154 /* A leading `SIG' may be omitted. */
155 for (sig
= 0; sig
<= NSIG
; sig
++)
156 if (strcasecmp (string
, signal_names
[sig
]) == 0 ||
157 (STREQN (signal_names
[sig
], "SIG", 3) &&
158 strcasecmp (string
, &(signal_names
[sig
])[3]) == 0))
164 /* Non-zero when we catch a trapped signal. */
165 static int catch_flag
;
173 if (catch_flag
== 0) /* simple optimization */
178 /* Preserve $? when running trap. */
179 old_exit_value
= last_command_exit_value
;
181 for (sig
= 1; sig
< NSIG
; sig
++)
183 /* XXX this could be made into a counter by using
184 while (pending_traps[sig]--) instead of the if statement. */
185 if (pending_traps
[sig
])
187 #if defined (HAVE_POSIX_SIGNALS)
193 sigaddset (&set
, sig
);
194 sigprocmask (SIG_BLOCK
, &set
, &oset
);
196 # if defined (HAVE_BSD_SIGNALS)
197 int oldmask
= sigblock (sigmask (sig
));
199 #endif /* HAVE_POSIX_SIGNALS */
203 run_interrupt_trap ();
207 parse_and_execute (savestring (trap_list
[sig
]), "trap", SEVAL_NONINT
|SEVAL_NOHIST
);
209 pending_traps
[sig
] = 0;
211 #if defined (HAVE_POSIX_SIGNALS)
212 sigprocmask (SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
214 # if defined (HAVE_BSD_SIGNALS)
215 sigsetmask (oldmask
);
217 #endif /* POSIX_VERSION */
221 last_command_exit_value
= old_exit_value
;
229 (trap_list
[sig
] == (char *)DEFAULT_SIG
) ||
230 (trap_list
[sig
] == (char *)IGNORE_SIG
))
231 programming_error ("trap_handler: bad signal %d", sig
);
234 #if defined (MUST_REINSTALL_SIGHANDLERS)
235 set_signal_handler (sig
, trap_handler
);
236 #endif /* MUST_REINSTALL_SIGHANDLERS */
239 pending_traps
[sig
]++;
241 if (interrupt_immediately
)
242 run_pending_traps ();
248 #if defined (JOB_CONTROL) && defined (SIGCHLD)
249 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
251 set_sigchld_trap (command_string
)
252 char *command_string
;
254 set_signal (SIGCHLD
, command_string
);
257 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
258 SIGCHLD trap handler is DEFAULT_SIG. */
260 maybe_set_sigchld_trap (command_string
)
261 char *command_string
;
263 if ((sigmodes
[SIGCHLD
] & SIG_TRAPPED
) == 0)
264 set_signal (SIGCHLD
, command_string
);
266 #endif /* JOB_CONTROL && SIGCHLD */
269 set_debug_trap (command
)
272 set_signal (DEBUG_TRAP
, command
);
276 set_sigint_trap (command
)
279 set_signal (SIGINT
, command
);
282 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
283 things, like waiting for command substitution or executing commands
284 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
286 set_sigint_handler ()
288 if (sigmodes
[SIGINT
] & SIG_HARD_IGNORE
)
289 return ((SigHandler
*)SIG_IGN
);
291 else if (sigmodes
[SIGINT
] & SIG_IGNORED
)
292 return ((SigHandler
*)set_signal_handler (SIGINT
, SIG_IGN
)); /* XXX */
294 else if (sigmodes
[SIGINT
] & SIG_TRAPPED
)
295 return ((SigHandler
*)set_signal_handler (SIGINT
, trap_handler
));
297 /* The signal is not trapped, so set the handler to the shell's special
298 interrupt handler. */
299 else if (interactive
) /* XXX - was interactive_shell */
300 return (set_signal_handler (SIGINT
, sigint_sighandler
));
302 return (set_signal_handler (SIGINT
, termination_unwind_protect
));
305 /* Return the correct handler for signal SIG according to the values in
308 trap_to_sighandler (sig
)
311 if (sigmodes
[sig
] & (SIG_IGNORED
|SIG_HARD_IGNORE
))
313 else if (sigmodes
[sig
] & SIG_TRAPPED
)
314 return (trap_handler
);
319 /* Set SIG to call STRING as a command. */
321 set_signal (sig
, string
)
325 if (sig
== DEBUG_TRAP
|| sig
== EXIT_TRAP
)
327 change_signal (sig
, savestring (string
));
328 if (sig
== EXIT_TRAP
&& interactive
== 0)
329 initialize_terminating_signals ();
333 /* A signal ignored on entry to the shell cannot be trapped or reset, but
334 no error is reported when attempting to do so. -- Posix.2 */
335 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
338 /* Make sure we have original_signals[sig] if the signal has not yet
340 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
342 /* If we aren't sure of the original value, check it. */
343 if (original_signals
[sig
] == IMPOSSIBLE_TRAP_HANDLER
)
345 original_signals
[sig
] = (SigHandler
*)set_signal_handler (sig
, SIG_DFL
);
346 set_signal_handler (sig
, original_signals
[sig
]);
349 /* Signals ignored on entry to the shell cannot be trapped or reset. */
350 if (original_signals
[sig
] == SIG_IGN
)
352 sigmodes
[sig
] |= SIG_HARD_IGNORE
;
357 /* Only change the system signal handler if SIG_NO_TRAP is not set.
358 The trap command string is changed in either case. The shell signal
359 handlers for SIGINT and SIGCHLD run the user specified traps in an
360 environment in which it is safe to do so. */
361 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
363 set_signal_handler (sig
, SIG_IGN
);
364 change_signal (sig
, savestring (string
));
365 set_signal_handler (sig
, trap_handler
);
368 change_signal (sig
, savestring (string
));
372 free_trap_command (sig
)
375 if ((sigmodes
[sig
] & SIG_TRAPPED
) && trap_list
[sig
] &&
376 (trap_list
[sig
] != (char *)IGNORE_SIG
) &&
377 (trap_list
[sig
] != (char *)DEFAULT_SIG
) &&
378 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
))
379 free (trap_list
[sig
]);
382 /* If SIG has a string assigned to it, get rid of it. Then give it
385 change_signal (sig
, value
)
389 if ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
390 free_trap_command (sig
);
391 trap_list
[sig
] = value
;
393 sigmodes
[sig
] |= SIG_TRAPPED
;
394 if (value
== (char *)IGNORE_SIG
)
395 sigmodes
[sig
] |= SIG_IGNORED
;
397 sigmodes
[sig
] &= ~SIG_IGNORED
;
398 if (sigmodes
[sig
] & SIG_INPROGRESS
)
399 sigmodes
[sig
] |= SIG_CHANGED
;
402 #define GET_ORIGINAL_SIGNAL(sig) \
403 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
404 get_original_signal (sig)
407 get_original_signal (sig
)
410 /* If we aren't sure the of the original value, then get it. */
411 if (original_signals
[sig
] == (SigHandler
*)IMPOSSIBLE_TRAP_HANDLER
)
413 original_signals
[sig
] =
414 (SigHandler
*) set_signal_handler (sig
, SIG_DFL
);
415 set_signal_handler (sig
, original_signals
[sig
]);
417 /* Signals ignored on entry to the shell cannot be trapped. */
418 if (original_signals
[sig
] == SIG_IGN
)
419 sigmodes
[sig
] |= SIG_HARD_IGNORE
;
423 /* Restore the default action for SIG; i.e., the action the shell
424 would have taken before you used the trap command. This is called
425 from trap_builtin (), which takes care to restore the handlers for
426 the signals the shell treats specially. */
428 restore_default_signal (sig
)
431 if (sig
== DEBUG_TRAP
|| sig
== EXIT_TRAP
)
433 if ((sig
!= DEBUG_TRAP
) || (sigmodes
[sig
] & SIG_INPROGRESS
) == 0)
434 free_trap_command (sig
);
435 trap_list
[sig
] = (char *)NULL
;
436 sigmodes
[sig
] &= ~SIG_TRAPPED
;
437 if (sigmodes
[sig
] & SIG_INPROGRESS
)
438 sigmodes
[sig
] |= SIG_CHANGED
;
442 GET_ORIGINAL_SIGNAL (sig
);
444 /* A signal ignored on entry to the shell cannot be trapped or reset, but
445 no error is reported when attempting to do so. Thanks Posix.2. */
446 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
449 /* If we aren't trapping this signal, don't bother doing anything else. */
450 if ((sigmodes
[sig
] & SIG_TRAPPED
) == 0)
453 /* Only change the signal handler for SIG if it allows it. */
454 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
455 set_signal_handler (sig
, original_signals
[sig
]);
457 /* Change the trap command in either case. */
458 change_signal (sig
, (char *)DEFAULT_SIG
);
460 /* Mark the signal as no longer trapped. */
461 sigmodes
[sig
] &= ~SIG_TRAPPED
;
464 /* Make this signal be ignored. */
469 if ((sig
== EXIT_TRAP
|| sig
== DEBUG_TRAP
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
471 change_signal (sig
, (char *)IGNORE_SIG
);
475 GET_ORIGINAL_SIGNAL (sig
);
477 /* A signal ignored on entry to the shell cannot be trapped or reset.
478 No error is reported when the user attempts to do so. */
479 if (sigmodes
[sig
] & SIG_HARD_IGNORE
)
482 /* If already trapped and ignored, no change necessary. */
483 if (sigmodes
[sig
] & SIG_IGNORED
)
486 /* Only change the signal handler for SIG if it allows it. */
487 if ((sigmodes
[sig
] & SIG_NO_TRAP
) == 0)
488 set_signal_handler (sig
, SIG_IGN
);
490 /* Change the trap command in either case. */
491 change_signal (sig
, (char *)IGNORE_SIG
);
494 /* Handle the calling of "trap 0". The only sticky situation is when
495 the command to be executed includes an "exit". This is why we have
496 to provide our own place for top_level to jump to. */
501 int code
, old_exit_value
;
503 old_exit_value
= last_command_exit_value
;
505 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
506 currently running in the trap handler (call to exit in the list of
507 commands given to trap 0). */
508 if ((sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
) &&
509 (sigmodes
[EXIT_TRAP
] & (SIG_IGNORED
|SIG_INPROGRESS
)) == 0)
511 trap_command
= savestring (trap_list
[EXIT_TRAP
]);
512 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
;
513 sigmodes
[EXIT_TRAP
] |= SIG_INPROGRESS
;
515 code
= setjmp (top_level
);
518 parse_and_execute (trap_command
, "exit trap", SEVAL_NONINT
|SEVAL_NOHIST
);
519 else if (code
== EXITPROG
)
520 return (last_command_exit_value
);
522 return (old_exit_value
);
525 return (old_exit_value
);
529 run_trap_cleanup (sig
)
532 sigmodes
[sig
] &= ~(SIG_INPROGRESS
|SIG_CHANGED
);
535 /* Run a trap command for SIG. SIG is one of the signals the shell treats
538 _run_trap_internal (sig
, tag
)
542 char *trap_command
, *old_trap
;
543 int old_exit_value
, old_line_number
;
545 /* Run the trap only if SIG is trapped and not ignored, and we are not
546 currently executing in the trap handler. */
547 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0) &&
548 (trap_list
[sig
] != (char *)IMPOSSIBLE_TRAP_HANDLER
) &&
549 ((sigmodes
[sig
] & SIG_INPROGRESS
) == 0))
551 old_trap
= trap_list
[sig
];
552 sigmodes
[sig
] |= SIG_INPROGRESS
;
553 sigmodes
[sig
] &= ~SIG_CHANGED
; /* just to be sure */
554 trap_command
= savestring (old_trap
);
556 running_trap
= sig
+ 1;
557 old_exit_value
= last_command_exit_value
;
558 /* Need to copy the value of line_number because parse_and_execute
559 resets it to 1, and the trap command might want it. */
560 trap_line_number
= line_number
;
561 parse_and_execute (trap_command
, tag
, SEVAL_NONINT
|SEVAL_NOHIST
);
562 last_command_exit_value
= old_exit_value
;
565 sigmodes
[sig
] &= ~SIG_INPROGRESS
;
567 if (sigmodes
[sig
] & SIG_CHANGED
)
570 sigmodes
[sig
] &= ~SIG_CHANGED
;
578 if ((sigmodes
[DEBUG_TRAP
] & SIG_TRAPPED
) && (sigmodes
[DEBUG_TRAP
] & SIG_INPROGRESS
) == 0)
579 _run_trap_internal (DEBUG_TRAP
, "debug trap");
582 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
583 declared here to localize the trap functions. */
585 run_interrupt_trap ()
587 _run_trap_internal (SIGINT
, "interrupt trap");
590 /* Free all the allocated strings in the list of traps and reset the trap
591 values to the default. */
597 for (i
= 0; i
< NSIG
+1; i
++)
599 free_trap_command (i
);
600 trap_list
[i
] = (char *)DEFAULT_SIG
;
601 sigmodes
[i
] &= ~SIG_TRAPPED
;
603 trap_list
[DEBUG_TRAP
] = trap_list
[EXIT_TRAP
] = (char *)NULL
;
606 /* Reset the handler for SIG to the original value. */
611 set_signal_handler (sig
, original_signals
[sig
]);
614 /* Set the handler signal SIG to the original and free any trap
615 command associated with it. */
620 set_signal_handler (sig
, original_signals
[sig
]);
621 change_signal (sig
, (char *)DEFAULT_SIG
);
622 sigmodes
[sig
] &= ~SIG_TRAPPED
;
626 reset_or_restore_signal_handlers (reset
)
631 /* Take care of the exit trap first */
632 if (sigmodes
[EXIT_TRAP
] & SIG_TRAPPED
)
634 free_trap_command (EXIT_TRAP
);
635 trap_list
[EXIT_TRAP
] = (char *)NULL
;
636 sigmodes
[EXIT_TRAP
] &= ~SIG_TRAPPED
;
638 for (i
= 1; i
< NSIG
; i
++)
640 if (sigmodes
[i
] & SIG_TRAPPED
)
642 if (trap_list
[i
] == (char *)IGNORE_SIG
)
643 set_signal_handler (i
, SIG_IGN
);
647 else if (sigmodes
[i
] & SIG_SPECIAL
)
653 reset_signal_handlers ()
655 reset_or_restore_signal_handlers (reset_signal
);
658 /* Reset all trapped signals to their original values. Signals set to be
659 ignored with trap '' SIGNAL should be ignored, so we make sure that they
660 are. Called by child processes after they are forked. */
662 restore_original_signals ()
664 reset_or_restore_signal_handlers (restore_signal
);
667 /* If a trap handler exists for signal SIG, then call it; otherwise just
670 maybe_call_trap_handler (sig
)
673 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
674 if ((sigmodes
[sig
] & SIG_TRAPPED
) && ((sigmodes
[sig
] & SIG_IGNORED
) == 0))
679 run_interrupt_trap ();
698 signal_is_trapped (sig
)
701 return (sigmodes
[sig
] & SIG_TRAPPED
);
705 signal_is_special (sig
)
708 return (sigmodes
[sig
] & SIG_SPECIAL
);
712 signal_is_ignored (sig
)
715 return (sigmodes
[sig
] & SIG_IGNORED
);
719 set_signal_ignored (sig
)
722 sigmodes
[sig
] |= SIG_HARD_IGNORE
;
723 original_signals
[sig
] = SIG_IGN
;