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