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