]> git.ipfire.org Git - thirdparty/bash.git/blame - trap.c
Bash-5.1 patch 4: fix key-value pair associative array assignment word expansions
[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
726f6388
JA
484 if ((sig >= NSIG) ||
485 (trap_list[sig] == (char *)DEFAULT_SIG) ||
486 (trap_list[sig] == (char *)IGNORE_SIG))
b80f6443 487 programming_error (_("trap_handler: bad signal %d"), sig);
726f6388
JA
488 else
489 {
28ef6c31 490 oerrno = errno;
ccc6cda3 491#if defined (MUST_REINSTALL_SIGHANDLERS)
3185942a
JA
492# if defined (JOB_CONTROL) && defined (SIGCHLD)
493 if (sig != SIGCHLD)
494# endif /* JOB_CONTROL && SIGCHLD */
726f6388 495 set_signal_handler (sig, trap_handler);
ccc6cda3 496#endif /* MUST_REINSTALL_SIGHANDLERS */
726f6388 497
8868edaf 498 set_trap_state (sig);
ac50fbac
CR
499
500 if (this_shell_builtin && (this_shell_builtin == wait_builtin))
7117c2d2
JA
501 {
502 wait_signal_received = sig;
8868edaf 503 if (waiting_for_child && wait_intr_flag)
a0c0a00f 504 sh_longjmp (wait_intr_buf, 1);
7117c2d2
JA
505 }
506
ac50fbac
CR
507#if defined (READLINE)
508 /* Set the event hook so readline will call it after the signal handlers
509 finish executing, so if this interrupted character input we can get
510 quick response. */
8868edaf 511 if (RL_ISSTATE (RL_STATE_SIGHANDLER))
ac50fbac
CR
512 bashline_set_event_hook ();
513#endif
514
bb70624e 515 errno = oerrno;
726f6388 516 }
d233b485 517
ccc6cda3 518 SIGRETURN (0);
726f6388
JA
519}
520
ac50fbac 521int
8868edaf
CR
522next_pending_trap (start)
523 int start;
ac50fbac
CR
524{
525 register int i;
526
8868edaf 527 for (i = start; i < NSIG; i++)
ac50fbac
CR
528 if (pending_traps[i])
529 return i;
530 return -1;
531}
532
8868edaf
CR
533int
534first_pending_trap ()
535{
536 return (next_pending_trap (1));
537}
538
d233b485
CR
539/* Return > 0 if any of the "real" signals (not fake signals like EXIT) are
540 trapped. */
ac50fbac
CR
541int
542any_signals_trapped ()
543{
544 register int i;
545
546 for (i = 1; i < NSIG; i++)
547 if (sigmodes[i] & SIG_TRAPPED)
548 return i;
549 return -1;
550}
551
8868edaf
CR
552void
553clear_pending_traps ()
554{
555 register int i;
556
557 for (i = 1; i < NSIG; i++)
558 pending_traps[i] = 0;
559}
560
ac50fbac
CR
561void
562check_signals ()
563{
564 CHECK_ALRM; /* set by the read builtin */
565 QUIT;
566}
567
568/* Convenience functions the rest of the shell can use */
569void
570check_signals_and_traps ()
571{
572 check_signals ();
573
574 run_pending_traps ();
575}
576
726f6388 577#if defined (JOB_CONTROL) && defined (SIGCHLD)
cce855bc
JA
578
579#ifdef INCLUDE_UNUSED
726f6388
JA
580/* Make COMMAND_STRING be executed when SIGCHLD is caught. */
581void
582set_sigchld_trap (command_string)
583 char *command_string;
584{
726f6388
JA
585 set_signal (SIGCHLD, command_string);
586}
cce855bc 587#endif
726f6388 588
95732b49 589/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
3185942a
JA
590 is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
591 to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
592 reset the disposition to the default and not have the original signal
593 accidentally restored, undoing the user's command. */
726f6388
JA
594void
595maybe_set_sigchld_trap (command_string)
596 char *command_string;
597{
3185942a 598 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
726f6388
JA
599 set_signal (SIGCHLD, command_string);
600}
3185942a
JA
601
602/* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
603 as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
604 or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
605void
606set_impossible_sigchld_trap ()
607{
608 restore_default_signal (SIGCHLD);
609 change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER);
610 sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */
611}
ac50fbac
CR
612
613/* Act as if we received SIGCHLD NCHILD times and increment
614 pending_traps[SIGCHLD] by that amount. This allows us to still run the
615 SIGCHLD trap once for each exited child. */
616void
617queue_sigchld_trap (nchild)
618 int nchild;
619{
620 if (nchild > 0)
621 {
622 catch_flag = 1;
623 pending_traps[SIGCHLD] += nchild;
624 trapped_signal_received = SIGCHLD;
625 }
626}
726f6388
JA
627#endif /* JOB_CONTROL && SIGCHLD */
628
a0c0a00f
CR
629/* Set a trap for SIG only if SIG is not already trapped. */
630static inline void
631trap_if_untrapped (sig, command)
632 int sig;
633 char *command;
634{
635 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
636 set_signal (sig, command);
637}
638
ccc6cda3
JA
639void
640set_debug_trap (command)
726f6388
JA
641 char *command;
642{
ccc6cda3
JA
643 set_signal (DEBUG_TRAP, command);
644}
726f6388 645
a0c0a00f
CR
646/* Separate function to call when functions and sourced files want to restore
647 the original version of the DEBUG trap before returning. Unless the -T
648 option is set, source and shell function execution save the old debug trap
649 and unset the trap. If the function or sourced file changes the DEBUG trap,
650 SIG_TRAPPED will be set and we don't bother restoring the original trap string.
651 This is used by both functions and the source builtin. */
652void
653maybe_set_debug_trap (command)
654 char *command;
655{
656 trap_if_untrapped (DEBUG_TRAP, command);
657}
658
f73dda09
JA
659void
660set_error_trap (command)
661 char *command;
662{
663 set_signal (ERROR_TRAP, command);
664}
665
a0c0a00f
CR
666void
667maybe_set_error_trap (command)
668 char *command;
669{
670 trap_if_untrapped (ERROR_TRAP, command);
671}
672
b80f6443
JA
673void
674set_return_trap (command)
675 char *command;
676{
677 set_signal (RETURN_TRAP, command);
678}
679
a0c0a00f
CR
680void
681maybe_set_return_trap (command)
682 char *command;
683{
684 trap_if_untrapped (RETURN_TRAP, command);
685}
686
cce855bc 687#ifdef INCLUDE_UNUSED
ccc6cda3
JA
688void
689set_sigint_trap (command)
690 char *command;
691{
726f6388
JA
692 set_signal (SIGINT, command);
693}
cce855bc 694#endif
726f6388
JA
695
696/* Reset the SIGINT handler so that subshells that are doing `shellsy'
697 things, like waiting for command substitution or executing commands
698 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
699SigHandler *
700set_sigint_handler ()
701{
702 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
703 return ((SigHandler *)SIG_IGN);
704
705 else if (sigmodes[SIGINT] & SIG_IGNORED)
ccc6cda3
JA
706 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
707
726f6388
JA
708 else if (sigmodes[SIGINT] & SIG_TRAPPED)
709 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
710
711 /* The signal is not trapped, so set the handler to the shell's special
712 interrupt handler. */
713 else if (interactive) /* XXX - was interactive_shell */
714 return (set_signal_handler (SIGINT, sigint_sighandler));
715 else
0628567a 716 return (set_signal_handler (SIGINT, termsig_sighandler));
726f6388
JA
717}
718
e8ce775d
JA
719/* Return the correct handler for signal SIG according to the values in
720 sigmodes[SIG]. */
721SigHandler *
722trap_to_sighandler (sig)
723 int sig;
724{
725 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
726 return (SIG_IGN);
727 else if (sigmodes[sig] & SIG_TRAPPED)
728 return (trap_handler);
729 else
730 return (SIG_DFL);
731}
732
726f6388
JA
733/* Set SIG to call STRING as a command. */
734void
735set_signal (sig, string)
736 int sig;
737 char *string;
738{
ac50fbac
CR
739 sigset_t set, oset;
740
f73dda09 741 if (SPECIAL_TRAP (sig))
ccc6cda3
JA
742 {
743 change_signal (sig, savestring (string));
d166f048
JA
744 if (sig == EXIT_TRAP && interactive == 0)
745 initialize_terminating_signals ();
ccc6cda3
JA
746 return;
747 }
748
726f6388
JA
749 /* A signal ignored on entry to the shell cannot be trapped or reset, but
750 no error is reported when attempting to do so. -- Posix.2 */
751 if (sigmodes[sig] & SIG_HARD_IGNORE)
752 return;
753
754 /* Make sure we have original_signals[sig] if the signal has not yet
755 been trapped. */
756 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
757 {
758 /* If we aren't sure of the original value, check it. */
759 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
0628567a 760 GETORIGSIG (sig);
726f6388 761 if (original_signals[sig] == SIG_IGN)
0628567a 762 return;
726f6388
JA
763 }
764
765 /* Only change the system signal handler if SIG_NO_TRAP is not set.
766 The trap command string is changed in either case. The shell signal
767 handlers for SIGINT and SIGCHLD run the user specified traps in an
768 environment in which it is safe to do so. */
769 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
770 {
ac50fbac 771 BLOCK_SIGNAL (sig, set, oset);
726f6388
JA
772 change_signal (sig, savestring (string));
773 set_signal_handler (sig, trap_handler);
ac50fbac 774 UNBLOCK_SIGNAL (oset);
726f6388
JA
775 }
776 else
777 change_signal (sig, savestring (string));
778}
779
780static void
781free_trap_command (sig)
782 int sig;
783{
784 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
785 (trap_list[sig] != (char *)IGNORE_SIG) &&
786 (trap_list[sig] != (char *)DEFAULT_SIG) &&
787 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
788 free (trap_list[sig]);
789}
ccc6cda3 790
726f6388
JA
791/* If SIG has a string assigned to it, get rid of it. Then give it
792 VALUE. */
793static void
794change_signal (sig, value)
795 int sig;
796 char *value;
797{
d166f048
JA
798 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
799 free_trap_command (sig);
726f6388
JA
800 trap_list[sig] = value;
801
802 sigmodes[sig] |= SIG_TRAPPED;
803 if (value == (char *)IGNORE_SIG)
804 sigmodes[sig] |= SIG_IGNORED;
805 else
806 sigmodes[sig] &= ~SIG_IGNORED;
807 if (sigmodes[sig] & SIG_INPROGRESS)
808 sigmodes[sig] |= SIG_CHANGED;
809}
810
ac50fbac 811void
726f6388
JA
812get_original_signal (sig)
813 int sig;
814{
815 /* If we aren't sure the of the original value, then get it. */
0001803f 816 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
0628567a 817 GETORIGSIG (sig);
726f6388
JA
818}
819
495aee44
CR
820void
821get_all_original_signals ()
822{
823 register int i;
824
825 for (i = 1; i < NSIG; i++)
826 GET_ORIGINAL_SIGNAL (i);
827}
828
829void
830set_original_signal (sig, handler)
831 int sig;
832 SigHandler *handler;
833{
834 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
835 SETORIGSIG (sig, handler);
836}
837
726f6388
JA
838/* Restore the default action for SIG; i.e., the action the shell
839 would have taken before you used the trap command. This is called
840 from trap_builtin (), which takes care to restore the handlers for
841 the signals the shell treats specially. */
842void
843restore_default_signal (sig)
844 int sig;
845{
f73dda09 846 if (SPECIAL_TRAP (sig))
726f6388 847 {
b80f6443
JA
848 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
849 (sigmodes[sig] & SIG_INPROGRESS) == 0)
d166f048 850 free_trap_command (sig);
726f6388
JA
851 trap_list[sig] = (char *)NULL;
852 sigmodes[sig] &= ~SIG_TRAPPED;
d166f048
JA
853 if (sigmodes[sig] & SIG_INPROGRESS)
854 sigmodes[sig] |= SIG_CHANGED;
726f6388
JA
855 return;
856 }
857
858 GET_ORIGINAL_SIGNAL (sig);
859
860 /* A signal ignored on entry to the shell cannot be trapped or reset, but
861 no error is reported when attempting to do so. Thanks Posix.2. */
862 if (sigmodes[sig] & SIG_HARD_IGNORE)
863 return;
864
865 /* If we aren't trapping this signal, don't bother doing anything else. */
ac50fbac
CR
866 /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
867 sentinel to determine whether or not disposition is reset to the default
868 while the trap handler is executing. */
869 if (((sigmodes[sig] & SIG_TRAPPED) == 0) &&
870 (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
726f6388
JA
871 return;
872
873 /* Only change the signal handler for SIG if it allows it. */
ccc6cda3 874 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
726f6388
JA
875 set_signal_handler (sig, original_signals[sig]);
876
877 /* Change the trap command in either case. */
878 change_signal (sig, (char *)DEFAULT_SIG);
879
880 /* Mark the signal as no longer trapped. */
881 sigmodes[sig] &= ~SIG_TRAPPED;
882}
883
884/* Make this signal be ignored. */
885void
886ignore_signal (sig)
887 int sig;
888{
f73dda09 889 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
ccc6cda3
JA
890 {
891 change_signal (sig, (char *)IGNORE_SIG);
892 return;
893 }
894
726f6388
JA
895 GET_ORIGINAL_SIGNAL (sig);
896
897 /* A signal ignored on entry to the shell cannot be trapped or reset.
ccc6cda3 898 No error is reported when the user attempts to do so. */
726f6388
JA
899 if (sigmodes[sig] & SIG_HARD_IGNORE)
900 return;
901
902 /* If already trapped and ignored, no change necessary. */
ccc6cda3 903 if (sigmodes[sig] & SIG_IGNORED)
726f6388
JA
904 return;
905
906 /* Only change the signal handler for SIG if it allows it. */
ccc6cda3 907 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
726f6388
JA
908 set_signal_handler (sig, SIG_IGN);
909
910 /* Change the trap command in either case. */
911 change_signal (sig, (char *)IGNORE_SIG);
912}
913
914/* Handle the calling of "trap 0". The only sticky situation is when
915 the command to be executed includes an "exit". This is why we have
916 to provide our own place for top_level to jump to. */
917int
918run_exit_trap ()
919{
ccc6cda3 920 char *trap_command;
b80f6443 921 int code, function_code, retval;
495aee44
CR
922#if defined (ARRAY_VARS)
923 ARRAY *ps;
924#endif
726f6388 925
b80f6443 926 trap_saved_exit_value = last_command_exit_value;
495aee44
CR
927#if defined (ARRAY_VARS)
928 ps = save_pipestatus_array ();
929#endif
b80f6443 930 function_code = 0;
726f6388 931
ccc6cda3
JA
932 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
933 currently running in the trap handler (call to exit in the list of
934 commands given to trap 0). */
935 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
936 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
726f6388 937 {
ccc6cda3
JA
938 trap_command = savestring (trap_list[EXIT_TRAP]);
939 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
940 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
726f6388 941
b80f6443
JA
942 retval = trap_saved_exit_value;
943 running_trap = 1;
944
ac50fbac 945 code = setjmp_nosigs (top_level);
726f6388 946
b80f6443
JA
947 /* If we're in a function, make sure return longjmps come here, too. */
948 if (return_catch_flag)
ac50fbac 949 function_code = setjmp_nosigs (return_catch);
b80f6443
JA
950
951 if (code == 0 && function_code == 0)
cce855bc
JA
952 {
953 reset_parser ();
17345e5a 954 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
cce855bc 955 }
b80f6443
JA
956 else if (code == ERREXIT)
957 retval = last_command_exit_value;
726f6388 958 else if (code == EXITPROG)
b80f6443
JA
959 retval = last_command_exit_value;
960 else if (function_code != 0)
961 retval = return_catch_value;
726f6388 962 else
b80f6443
JA
963 retval = trap_saved_exit_value;
964
965 running_trap = 0;
a0c0a00f
CR
966#if defined (ARRAY_VARS)
967 array_dispose (ps);
968#endif
969
b80f6443 970 return retval;
726f6388
JA
971 }
972
495aee44
CR
973#if defined (ARRAY_VARS)
974 restore_pipestatus_array (ps);
975#endif
b80f6443 976 return (trap_saved_exit_value);
726f6388
JA
977}
978
ccc6cda3
JA
979void
980run_trap_cleanup (sig)
981 int sig;
982{
8868edaf 983 /* XXX - should we clean up trap_list[sig] == IMPOSSIBLE_TRAP_HANDLER? */
ccc6cda3
JA
984 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
985}
986
ac50fbac
CR
987#define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
988
ccc6cda3 989/* Run a trap command for SIG. SIG is one of the signals the shell treats
b80f6443
JA
990 specially. Returns the exit status of the executed trap command list. */
991static int
ccc6cda3 992_run_trap_internal (sig, tag)
726f6388 993 int sig;
ccc6cda3 994 char *tag;
726f6388 995{
ccc6cda3 996 char *trap_command, *old_trap;
d233b485 997 int trap_exit_value;
8868edaf
CR
998 volatile int save_return_catch_flag, function_code;
999 int old_modes, old_running, old_int;
ac50fbac 1000 int flags;
b80f6443 1001 procenv_t save_return_catch;
0001803f 1002 WORD_LIST *save_subst_varlist;
a0c0a00f 1003 HASH_TABLE *save_tempenv;
ac50fbac 1004 sh_parser_state_t pstate;
495aee44
CR
1005#if defined (ARRAY_VARS)
1006 ARRAY *ps;
1007#endif
ccc6cda3 1008
8868edaf
CR
1009 old_modes = old_running = -1;
1010
b80f6443 1011 trap_exit_value = function_code = 0;
a0c0a00f 1012 trap_saved_exit_value = last_command_exit_value;
ccc6cda3
JA
1013 /* Run the trap only if SIG is trapped and not ignored, and we are not
1014 currently executing in the trap handler. */
1015 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
1016 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
8868edaf 1017#if 1
ac50fbac
CR
1018 /* Uncomment this to allow some special signals to recursively execute
1019 trap handlers. */
1020 (RECURSIVE_SIG (sig) || (sigmodes[sig] & SIG_INPROGRESS) == 0))
1021#else
ccc6cda3 1022 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
ac50fbac 1023#endif
ccc6cda3
JA
1024 {
1025 old_trap = trap_list[sig];
8868edaf
CR
1026 old_modes = sigmodes[sig];
1027 old_running = running_trap;
1028
ccc6cda3
JA
1029 sigmodes[sig] |= SIG_INPROGRESS;
1030 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
1031 trap_command = savestring (old_trap);
1032
1033 running_trap = sig + 1;
ac50fbac 1034
a0c0a00f
CR
1035 old_int = interrupt_state; /* temporarily suppress pending interrupts */
1036 CLRINTERRUPT;
1037
495aee44
CR
1038#if defined (ARRAY_VARS)
1039 ps = save_pipestatus_array ();
1040#endif
bb70624e 1041
ac50fbac 1042 save_parser_state (&pstate);
0001803f
CR
1043 save_subst_varlist = subst_assign_varlist;
1044 subst_assign_varlist = 0;
a0c0a00f
CR
1045 save_tempenv = temporary_env;
1046 temporary_env = 0; /* traps should not run with temporary env */
b80f6443 1047
ac50fbac 1048#if defined (JOB_CONTROL)
7f89f4cd
CR
1049 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1050 save_pipeline (1); /* XXX only provides one save level */
ac50fbac
CR
1051#endif
1052
b80f6443
JA
1053 /* If we're in a function, make sure return longjmps come here, too. */
1054 save_return_catch_flag = return_catch_flag;
1055 if (return_catch_flag)
1056 {
1057 COPY_PROCENV (return_catch, save_return_catch);
ac50fbac 1058 function_code = setjmp_nosigs (return_catch);
b80f6443
JA
1059 }
1060
17345e5a 1061 flags = SEVAL_NONINT|SEVAL_NOHIST;
89a92869 1062 if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
17345e5a 1063 flags |= SEVAL_RESETLINE;
d233b485 1064 evalnest++;
b80f6443 1065 if (function_code == 0)
a0c0a00f
CR
1066 {
1067 parse_and_execute (trap_command, tag, flags);
1068 trap_exit_value = last_command_exit_value;
1069 }
1070 else
1071 trap_exit_value = return_catch_value;
d233b485 1072 evalnest--;
ac50fbac
CR
1073
1074#if defined (JOB_CONTROL)
7f89f4cd
CR
1075 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1076 restore_pipeline (1);
ac50fbac 1077#endif
bb70624e 1078
0001803f 1079 subst_assign_varlist = save_subst_varlist;
ac50fbac 1080 restore_parser_state (&pstate);
0001803f 1081
495aee44
CR
1082#if defined (ARRAY_VARS)
1083 restore_pipestatus_array (ps);
1084#endif
a0c0a00f
CR
1085
1086 temporary_env = save_tempenv;
ccc6cda3 1087
8868edaf
CR
1088 if ((old_modes & SIG_INPROGRESS) == 0)
1089 sigmodes[sig] &= ~SIG_INPROGRESS;
1090
1091 running_trap = old_running;
a0c0a00f 1092 interrupt_state = old_int;
ccc6cda3
JA
1093
1094 if (sigmodes[sig] & SIG_CHANGED)
1095 {
b80f6443
JA
1096#if 0
1097 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
1098 the places where they can be changed using unwind-protects. For
1099 example, look at execute_cmd.c:execute_function(). */
1100 if (SPECIAL_TRAP (sig) == 0)
1101#endif
1102 free (old_trap);
ccc6cda3 1103 sigmodes[sig] &= ~SIG_CHANGED;
d233b485
CR
1104
1105 CHECK_TERMSIG; /* some pathological conditions lead here */
ccc6cda3 1106 }
b80f6443
JA
1107
1108 if (save_return_catch_flag)
1109 {
1110 return_catch_flag = save_return_catch_flag;
1111 return_catch_value = trap_exit_value;
1112 COPY_PROCENV (save_return_catch, return_catch);
1113 if (function_code)
a0c0a00f
CR
1114 {
1115#if 0
1116 from_return_trap = sig == RETURN_TRAP;
1117#endif
1118 sh_longjmp (return_catch, 1);
1119 }
b80f6443 1120 }
ccc6cda3 1121 }
b80f6443
JA
1122
1123 return trap_exit_value;
ccc6cda3
JA
1124}
1125
b80f6443 1126int
ccc6cda3
JA
1127run_debug_trap ()
1128{
d233b485 1129 int trap_exit_value, old_verbose;
89a92869 1130 pid_t save_pgrp;
d233b485 1131#if defined (PGRP_PIPE)
89a92869 1132 int save_pipe[2];
d233b485 1133#endif
b80f6443
JA
1134
1135 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
1136 trap_exit_value = 0;
1137 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
1138 {
89a92869
CR
1139#if defined (JOB_CONTROL)
1140 save_pgrp = pipeline_pgrp;
1141 pipeline_pgrp = 0;
1142 save_pipeline (1);
1143# if defined (PGRP_PIPE)
1144 save_pgrp_pipe (save_pipe, 1);
1145# endif
1146 stop_making_children ();
1147#endif
1148
d233b485 1149 old_verbose = echo_input_at_read;
8868edaf 1150 echo_input_at_read = suppress_debug_trap_verbose ? 0 : echo_input_at_read;
d233b485 1151
b80f6443 1152 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
89a92869 1153
d233b485
CR
1154 echo_input_at_read = old_verbose;
1155
89a92869
CR
1156#if defined (JOB_CONTROL)
1157 pipeline_pgrp = save_pgrp;
1158 restore_pipeline (1);
1159# if defined (PGRP_PIPE)
1160 close_pgrp_pipe ();
1161 restore_pgrp_pipe (save_pipe);
1162# endif
d233b485 1163 if (pipeline_pgrp > 0 && ((subshell_environment & (SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0))
89a92869 1164 give_terminal_to (pipeline_pgrp, 1);
d233b485 1165
89a92869
CR
1166 notify_and_cleanup ();
1167#endif
b80f6443
JA
1168
1169#if defined (DEBUGGER)
1170 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
1171 a function or sourced script, we force a `return'. */
1172 if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
1173 {
1174 return_catch_value = trap_exit_value;
a0c0a00f 1175 sh_longjmp (return_catch, 1);
b80f6443
JA
1176 }
1177#endif
1178 }
1179 return trap_exit_value;
ccc6cda3
JA
1180}
1181
f73dda09
JA
1182void
1183run_error_trap ()
1184{
b80f6443 1185 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
f73dda09
JA
1186 _run_trap_internal (ERROR_TRAP, "error trap");
1187}
1188
b80f6443
JA
1189void
1190run_return_trap ()
1191{
1192 int old_exit_value;
1193
95732b49
JA
1194#if 0
1195 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
1196 return;
1197#endif
1198
b80f6443
JA
1199 if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
1200 {
1201 old_exit_value = last_command_exit_value;
1202 _run_trap_internal (RETURN_TRAP, "return trap");
1203 last_command_exit_value = old_exit_value;
1204 }
1205}
1206
ccc6cda3
JA
1207/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
1208 declared here to localize the trap functions. */
1209void
a0c0a00f
CR
1210run_interrupt_trap (will_throw)
1211 int will_throw; /* from throw_to_top_level? */
ccc6cda3 1212{
a0c0a00f
CR
1213 if (will_throw && running_trap > 0)
1214 run_trap_cleanup (running_trap - 1);
8868edaf
CR
1215 pending_traps[SIGINT] = 0; /* run_pending_traps does this */
1216 catch_flag = 0;
ccc6cda3 1217 _run_trap_internal (SIGINT, "interrupt trap");
726f6388
JA
1218}
1219
1220/* Free all the allocated strings in the list of traps and reset the trap
0001803f
CR
1221 values to the default. Intended to be called from subshells that want
1222 to complete work done by reset_signal_handlers upon execution of a
ac50fbac
CR
1223 subsequent `trap' command that changes a signal's disposition. We need
1224 to make sure that we duplicate the behavior of
1225 reset_or_restore_signal_handlers and not change the disposition of signals
1226 that are set to be ignored. */
726f6388
JA
1227void
1228free_trap_strings ()
1229{
1230 register int i;
1231
a0c0a00f 1232 for (i = 0; i < NSIG; i++)
ac50fbac
CR
1233 {
1234 if (trap_list[i] != (char *)IGNORE_SIG)
1235 free_trap_string (i);
1236 }
a0c0a00f
CR
1237 for (i = NSIG; i < BASH_NSIG; i++)
1238 {
1239 /* Don't free the trap string if the subshell inherited the trap */
1240 if ((sigmodes[i] & SIG_TRAPPED) == 0)
1241 {
1242 free_trap_string (i);
1243 trap_list[i] = (char *)NULL;
1244 }
1245 }
726f6388 1246}
0001803f
CR
1247
1248/* Free a trap command string associated with SIG without changing signal
1249 disposition. Intended to be called from free_trap_strings() */
1250static void
1251free_trap_string (sig)
1252 int sig;
1253{
1254 change_signal (sig, (char *)DEFAULT_SIG);
d233b485 1255 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
0001803f 1256}
726f6388 1257
495aee44
CR
1258/* Reset the handler for SIG to the original value but leave the trap string
1259 in place. */
726f6388
JA
1260static void
1261reset_signal (sig)
1262 int sig;
1263{
1264 set_signal_handler (sig, original_signals[sig]);
d233b485 1265 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
726f6388
JA
1266}
1267
ccc6cda3
JA
1268/* Set the handler signal SIG to the original and free any trap
1269 command associated with it. */
1270static void
1271restore_signal (sig)
1272 int sig;
726f6388 1273{
ccc6cda3
JA
1274 set_signal_handler (sig, original_signals[sig]);
1275 change_signal (sig, (char *)DEFAULT_SIG);
1276 sigmodes[sig] &= ~SIG_TRAPPED;
726f6388
JA
1277}
1278
ccc6cda3
JA
1279static void
1280reset_or_restore_signal_handlers (reset)
f73dda09 1281 sh_resetsig_func_t *reset;
726f6388
JA
1282{
1283 register int i;
1284
ccc6cda3
JA
1285 /* Take care of the exit trap first */
1286 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
726f6388 1287 {
d233b485 1288 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
95732b49
JA
1289 if (reset != reset_signal)
1290 {
1291 free_trap_command (EXIT_TRAP);
1292 trap_list[EXIT_TRAP] = (char *)NULL;
1293 }
726f6388 1294 }
b80f6443 1295
726f6388
JA
1296 for (i = 1; i < NSIG; i++)
1297 {
ccc6cda3 1298 if (sigmodes[i] & SIG_TRAPPED)
726f6388
JA
1299 {
1300 if (trap_list[i] == (char *)IGNORE_SIG)
1301 set_signal_handler (i, SIG_IGN);
1302 else
ccc6cda3 1303 (*reset) (i);
726f6388 1304 }
ccc6cda3
JA
1305 else if (sigmodes[i] & SIG_SPECIAL)
1306 (*reset) (i);
a0c0a00f 1307 pending_traps[i] = 0; /* XXX */
726f6388 1308 }
f73dda09
JA
1309
1310 /* Command substitution and other child processes don't inherit the
b80f6443
JA
1311 debug, error, or return traps. If we're in the debugger, and the
1312 `functrace' or `errtrace' options have been set, then let command
1313 substitutions inherit them. Let command substitution inherit the
1314 RETURN trap if we're in the debugger and tracing functions. */
0628567a
JA
1315 if (function_trace_mode == 0)
1316 {
1317 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
1318 sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
1319 }
1320 if (error_trace_mode == 0)
b80f6443 1321 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
726f6388
JA
1322}
1323
f73dda09 1324/* Reset trapped signals to their original values, but don't free the
495aee44
CR
1325 trap strings. Called by the command substitution code and other places
1326 that create a "subshell environment". */
726f6388 1327void
ccc6cda3 1328reset_signal_handlers ()
726f6388 1329{
ccc6cda3
JA
1330 reset_or_restore_signal_handlers (reset_signal);
1331}
726f6388 1332
ccc6cda3
JA
1333/* Reset all trapped signals to their original values. Signals set to be
1334 ignored with trap '' SIGNAL should be ignored, so we make sure that they
1335 are. Called by child processes after they are forked. */
1336void
1337restore_original_signals ()
1338{
1339 reset_or_restore_signal_handlers (restore_signal);
726f6388
JA
1340}
1341
1342/* If a trap handler exists for signal SIG, then call it; otherwise just
ac50fbac 1343 return failure. Returns 1 if it called the trap handler. */
726f6388
JA
1344int
1345maybe_call_trap_handler (sig)
1346 int sig;
1347{
1348 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
ccc6cda3 1349 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
726f6388
JA
1350 {
1351 switch (sig)
1352 {
1353 case SIGINT:
a0c0a00f 1354 run_interrupt_trap (0);
726f6388 1355 break;
ccc6cda3 1356 case EXIT_TRAP:
726f6388
JA
1357 run_exit_trap ();
1358 break;
ccc6cda3
JA
1359 case DEBUG_TRAP:
1360 run_debug_trap ();
1361 break;
f73dda09
JA
1362 case ERROR_TRAP:
1363 run_error_trap ();
1364 break;
726f6388
JA
1365 default:
1366 trap_handler (sig);
1367 break;
1368 }
1369 return (1);
1370 }
1371 else
1372 return (0);
1373}
1374
1375int
1376signal_is_trapped (sig)
1377 int sig;
1378{
1379 return (sigmodes[sig] & SIG_TRAPPED);
1380}
1381
ac50fbac
CR
1382int
1383signal_is_pending (sig)
1384 int sig;
1385{
1386 return (pending_traps[sig]);
1387}
1388
726f6388
JA
1389int
1390signal_is_special (sig)
1391 int sig;
1392{
1393 return (sigmodes[sig] & SIG_SPECIAL);
1394}
1395
1396int
1397signal_is_ignored (sig)
1398 int sig;
1399{
1400 return (sigmodes[sig] & SIG_IGNORED);
1401}
1402
495aee44
CR
1403int
1404signal_is_hard_ignored (sig)
1405 int sig;
1406{
1407 return (sigmodes[sig] & SIG_HARD_IGNORE);
1408}
1409
726f6388 1410void
ac50fbac 1411set_signal_hard_ignored (sig)
726f6388
JA
1412 int sig;
1413{
1414 sigmodes[sig] |= SIG_HARD_IGNORE;
ccc6cda3 1415 original_signals[sig] = SIG_IGN;
726f6388 1416}
95732b49 1417
ac50fbac
CR
1418void
1419set_signal_ignored (sig)
1420 int sig;
1421{
1422 original_signals[sig] = SIG_IGN;
1423}
1424
95732b49
JA
1425int
1426signal_in_progress (sig)
1427 int sig;
1428{
1429 return (sigmodes[sig] & SIG_INPROGRESS);
1430}
8868edaf
CR
1431
1432#if 0 /* TAG: bash-5.2 */
1433int
1434block_trapped_signals (maskp, omaskp)
1435 sigset_t *maskp;
1436 sigset_t *omaskp;
1437{
1438 int i;
1439
1440 sigemptyset (maskp);
1441 for (i = 1; i < NSIG; i++)
1442 if (sigmodes[i] & SIG_TRAPPED)
1443 sigaddset (maskp, i);
1444 return (sigprocmask (SIG_BLOCK, maskp, omaskp));
1445}
1446
1447int
1448unblock_trapped_signals (maskp)
1449 sigset_t *maskp;
1450{
1451 return (sigprocmask (SIG_SETMASK, maskp, 0));
1452}
1453#endif