]> git.ipfire.org Git - thirdparty/bash.git/blob - trap.c
allow some job notifications while running $PROMPT_COMMAND; allow notifications while...
[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-2023 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 <signal.h>
37
38 #include "trap.h"
39
40 #include "shell.h"
41 #include "execute_cmd.h"
42 #include "flags.h"
43 #include "parser.h"
44 #include "input.h" /* for save_token_state, restore_token_state */
45 #include "jobs.h"
46 #include "signames.h"
47 #include "builtins.h"
48 #include "builtins/common.h"
49 #include "builtins/builtext.h"
50
51 #if defined (READLINE)
52 # include <readline/readline.h>
53 # include "bashline.h"
54 #endif
55
56 #ifndef errno
57 extern int errno;
58 #endif
59
60 /* Flags which describe the current handling state of a signal. */
61 #define SIG_INHERITED 0x0 /* Value inherited from parent. */
62 #define SIG_TRAPPED 0x1 /* Currently trapped. */
63 #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
64 #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
65 #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
66 #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
67 #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
68 #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
69 #define SIG_ASYNCSIG 0x80 /* The signal is ignored because it's in an asynchronous command. */
70
71 #define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
72
73 /* An array of such flags, one for each signal, describing what the
74 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
75 assumes this. */
76 static int sigmodes[BASH_NSIG];
77
78 static void free_trap_command (int);
79 static void change_signal (int, char *);
80
81 static int _run_trap_internal (int, char *);
82
83 static void free_trap_string (int);
84 static void reset_signal (int);
85 static void restore_signal (int);
86 static void reset_or_restore_signal_handlers (sh_resetsig_func_t *);
87 static void reinit_trap (int);
88
89 static void trap_if_untrapped (int, const char *);
90
91 /* Variables used here but defined in other files. */
92
93 extern volatile int from_return_trap;
94 extern int waiting_for_child;
95
96 extern WORD_LIST *subst_assign_varlist;
97
98 /* The list of things to do originally, before we started trapping. */
99 SigHandler *original_signals[NSIG];
100
101 /* For each signal, a slot for a string, which is a command to be
102 executed when that signal is received. The slot can also contain
103 DEFAULT_SIG, which means do whatever you were going to do before
104 you were so rudely interrupted, or IGNORE_SIG, which says ignore
105 this signal. */
106 char *trap_list[BASH_NSIG];
107
108 /* A bitmap of signals received for which we have trap handlers. */
109 int pending_traps[NSIG];
110
111 /* Set to the number of the signal we're running the trap for + 1.
112 Used in execute_cmd.c and builtins/common.c to clean up when
113 parse_and_execute does not return normally after executing the
114 trap command (e.g., when `return' is executed in the trap command). */
115 int running_trap;
116
117 /* The execution context (function/source execution level) when we began
118 running this trap command. This is used to determine whether we have
119 executed any shell functions or sourced files from the trap action, and
120 determines where `return' without arguments gets its return status. */
121 int trap_return_context;
122
123 /* Set to last_command_exit_value before running a trap. */
124 int trap_saved_exit_value;
125
126 /* The (trapped) signal received while executing in the `wait' builtin */
127 int wait_signal_received;
128
129 int trapped_signal_received;
130
131 /* Set to 1 to suppress the effect of `set v' in the DEBUG trap. */
132 int suppress_debug_trap_verbose = 0;
133
134 #define GETORIGSIG(sig) \
135 do { \
136 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
137 set_signal_handler (sig, original_signals[sig]); \
138 if (original_signals[sig] == SIG_IGN) \
139 sigmodes[sig] |= SIG_HARD_IGNORE; \
140 } while (0)
141
142 #define SETORIGSIG(sig,handler) \
143 do { \
144 original_signals[sig] = handler; \
145 if (original_signals[sig] == SIG_IGN) \
146 sigmodes[sig] |= SIG_HARD_IGNORE; \
147 } while (0)
148
149 #define GET_ORIGINAL_SIGNAL(sig) \
150 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
151 GETORIGSIG(sig)
152
153 void
154 initialize_traps (void)
155 {
156 register int i;
157
158 initialize_signames();
159
160 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
161 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED;
162 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
163
164 for (i = 1; i < NSIG; i++)
165 {
166 pending_traps[i] = 0;
167 trap_list[i] = (char *)DEFAULT_SIG;
168 sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
169 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
170 }
171
172 /* Show which signals are treated specially by the shell. */
173 #if defined (SIGCHLD)
174 GETORIGSIG (SIGCHLD);
175 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
176 #endif /* SIGCHLD */
177
178 GETORIGSIG (SIGINT);
179 sigmodes[SIGINT] |= SIG_SPECIAL;
180
181 #if defined (__BEOS__)
182 /* BeOS sets SIGINT to SIG_IGN! */
183 original_signals[SIGINT] = SIG_DFL;
184 sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
185 #endif
186
187 GETORIGSIG (SIGQUIT);
188 sigmodes[SIGQUIT] |= SIG_SPECIAL;
189
190 if (interactive)
191 {
192 GETORIGSIG (SIGTERM);
193 sigmodes[SIGTERM] |= SIG_SPECIAL;
194 }
195
196 get_original_tty_job_signals ();
197 }
198
199 #ifdef DEBUG
200 /* Return a printable representation of the trap handler for SIG. */
201 static char *
202 trap_handler_string (int sig)
203 {
204 if (trap_list[sig] == (char *)DEFAULT_SIG)
205 return "DEFAULT_SIG";
206 else if (trap_list[sig] == (char *)IGNORE_SIG)
207 return "IGNORE_SIG";
208 else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
209 return "IMPOSSIBLE_TRAP_HANDLER";
210 else if (trap_list[sig])
211 return trap_list[sig];
212 else
213 return "NULL";
214 }
215 #endif
216
217 /* Return the print name of this signal. */
218 char *
219 signal_name (int sig)
220 {
221 char *ret;
222
223 /* on cygwin32, signal_names[sig] could be null */
224 ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL)
225 ? _("invalid signal number")
226 : signal_names[sig];
227
228 return ret;
229 }
230
231 /* Turn a string into a signal number, or a number into
232 a signal number. If STRING is "2", "SIGINT", or "INT",
233 then (int)2 is returned. Return NO_SIG if STRING doesn't
234 contain a valid signal descriptor. */
235 int
236 decode_signal (const char *string, int flags)
237 {
238 intmax_t sig;
239 char *name;
240
241 if (valid_number (string, &sig))
242 return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
243
244 #if defined (SIGRTMIN) && defined (SIGRTMAX)
245 if (STREQN (string, "SIGRTMIN+", 9) || ((flags & DSIG_NOCASE) && strncasecmp (string, "SIGRTMIN+", 9) == 0))
246 {
247 if (valid_number (string+9, &sig) && sig >= 0 && sig <= SIGRTMAX - SIGRTMIN)
248 return (SIGRTMIN + sig);
249 else
250 return NO_SIG;
251 }
252 else if (STREQN (string, "RTMIN+", 6) || ((flags & DSIG_NOCASE) && strncasecmp (string, "RTMIN+", 6) == 0))
253 {
254 if (valid_number (string+6, &sig) && sig >= 0 && sig <= SIGRTMAX - SIGRTMIN)
255 return (SIGRTMIN + sig);
256 else
257 return NO_SIG;
258 }
259 #endif /* SIGRTMIN && SIGRTMAX */
260
261 /* A leading `SIG' may be omitted. */
262 for (sig = 0; sig < BASH_NSIG; sig++)
263 {
264 name = signal_names[sig];
265 if (name == 0 || name[0] == '\0')
266 continue;
267
268 /* Check name without the SIG prefix first case sensitively or
269 insensitively depending on whether flags includes DSIG_NOCASE */
270 if (STREQN (name, "SIG", 3))
271 {
272 name += 3;
273
274 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
275 return ((int)sig);
276 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
277 return ((int)sig);
278 /* If we can't use the `SIG' prefix to match, punt on this
279 name now. */
280 else if ((flags & DSIG_SIGPREFIX) == 0)
281 continue;
282 }
283
284 /* Check name with SIG prefix case sensitively or insensitively
285 depending on whether flags includes DSIG_NOCASE */
286 name = signal_names[sig];
287 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
288 return ((int)sig);
289 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
290 return ((int)sig);
291 }
292
293 return (NO_SIG);
294 }
295
296 static char *
297 save_bash_trapsig (void)
298 {
299 char *ret;
300
301 if (ret = get_string_value ("BASH_TRAPSIG"))
302 ret = savestring (ret);
303 return ret;
304 }
305
306 static void
307 set_bash_trapsig (int sig)
308 {
309 bind_var_to_int ("BASH_TRAPSIG", sig, 0);
310 }
311
312 static void
313 restore_bash_trapsig (char *oldval)
314 {
315 if (oldval == 0)
316 unbind_variable_noref ("BASH_TRAPSIG");
317 else
318 {
319 bind_variable ("BASH_TRAPSIG", oldval, 0);
320 free (oldval);
321 }
322 }
323
324 /* Non-zero when we catch a trapped signal. */
325 static int catch_flag;
326
327 void
328 run_pending_traps (void)
329 {
330 register int sig;
331 int x;
332 volatile int old_exit_value, old_running, old_context;
333 WORD_LIST *save_subst_varlist;
334 HASH_TABLE *save_tempenv;
335 sh_parser_state_t pstate;
336 volatile int save_return_catch_flag, function_code;
337 procenv_t save_return_catch;
338 char *trap_command, *old_trap;
339 char *old_trapsig;
340 #if defined (ARRAY_VARS)
341 ARRAY *ps;
342 #endif
343
344 if (catch_flag == 0) /* simple optimization */
345 return;
346
347 if (running_trap > 0)
348 {
349 internal_debug ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap-1);
350 #if defined (SIGWINCH)
351 if (running_trap == SIGWINCH+1 && pending_traps[SIGWINCH])
352 return; /* no recursive SIGWINCH trap invocations */
353 #endif
354 /* could check for running the trap handler for the same signal here
355 (running_trap == sig+1) */
356 if (evalnest_max > 0 && evalnest > evalnest_max)
357 {
358 internal_error (_("trap handler: maximum trap handler level exceeded (%d)"), evalnest_max);
359 evalnest = 0;
360 jump_to_top_level (DISCARD);
361 }
362 }
363
364 catch_flag = trapped_signal_received = 0;
365
366 /* Preserve $? when running trap. */
367 trap_saved_exit_value = old_exit_value = last_command_exit_value;
368 #if defined (ARRAY_VARS)
369 ps = save_pipestatus_array ();
370 #endif
371 old_running = running_trap;
372 old_context = trap_return_context;
373 old_trapsig = save_bash_trapsig ();
374
375 for (sig = 1; sig < NSIG; sig++)
376 {
377 /* XXX this could be made into a counter by using
378 while (pending_traps[sig]--) instead of the if statement. */
379 if (pending_traps[sig])
380 {
381 /* XXX - set last_command_exit_value = trap_saved_exit_value here? */
382 running_trap = sig + 1;
383 trap_return_context = funcnest + sourcenest;
384
385 set_bash_trapsig (sig);
386
387 if (sig == SIGINT)
388 {
389 pending_traps[sig] = 0; /* XXX */
390 /* We don't modify evalnest here, since run_interrupt_trap() calls
391 _run_trap_internal, which does. */
392 run_interrupt_trap (0);
393 CLRINTERRUPT; /* interrupts don't stack */
394 }
395 #if defined (JOB_CONTROL) && defined (SIGCHLD)
396 else if (sig == SIGCHLD &&
397 trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER &&
398 (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0)
399 {
400 sigmodes[SIGCHLD] |= SIG_INPROGRESS;
401 /* We modify evalnest here even though run_sigchld_trap can run
402 the trap action more than once */
403 evalnest++;
404 x = pending_traps[sig];
405 pending_traps[sig] = 0;
406 run_sigchld_trap (x); /* use as counter */
407 running_trap = 0;
408 evalnest--;
409 sigmodes[SIGCHLD] &= ~SIG_INPROGRESS;
410 /* continue here rather than reset pending_traps[SIGCHLD] below in
411 case there are recursive calls to run_pending_traps and children
412 have been reaped while run_sigchld_trap was running. */
413 continue;
414 }
415 else if (sig == SIGCHLD &&
416 trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER &&
417 (sigmodes[SIGCHLD] & SIG_INPROGRESS) != 0)
418 {
419 /* This can happen when run_pending_traps is called while
420 running a SIGCHLD trap handler. */
421 running_trap = 0;
422 /* want to leave pending_traps[SIGCHLD] alone here */
423 continue; /* XXX */
424 }
425 else if (sig == SIGCHLD && (sigmodes[SIGCHLD] & SIG_INPROGRESS))
426 {
427 /* whoops -- print warning? */
428 running_trap = 0; /* XXX */
429 /* want to leave pending_traps[SIGCHLD] alone here */
430 continue;
431 }
432 #endif
433 else if (trap_list[sig] == (char *)DEFAULT_SIG ||
434 trap_list[sig] == (char *)IGNORE_SIG ||
435 trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
436 {
437 /* This is possible due to a race condition. Say a bash
438 process has SIGTERM trapped. A subshell is spawned
439 using { list; } & and the parent does something and kills
440 the subshell with SIGTERM. It's possible for the subshell
441 to set pending_traps[SIGTERM] to 1 before the code in
442 execute_cmd.c eventually calls restore_original_signals
443 to reset the SIGTERM signal handler in the subshell. The
444 next time run_pending_traps is called, pending_traps[SIGTERM]
445 will be 1, but the trap handler in trap_list[SIGTERM] will
446 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
447 Unless we catch this, the subshell will dump core when
448 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
449 usually 0x0. */
450 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
451 sig, trap_list[sig]);
452 if (trap_list[sig] == (char *)DEFAULT_SIG)
453 {
454 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig));
455 kill (getpid (), sig);
456 }
457 }
458 else
459 {
460 /* XXX - why not set SIG_INPROGRESS, clear SIG_CHANGED here? */
461 old_trap = trap_list[sig];
462 trap_command = savestring (old_trap);
463
464 save_parser_state (&pstate);
465 save_subst_varlist = subst_assign_varlist;
466 subst_assign_varlist = 0;
467 save_tempenv = temporary_env;
468 temporary_env = 0; /* traps should not run with temporary env */
469
470 #if defined (JOB_CONTROL)
471 save_pipeline (1); /* XXX only provides one save level */
472 #endif
473 /* XXX - set pending_traps[sig] = 0 here? */
474 pending_traps[sig] = 0;
475 evalnest++;
476
477 function_code = 0;
478 save_return_catch_flag = return_catch_flag;
479 if (return_catch_flag)
480 {
481 COPY_PROCENV (return_catch, save_return_catch);
482 function_code = setjmp_nosigs (return_catch);
483 }
484
485 if (function_code == 0)
486 /* XXX is x always last_command_exit_value? */
487 x = parse_and_execute (trap_command, "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE|SEVAL_NOOPTIMIZE);
488 else
489 {
490 parse_and_execute_cleanup (sig + 1); /* XXX - could use -1 */
491 x = return_catch_value;
492 }
493
494 evalnest--;
495 #if defined (JOB_CONTROL)
496 restore_pipeline (1);
497 #endif
498
499 subst_assign_varlist = save_subst_varlist;
500 restore_parser_state (&pstate);
501 temporary_env = save_tempenv;
502
503 if (save_return_catch_flag)
504 {
505 return_catch_flag = save_return_catch_flag;
506 return_catch_value = x;
507 COPY_PROCENV (save_return_catch, return_catch);
508 if (function_code)
509 {
510 running_trap = old_running; /* XXX */
511 trap_return_context = old_context;
512 restore_bash_trapsig (old_trapsig);
513 /* caller will set last_command_exit_value */
514 sh_longjmp (return_catch, 1);
515 }
516 }
517 }
518
519 pending_traps[sig] = 0; /* XXX - move before evalstring? */
520 running_trap = old_running;
521 trap_return_context = old_context;
522 }
523 }
524
525 #if defined (ARRAY_VARS)
526 restore_pipestatus_array (ps);
527 #endif
528 restore_bash_trapsig (old_trapsig);
529 last_command_exit_value = old_exit_value;
530 }
531
532 /* Set the private state variables noting that we received a signal SIG
533 for which we have a trap set. */
534 void
535 set_trap_state (int sig)
536 {
537 catch_flag = 1;
538 pending_traps[sig]++;
539 trapped_signal_received = sig;
540 }
541
542 sighandler
543 trap_handler (int sig)
544 {
545 int oerrno;
546
547 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
548 {
549 internal_debug ("trap_handler: signal %d: signal not trapped", sig);
550 SIGRETURN (0);
551 }
552
553 /* This means we're in a subshell, but have not yet reset the handler for
554 trapped signals. We're not supposed to execute the trap in this situation;
555 we should restore the original signal and resend the signal to ourselves
556 to preserve the Posix "signal traps that are not being ignored shall be
557 set to the default action" semantics. */
558 if ((subshell_environment & SUBSHELL_IGNTRAP) && trap_list[sig] != (char *)IGNORE_SIG)
559 {
560 sigset_t mask;
561
562 /* Paranoia */
563 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
564 original_signals[sig] = SIG_DFL;
565
566 restore_signal (sig);
567
568 /* Make sure we let the signal we just caught through */
569 sigemptyset (&mask);
570 sigprocmask (SIG_SETMASK, (sigset_t *)NULL, &mask);
571 sigdelset (&mask, sig);
572 sigprocmask (SIG_SETMASK, &mask, (sigset_t *)NULL);
573
574 kill (getpid (), sig);
575
576 SIGRETURN (0);
577 }
578
579 if ((sig >= NSIG) ||
580 (trap_list[sig] == (char *)DEFAULT_SIG) ||
581 (trap_list[sig] == (char *)IGNORE_SIG))
582 programming_error (_("trap_handler: bad signal %d"), sig);
583 else
584 {
585 oerrno = errno;
586 #if defined (MUST_REINSTALL_SIGHANDLERS)
587 # if defined (JOB_CONTROL) && defined (SIGCHLD)
588 if (sig != SIGCHLD)
589 # endif /* JOB_CONTROL && SIGCHLD */
590 set_signal_handler (sig, trap_handler);
591 #endif /* MUST_REINSTALL_SIGHANDLERS */
592
593 set_trap_state (sig);
594
595 if (this_shell_builtin && (this_shell_builtin == wait_builtin))
596 {
597 wait_signal_received = sig;
598 if (waiting_for_child && wait_intr_flag)
599 sh_longjmp (wait_intr_buf, 1);
600 }
601
602 #if defined (READLINE)
603 /* Set the event hook so readline will call it after the signal handlers
604 finish executing, so if this interrupted character input we can get
605 quick response. */
606 if (RL_ISSTATE (RL_STATE_SIGHANDLER))
607 bashline_set_event_hook ();
608 #endif
609
610 errno = oerrno;
611 }
612
613 SIGRETURN (0);
614 }
615
616 int
617 next_pending_trap (int start)
618 {
619 register int i;
620
621 for (i = start; i < NSIG; i++)
622 if (pending_traps[i])
623 return i;
624 return -1;
625 }
626
627 int
628 first_pending_trap (void)
629 {
630 return (next_pending_trap (1));
631 }
632
633 /* Return > 0 if any of the "real" signals (not fake signals like EXIT) are
634 trapped. */
635 int
636 any_signals_trapped (void)
637 {
638 register int i;
639
640 for (i = 1; i < NSIG; i++)
641 if ((sigmodes[i] & SIG_TRAPPED) && (sigmodes[i] & SIG_IGNORED) == 0)
642 return i;
643 return -1;
644 }
645
646 void
647 clear_pending_traps (void)
648 {
649 register int i;
650
651 for (i = 1; i < NSIG; i++)
652 pending_traps[i] = 0;
653 }
654
655 void
656 check_signals (void)
657 {
658 /* Add any other shell timeouts here */
659 check_read_timeout (); /* set by the read builtin */
660 QUIT;
661 }
662
663 /* Convenience functions the rest of the shell can use */
664 void
665 check_signals_and_traps (void)
666 {
667 check_signals ();
668
669 run_pending_traps ();
670 }
671
672 #if defined (JOB_CONTROL) && defined (SIGCHLD)
673
674 #ifdef INCLUDE_UNUSED
675 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
676 void
677 set_sigchld_trap (const char *command_string)
678 {
679 set_signal (SIGCHLD, command_string);
680 }
681 #endif
682
683 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
684 is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
685 to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
686 reset the disposition to the default and not have the original signal
687 accidentally restored, undoing the user's command. */
688 void
689 uw_maybe_set_sigchld_trap (void *command_string)
690 {
691 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
692 set_signal (SIGCHLD, (const char *)command_string);
693 }
694
695 /* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
696 as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
697 or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
698 void
699 set_impossible_sigchld_trap (void)
700 {
701 restore_default_signal (SIGCHLD);
702 change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER);
703 sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* uw_maybe_set_sigchld_trap checks this */
704 }
705
706 /* Act as if we received SIGCHLD NCHILD times and increment
707 pending_traps[SIGCHLD] by that amount. This allows us to still run the
708 SIGCHLD trap once for each exited child. */
709 void
710 queue_sigchld_trap (int nchild)
711 {
712 if (nchild > 0)
713 {
714 catch_flag = 1;
715 pending_traps[SIGCHLD] += nchild;
716 trapped_signal_received = SIGCHLD;
717 }
718 }
719 #endif /* JOB_CONTROL && SIGCHLD */
720
721 /* Set a trap for SIG only if SIG is not already trapped. */
722 static inline void
723 trap_if_untrapped (int sig, const char *command)
724 {
725 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
726 set_signal (sig, command);
727 }
728
729 void
730 set_debug_trap (const char *command)
731 {
732 set_signal (DEBUG_TRAP, command);
733 }
734
735 /* Separate function to call when functions and sourced files want to restore
736 the original version of the DEBUG trap before returning. Unless the -T
737 option is set, source and shell function execution save the old debug trap
738 and unset the trap. If the function or sourced file changes the DEBUG trap,
739 SIG_TRAPPED will be set and we don't bother restoring the original trap string.
740 This is used by both functions and the source builtin. */
741 void
742 uw_maybe_set_debug_trap (void *command)
743 {
744 trap_if_untrapped (DEBUG_TRAP, command);
745 }
746
747 void
748 set_error_trap (const char *command)
749 {
750 set_signal (ERROR_TRAP, command);
751 }
752
753 void
754 uw_set_error_trap (void *command)
755 {
756 set_error_trap (command);
757 }
758
759 void
760 uw_maybe_set_error_trap (void *command)
761 {
762 trap_if_untrapped (ERROR_TRAP, command);
763 }
764
765 void
766 set_return_trap (const char *command)
767 {
768 set_signal (RETURN_TRAP, command);
769 }
770
771 void
772 uw_maybe_set_return_trap (void *command)
773 {
774 trap_if_untrapped (RETURN_TRAP, command);
775 }
776
777 #ifdef INCLUDE_UNUSED
778 void
779 set_sigint_trap (const char *command)
780 {
781 set_signal (SIGINT, command);
782 }
783 #endif
784
785 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
786 things, like waiting for command substitution or executing commands
787 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
788 SigHandler *
789 set_sigint_handler (void)
790 {
791 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
792 return ((SigHandler *)SIG_IGN);
793
794 else if (sigmodes[SIGINT] & SIG_IGNORED)
795 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
796
797 else if (sigmodes[SIGINT] & SIG_TRAPPED)
798 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
799
800 /* The signal is not trapped, so set the handler to the shell's special
801 interrupt handler. Make sure this agrees with code in sig.c and
802 builtins/trap.def */
803 else if (interactive) /* XXX - was interactive_shell */
804 return (set_signal_handler (SIGINT, sigint_sighandler));
805 else
806 return (set_signal_handler (SIGINT, termsig_sighandler));
807 }
808
809 /* Return the correct handler for signal SIG according to the values in
810 sigmodes[SIG]. */
811 SigHandler *
812 trap_to_sighandler (int sig)
813 {
814 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
815 return (SIG_IGN);
816 else if (sigmodes[sig] & SIG_TRAPPED)
817 return (trap_handler);
818 else
819 return (SIG_DFL);
820 }
821
822 /* Set SIG to call STRING as a command. */
823 void
824 set_signal (int sig, const char *string)
825 {
826 sigset_t set, oset;
827
828 if (SPECIAL_TRAP (sig))
829 {
830 change_signal (sig, savestring (string));
831 if (sig == EXIT_TRAP && interactive == 0)
832 initialize_terminating_signals ();
833 return;
834 }
835
836 /* A signal ignored on entry to the shell cannot be trapped or reset, but
837 no error is reported when attempting to do so. -- Posix.2 */
838 if (sigmodes[sig] & SIG_HARD_IGNORE)
839 return;
840
841 /* Make sure we have original_signals[sig] if the signal has not yet
842 been trapped. */
843 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
844 {
845 /* If we aren't sure of the original value, check it. */
846 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
847 GETORIGSIG (sig);
848 if (original_signals[sig] == SIG_IGN && (sigmodes[sig] & SIG_ASYNCSIG) == 0)
849 return; /* XXX */
850 }
851
852 /* Only change the system signal handler if SIG_NO_TRAP is not set.
853 The trap command string is changed in either case. The shell signal
854 handlers for SIGINT and SIGCHLD run the user specified traps in an
855 environment in which it is safe to do so. */
856 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
857 {
858 BLOCK_SIGNAL (sig, set, oset);
859 change_signal (sig, savestring (string));
860 set_signal_handler (sig, trap_handler);
861 UNBLOCK_SIGNAL (oset);
862 }
863 else
864 change_signal (sig, savestring (string));
865 }
866
867 static void
868 free_trap_command (int sig)
869 {
870 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
871 (trap_list[sig] != (char *)IGNORE_SIG) &&
872 (trap_list[sig] != (char *)DEFAULT_SIG) &&
873 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
874 free (trap_list[sig]);
875 }
876
877 /* If SIG has a string assigned to it, get rid of it. Then give it
878 VALUE. */
879 static void
880 change_signal (int sig, char *value)
881 {
882 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
883 free_trap_command (sig);
884 trap_list[sig] = value;
885
886 sigmodes[sig] |= SIG_TRAPPED;
887 if (value == (char *)IGNORE_SIG)
888 sigmodes[sig] |= SIG_IGNORED;
889 else
890 sigmodes[sig] &= ~SIG_IGNORED;
891 if (sigmodes[sig] & SIG_INPROGRESS)
892 sigmodes[sig] |= SIG_CHANGED;
893 }
894
895 void
896 get_original_signal (int sig)
897 {
898 /* If we aren't sure the of the original value, then get it. */
899 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
900 GETORIGSIG (sig);
901 }
902
903 void
904 get_all_original_signals (void)
905 {
906 register int i;
907
908 for (i = 1; i < NSIG; i++)
909 GET_ORIGINAL_SIGNAL (i);
910 }
911
912 void
913 set_original_signal (int sig, SigHandler *handler)
914 {
915 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
916 SETORIGSIG (sig, handler);
917 }
918
919 /* Restore the default action for SIG; i.e., the action the shell
920 would have taken before you used the trap command. This is called
921 from trap_builtin (), which takes care to restore the handlers for
922 the signals the shell treats specially. */
923 void
924 restore_default_signal (int sig)
925 {
926 if (SPECIAL_TRAP (sig))
927 {
928 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
929 (sigmodes[sig] & SIG_INPROGRESS) == 0)
930 free_trap_command (sig);
931 trap_list[sig] = (char *)NULL;
932 sigmodes[sig] &= ~SIG_TRAPPED;
933 if (sigmodes[sig] & SIG_INPROGRESS)
934 sigmodes[sig] |= SIG_CHANGED;
935 return;
936 }
937
938 GET_ORIGINAL_SIGNAL (sig);
939
940 /* A signal ignored on entry to the shell cannot be trapped or reset, but
941 no error is reported when attempting to do so. Thanks Posix.2. */
942 if (sigmodes[sig] & SIG_HARD_IGNORE)
943 return;
944
945 /* Even if the signal is not trapped, POSIX interp 751 requires that we
946 allow `trap - SIGINT' to reset the signal disposition for SIGINT to
947 SIG_DFL. */
948 if ((sigmodes[sig] & (SIG_TRAPPED|SIG_ASYNCSIG|SIG_NO_TRAP)) == SIG_ASYNCSIG)
949 {
950 original_signals[sig] = SIG_DFL; /* XXX */
951 set_signal_handler (sig, SIG_DFL);
952 change_signal (sig, (char *)DEFAULT_SIG);
953 return;
954 }
955
956 /* If we aren't trapping this signal, don't bother doing anything else. */
957 /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
958 sentinel to determine whether or not disposition is reset to the default
959 while the trap handler is executing. */
960 if (((sigmodes[sig] & SIG_TRAPPED) == 0) &&
961 (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
962 return;
963
964 /* Only change the signal handler for SIG if it allows it. */
965 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
966 set_signal_handler (sig, original_signals[sig]);
967
968 /* Change the trap command in either case. */
969 change_signal (sig, (char *)DEFAULT_SIG);
970
971 /* Mark the signal as no longer trapped. */
972 sigmodes[sig] &= ~SIG_TRAPPED;
973 }
974
975 /* Make this signal be ignored. */
976 void
977 ignore_signal (int sig)
978 {
979 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
980 {
981 change_signal (sig, (char *)IGNORE_SIG);
982 return;
983 }
984
985 GET_ORIGINAL_SIGNAL (sig);
986
987 /* A signal ignored on entry to the shell cannot be trapped or reset.
988 No error is reported when the user attempts to do so. */
989 if (sigmodes[sig] & SIG_HARD_IGNORE)
990 return;
991
992 /* If already trapped and ignored, no change necessary. */
993 if (sigmodes[sig] & SIG_IGNORED)
994 {
995 sigmodes[sig] |= SIG_TRAPPED; /* just make sure */
996 /* XXX - turn off SIG_ASYNCSIG here? */
997 return;
998 }
999
1000 /* Only change the signal handler for SIG if it allows it. */
1001 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
1002 set_signal_handler (sig, SIG_IGN);
1003
1004 /* Change the trap command in either case. */
1005 change_signal (sig, (char *)IGNORE_SIG);
1006 }
1007
1008 /* Handle the calling of "trap 0". The only sticky situation is when
1009 the command to be executed includes an "exit". This is why we have
1010 to provide our own place for top_level to jump to. */
1011 int
1012 run_exit_trap (void)
1013 {
1014 char *trap_command;
1015 char *old_trapsig;
1016 int code, function_code, retval;
1017 #if defined (ARRAY_VARS)
1018 ARRAY *ps;
1019 #endif
1020
1021 trap_saved_exit_value = last_command_exit_value;
1022 #if defined (ARRAY_VARS)
1023 ps = save_pipestatus_array ();
1024 #endif
1025 function_code = 0;
1026
1027 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
1028 currently running in the trap handler (call to exit in the list of
1029 commands given to trap 0). */
1030 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
1031 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
1032 {
1033 trap_command = savestring (trap_list[EXIT_TRAP]);
1034 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
1035 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
1036
1037 retval = trap_saved_exit_value;
1038 running_trap = 1;
1039 trap_return_context = funcnest + sourcenest;
1040
1041 old_trapsig = save_bash_trapsig ();
1042 set_bash_trapsig (EXIT_TRAP);
1043
1044 code = setjmp_nosigs (top_level);
1045
1046 /* If we're in a function, make sure return longjmps come here, too. */
1047 if (return_catch_flag)
1048 function_code = setjmp_nosigs (return_catch);
1049
1050 if (code == 0 && function_code == 0)
1051 {
1052 reset_parser ();
1053 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE|SEVAL_NOOPTIMIZE);
1054 }
1055 else if (code == ERREXIT)
1056 retval = last_command_exit_value;
1057 else if (code == EXITPROG || code == EXITBLTIN)
1058 retval = last_command_exit_value;
1059 else if (function_code != 0)
1060 retval = return_catch_value;
1061 else
1062 retval = trap_saved_exit_value;
1063
1064 running_trap = 0;
1065 #if defined (ARRAY_VARS)
1066 array_dispose (ps);
1067 #endif
1068 restore_bash_trapsig (old_trapsig);
1069
1070 return retval;
1071 }
1072
1073 #if defined (ARRAY_VARS)
1074 restore_pipestatus_array (ps);
1075 #endif
1076 return (trap_saved_exit_value);
1077 }
1078
1079 void
1080 run_trap_cleanup (int sig)
1081 {
1082 /* XXX - should we clean up trap_list[sig] == IMPOSSIBLE_TRAP_HANDLER? */
1083 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
1084 }
1085
1086 #define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
1087
1088 /* Run a trap command for SIG. SIG is one of the signals the shell treats
1089 specially. Returns the exit status of the executed trap command list. */
1090 static int
1091 _run_trap_internal (int sig, char *tag)
1092 {
1093 char *trap_command, *old_trap;
1094 char *old_trapsig;
1095 int trap_exit_value;
1096 volatile int save_return_catch_flag, function_code;
1097 int old_modes, old_running, old_int, old_context;
1098 int flags;
1099 procenv_t save_return_catch;
1100 WORD_LIST *save_subst_varlist;
1101 HASH_TABLE *save_tempenv;
1102 sh_parser_state_t pstate;
1103 #if defined (ARRAY_VARS)
1104 ARRAY *ps;
1105 #endif
1106
1107 old_modes = old_running = old_context = -1;
1108
1109 trap_exit_value = 0;
1110 trap_saved_exit_value = last_command_exit_value;
1111 /* Run the trap only if SIG is trapped and not ignored, and we are not
1112 currently executing in the trap handler. */
1113 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
1114 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
1115 #if 1
1116 /* Uncomment this to allow some special signals to recursively execute
1117 trap handlers. */
1118 (RECURSIVE_SIG (sig) || (sigmodes[sig] & SIG_INPROGRESS) == 0))
1119 #else
1120 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
1121 #endif
1122 {
1123 old_trap = trap_list[sig];
1124 old_modes = sigmodes[sig];
1125 old_running = running_trap;
1126 old_context = trap_return_context;
1127
1128 sigmodes[sig] |= SIG_INPROGRESS;
1129 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
1130 trap_command = savestring (old_trap);
1131
1132 old_trapsig = save_bash_trapsig ();
1133 set_bash_trapsig (sig);
1134
1135 running_trap = sig + 1;
1136 trap_return_context = funcnest + sourcenest;
1137
1138 old_int = interrupt_state; /* temporarily suppress pending interrupts */
1139 CLRINTERRUPT;
1140
1141 #if defined (ARRAY_VARS)
1142 ps = save_pipestatus_array ();
1143 #endif
1144
1145 save_parser_state (&pstate);
1146 save_subst_varlist = subst_assign_varlist;
1147 subst_assign_varlist = 0;
1148 save_tempenv = temporary_env;
1149 temporary_env = 0; /* traps should not run with temporary env */
1150
1151 /* Will be restored by restore_parser_state */
1152 if (shell_eof_token)
1153 {
1154 reset_parser (); /* resets parser-private state */
1155 shell_eof_token = 0;
1156 }
1157
1158 #if defined (JOB_CONTROL)
1159 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1160 save_pipeline (1); /* XXX only provides one save level */
1161 #endif
1162
1163 /* XXX - set pending_traps[sig] = 0 here? */
1164 evalnest++;
1165
1166 /* If we're in a function, make sure return longjmps come here, too. */
1167 function_code = 0;
1168 save_return_catch_flag = return_catch_flag;
1169 if (return_catch_flag)
1170 {
1171 COPY_PROCENV (return_catch, save_return_catch);
1172 function_code = setjmp_nosigs (return_catch);
1173 }
1174
1175 flags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOOPTIMIZE;
1176 if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
1177 flags |= SEVAL_RESETLINE;
1178 if (function_code == 0)
1179 {
1180 parse_and_execute (trap_command, tag, flags);
1181 trap_exit_value = last_command_exit_value;
1182 }
1183 else
1184 trap_exit_value = return_catch_value;
1185 evalnest--;
1186
1187 #if defined (JOB_CONTROL)
1188 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1189 restore_pipeline (1);
1190 #endif
1191
1192 subst_assign_varlist = save_subst_varlist;
1193 restore_parser_state (&pstate);
1194
1195 #if defined (ARRAY_VARS)
1196 restore_pipestatus_array (ps);
1197 #endif
1198
1199 temporary_env = save_tempenv;
1200
1201 if ((old_modes & SIG_INPROGRESS) == 0)
1202 sigmodes[sig] &= ~SIG_INPROGRESS;
1203
1204 restore_bash_trapsig (old_trapsig);
1205
1206 running_trap = old_running;
1207 interrupt_state = old_int;
1208 trap_return_context = old_context;
1209
1210 if (sigmodes[sig] & SIG_CHANGED)
1211 {
1212 #if 0
1213 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
1214 the places where they can be changed using unwind-protects. For
1215 example, look at execute_cmd.c:execute_function(). */
1216 if (SPECIAL_TRAP (sig) == 0)
1217 #endif
1218 free (old_trap);
1219 sigmodes[sig] &= ~SIG_CHANGED;
1220
1221 CHECK_TERMSIG; /* some pathological conditions lead here */
1222 }
1223
1224 if (save_return_catch_flag)
1225 {
1226 return_catch_flag = save_return_catch_flag;
1227 return_catch_value = trap_exit_value;
1228 COPY_PROCENV (save_return_catch, return_catch);
1229 if (function_code)
1230 {
1231 #if 0
1232 from_return_trap = sig == RETURN_TRAP;
1233 #endif
1234 sh_longjmp (return_catch, 1);
1235 }
1236 }
1237 }
1238
1239 return trap_exit_value;
1240 }
1241
1242 int
1243 run_debug_trap (void)
1244 {
1245 int trap_exit_value, old_verbose;
1246 pid_t save_pgrp;
1247 #if defined (PGRP_PIPE)
1248 int save_pipe[2];
1249 #endif
1250
1251 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
1252 trap_exit_value = 0;
1253 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
1254 {
1255 #if defined (JOB_CONTROL)
1256 save_pgrp = pipeline_pgrp;
1257 pipeline_pgrp = 0;
1258 save_pipeline (1);
1259 # if defined (PGRP_PIPE)
1260 save_pgrp_pipe (save_pipe, 1);
1261 # endif
1262 stop_making_children ();
1263 #endif
1264
1265 old_verbose = echo_input_at_read;
1266 echo_input_at_read = suppress_debug_trap_verbose ? 0 : echo_input_at_read;
1267
1268 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
1269
1270 echo_input_at_read = old_verbose;
1271
1272 #if defined (JOB_CONTROL)
1273 pipeline_pgrp = save_pgrp;
1274 restore_pipeline (1);
1275 # if defined (PGRP_PIPE)
1276 close_pgrp_pipe ();
1277 restore_pgrp_pipe (save_pipe);
1278 # endif
1279 if (pipeline_pgrp > 0 && ((subshell_environment & (SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0))
1280 give_terminal_to (pipeline_pgrp, 1);
1281
1282 notify_and_cleanup ();
1283 #endif
1284
1285 #if defined (DEBUGGER)
1286 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
1287 a function or sourced script, we force a `return'. */
1288 if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
1289 {
1290 return_catch_value = trap_exit_value;
1291 sh_longjmp (return_catch, 1);
1292 }
1293 #endif
1294 }
1295 return trap_exit_value;
1296 }
1297
1298 void
1299 run_error_trap (void)
1300 {
1301 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
1302 _run_trap_internal (ERROR_TRAP, "error trap");
1303 }
1304
1305 void
1306 run_return_trap (void)
1307 {
1308 int old_exit_value;
1309
1310 #if 0
1311 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
1312 return;
1313 #endif
1314
1315 if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
1316 {
1317 old_exit_value = last_command_exit_value;
1318 _run_trap_internal (RETURN_TRAP, "return trap");
1319 last_command_exit_value = old_exit_value;
1320 }
1321 }
1322
1323 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
1324 declared here to localize the trap functions. */
1325 /* WILL_THROW indicates whether we're run from throw_to_top_level */
1326 void
1327 run_interrupt_trap (int will_throw)
1328 {
1329 if (will_throw && running_trap > 0)
1330 run_trap_cleanup (running_trap - 1);
1331 pending_traps[SIGINT] = 0; /* run_pending_traps does this */
1332 catch_flag = 0;
1333 _run_trap_internal (SIGINT, "interrupt trap");
1334 }
1335
1336 /* Free all the allocated strings in the list of traps and reset the trap
1337 values to the default. Intended to be called from subshells that want
1338 to complete work done by reset_signal_handlers upon execution of a
1339 subsequent `trap' command that changes a signal's disposition. We need
1340 to make sure that we duplicate the behavior of
1341 reset_or_restore_signal_handlers and not change the disposition of signals
1342 that are set to be ignored. */
1343 void
1344 free_trap_strings (void)
1345 {
1346 register int i;
1347
1348 for (i = 0; i < NSIG; i++)
1349 {
1350 if (trap_list[i] != (char *)IGNORE_SIG)
1351 free_trap_string (i);
1352 }
1353 for (i = NSIG; i < BASH_NSIG; i++)
1354 {
1355 /* Don't free the trap string if the subshell inherited the trap */
1356 if ((sigmodes[i] & SIG_TRAPPED) == 0)
1357 {
1358 free_trap_string (i);
1359 trap_list[i] = (char *)NULL;
1360 }
1361 }
1362 }
1363
1364 /* Free a trap command string associated with SIG without changing signal
1365 disposition. Intended to be called from free_trap_strings() */
1366 static void
1367 free_trap_string (int sig)
1368 {
1369 change_signal (sig, (char *)DEFAULT_SIG);
1370 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1371 }
1372
1373 /* Reset the handler for SIG to the original value but leave the trap string
1374 in place. */
1375 static void
1376 reset_signal (int sig)
1377 {
1378 #if 1
1379 /* If we have a trapped signal that was previously ignored because it was
1380 SIGINT or SIGQUIT in an asynchronous list, then we need to restore the
1381 default signal and not the (artificial) SIG_IGN. We know that the signal
1382 was not ignored at shell invocation because you can't trap it if
1383 SIG_HARD_IGNORE is set. */
1384 if ((sigmodes[sig] & SIG_ASYNCSIG) && signal_is_trapped (sig) && original_signals[sig] == SIG_IGN)
1385 original_signals[sig] = SIG_DFL;
1386 #endif
1387 set_signal_handler (sig, original_signals[sig]);
1388 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1389 }
1390
1391 /* Set the handler signal SIG to the original and free any trap
1392 command associated with it. */
1393 static void
1394 restore_signal (int sig)
1395 {
1396 #if 1
1397 /* If we have a trapped signal that was previously ignored because it was
1398 SIGINT or SIGQUIT in an asynchronous list, then we need to restore the
1399 default signal and not the (artificial) SIG_IGN. We know that the signal
1400 was not ignored at shell invocation because you can't trap it if
1401 SIG_HARD_IGNORE is set. */
1402 if ((sigmodes[sig] & SIG_ASYNCSIG) && signal_is_trapped (sig) && original_signals[sig] == SIG_IGN)
1403 original_signals[sig] = SIG_DFL;
1404 #endif
1405 set_signal_handler (sig, original_signals[sig]);
1406 change_signal (sig, (char *)DEFAULT_SIG);
1407 sigmodes[sig] &= ~SIG_TRAPPED;
1408 }
1409
1410 static void
1411 reset_or_restore_signal_handlers (sh_resetsig_func_t *reset)
1412 {
1413 register int i;
1414
1415 /* Take care of the exit trap first */
1416 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
1417 {
1418 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1419 if (reset != reset_signal)
1420 {
1421 free_trap_command (EXIT_TRAP);
1422 trap_list[EXIT_TRAP] = (char *)NULL;
1423 }
1424 }
1425
1426 for (i = 1; i < NSIG; i++)
1427 {
1428 if (sigmodes[i] & SIG_TRAPPED)
1429 {
1430 if (trap_list[i] == (char *)IGNORE_SIG)
1431 set_signal_handler (i, SIG_IGN);
1432 else
1433 (*reset) (i);
1434 }
1435 else if (sigmodes[i] & SIG_SPECIAL)
1436 (*reset) (i);
1437 pending_traps[i] = 0; /* XXX */
1438 }
1439
1440 /* Command substitution and other child processes don't inherit the
1441 debug, error, or return traps. If we're in the debugger, and the
1442 `functrace' or `errtrace' options have been set, then let command
1443 substitutions inherit them. Let command substitution inherit the
1444 RETURN trap if we're in the debugger and tracing functions. */
1445 if (function_trace_mode == 0)
1446 {
1447 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
1448 sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
1449 }
1450 if (error_trace_mode == 0)
1451 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
1452 }
1453
1454 /* Reset trapped signals to their original values, but don't free the
1455 trap strings. Called by the command substitution code and other places
1456 that create a "subshell environment". */
1457 void
1458 reset_signal_handlers (void)
1459 {
1460 reset_or_restore_signal_handlers (reset_signal);
1461 }
1462
1463 /* Reset all trapped signals to their original values. Signals set to be
1464 ignored with trap '' SIGNAL should be ignored, so we make sure that they
1465 are. Called by child processes after they are forked. */
1466 void
1467 restore_original_signals (void)
1468 {
1469 reset_or_restore_signal_handlers (restore_signal);
1470 }
1471
1472 /* Change the flags associated with signal SIG without changing the trap
1473 string. The string is TRAP_LIST[SIG] if we need it. */
1474 static void
1475 reinit_trap (int sig)
1476 {
1477 sigmodes[sig] |= SIG_TRAPPED;
1478 if (trap_list[sig] == (char *)IGNORE_SIG)
1479 sigmodes[sig] |= SIG_IGNORED;
1480 else
1481 sigmodes[sig] &= ~SIG_IGNORED;
1482 if (sigmodes[sig] & SIG_INPROGRESS)
1483 sigmodes[sig] |= SIG_CHANGED;
1484 }
1485
1486 /* Undo the effects of reset_signal_handlers(), which unsets the traps but
1487 leaves the trap strings in place. This understands how reset_signal_handlers
1488 works. */
1489 void
1490 restore_traps (void)
1491 {
1492 char *trapstr;
1493 int i;
1494
1495 /* Take care of the exit trap first. If TRAP_LIST[0] is non-null, the trap
1496 has been set. */
1497 trapstr = trap_list[EXIT_TRAP];
1498 if (trapstr)
1499 reinit_trap (EXIT_TRAP);
1500
1501 /* Then DEBUG, RETURN, and ERROR. TRAP_LIST[N] == 0 if these signals are
1502 not trapped. This knows what reset_signal_handlers does for these traps */
1503 trapstr = trap_list[DEBUG_TRAP];
1504 if (trapstr && function_trace_mode == 0)
1505 reinit_trap (DEBUG_TRAP);
1506 trapstr = trap_list[RETURN_TRAP];
1507 if (trapstr && function_trace_mode == 0)
1508 reinit_trap (RETURN_TRAP);
1509 trapstr = trap_list[ERROR_TRAP];
1510 if (trapstr && error_trace_mode == 0)
1511 reinit_trap (ERROR_TRAP);
1512
1513 /* And finally all the `real' signals. reset_signal_handlers just changes the
1514 signal handler for these signals, leaving the trap value in place. We
1515 intuit what to do based on that value. We assume that signals marked as
1516 SIG_SPECIAL are reinitialized by initialize_signals (), so we don't
1517 change the signal handler unless the signal is supposed to be ignored. */
1518 for (i = 1; i < NSIG; i++)
1519 {
1520 trapstr = trap_list[i];
1521 if (sigmodes[i] & SIG_SPECIAL)
1522 {
1523 if (trapstr && trapstr != (char *)DEFAULT_SIG)
1524 reinit_trap (i);
1525 if (trapstr == (char *)IGNORE_SIG && (sigmodes[i] & SIG_NO_TRAP) == 0)
1526 set_signal_handler (i, SIG_IGN);
1527 }
1528 else if (trapstr == (char *)IGNORE_SIG)
1529 {
1530 reinit_trap (i);
1531 if ((sigmodes[i] & SIG_NO_TRAP) == 0)
1532 set_signal_handler (i, SIG_IGN);
1533 }
1534 else if (trapstr != (char *)DEFAULT_SIG)
1535 /* set_signal duplicates the string argument before freeing it. */
1536 set_signal (i, trapstr);
1537
1538 pending_traps[i] = 0; /* XXX */
1539 }
1540 }
1541
1542 /* If a trap handler exists for signal SIG, then call it; otherwise just
1543 return failure. Returns 1 if it called the trap handler. */
1544 int
1545 maybe_call_trap_handler (int sig)
1546 {
1547 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1548 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
1549 {
1550 switch (sig)
1551 {
1552 case SIGINT:
1553 run_interrupt_trap (0);
1554 break;
1555 case EXIT_TRAP:
1556 run_exit_trap ();
1557 break;
1558 case DEBUG_TRAP:
1559 run_debug_trap ();
1560 break;
1561 case ERROR_TRAP:
1562 run_error_trap ();
1563 break;
1564 default:
1565 trap_handler (sig);
1566 break;
1567 }
1568 return (1);
1569 }
1570 else
1571 return (0);
1572 }
1573
1574 int
1575 signal_is_trapped (int sig)
1576 {
1577 return (sigmodes[sig] & SIG_TRAPPED);
1578 }
1579
1580 int
1581 signal_is_pending (int sig)
1582 {
1583 return (pending_traps[sig]);
1584 }
1585
1586 int
1587 signal_is_special (int sig)
1588 {
1589 return (sigmodes[sig] & SIG_SPECIAL);
1590 }
1591
1592 int
1593 signal_is_ignored (int sig)
1594 {
1595 return (sigmodes[sig] & SIG_IGNORED);
1596 }
1597
1598 int
1599 signal_is_hard_ignored (int sig)
1600 {
1601 return (sigmodes[sig] & SIG_HARD_IGNORE);
1602 }
1603
1604 void
1605 set_signal_hard_ignored (int sig)
1606 {
1607 sigmodes[sig] |= SIG_HARD_IGNORE;
1608 original_signals[sig] = SIG_IGN;
1609 }
1610
1611 void
1612 set_signal_ignored (int sig)
1613 {
1614 original_signals[sig] = SIG_IGN;
1615 }
1616
1617 void
1618 set_signal_async_ignored (int sig)
1619 {
1620 original_signals[sig] = SIG_IGN;
1621 sigmodes[sig] |= SIG_ASYNCSIG|SIG_IGNORED;
1622 }
1623
1624 int
1625 signal_is_async_ignored (int sig)
1626 {
1627 return (sigmodes[sig] & SIG_ASYNCSIG);
1628 }
1629
1630 int
1631 signal_in_progress (int sig)
1632 {
1633 return (sigmodes[sig] & SIG_INPROGRESS);
1634 }
1635
1636 #if 0 /* unused */
1637 int
1638 block_trapped_signals (sigset_t *maskp, sigset_t *omaskp)
1639 {
1640 int i;
1641
1642 sigemptyset (maskp);
1643 for (i = 1; i < NSIG; i++)
1644 if (sigmodes[i] & SIG_TRAPPED)
1645 sigaddset (maskp, i);
1646 return (sigprocmask (SIG_BLOCK, maskp, omaskp));
1647 }
1648
1649 int
1650 unblock_trapped_signals (sigset_t *maskp)
1651 {
1652 return (sigprocmask (SIG_SETMASK, maskp, 0));
1653 }
1654 #endif