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