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