improve of cmpl.
[bush.git] / src / trap.c
blobbd4904cf37329e9985952ee50812d059e1b9dd3a
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 Bush, the Bourne Again SHell.
8 Bush 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 Bush 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 Bush. If not, see <http://www.gnu.org/licenses/>.
22 #include "config.h"
24 #if defined (HAVE_UNISTD_H)
25 # include <unistd.h>
26 #endif
28 #include "bushtypes.h"
29 #include "bushansi.h"
31 #include <stdio.h>
32 #include <errno.h>
34 #include "bushintl.h"
36 #include <signal.h>
38 #include "trap.h"
40 #include "shell.h"
41 #include "runner/execute_cmd.h"
42 #include "flags.h"
43 #include "lxrgmr/parser.h"
44 #include "input/input.h" /* for save_token_state, restore_token_state */
45 #include "jobs.h"
46 #include "signames.h"
47 #include "builtins.h"
48 #include "builtins/common.h"
49 #include "builtins/builtext.h"
51 #if defined (READLINE)
52 # include <readline/readline.h>
53 # include "input/bushline.h"
54 #endif
56 #ifndef errno
57 extern int errno;
58 #endif
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
74 assumes this. */
75 static int sigmodes[BUSH_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
104 this signal. */
105 char *trap_list[BUSH_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). */
114 int running_trap;
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) \
128 do { \
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; \
133 } while (0)
135 #define SETORIGSIG(sig,handler) \
136 do { \
137 original_signals[sig] = handler; \
138 if (original_signals[sig] == SIG_IGN) \
139 sigmodes[sig] |= SIG_HARD_IGNORE; \
140 } while (0)
142 #define GET_ORIGINAL_SIGNAL(sig) \
143 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
144 GETORIGSIG(sig)
146 void
147 initialize_traps ()
149 register int i;
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);
169 #endif /* SIGCHLD */
171 GETORIGSIG (SIGINT);
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;
178 #endif
180 GETORIGSIG (SIGQUIT);
181 sigmodes[SIGQUIT] |= SIG_SPECIAL;
183 if (interactive)
185 GETORIGSIG (SIGTERM);
186 sigmodes[SIGTERM] |= SIG_SPECIAL;
189 get_original_tty_job_signals ();
192 #ifdef DEBUG
193 /* Return a printable representation of the trap handler for SIG. */
194 static char *
195 trap_handler_string (sig)
196 int sig;
198 if (trap_list[sig] == (char *)DEFAULT_SIG)
199 return "DEFAULT_SIG";
200 else if (trap_list[sig] == (char *)IGNORE_SIG)
201 return "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];
206 else
207 return "NULL";
209 #endif
211 /* Return the print name of this signal. */
212 char *
213 signal_name (sig)
214 int sig;
216 char *ret;
218 /* on cygwin32, signal_names[sig] could be null */
219 ret = (sig >= BUSH_NSIG || sig < 0 || signal_names[sig] == NULL)
220 ? _("invalid signal number")
221 : signal_names[sig];
223 return ret;
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)
232 char *string;
233 int flags;
235 intmax_t sig;
236 char *name;
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);
246 else
247 return NO_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);
253 else
254 return NO_SIG;
256 #endif /* SIGRTMIN && SIGRTMAX */
258 /* A leading `SIG' may be omitted. */
259 for (sig = 0; sig < BUSH_NSIG; sig++)
261 name = signal_names[sig];
262 if (name == 0 || name[0] == '\0')
263 continue;
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))
269 name += 3;
271 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
272 return ((int)sig);
273 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
274 return ((int)sig);
275 /* If we can't use the `SIG' prefix to match, punt on this
276 name now. */
277 else if ((flags & DSIG_SIGPREFIX) == 0)
278 continue;
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)
285 return ((int)sig);
286 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
287 return ((int)sig);
290 return (NO_SIG);
293 /* Non-zero when we catch a trapped signal. */
294 static int catch_flag;
296 void
297 run_pending_traps ()
299 register int sig;
300 int old_exit_value, x;
301 int old_running;
302 WORD_LIST *save_subst_varlist;
303 HASH_TABLE *save_tempenv;
304 sh_parser_state_t pstate;
305 #if defined (ARRAY_VARS)
306 ARRAY *ps;
307 #endif
309 if (catch_flag == 0) /* simple optimization */
310 return;
312 if (running_trap > 0)
314 #if defined (DEBUG)
315 internal_warning ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap-1);
316 #endif
317 #if defined (SIGWINCH)
318 if (running_trap == SIGWINCH+1 && pending_traps[SIGWINCH])
319 return; /* no recursive SIGWINCH trap invocations */
320 #endif
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);
326 evalnest = 0;
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 ();
337 #endif
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)
347 /*continue*/;
349 running_trap = sig + 1;
351 if (sig == SIGINT)
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 */
367 evalnest++;
368 x = pending_traps[sig];
369 pending_traps[sig] = 0;
370 run_sigchld_trap (x); /* use as counter */
371 running_trap = 0;
372 evalnest--;
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. */
377 continue;
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. */
385 running_trap = 0;
386 /* want to leave pending_traps[SIGCHLD] alone here */
387 continue; /* XXX */
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 */
394 continue;
396 #endif
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 bush
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
413 usually 0x0. */
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);
422 else
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 */
433 #endif
434 /* XXX - set pending_traps[sig] = 0 here? */
435 pending_traps[sig] = 0;
436 evalnest++;
437 evalstring (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
438 evalnest--;
439 #if defined (JOB_CONTROL)
440 restore_pipeline (1);
441 #endif
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);
455 #endif
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. */
461 void
462 set_trap_state (sig)
463 int sig;
465 catch_flag = 1;
466 pending_traps[sig]++;
467 trapped_signal_received = sig;
470 sighandler
471 trap_handler (sig)
472 int sig;
474 int oerrno;
476 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
478 #if defined (DEBUG)
479 internal_warning ("trap_handler: signal %d: signal not trapped", sig);
480 #endif
481 SIGRETURN (0);
484 if ((sig >= NSIG) ||
485 (trap_list[sig] == (char *)DEFAULT_SIG) ||
486 (trap_list[sig] == (char *)IGNORE_SIG))
487 programming_error (_("trap_handler: bad signal %d"), sig);
488 else
490 oerrno = errno;
491 #if defined (MUST_REINSTALL_SIGHANDLERS)
492 # if defined (JOB_CONTROL) && defined (SIGCHLD)
493 if (sig != SIGCHLD)
494 # endif /* JOB_CONTROL && SIGCHLD */
495 set_signal_handler (sig, trap_handler);
496 #endif /* MUST_REINSTALL_SIGHANDLERS */
498 set_trap_state (sig);
500 if (this_shell_builtin && (this_shell_builtin == wait_builtin))
502 wait_signal_received = sig;
503 if (waiting_for_child && wait_intr_flag)
504 sh_longjmp (wait_intr_buf, 1);
507 #if defined (READLINE)
508 /* Set the event hook so readline will call it after the signal handlers
509 finish executing, so if this interrupted character input we can get
510 quick response. */
511 if (RL_ISSTATE (RL_STATE_SIGHANDLER))
512 bushline_set_event_hook ();
513 #endif
515 errno = oerrno;
518 SIGRETURN (0);
522 next_pending_trap (start)
523 int start;
525 register int i;
527 for (i = start; i < NSIG; i++)
528 if (pending_traps[i])
529 return i;
530 return -1;
534 first_pending_trap ()
536 return (next_pending_trap (1));
539 /* Return > 0 if any of the "real" signals (not fake signals like EXIT) are
540 trapped. */
542 any_signals_trapped ()
544 register int i;
546 for (i = 1; i < NSIG; i++)
547 if (sigmodes[i] & SIG_TRAPPED)
548 return i;
549 return -1;
552 void
553 clear_pending_traps ()
555 register int i;
557 for (i = 1; i < NSIG; i++)
558 pending_traps[i] = 0;
561 void
562 check_signals ()
564 CHECK_ALRM; /* set by the read builtin */
565 QUIT;
568 /* Convenience functions the rest of the shell can use */
569 void
570 check_signals_and_traps ()
572 check_signals ();
574 run_pending_traps ();
577 #if defined (JOB_CONTROL) && defined (SIGCHLD)
579 #ifdef INCLUDE_UNUSED
580 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
581 void
582 set_sigchld_trap (command_string)
583 char *command_string;
585 set_signal (SIGCHLD, command_string);
587 #endif
589 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
590 is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
591 to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
592 reset the disposition to the default and not have the original signal
593 accidentally restored, undoing the user's command. */
594 void
595 maybe_set_sigchld_trap (command_string)
596 char *command_string;
598 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
599 set_signal (SIGCHLD, command_string);
602 /* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
603 as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
604 or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
605 void
606 set_impossible_sigchld_trap ()
608 restore_default_signal (SIGCHLD);
609 change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER);
610 sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */
613 /* Act as if we received SIGCHLD NCHILD times and increment
614 pending_traps[SIGCHLD] by that amount. This allows us to still run the
615 SIGCHLD trap once for each exited child. */
616 void
617 queue_sigchld_trap (nchild)
618 int nchild;
620 if (nchild > 0)
622 catch_flag = 1;
623 pending_traps[SIGCHLD] += nchild;
624 trapped_signal_received = SIGCHLD;
627 #endif /* JOB_CONTROL && SIGCHLD */
629 /* Set a trap for SIG only if SIG is not already trapped. */
630 static inline void
631 trap_if_untrapped (sig, command)
632 int sig;
633 char *command;
635 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
636 set_signal (sig, command);
639 void
640 set_debug_trap (command)
641 char *command;
643 set_signal (DEBUG_TRAP, command);
646 /* Separate function to call when functions and sourced files want to restore
647 the original version of the DEBUG trap before returning. Unless the -T
648 option is set, source and shell function execution save the old debug trap
649 and unset the trap. If the function or sourced file changes the DEBUG trap,
650 SIG_TRAPPED will be set and we don't bother restoring the original trap string.
651 This is used by both functions and the source builtin. */
652 void
653 maybe_set_debug_trap (command)
654 char *command;
656 trap_if_untrapped (DEBUG_TRAP, command);
659 void
660 set_error_trap (command)
661 char *command;
663 set_signal (ERROR_TRAP, command);
666 void
667 maybe_set_error_trap (command)
668 char *command;
670 trap_if_untrapped (ERROR_TRAP, command);
673 void
674 set_return_trap (command)
675 char *command;
677 set_signal (RETURN_TRAP, command);
680 void
681 maybe_set_return_trap (command)
682 char *command;
684 trap_if_untrapped (RETURN_TRAP, command);
687 #ifdef INCLUDE_UNUSED
688 void
689 set_sigint_trap (command)
690 char *command;
692 set_signal (SIGINT, command);
694 #endif
696 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
697 things, like waiting for command substitution or executing commands
698 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
699 SigHandler *
700 set_sigint_handler ()
702 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
703 return ((SigHandler *)SIG_IGN);
705 else if (sigmodes[SIGINT] & SIG_IGNORED)
706 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
708 else if (sigmodes[SIGINT] & SIG_TRAPPED)
709 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
711 /* The signal is not trapped, so set the handler to the shell's special
712 interrupt handler. */
713 else if (interactive) /* XXX - was interactive_shell */
714 return (set_signal_handler (SIGINT, sigint_sighandler));
715 else
716 return (set_signal_handler (SIGINT, termsig_sighandler));
719 /* Return the correct handler for signal SIG according to the values in
720 sigmodes[SIG]. */
721 SigHandler *
722 trap_to_sighandler (sig)
723 int sig;
725 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
726 return (SIG_IGN);
727 else if (sigmodes[sig] & SIG_TRAPPED)
728 return (trap_handler);
729 else
730 return (SIG_DFL);
733 /* Set SIG to call STRING as a command. */
734 void
735 set_signal (sig, string)
736 int sig;
737 char *string;
739 sigset_t set, oset;
741 if (SPECIAL_TRAP (sig))
743 change_signal (sig, savestring (string));
744 if (sig == EXIT_TRAP && interactive == 0)
745 initialize_terminating_signals ();
746 return;
749 /* A signal ignored on entry to the shell cannot be trapped or reset, but
750 no error is reported when attempting to do so. -- Posix.2 */
751 if (sigmodes[sig] & SIG_HARD_IGNORE)
752 return;
754 /* Make sure we have original_signals[sig] if the signal has not yet
755 been trapped. */
756 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
758 /* If we aren't sure of the original value, check it. */
759 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
760 GETORIGSIG (sig);
761 if (original_signals[sig] == SIG_IGN)
762 return;
765 /* Only change the system signal handler if SIG_NO_TRAP is not set.
766 The trap command string is changed in either case. The shell signal
767 handlers for SIGINT and SIGCHLD run the user specified traps in an
768 environment in which it is safe to do so. */
769 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
771 BLOCK_SIGNAL (sig, set, oset);
772 change_signal (sig, savestring (string));
773 set_signal_handler (sig, trap_handler);
774 UNBLOCK_SIGNAL (oset);
776 else
777 change_signal (sig, savestring (string));
780 static void
781 free_trap_command (sig)
782 int sig;
784 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
785 (trap_list[sig] != (char *)IGNORE_SIG) &&
786 (trap_list[sig] != (char *)DEFAULT_SIG) &&
787 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
788 free (trap_list[sig]);
791 /* If SIG has a string assigned to it, get rid of it. Then give it
792 VALUE. */
793 static void
794 change_signal (sig, value)
795 int sig;
796 char *value;
798 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
799 free_trap_command (sig);
800 trap_list[sig] = value;
802 sigmodes[sig] |= SIG_TRAPPED;
803 if (value == (char *)IGNORE_SIG)
804 sigmodes[sig] |= SIG_IGNORED;
805 else
806 sigmodes[sig] &= ~SIG_IGNORED;
807 if (sigmodes[sig] & SIG_INPROGRESS)
808 sigmodes[sig] |= SIG_CHANGED;
811 void
812 get_original_signal (sig)
813 int sig;
815 /* If we aren't sure the of the original value, then get it. */
816 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
817 GETORIGSIG (sig);
820 void
821 get_all_original_signals ()
823 register int i;
825 for (i = 1; i < NSIG; i++)
826 GET_ORIGINAL_SIGNAL (i);
829 void
830 set_original_signal (sig, handler)
831 int sig;
832 SigHandler *handler;
834 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
835 SETORIGSIG (sig, handler);
838 /* Restore the default action for SIG; i.e., the action the shell
839 would have taken before you used the trap command. This is called
840 from trap_builtin (), which takes care to restore the handlers for
841 the signals the shell treats specially. */
842 void
843 restore_default_signal (sig)
844 int sig;
846 if (SPECIAL_TRAP (sig))
848 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
849 (sigmodes[sig] & SIG_INPROGRESS) == 0)
850 free_trap_command (sig);
851 trap_list[sig] = (char *)NULL;
852 sigmodes[sig] &= ~SIG_TRAPPED;
853 if (sigmodes[sig] & SIG_INPROGRESS)
854 sigmodes[sig] |= SIG_CHANGED;
855 return;
858 GET_ORIGINAL_SIGNAL (sig);
860 /* A signal ignored on entry to the shell cannot be trapped or reset, but
861 no error is reported when attempting to do so. Thanks Posix.2. */
862 if (sigmodes[sig] & SIG_HARD_IGNORE)
863 return;
865 /* If we aren't trapping this signal, don't bother doing anything else. */
866 /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
867 sentinel to determine whether or not disposition is reset to the default
868 while the trap handler is executing. */
869 if (((sigmodes[sig] & SIG_TRAPPED) == 0) &&
870 (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
871 return;
873 /* Only change the signal handler for SIG if it allows it. */
874 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
875 set_signal_handler (sig, original_signals[sig]);
877 /* Change the trap command in either case. */
878 change_signal (sig, (char *)DEFAULT_SIG);
880 /* Mark the signal as no longer trapped. */
881 sigmodes[sig] &= ~SIG_TRAPPED;
884 /* Make this signal be ignored. */
885 void
886 ignore_signal (sig)
887 int sig;
889 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
891 change_signal (sig, (char *)IGNORE_SIG);
892 return;
895 GET_ORIGINAL_SIGNAL (sig);
897 /* A signal ignored on entry to the shell cannot be trapped or reset.
898 No error is reported when the user attempts to do so. */
899 if (sigmodes[sig] & SIG_HARD_IGNORE)
900 return;
902 /* If already trapped and ignored, no change necessary. */
903 if (sigmodes[sig] & SIG_IGNORED)
904 return;
906 /* Only change the signal handler for SIG if it allows it. */
907 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
908 set_signal_handler (sig, SIG_IGN);
910 /* Change the trap command in either case. */
911 change_signal (sig, (char *)IGNORE_SIG);
914 /* Handle the calling of "trap 0". The only sticky situation is when
915 the command to be executed includes an "exit". This is why we have
916 to provide our own place for top_level to jump to. */
918 run_exit_trap ()
920 char *trap_command;
921 int code, function_code, retval;
922 #if defined (ARRAY_VARS)
923 ARRAY *ps;
924 #endif
926 trap_saved_exit_value = last_command_exit_value;
927 #if defined (ARRAY_VARS)
928 ps = save_pipestatus_array ();
929 #endif
930 function_code = 0;
932 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
933 currently running in the trap handler (call to exit in the list of
934 commands given to trap 0). */
935 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
936 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
938 trap_command = savestring (trap_list[EXIT_TRAP]);
939 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
940 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
942 retval = trap_saved_exit_value;
943 running_trap = 1;
945 code = setjmp_nosigs (top_level);
947 /* If we're in a function, make sure return longjmps come here, too. */
948 if (return_catch_flag)
949 function_code = setjmp_nosigs (return_catch);
951 if (code == 0 && function_code == 0)
953 reset_parser ();
954 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
956 else if (code == ERREXIT)
957 retval = last_command_exit_value;
958 else if (code == EXITPROG)
959 retval = last_command_exit_value;
960 else if (function_code != 0)
961 retval = return_catch_value;
962 else
963 retval = trap_saved_exit_value;
965 running_trap = 0;
966 #if defined (ARRAY_VARS)
967 array_dispose (ps);
968 #endif
970 return retval;
973 #if defined (ARRAY_VARS)
974 restore_pipestatus_array (ps);
975 #endif
976 return (trap_saved_exit_value);
979 void
980 run_trap_cleanup (sig)
981 int sig;
983 /* XXX - should we clean up trap_list[sig] == IMPOSSIBLE_TRAP_HANDLER? */
984 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
987 #define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
989 /* Run a trap command for SIG. SIG is one of the signals the shell treats
990 specially. Returns the exit status of the executed trap command list. */
991 static int
992 _run_trap_internal (sig, tag)
993 int sig;
994 char *tag;
996 char *trap_command, *old_trap;
997 int trap_exit_value;
998 volatile int save_return_catch_flag, function_code;
999 int old_modes, old_running, old_int;
1000 int flags;
1001 procenv_t save_return_catch;
1002 WORD_LIST *save_subst_varlist;
1003 HASH_TABLE *save_tempenv;
1004 sh_parser_state_t pstate;
1005 #if defined (ARRAY_VARS)
1006 ARRAY *ps;
1007 #endif
1009 old_modes = old_running = -1;
1011 trap_exit_value = function_code = 0;
1012 trap_saved_exit_value = last_command_exit_value;
1013 /* Run the trap only if SIG is trapped and not ignored, and we are not
1014 currently executing in the trap handler. */
1015 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
1016 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
1017 #if 1
1018 /* Uncomment this to allow some special signals to recursively execute
1019 trap handlers. */
1020 (RECURSIVE_SIG (sig) || (sigmodes[sig] & SIG_INPROGRESS) == 0))
1021 #else
1022 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
1023 #endif
1025 old_trap = trap_list[sig];
1026 old_modes = sigmodes[sig];
1027 old_running = running_trap;
1029 sigmodes[sig] |= SIG_INPROGRESS;
1030 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
1031 trap_command = savestring (old_trap);
1033 running_trap = sig + 1;
1035 old_int = interrupt_state; /* temporarily suppress pending interrupts */
1036 CLRINTERRUPT;
1038 #if defined (ARRAY_VARS)
1039 ps = save_pipestatus_array ();
1040 #endif
1042 save_parser_state (&pstate);
1043 save_subst_varlist = subst_assign_varlist;
1044 subst_assign_varlist = 0;
1045 save_tempenv = temporary_env;
1046 temporary_env = 0; /* traps should not run with temporary env */
1048 #if defined (JOB_CONTROL)
1049 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1050 save_pipeline (1); /* XXX only provides one save level */
1051 #endif
1053 /* If we're in a function, make sure return longjmps come here, too. */
1054 save_return_catch_flag = return_catch_flag;
1055 if (return_catch_flag)
1057 COPY_PROCENV (return_catch, save_return_catch);
1058 function_code = setjmp_nosigs (return_catch);
1061 flags = SEVAL_NONINT|SEVAL_NOHIST;
1062 if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
1063 flags |= SEVAL_RESETLINE;
1064 evalnest++;
1065 if (function_code == 0)
1067 parse_and_execute (trap_command, tag, flags);
1068 trap_exit_value = last_command_exit_value;
1070 else
1071 trap_exit_value = return_catch_value;
1072 evalnest--;
1074 #if defined (JOB_CONTROL)
1075 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1076 restore_pipeline (1);
1077 #endif
1079 subst_assign_varlist = save_subst_varlist;
1080 restore_parser_state (&pstate);
1082 #if defined (ARRAY_VARS)
1083 restore_pipestatus_array (ps);
1084 #endif
1086 temporary_env = save_tempenv;
1088 if ((old_modes & SIG_INPROGRESS) == 0)
1089 sigmodes[sig] &= ~SIG_INPROGRESS;
1091 running_trap = old_running;
1092 interrupt_state = old_int;
1094 if (sigmodes[sig] & SIG_CHANGED)
1096 #if 0
1097 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
1098 the places where they can be changed using unwind-protects. For
1099 example, look at execute_cmd.c:execute_function(). */
1100 if (SPECIAL_TRAP (sig) == 0)
1101 #endif
1102 free (old_trap);
1103 sigmodes[sig] &= ~SIG_CHANGED;
1105 CHECK_TERMSIG; /* some pathological conditions lead here */
1108 if (save_return_catch_flag)
1110 return_catch_flag = save_return_catch_flag;
1111 return_catch_value = trap_exit_value;
1112 COPY_PROCENV (save_return_catch, return_catch);
1113 if (function_code)
1115 #if 0
1116 from_return_trap = sig == RETURN_TRAP;
1117 #endif
1118 sh_longjmp (return_catch, 1);
1123 return trap_exit_value;
1127 run_debug_trap ()
1129 int trap_exit_value, old_verbose;
1130 pid_t save_pgrp;
1131 #if defined (PGRP_PIPE)
1132 int save_pipe[2];
1133 #endif
1135 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
1136 trap_exit_value = 0;
1137 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
1139 #if defined (JOB_CONTROL)
1140 save_pgrp = pipeline_pgrp;
1141 pipeline_pgrp = 0;
1142 save_pipeline (1);
1143 # if defined (PGRP_PIPE)
1144 save_pgrp_pipe (save_pipe, 1);
1145 # endif
1146 stop_making_children ();
1147 #endif
1149 old_verbose = echo_input_at_read;
1150 echo_input_at_read = suppress_debug_trap_verbose ? 0 : echo_input_at_read;
1152 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
1154 echo_input_at_read = old_verbose;
1156 #if defined (JOB_CONTROL)
1157 pipeline_pgrp = save_pgrp;
1158 restore_pipeline (1);
1159 # if defined (PGRP_PIPE)
1160 close_pgrp_pipe ();
1161 restore_pgrp_pipe (save_pipe);
1162 # endif
1163 if (pipeline_pgrp > 0 && ((subshell_environment & (SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0))
1164 give_terminal_to (pipeline_pgrp, 1);
1166 notify_and_cleanup ();
1167 #endif
1169 #if defined (DEBUGGER)
1170 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
1171 a function or sourced script, we force a `return'. */
1172 if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
1174 return_catch_value = trap_exit_value;
1175 sh_longjmp (return_catch, 1);
1177 #endif
1179 return trap_exit_value;
1182 void
1183 run_error_trap ()
1185 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
1186 _run_trap_internal (ERROR_TRAP, "error trap");
1189 void
1190 run_return_trap ()
1192 int old_exit_value;
1194 #if 0
1195 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
1196 return;
1197 #endif
1199 if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
1201 old_exit_value = last_command_exit_value;
1202 _run_trap_internal (RETURN_TRAP, "return trap");
1203 last_command_exit_value = old_exit_value;
1207 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
1208 declared here to localize the trap functions. */
1209 void
1210 run_interrupt_trap (will_throw)
1211 int will_throw; /* from throw_to_top_level? */
1213 if (will_throw && running_trap > 0)
1214 run_trap_cleanup (running_trap - 1);
1215 pending_traps[SIGINT] = 0; /* run_pending_traps does this */
1216 catch_flag = 0;
1217 _run_trap_internal (SIGINT, "interrupt trap");
1220 /* Free all the allocated strings in the list of traps and reset the trap
1221 values to the default. Intended to be called from subshells that want
1222 to complete work done by reset_signal_handlers upon execution of a
1223 subsequent `trap' command that changes a signal's disposition. We need
1224 to make sure that we duplicate the behavior of
1225 reset_or_restore_signal_handlers and not change the disposition of signals
1226 that are set to be ignored. */
1227 void
1228 free_trap_strings ()
1230 register int i;
1232 for (i = 0; i < NSIG; i++)
1234 if (trap_list[i] != (char *)IGNORE_SIG)
1235 free_trap_string (i);
1237 for (i = NSIG; i < BUSH_NSIG; i++)
1239 /* Don't free the trap string if the subshell inherited the trap */
1240 if ((sigmodes[i] & SIG_TRAPPED) == 0)
1242 free_trap_string (i);
1243 trap_list[i] = (char *)NULL;
1248 /* Free a trap command string associated with SIG without changing signal
1249 disposition. Intended to be called from free_trap_strings() */
1250 static void
1251 free_trap_string (sig)
1252 int sig;
1254 change_signal (sig, (char *)DEFAULT_SIG);
1255 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1258 /* Reset the handler for SIG to the original value but leave the trap string
1259 in place. */
1260 static void
1261 reset_signal (sig)
1262 int sig;
1264 set_signal_handler (sig, original_signals[sig]);
1265 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1268 /* Set the handler signal SIG to the original and free any trap
1269 command associated with it. */
1270 static void
1271 restore_signal (sig)
1272 int sig;
1274 set_signal_handler (sig, original_signals[sig]);
1275 change_signal (sig, (char *)DEFAULT_SIG);
1276 sigmodes[sig] &= ~SIG_TRAPPED;
1279 static void
1280 reset_or_restore_signal_handlers (reset)
1281 sh_resetsig_func_t *reset;
1283 register int i;
1285 /* Take care of the exit trap first */
1286 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
1288 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1289 if (reset != reset_signal)
1291 free_trap_command (EXIT_TRAP);
1292 trap_list[EXIT_TRAP] = (char *)NULL;
1296 for (i = 1; i < NSIG; i++)
1298 if (sigmodes[i] & SIG_TRAPPED)
1300 if (trap_list[i] == (char *)IGNORE_SIG)
1301 set_signal_handler (i, SIG_IGN);
1302 else
1303 (*reset) (i);
1305 else if (sigmodes[i] & SIG_SPECIAL)
1306 (*reset) (i);
1307 pending_traps[i] = 0; /* XXX */
1310 /* Command substitution and other child processes don't inherit the
1311 debug, error, or return traps. If we're in the debugger, and the
1312 `functrace' or `errtrace' options have been set, then let command
1313 substitutions inherit them. Let command substitution inherit the
1314 RETURN trap if we're in the debugger and tracing functions. */
1315 if (function_trace_mode == 0)
1317 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
1318 sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
1320 if (error_trace_mode == 0)
1321 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
1324 /* Reset trapped signals to their original values, but don't free the
1325 trap strings. Called by the command substitution code and other places
1326 that create a "subshell environment". */
1327 void
1328 reset_signal_handlers ()
1330 reset_or_restore_signal_handlers (reset_signal);
1333 /* Reset all trapped signals to their original values. Signals set to be
1334 ignored with trap '' SIGNAL should be ignored, so we make sure that they
1335 are. Called by child processes after they are forked. */
1336 void
1337 restore_original_signals ()
1339 reset_or_restore_signal_handlers (restore_signal);
1342 /* If a trap handler exists for signal SIG, then call it; otherwise just
1343 return failure. Returns 1 if it called the trap handler. */
1345 maybe_call_trap_handler (sig)
1346 int sig;
1348 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1349 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
1351 switch (sig)
1353 case SIGINT:
1354 run_interrupt_trap (0);
1355 break;
1356 case EXIT_TRAP:
1357 run_exit_trap ();
1358 break;
1359 case DEBUG_TRAP:
1360 run_debug_trap ();
1361 break;
1362 case ERROR_TRAP:
1363 run_error_trap ();
1364 break;
1365 default:
1366 trap_handler (sig);
1367 break;
1369 return (1);
1371 else
1372 return (0);
1376 signal_is_trapped (sig)
1377 int sig;
1379 return (sigmodes[sig] & SIG_TRAPPED);
1383 signal_is_pending (sig)
1384 int sig;
1386 return (pending_traps[sig]);
1390 signal_is_special (sig)
1391 int sig;
1393 return (sigmodes[sig] & SIG_SPECIAL);
1397 signal_is_ignored (sig)
1398 int sig;
1400 return (sigmodes[sig] & SIG_IGNORED);
1404 signal_is_hard_ignored (sig)
1405 int sig;
1407 return (sigmodes[sig] & SIG_HARD_IGNORE);
1410 void
1411 set_signal_hard_ignored (sig)
1412 int sig;
1414 sigmodes[sig] |= SIG_HARD_IGNORE;
1415 original_signals[sig] = SIG_IGN;
1418 void
1419 set_signal_ignored (sig)
1420 int sig;
1422 original_signals[sig] = SIG_IGN;
1426 signal_in_progress (sig)
1427 int sig;
1429 return (sigmodes[sig] & SIG_INPROGRESS);
1432 #if 0 /* TAG: bush-5.2 */
1434 block_trapped_signals (maskp, omaskp)
1435 sigset_t *maskp;
1436 sigset_t *omaskp;
1438 int i;
1440 sigemptyset (maskp);
1441 for (i = 1; i < NSIG; i++)
1442 if (sigmodes[i] & SIG_TRAPPED)
1443 sigaddset (maskp, i);
1444 return (sigprocmask (SIG_BLOCK, maskp, omaskp));
1448 unblock_trapped_signals (maskp)
1449 sigset_t *maskp;
1451 return (sigprocmask (SIG_SETMASK, maskp, 0));
1453 #endif