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