1/* trap.c -- Not the trap command, but useful functions for manipulating
2   those objects.  The trap command is in builtins/trap.def. */
3
4/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
5
6   This file is part of GNU Bash, the Bourne Again SHell.
7
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 2, or (at your option) any later
11   version.
12
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
16   for more details.
17
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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
21
22#include "config.h"
23
24#if defined (HAVE_UNISTD_H)
25#  include <unistd.h>
26#endif
27
28#include "bashtypes.h"
29#include "bashansi.h"
30
31#include <stdio.h>
32#include <errno.h>
33
34#include "bashintl.h"
35
36#include "trap.h"
37
38#include "shell.h"
39#include "flags.h"
40#include "input.h"	/* for save_token_state, restore_token_state */
41#include "signames.h"
42#include "builtins.h"
43#include "builtins/common.h"
44#include "builtins/builtext.h"
45
46#ifndef errno
47extern int errno;
48#endif
49
50/* Flags which describe the current handling state of a signal. */
51#define SIG_INHERITED   0x0	/* Value inherited from parent. */
52#define SIG_TRAPPED     0x1	/* Currently trapped. */
53#define SIG_HARD_IGNORE 0x2	/* Signal was ignored on shell entry. */
54#define SIG_SPECIAL     0x4	/* Treat this signal specially. */
55#define SIG_NO_TRAP     0x8	/* Signal cannot be trapped. */
56#define SIG_INPROGRESS	0x10	/* Signal handler currently executing. */
57#define SIG_CHANGED	0x20	/* Trap value changed in trap handler. */
58#define SIG_IGNORED	0x40	/* The signal is currently being ignored. */
59
60#define SPECIAL_TRAP(s)	((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
61
62/* An array of such flags, one for each signal, describing what the
63   shell will do with a signal.  DEBUG_TRAP == NSIG; some code below
64   assumes this. */
65static int sigmodes[BASH_NSIG];
66
67static void free_trap_command __P((int));
68static void change_signal __P((int, char *));
69
70static void get_original_signal __P((int));
71
72static int _run_trap_internal __P((int, char *));
73
74static void reset_signal __P((int));
75static void restore_signal __P((int));
76static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
77
78/* Variables used here but defined in other files. */
79extern int last_command_exit_value;
80extern int line_number;
81
82extern char *this_command_name;
83extern sh_builtin_func_t *this_shell_builtin;
84extern procenv_t wait_intr_buf;
85extern int return_catch_flag, return_catch_value;
86extern int subshell_level;
87
88/* The list of things to do originally, before we started trapping. */
89SigHandler *original_signals[NSIG];
90
91/* For each signal, a slot for a string, which is a command to be
92   executed when that signal is recieved.  The slot can also contain
93   DEFAULT_SIG, which means do whatever you were going to do before
94   you were so rudely interrupted, or IGNORE_SIG, which says ignore
95   this signal. */
96char *trap_list[BASH_NSIG];
97
98/* A bitmap of signals received for which we have trap handlers. */
99int pending_traps[NSIG];
100
101/* Set to the number of the signal we're running the trap for + 1.
102   Used in execute_cmd.c and builtins/common.c to clean up when
103   parse_and_execute does not return normally after executing the
104   trap command (e.g., when `return' is executed in the trap command). */
105int running_trap;
106
107/* Set to last_command_exit_value before running a trap. */
108int trap_saved_exit_value;
109
110/* The (trapped) signal received while executing in the `wait' builtin */
111int wait_signal_received;
112
113/* A value which can never be the target of a trap handler. */
114#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
115
116#define GETORIGSIG(sig) \
117  do { \
118    original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
119    set_signal_handler (sig, original_signals[sig]); \
120    if (original_signals[sig] == SIG_IGN) \
121      sigmodes[sig] |= SIG_HARD_IGNORE; \
122  } while (0)
123
124#define GET_ORIGINAL_SIGNAL(sig) \
125  if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
126    GETORIGSIG(sig)
127
128void
129initialize_traps ()
130{
131  register int i;
132
133  initialize_signames();
134
135  trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
136  sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED;
137  original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
138
139  for (i = 1; i < NSIG; i++)
140    {
141      pending_traps[i] = 0;
142      trap_list[i] = (char *)DEFAULT_SIG;
143      sigmodes[i] = SIG_INHERITED;
144      original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
145    }
146
147  /* Show which signals are treated specially by the shell. */
148#if defined (SIGCHLD)
149  GETORIGSIG (SIGCHLD);
150  sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
151#endif /* SIGCHLD */
152
153  GETORIGSIG (SIGINT);
154  sigmodes[SIGINT] |= SIG_SPECIAL;
155
156#if defined (__BEOS__)
157  /* BeOS sets SIGINT to SIG_IGN! */
158  original_signals[SIGINT] = SIG_DFL;
159  sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
160#endif
161
162  GETORIGSIG (SIGQUIT);
163  sigmodes[SIGQUIT] |= SIG_SPECIAL;
164
165  if (interactive)
166    {
167      GETORIGSIG (SIGTERM);
168      sigmodes[SIGTERM] |= SIG_SPECIAL;
169    }
170}
171
172#ifdef INCLUDE_UNUSED
173/* Return a printable representation of the trap handler for SIG. */
174static char *
175trap_handler_string (sig)
176     int sig;
177{
178  if (trap_list[sig] == (char *)DEFAULT_SIG)
179    return "DEFAULT_SIG";
180  else if (trap_list[sig] == (char *)IGNORE_SIG)
181    return "IGNORE_SIG";
182  else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
183    return "IMPOSSIBLE_TRAP_HANDLER";
184  else if (trap_list[sig])
185    return trap_list[sig];
186  else
187    return "NULL";
188}
189#endif
190
191/* Return the print name of this signal. */
192char *
193signal_name (sig)
194     int sig;
195{
196  char *ret;
197
198  /* on cygwin32, signal_names[sig] could be null */
199  ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL)
200	? _("invalid signal number")
201	: signal_names[sig];
202
203  return ret;
204}
205
206/* Turn a string into a signal number, or a number into
207   a signal number.  If STRING is "2", "SIGINT", or "INT",
208   then (int)2 is returned.  Return NO_SIG if STRING doesn't
209   contain a valid signal descriptor. */
210int
211decode_signal (string, flags)
212     char *string;
213     int flags;
214{
215  intmax_t sig;
216  char *name;
217
218  if (legal_number (string, &sig))
219    return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
220
221  /* A leading `SIG' may be omitted. */
222  for (sig = 0; sig < BASH_NSIG; sig++)
223    {
224      name = signal_names[sig];
225      if (name == 0 || name[0] == '\0')
226	continue;
227
228      /* Check name without the SIG prefix first case sensitivly or
229	 insensitively depending on whether flags includes DSIG_NOCASE */
230      if (STREQN (name, "SIG", 3))
231	{
232	  name += 3;
233
234	  if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
235	    return ((int)sig);
236	  else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
237	    return ((int)sig);
238	  /* If we can't use the `SIG' prefix to match, punt on this
239	     name now. */
240	  else if ((flags & DSIG_SIGPREFIX) == 0)
241	    continue;
242	}
243
244      /* Check name with SIG prefix case sensitively or insensitively
245	 depending on whether flags includes DSIG_NOCASE */
246      name = signal_names[sig];
247      if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
248	return ((int)sig);
249      else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
250	return ((int)sig);
251    }
252
253  return (NO_SIG);
254}
255
256/* Non-zero when we catch a trapped signal. */
257static int catch_flag;
258
259void
260run_pending_traps ()
261{
262  register int sig;
263  int old_exit_value, *token_state;
264
265  if (catch_flag == 0)		/* simple optimization */
266    return;
267
268  catch_flag = 0;
269
270  /* Preserve $? when running trap. */
271  old_exit_value = last_command_exit_value;
272
273  for (sig = 1; sig < NSIG; sig++)
274    {
275      /* XXX this could be made into a counter by using
276	 while (pending_traps[sig]--) instead of the if statement. */
277      if (pending_traps[sig])
278	{
279#if defined (HAVE_POSIX_SIGNALS)
280	  sigset_t set, oset;
281
282	  sigemptyset (&set);
283	  sigemptyset (&oset);
284
285	  sigaddset (&set, sig);
286	  sigprocmask (SIG_BLOCK, &set, &oset);
287#else
288#  if defined (HAVE_BSD_SIGNALS)
289	  int oldmask = sigblock (sigmask (sig));
290#  endif
291#endif /* HAVE_POSIX_SIGNALS */
292
293	  if (sig == SIGINT)
294	    {
295	      run_interrupt_trap ();
296	      CLRINTERRUPT;
297	    }
298	  else if (trap_list[sig] == (char *)DEFAULT_SIG ||
299		   trap_list[sig] == (char *)IGNORE_SIG ||
300		   trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
301	    {
302	      /* This is possible due to a race condition.  Say a bash
303		 process has SIGTERM trapped.  A subshell is spawned
304		 using { list; } & and the parent does something and kills
305		 the subshell with SIGTERM.  It's possible for the subshell
306		 to set pending_traps[SIGTERM] to 1 before the code in
307		 execute_cmd.c eventually calls restore_original_signals
308		 to reset the SIGTERM signal handler in the subshell.  The
309		 next time run_pending_traps is called, pending_traps[SIGTERM]
310		 will be 1, but the trap handler in trap_list[SIGTERM] will
311		 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
312		 Unless we catch this, the subshell will dump core when
313		 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
314		 usually 0x0. */
315	      internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
316				sig, trap_list[sig]);
317	      if (trap_list[sig] == (char *)DEFAULT_SIG)
318		{
319		  internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig));
320		  kill (getpid (), sig);
321		}
322	    }
323	  else
324	    {
325	      token_state = save_token_state ();
326	      parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST);
327	      restore_token_state (token_state);
328	      free (token_state);
329	    }
330
331	  pending_traps[sig] = 0;
332
333#if defined (HAVE_POSIX_SIGNALS)
334	  sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
335#else
336#  if defined (HAVE_BSD_SIGNALS)
337	  sigsetmask (oldmask);
338#  endif
339#endif /* POSIX_VERSION */
340	}
341    }
342
343  last_command_exit_value = old_exit_value;
344}
345
346sighandler
347trap_handler (sig)
348     int sig;
349{
350  int oerrno;
351
352  if ((sig >= NSIG) ||
353      (trap_list[sig] == (char *)DEFAULT_SIG) ||
354      (trap_list[sig] == (char *)IGNORE_SIG))
355    programming_error (_("trap_handler: bad signal %d"), sig);
356  else
357    {
358      oerrno = errno;
359#if defined (MUST_REINSTALL_SIGHANDLERS)
360      set_signal_handler (sig, trap_handler);
361#endif /* MUST_REINSTALL_SIGHANDLERS */
362
363      catch_flag = 1;
364      pending_traps[sig]++;
365
366      if (interrupt_immediately && this_shell_builtin && (this_shell_builtin == wait_builtin))
367	{
368	  wait_signal_received = sig;
369	  longjmp (wait_intr_buf, 1);
370	}
371
372      if (interrupt_immediately)
373	run_pending_traps ();
374
375      errno = oerrno;
376    }
377
378  SIGRETURN (0);
379}
380
381#if defined (JOB_CONTROL) && defined (SIGCHLD)
382
383#ifdef INCLUDE_UNUSED
384/* Make COMMAND_STRING be executed when SIGCHLD is caught. */
385void
386set_sigchld_trap (command_string)
387     char *command_string;
388{
389  set_signal (SIGCHLD, command_string);
390}
391#endif
392
393/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
394   is not already trapped. */
395void
396maybe_set_sigchld_trap (command_string)
397     char *command_string;
398{
399  if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
400    set_signal (SIGCHLD, command_string);
401}
402#endif /* JOB_CONTROL && SIGCHLD */
403
404void
405set_debug_trap (command)
406     char *command;
407{
408  set_signal (DEBUG_TRAP, command);
409}
410
411void
412set_error_trap (command)
413     char *command;
414{
415  set_signal (ERROR_TRAP, command);
416}
417
418void
419set_return_trap (command)
420     char *command;
421{
422  set_signal (RETURN_TRAP, command);
423}
424
425#ifdef INCLUDE_UNUSED
426void
427set_sigint_trap (command)
428     char *command;
429{
430  set_signal (SIGINT, command);
431}
432#endif
433
434/* Reset the SIGINT handler so that subshells that are doing `shellsy'
435   things, like waiting for command substitution or executing commands
436   in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
437SigHandler *
438set_sigint_handler ()
439{
440  if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
441    return ((SigHandler *)SIG_IGN);
442
443  else if (sigmodes[SIGINT] & SIG_IGNORED)
444    return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
445
446  else if (sigmodes[SIGINT] & SIG_TRAPPED)
447    return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
448
449  /* The signal is not trapped, so set the handler to the shell's special
450     interrupt handler. */
451  else if (interactive)	/* XXX - was interactive_shell */
452    return (set_signal_handler (SIGINT, sigint_sighandler));
453  else
454    return (set_signal_handler (SIGINT, termsig_sighandler));
455}
456
457/* Return the correct handler for signal SIG according to the values in
458   sigmodes[SIG]. */
459SigHandler *
460trap_to_sighandler (sig)
461     int sig;
462{
463  if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
464    return (SIG_IGN);
465  else if (sigmodes[sig] & SIG_TRAPPED)
466    return (trap_handler);
467  else
468    return (SIG_DFL);
469}
470
471/* Set SIG to call STRING as a command. */
472void
473set_signal (sig, string)
474     int sig;
475     char *string;
476{
477  if (SPECIAL_TRAP (sig))
478    {
479      change_signal (sig, savestring (string));
480      if (sig == EXIT_TRAP && interactive == 0)
481	initialize_terminating_signals ();
482      return;
483    }
484
485  /* A signal ignored on entry to the shell cannot be trapped or reset, but
486     no error is reported when attempting to do so.  -- Posix.2 */
487  if (sigmodes[sig] & SIG_HARD_IGNORE)
488    return;
489
490  /* Make sure we have original_signals[sig] if the signal has not yet
491     been trapped. */
492  if ((sigmodes[sig] & SIG_TRAPPED) == 0)
493    {
494      /* If we aren't sure of the original value, check it. */
495      if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
496        GETORIGSIG (sig);
497      if (original_signals[sig] == SIG_IGN)
498	return;
499    }
500
501  /* Only change the system signal handler if SIG_NO_TRAP is not set.
502     The trap command string is changed in either case.  The shell signal
503     handlers for SIGINT and SIGCHLD run the user specified traps in an
504     environment in which it is safe to do so. */
505  if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
506    {
507      set_signal_handler (sig, SIG_IGN);
508      change_signal (sig, savestring (string));
509      set_signal_handler (sig, trap_handler);
510    }
511  else
512    change_signal (sig, savestring (string));
513}
514
515static void
516free_trap_command (sig)
517     int sig;
518{
519  if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
520      (trap_list[sig] != (char *)IGNORE_SIG) &&
521      (trap_list[sig] != (char *)DEFAULT_SIG) &&
522      (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
523    free (trap_list[sig]);
524}
525
526/* If SIG has a string assigned to it, get rid of it.  Then give it
527   VALUE. */
528static void
529change_signal (sig, value)
530     int sig;
531     char *value;
532{
533  if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
534    free_trap_command (sig);
535  trap_list[sig] = value;
536
537  sigmodes[sig] |= SIG_TRAPPED;
538  if (value == (char *)IGNORE_SIG)
539    sigmodes[sig] |= SIG_IGNORED;
540  else
541    sigmodes[sig] &= ~SIG_IGNORED;
542  if (sigmodes[sig] & SIG_INPROGRESS)
543    sigmodes[sig] |= SIG_CHANGED;
544}
545
546static void
547get_original_signal (sig)
548     int sig;
549{
550  /* If we aren't sure the of the original value, then get it. */
551  if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
552    GETORIGSIG (sig);
553}
554
555/* Restore the default action for SIG; i.e., the action the shell
556   would have taken before you used the trap command.  This is called
557   from trap_builtin (), which takes care to restore the handlers for
558   the signals the shell treats specially. */
559void
560restore_default_signal (sig)
561     int sig;
562{
563  if (SPECIAL_TRAP (sig))
564    {
565      if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
566	  (sigmodes[sig] & SIG_INPROGRESS) == 0)
567	free_trap_command (sig);
568      trap_list[sig] = (char *)NULL;
569      sigmodes[sig] &= ~SIG_TRAPPED;
570      if (sigmodes[sig] & SIG_INPROGRESS)
571	sigmodes[sig] |= SIG_CHANGED;
572      return;
573    }
574
575  GET_ORIGINAL_SIGNAL (sig);
576
577  /* A signal ignored on entry to the shell cannot be trapped or reset, but
578     no error is reported when attempting to do so.  Thanks Posix.2. */
579  if (sigmodes[sig] & SIG_HARD_IGNORE)
580    return;
581
582  /* If we aren't trapping this signal, don't bother doing anything else. */
583  if ((sigmodes[sig] & SIG_TRAPPED) == 0)
584    return;
585
586  /* Only change the signal handler for SIG if it allows it. */
587  if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
588    set_signal_handler (sig, original_signals[sig]);
589
590  /* Change the trap command in either case. */
591  change_signal (sig, (char *)DEFAULT_SIG);
592
593  /* Mark the signal as no longer trapped. */
594  sigmodes[sig] &= ~SIG_TRAPPED;
595}
596
597/* Make this signal be ignored. */
598void
599ignore_signal (sig)
600     int sig;
601{
602  if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
603    {
604      change_signal (sig, (char *)IGNORE_SIG);
605      return;
606    }
607
608  GET_ORIGINAL_SIGNAL (sig);
609
610  /* A signal ignored on entry to the shell cannot be trapped or reset.
611     No error is reported when the user attempts to do so. */
612  if (sigmodes[sig] & SIG_HARD_IGNORE)
613    return;
614
615  /* If already trapped and ignored, no change necessary. */
616  if (sigmodes[sig] & SIG_IGNORED)
617    return;
618
619  /* Only change the signal handler for SIG if it allows it. */
620  if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
621    set_signal_handler (sig, SIG_IGN);
622
623  /* Change the trap command in either case. */
624  change_signal (sig, (char *)IGNORE_SIG);
625}
626
627/* Handle the calling of "trap 0".  The only sticky situation is when
628   the command to be executed includes an "exit".  This is why we have
629   to provide our own place for top_level to jump to. */
630int
631run_exit_trap ()
632{
633  char *trap_command;
634  int code, function_code, retval;
635
636  trap_saved_exit_value = last_command_exit_value;
637  function_code = 0;
638
639  /* Run the trap only if signal 0 is trapped and not ignored, and we are not
640     currently running in the trap handler (call to exit in the list of
641     commands given to trap 0). */
642  if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
643      (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
644    {
645      trap_command = savestring (trap_list[EXIT_TRAP]);
646      sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
647      sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
648
649      retval = trap_saved_exit_value;
650      running_trap = 1;
651
652      code = setjmp (top_level);
653
654      /* If we're in a function, make sure return longjmps come here, too. */
655      if (return_catch_flag)
656	function_code = setjmp (return_catch);
657
658      if (code == 0 && function_code == 0)
659	{
660	  reset_parser ();
661	  parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST);
662	}
663      else if (code == ERREXIT)
664	retval = last_command_exit_value;
665      else if (code == EXITPROG)
666	retval = last_command_exit_value;
667      else if (function_code != 0)
668        retval = return_catch_value;
669      else
670	retval = trap_saved_exit_value;
671
672      running_trap = 0;
673      return retval;
674    }
675
676  return (trap_saved_exit_value);
677}
678
679void
680run_trap_cleanup (sig)
681     int sig;
682{
683  sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
684}
685
686/* Run a trap command for SIG.  SIG is one of the signals the shell treats
687   specially.  Returns the exit status of the executed trap command list. */
688static int
689_run_trap_internal (sig, tag)
690     int sig;
691     char *tag;
692{
693  char *trap_command, *old_trap;
694  int trap_exit_value, *token_state;
695  int save_return_catch_flag, function_code;
696  procenv_t save_return_catch;
697
698  trap_exit_value = function_code = 0;
699  /* Run the trap only if SIG is trapped and not ignored, and we are not
700     currently executing in the trap handler. */
701  if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
702      (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
703      ((sigmodes[sig] & SIG_INPROGRESS) == 0))
704    {
705      old_trap = trap_list[sig];
706      sigmodes[sig] |= SIG_INPROGRESS;
707      sigmodes[sig] &= ~SIG_CHANGED;		/* just to be sure */
708      trap_command =  savestring (old_trap);
709
710      running_trap = sig + 1;
711      trap_saved_exit_value = last_command_exit_value;
712
713      token_state = save_token_state ();
714
715      /* If we're in a function, make sure return longjmps come here, too. */
716      save_return_catch_flag = return_catch_flag;
717      if (return_catch_flag)
718	{
719	  COPY_PROCENV (return_catch, save_return_catch);
720	  function_code = setjmp (return_catch);
721	}
722
723      if (function_code == 0)
724	parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST);
725
726      restore_token_state (token_state);
727      free (token_state);
728
729      trap_exit_value = last_command_exit_value;
730      last_command_exit_value = trap_saved_exit_value;
731      running_trap = 0;
732
733      sigmodes[sig] &= ~SIG_INPROGRESS;
734
735      if (sigmodes[sig] & SIG_CHANGED)
736	{
737#if 0
738	  /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
739	     the places where they can be changed using unwind-protects.  For
740	     example, look at execute_cmd.c:execute_function(). */
741	  if (SPECIAL_TRAP (sig) == 0)
742#endif
743	    free (old_trap);
744	  sigmodes[sig] &= ~SIG_CHANGED;
745	}
746
747      if (save_return_catch_flag)
748	{
749	  return_catch_flag = save_return_catch_flag;
750	  return_catch_value = trap_exit_value;
751	  COPY_PROCENV (save_return_catch, return_catch);
752	  if (function_code)
753	    longjmp (return_catch, 1);
754	}
755    }
756
757  return trap_exit_value;
758}
759
760int
761run_debug_trap ()
762{
763  int trap_exit_value;
764
765  /* XXX - question:  should the DEBUG trap inherit the RETURN trap? */
766  trap_exit_value = 0;
767  if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
768    {
769      trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
770
771#if defined (DEBUGGER)
772      /* If we're in the debugger and the DEBUG trap returns 2 while we're in
773	 a function or sourced script, we force a `return'. */
774      if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
775	{
776	  return_catch_value = trap_exit_value;
777	  longjmp (return_catch, 1);
778	}
779#endif
780    }
781  return trap_exit_value;
782}
783
784void
785run_error_trap ()
786{
787  if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
788    _run_trap_internal (ERROR_TRAP, "error trap");
789}
790
791void
792run_return_trap ()
793{
794  int old_exit_value;
795
796#if 0
797  if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
798    return;
799#endif
800
801  if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
802    {
803      old_exit_value = last_command_exit_value;
804      _run_trap_internal (RETURN_TRAP, "return trap");
805      last_command_exit_value = old_exit_value;
806    }
807}
808
809/* Run a trap set on SIGINT.  This is called from throw_to_top_level (), and
810   declared here to localize the trap functions. */
811void
812run_interrupt_trap ()
813{
814  _run_trap_internal (SIGINT, "interrupt trap");
815}
816
817#ifdef INCLUDE_UNUSED
818/* Free all the allocated strings in the list of traps and reset the trap
819   values to the default. */
820void
821free_trap_strings ()
822{
823  register int i;
824
825  for (i = 0; i < BASH_NSIG; i++)
826    {
827      free_trap_command (i);
828      trap_list[i] = (char *)DEFAULT_SIG;
829      sigmodes[i] &= ~SIG_TRAPPED;
830    }
831  trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
832}
833#endif
834
835/* Reset the handler for SIG to the original value. */
836static void
837reset_signal (sig)
838     int sig;
839{
840  set_signal_handler (sig, original_signals[sig]);
841  sigmodes[sig] &= ~SIG_TRAPPED;
842}
843
844/* Set the handler signal SIG to the original and free any trap
845   command associated with it. */
846static void
847restore_signal (sig)
848     int sig;
849{
850  set_signal_handler (sig, original_signals[sig]);
851  change_signal (sig, (char *)DEFAULT_SIG);
852  sigmodes[sig] &= ~SIG_TRAPPED;
853}
854
855static void
856reset_or_restore_signal_handlers (reset)
857     sh_resetsig_func_t *reset;
858{
859  register int i;
860
861  /* Take care of the exit trap first */
862  if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
863    {
864      sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
865      if (reset != reset_signal)
866	{
867	  free_trap_command (EXIT_TRAP);
868	  trap_list[EXIT_TRAP] = (char *)NULL;
869	}
870    }
871
872  for (i = 1; i < NSIG; i++)
873    {
874      if (sigmodes[i] & SIG_TRAPPED)
875	{
876	  if (trap_list[i] == (char *)IGNORE_SIG)
877	    set_signal_handler (i, SIG_IGN);
878	  else
879	    (*reset) (i);
880	}
881      else if (sigmodes[i] & SIG_SPECIAL)
882	(*reset) (i);
883    }
884
885  /* Command substitution and other child processes don't inherit the
886     debug, error, or return traps.  If we're in the debugger, and the
887     `functrace' or `errtrace' options have been set, then let command
888     substitutions inherit them.  Let command substitution inherit the
889     RETURN trap if we're in the debugger and tracing functions. */
890  if (function_trace_mode == 0)
891    {
892      sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
893      sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
894    }
895  if (error_trace_mode == 0)
896    sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
897}
898
899/* Reset trapped signals to their original values, but don't free the
900   trap strings.  Called by the command substitution code. */
901void
902reset_signal_handlers ()
903{
904  reset_or_restore_signal_handlers (reset_signal);
905}
906
907/* Reset all trapped signals to their original values.  Signals set to be
908   ignored with trap '' SIGNAL should be ignored, so we make sure that they
909   are.  Called by child processes after they are forked. */
910void
911restore_original_signals ()
912{
913  reset_or_restore_signal_handlers (restore_signal);
914}
915
916/* If a trap handler exists for signal SIG, then call it; otherwise just
917   return failure. */
918int
919maybe_call_trap_handler (sig)
920     int sig;
921{
922  /* Call the trap handler for SIG if the signal is trapped and not ignored. */
923  if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
924    {
925      switch (sig)
926	{
927	case SIGINT:
928	  run_interrupt_trap ();
929	  break;
930	case EXIT_TRAP:
931	  run_exit_trap ();
932	  break;
933	case DEBUG_TRAP:
934	  run_debug_trap ();
935	  break;
936	case ERROR_TRAP:
937	  run_error_trap ();
938	  break;
939	default:
940	  trap_handler (sig);
941	  break;
942	}
943      return (1);
944    }
945  else
946    return (0);
947}
948
949int
950signal_is_trapped (sig)
951     int sig;
952{
953  return (sigmodes[sig] & SIG_TRAPPED);
954}
955
956int
957signal_is_special (sig)
958     int sig;
959{
960  return (sigmodes[sig] & SIG_SPECIAL);
961}
962
963int
964signal_is_ignored (sig)
965     int sig;
966{
967  return (sigmodes[sig] & SIG_IGNORED);
968}
969
970void
971set_signal_ignored (sig)
972     int sig;
973{
974  sigmodes[sig] |= SIG_HARD_IGNORE;
975  original_signals[sig] = SIG_IGN;
976}
977
978int
979signal_in_progress (sig)
980     int sig;
981{
982  return (sigmodes[sig] & SIG_INPROGRESS);
983}
984