]> git.ipfire.org Git - thirdparty/bash.git/blob - trap.c
Imported from ../bash-3.2.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-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
47 extern 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. */
65 static int sigmodes[BASH_NSIG];
66
67 static void free_trap_command __P((int));
68 static void change_signal __P((int, char *));
69
70 static void get_original_signal __P((int));
71
72 static int _run_trap_internal __P((int, char *));
73
74 static void reset_signal __P((int));
75 static void restore_signal __P((int));
76 static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
77
78 /* Variables used here but defined in other files. */
79 extern int last_command_exit_value;
80 extern int line_number;
81
82 extern char *this_command_name;
83 extern sh_builtin_func_t *this_shell_builtin;
84 extern procenv_t wait_intr_buf;
85 extern int return_catch_flag, return_catch_value;
86 extern int subshell_level;
87
88 /* The list of things to do originally, before we started trapping. */
89 SigHandler *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. */
96 char *trap_list[BASH_NSIG];
97
98 /* A bitmap of signals received for which we have trap handlers. */
99 int 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). */
105 int running_trap;
106
107 /* Set to last_command_exit_value before running a trap. */
108 int trap_saved_exit_value;
109
110 /* The (trapped) signal received while executing in the `wait' builtin */
111 int 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
128 void
129 initialize_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. */
174 static char *
175 trap_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. */
192 char *
193 signal_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. */
210 int
211 decode_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. */
257 static int catch_flag;
258
259 void
260 run_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
346 sighandler
347 trap_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. */
385 void
386 set_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. */
395 void
396 maybe_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
404 void
405 set_debug_trap (command)
406 char *command;
407 {
408 set_signal (DEBUG_TRAP, command);
409 }
410
411 void
412 set_error_trap (command)
413 char *command;
414 {
415 set_signal (ERROR_TRAP, command);
416 }
417
418 void
419 set_return_trap (command)
420 char *command;
421 {
422 set_signal (RETURN_TRAP, command);
423 }
424
425 #ifdef INCLUDE_UNUSED
426 void
427 set_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. */
437 SigHandler *
438 set_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]. */
459 SigHandler *
460 trap_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. */
472 void
473 set_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
515 static void
516 free_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. */
528 static void
529 change_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
546 static void
547 get_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. */
559 void
560 restore_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. */
598 void
599 ignore_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. */
630 int
631 run_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
679 void
680 run_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. */
688 static 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
760 int
761 run_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
784 void
785 run_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
791 void
792 run_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. */
811 void
812 run_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. */
820 void
821 free_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. */
836 static void
837 reset_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. */
846 static void
847 restore_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
855 static void
856 reset_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. */
901 void
902 reset_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. */
910 void
911 restore_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. */
918 int
919 maybe_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
949 int
950 signal_is_trapped (sig)
951 int sig;
952 {
953 return (sigmodes[sig] & SIG_TRAPPED);
954 }
955
956 int
957 signal_is_special (sig)
958 int sig;
959 {
960 return (sigmodes[sig] & SIG_SPECIAL);
961 }
962
963 int
964 signal_is_ignored (sig)
965 int sig;
966 {
967 return (sigmodes[sig] & SIG_IGNORED);
968 }
969
970 void
971 set_signal_ignored (sig)
972 int sig;
973 {
974 sigmodes[sig] |= SIG_HARD_IGNORE;
975 original_signals[sig] = SIG_IGN;
976 }
977
978 int
979 signal_in_progress (sig)
980 int sig;
981 {
982 return (sigmodes[sig] & SIG_INPROGRESS);
983 }