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