]> git.ipfire.org Git - thirdparty/bash.git/blob - trap.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/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 }