]> git.ipfire.org Git - thirdparty/bash.git/blame - trap.c
Bash-4.0 patchlevel 38
[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
3185942a 4/* Copyright (C) 1987-2009 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
cce855bc
JA
36#include "trap.h"
37
726f6388 38#include "shell.h"
b80f6443 39#include "flags.h"
bb70624e 40#include "input.h" /* for save_token_state, restore_token_state */
3185942a 41#include "jobs.h"
726f6388 42#include "signames.h"
7117c2d2 43#include "builtins.h"
ccc6cda3 44#include "builtins/common.h"
7117c2d2 45#include "builtins/builtext.h"
726f6388 46
bb70624e
JA
47#ifndef errno
48extern int errno;
49#endif
50
726f6388
JA
51/* Flags which describe the current handling state of a signal. */
52#define SIG_INHERITED 0x0 /* Value inherited from parent. */
53#define SIG_TRAPPED 0x1 /* Currently trapped. */
54#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
55#define SIG_SPECIAL 0x4 /* Treat this signal specially. */
56#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
ccc6cda3
JA
57#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
58#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
59#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
726f6388 60
b80f6443 61#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
f73dda09 62
726f6388 63/* An array of such flags, one for each signal, describing what the
ccc6cda3
JA
64 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
65 assumes this. */
f73dda09
JA
66static int sigmodes[BASH_NSIG];
67
68static void free_trap_command __P((int));
69static void change_signal __P((int, char *));
70
71static void get_original_signal __P((int));
72
b80f6443 73static int _run_trap_internal __P((int, char *));
726f6388 74
f73dda09
JA
75static void reset_signal __P((int));
76static void restore_signal __P((int));
77static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
726f6388
JA
78
79/* Variables used here but defined in other files. */
726f6388 80extern int last_command_exit_value;
d166f048 81extern int line_number;
726f6388 82
b80f6443 83extern char *this_command_name;
7117c2d2
JA
84extern sh_builtin_func_t *this_shell_builtin;
85extern procenv_t wait_intr_buf;
b80f6443
JA
86extern int return_catch_flag, return_catch_value;
87extern int subshell_level;
7117c2d2 88
726f6388
JA
89/* The list of things to do originally, before we started trapping. */
90SigHandler *original_signals[NSIG];
91
92/* For each signal, a slot for a string, which is a command to be
93 executed when that signal is recieved. The slot can also contain
94 DEFAULT_SIG, which means do whatever you were going to do before
95 you were so rudely interrupted, or IGNORE_SIG, which says ignore
96 this signal. */
f73dda09 97char *trap_list[BASH_NSIG];
726f6388
JA
98
99/* A bitmap of signals received for which we have trap handlers. */
100int pending_traps[NSIG];
101
ccc6cda3
JA
102/* Set to the number of the signal we're running the trap for + 1.
103 Used in execute_cmd.c and builtins/common.c to clean up when
104 parse_and_execute does not return normally after executing the
105 trap command (e.g., when `return' is executed in the trap command). */
106int running_trap;
107
b80f6443
JA
108/* Set to last_command_exit_value before running a trap. */
109int trap_saved_exit_value;
d166f048 110
7117c2d2
JA
111/* The (trapped) signal received while executing in the `wait' builtin */
112int wait_signal_received;
113
726f6388
JA
114/* A value which can never be the target of a trap handler. */
115#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
116
0628567a
JA
117#define GETORIGSIG(sig) \
118 do { \
119 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
120 set_signal_handler (sig, original_signals[sig]); \
121 if (original_signals[sig] == SIG_IGN) \
122 sigmodes[sig] |= SIG_HARD_IGNORE; \
123 } while (0)
124
125#define GET_ORIGINAL_SIGNAL(sig) \
126 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
127 GETORIGSIG(sig)
128
726f6388
JA
129void
130initialize_traps ()
131{
132 register int i;
133
0628567a
JA
134 initialize_signames();
135
b80f6443
JA
136 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
137 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED;
ccc6cda3 138 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
726f6388
JA
139
140 for (i = 1; i < NSIG; i++)
141 {
142 pending_traps[i] = 0;
143 trap_list[i] = (char *)DEFAULT_SIG;
144 sigmodes[i] = SIG_INHERITED;
145 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
146 }
147
148 /* Show which signals are treated specially by the shell. */
149#if defined (SIGCHLD)
0628567a 150 GETORIGSIG (SIGCHLD);
726f6388
JA
151 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
152#endif /* SIGCHLD */
153
0628567a 154 GETORIGSIG (SIGINT);
726f6388
JA
155 sigmodes[SIGINT] |= SIG_SPECIAL;
156
b72432fd
JA
157#if defined (__BEOS__)
158 /* BeOS sets SIGINT to SIG_IGN! */
159 original_signals[SIGINT] = SIG_DFL;
0628567a 160 sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
b72432fd
JA
161#endif
162
0628567a 163 GETORIGSIG (SIGQUIT);
726f6388
JA
164 sigmodes[SIGQUIT] |= SIG_SPECIAL;
165
166 if (interactive)
167 {
0628567a 168 GETORIGSIG (SIGTERM);
726f6388
JA
169 sigmodes[SIGTERM] |= SIG_SPECIAL;
170 }
171}
172
bb70624e
JA
173#ifdef INCLUDE_UNUSED
174/* Return a printable representation of the trap handler for SIG. */
175static char *
176trap_handler_string (sig)
177 int sig;
178{
179 if (trap_list[sig] == (char *)DEFAULT_SIG)
180 return "DEFAULT_SIG";
181 else if (trap_list[sig] == (char *)IGNORE_SIG)
182 return "IGNORE_SIG";
183 else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
184 return "IMPOSSIBLE_TRAP_HANDLER";
185 else if (trap_list[sig])
186 return trap_list[sig];
187 else
188 return "NULL";
189}
190#endif
191
726f6388
JA
192/* Return the print name of this signal. */
193char *
194signal_name (sig)
195 int sig;
196{
cce855bc
JA
197 char *ret;
198
199 /* on cygwin32, signal_names[sig] could be null */
b80f6443
JA
200 ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL)
201 ? _("invalid signal number")
202 : signal_names[sig];
203
cce855bc 204 return ret;
726f6388
JA
205}
206
207/* Turn a string into a signal number, or a number into
208 a signal number. If STRING is "2", "SIGINT", or "INT",
209 then (int)2 is returned. Return NO_SIG if STRING doesn't
210 contain a valid signal descriptor. */
211int
b80f6443 212decode_signal (string, flags)
726f6388 213 char *string;
b80f6443 214 int flags;
726f6388 215{
7117c2d2 216 intmax_t sig;
b80f6443 217 char *name;
726f6388 218
ccc6cda3 219 if (legal_number (string, &sig))
f73dda09 220 return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
726f6388 221
e8ce775d 222 /* A leading `SIG' may be omitted. */
f73dda09 223 for (sig = 0; sig < BASH_NSIG; sig++)
b72432fd 224 {
b80f6443
JA
225 name = signal_names[sig];
226 if (name == 0 || name[0] == '\0')
b72432fd 227 continue;
b80f6443
JA
228
229 /* Check name without the SIG prefix first case sensitivly or
230 insensitively depending on whether flags includes DSIG_NOCASE */
231 if (STREQN (name, "SIG", 3))
232 {
233 name += 3;
234
235 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
236 return ((int)sig);
237 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
238 return ((int)sig);
239 /* If we can't use the `SIG' prefix to match, punt on this
240 name now. */
241 else if ((flags & DSIG_SIGPREFIX) == 0)
242 continue;
243 }
244
245 /* Check name with SIG prefix case sensitively or insensitively
246 depending on whether flags includes DSIG_NOCASE */
247 name = signal_names[sig];
248 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
249 return ((int)sig);
250 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
b72432fd
JA
251 return ((int)sig);
252 }
726f6388
JA
253
254 return (NO_SIG);
255}
256
257/* Non-zero when we catch a trapped signal. */
ccc6cda3 258static int catch_flag;
726f6388
JA
259
260void
261run_pending_traps ()
262{
263 register int sig;
bb70624e 264 int old_exit_value, *token_state;
726f6388
JA
265
266 if (catch_flag == 0) /* simple optimization */
267 return;
268
269 catch_flag = 0;
270
271 /* Preserve $? when running trap. */
272 old_exit_value = last_command_exit_value;
273
274 for (sig = 1; sig < NSIG; sig++)
275 {
276 /* XXX this could be made into a counter by using
28ef6c31 277 while (pending_traps[sig]--) instead of the if statement. */
726f6388
JA
278 if (pending_traps[sig])
279 {
ccc6cda3 280#if defined (HAVE_POSIX_SIGNALS)
726f6388
JA
281 sigset_t set, oset;
282
283 sigemptyset (&set);
284 sigemptyset (&oset);
285
286 sigaddset (&set, sig);
287 sigprocmask (SIG_BLOCK, &set, &oset);
288#else
289# if defined (HAVE_BSD_SIGNALS)
290 int oldmask = sigblock (sigmask (sig));
291# endif
ccc6cda3 292#endif /* HAVE_POSIX_SIGNALS */
726f6388
JA
293
294 if (sig == SIGINT)
295 {
296 run_interrupt_trap ();
ccc6cda3 297 CLRINTERRUPT;
726f6388 298 }
3185942a
JA
299#if defined (JOB_CONTROL) && defined (SIGCHLD)
300 else if (sig == SIGCHLD &&
301 trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER &&
302 (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0)
303 {
304 run_sigchld_trap (pending_traps[sig]); /* use as counter */
305 }
306#endif
bb70624e
JA
307 else if (trap_list[sig] == (char *)DEFAULT_SIG ||
308 trap_list[sig] == (char *)IGNORE_SIG ||
309 trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
310 {
311 /* This is possible due to a race condition. Say a bash
312 process has SIGTERM trapped. A subshell is spawned
313 using { list; } & and the parent does something and kills
314 the subshell with SIGTERM. It's possible for the subshell
315 to set pending_traps[SIGTERM] to 1 before the code in
316 execute_cmd.c eventually calls restore_original_signals
317 to reset the SIGTERM signal handler in the subshell. The
318 next time run_pending_traps is called, pending_traps[SIGTERM]
319 will be 1, but the trap handler in trap_list[SIGTERM] will
320 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
321 Unless we catch this, the subshell will dump core when
322 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
323 usually 0x0. */
b80f6443 324 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
f73dda09 325 sig, trap_list[sig]);
bb70624e
JA
326 if (trap_list[sig] == (char *)DEFAULT_SIG)
327 {
b80f6443 328 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig));
bb70624e
JA
329 kill (getpid (), sig);
330 }
331 }
726f6388 332 else
bb70624e
JA
333 {
334 token_state = save_token_state ();
17345e5a 335 parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
bb70624e
JA
336 restore_token_state (token_state);
337 free (token_state);
338 }
726f6388
JA
339
340 pending_traps[sig] = 0;
341
ccc6cda3 342#if defined (HAVE_POSIX_SIGNALS)
726f6388
JA
343 sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
344#else
345# if defined (HAVE_BSD_SIGNALS)
346 sigsetmask (oldmask);
347# endif
348#endif /* POSIX_VERSION */
349 }
350 }
351
352 last_command_exit_value = old_exit_value;
353}
354
355sighandler
356trap_handler (sig)
357 int sig;
358{
bb70624e
JA
359 int oerrno;
360
3185942a
JA
361 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
362 {
363#if defined (DEBUG)
364 internal_warning ("trap_handler: signal %d: signal not trapped", sig);
365#endif
366 SIGRETURN (0);
367 }
368
726f6388
JA
369 if ((sig >= NSIG) ||
370 (trap_list[sig] == (char *)DEFAULT_SIG) ||
371 (trap_list[sig] == (char *)IGNORE_SIG))
b80f6443 372 programming_error (_("trap_handler: bad signal %d"), sig);
726f6388
JA
373 else
374 {
28ef6c31 375 oerrno = errno;
ccc6cda3 376#if defined (MUST_REINSTALL_SIGHANDLERS)
3185942a
JA
377# if defined (JOB_CONTROL) && defined (SIGCHLD)
378 if (sig != SIGCHLD)
379# endif /* JOB_CONTROL && SIGCHLD */
726f6388 380 set_signal_handler (sig, trap_handler);
ccc6cda3 381#endif /* MUST_REINSTALL_SIGHANDLERS */
726f6388
JA
382
383 catch_flag = 1;
384 pending_traps[sig]++;
385
7117c2d2
JA
386 if (interrupt_immediately && this_shell_builtin && (this_shell_builtin == wait_builtin))
387 {
388 wait_signal_received = sig;
389 longjmp (wait_intr_buf, 1);
390 }
391
726f6388
JA
392 if (interrupt_immediately)
393 run_pending_traps ();
bb70624e
JA
394
395 errno = oerrno;
726f6388 396 }
ccc6cda3
JA
397
398 SIGRETURN (0);
726f6388
JA
399}
400
401#if defined (JOB_CONTROL) && defined (SIGCHLD)
cce855bc
JA
402
403#ifdef INCLUDE_UNUSED
726f6388
JA
404/* Make COMMAND_STRING be executed when SIGCHLD is caught. */
405void
406set_sigchld_trap (command_string)
407 char *command_string;
408{
726f6388
JA
409 set_signal (SIGCHLD, command_string);
410}
cce855bc 411#endif
726f6388 412
95732b49 413/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
3185942a
JA
414 is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
415 to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
416 reset the disposition to the default and not have the original signal
417 accidentally restored, undoing the user's command. */
726f6388
JA
418void
419maybe_set_sigchld_trap (command_string)
420 char *command_string;
421{
3185942a 422 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
726f6388
JA
423 set_signal (SIGCHLD, command_string);
424}
3185942a
JA
425
426/* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
427 as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
428 or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
429void
430set_impossible_sigchld_trap ()
431{
432 restore_default_signal (SIGCHLD);
433 change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER);
434 sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */
435}
726f6388
JA
436#endif /* JOB_CONTROL && SIGCHLD */
437
ccc6cda3
JA
438void
439set_debug_trap (command)
726f6388
JA
440 char *command;
441{
ccc6cda3
JA
442 set_signal (DEBUG_TRAP, command);
443}
726f6388 444
f73dda09
JA
445void
446set_error_trap (command)
447 char *command;
448{
449 set_signal (ERROR_TRAP, command);
450}
451
b80f6443
JA
452void
453set_return_trap (command)
454 char *command;
455{
456 set_signal (RETURN_TRAP, command);
457}
458
cce855bc 459#ifdef INCLUDE_UNUSED
ccc6cda3
JA
460void
461set_sigint_trap (command)
462 char *command;
463{
726f6388
JA
464 set_signal (SIGINT, command);
465}
cce855bc 466#endif
726f6388
JA
467
468/* Reset the SIGINT handler so that subshells that are doing `shellsy'
469 things, like waiting for command substitution or executing commands
470 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
471SigHandler *
472set_sigint_handler ()
473{
474 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
475 return ((SigHandler *)SIG_IGN);
476
477 else if (sigmodes[SIGINT] & SIG_IGNORED)
ccc6cda3
JA
478 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
479
726f6388
JA
480 else if (sigmodes[SIGINT] & SIG_TRAPPED)
481 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
482
483 /* The signal is not trapped, so set the handler to the shell's special
484 interrupt handler. */
485 else if (interactive) /* XXX - was interactive_shell */
486 return (set_signal_handler (SIGINT, sigint_sighandler));
487 else
0628567a 488 return (set_signal_handler (SIGINT, termsig_sighandler));
726f6388
JA
489}
490
e8ce775d
JA
491/* Return the correct handler for signal SIG according to the values in
492 sigmodes[SIG]. */
493SigHandler *
494trap_to_sighandler (sig)
495 int sig;
496{
497 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
498 return (SIG_IGN);
499 else if (sigmodes[sig] & SIG_TRAPPED)
500 return (trap_handler);
501 else
502 return (SIG_DFL);
503}
504
726f6388
JA
505/* Set SIG to call STRING as a command. */
506void
507set_signal (sig, string)
508 int sig;
509 char *string;
510{
f73dda09 511 if (SPECIAL_TRAP (sig))
ccc6cda3
JA
512 {
513 change_signal (sig, savestring (string));
d166f048
JA
514 if (sig == EXIT_TRAP && interactive == 0)
515 initialize_terminating_signals ();
ccc6cda3
JA
516 return;
517 }
518
726f6388
JA
519 /* A signal ignored on entry to the shell cannot be trapped or reset, but
520 no error is reported when attempting to do so. -- Posix.2 */
521 if (sigmodes[sig] & SIG_HARD_IGNORE)
522 return;
523
524 /* Make sure we have original_signals[sig] if the signal has not yet
525 been trapped. */
526 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
527 {
528 /* If we aren't sure of the original value, check it. */
529 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
0628567a 530 GETORIGSIG (sig);
726f6388 531 if (original_signals[sig] == SIG_IGN)
0628567a 532 return;
726f6388
JA
533 }
534
535 /* Only change the system signal handler if SIG_NO_TRAP is not set.
536 The trap command string is changed in either case. The shell signal
537 handlers for SIGINT and SIGCHLD run the user specified traps in an
538 environment in which it is safe to do so. */
539 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
540 {
541 set_signal_handler (sig, SIG_IGN);
542 change_signal (sig, savestring (string));
543 set_signal_handler (sig, trap_handler);
544 }
545 else
546 change_signal (sig, savestring (string));
547}
548
549static void
550free_trap_command (sig)
551 int sig;
552{
553 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
554 (trap_list[sig] != (char *)IGNORE_SIG) &&
555 (trap_list[sig] != (char *)DEFAULT_SIG) &&
556 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
557 free (trap_list[sig]);
558}
ccc6cda3 559
726f6388
JA
560/* If SIG has a string assigned to it, get rid of it. Then give it
561 VALUE. */
562static void
563change_signal (sig, value)
564 int sig;
565 char *value;
566{
d166f048
JA
567 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
568 free_trap_command (sig);
726f6388
JA
569 trap_list[sig] = value;
570
571 sigmodes[sig] |= SIG_TRAPPED;
572 if (value == (char *)IGNORE_SIG)
573 sigmodes[sig] |= SIG_IGNORED;
574 else
575 sigmodes[sig] &= ~SIG_IGNORED;
576 if (sigmodes[sig] & SIG_INPROGRESS)
577 sigmodes[sig] |= SIG_CHANGED;
578}
579
726f6388
JA
580static void
581get_original_signal (sig)
582 int sig;
583{
584 /* If we aren't sure the of the original value, then get it. */
585 if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
0628567a 586 GETORIGSIG (sig);
726f6388
JA
587}
588
589/* Restore the default action for SIG; i.e., the action the shell
590 would have taken before you used the trap command. This is called
591 from trap_builtin (), which takes care to restore the handlers for
592 the signals the shell treats specially. */
593void
594restore_default_signal (sig)
595 int sig;
596{
f73dda09 597 if (SPECIAL_TRAP (sig))
726f6388 598 {
b80f6443
JA
599 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
600 (sigmodes[sig] & SIG_INPROGRESS) == 0)
d166f048 601 free_trap_command (sig);
726f6388
JA
602 trap_list[sig] = (char *)NULL;
603 sigmodes[sig] &= ~SIG_TRAPPED;
d166f048
JA
604 if (sigmodes[sig] & SIG_INPROGRESS)
605 sigmodes[sig] |= SIG_CHANGED;
726f6388
JA
606 return;
607 }
608
609 GET_ORIGINAL_SIGNAL (sig);
610
611 /* A signal ignored on entry to the shell cannot be trapped or reset, but
612 no error is reported when attempting to do so. Thanks Posix.2. */
613 if (sigmodes[sig] & SIG_HARD_IGNORE)
614 return;
615
616 /* If we aren't trapping this signal, don't bother doing anything else. */
ccc6cda3 617 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
726f6388
JA
618 return;
619
620 /* Only change the signal handler for SIG if it allows it. */
ccc6cda3 621 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
726f6388
JA
622 set_signal_handler (sig, original_signals[sig]);
623
624 /* Change the trap command in either case. */
625 change_signal (sig, (char *)DEFAULT_SIG);
626
627 /* Mark the signal as no longer trapped. */
628 sigmodes[sig] &= ~SIG_TRAPPED;
629}
630
631/* Make this signal be ignored. */
632void
633ignore_signal (sig)
634 int sig;
635{
f73dda09 636 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
ccc6cda3
JA
637 {
638 change_signal (sig, (char *)IGNORE_SIG);
639 return;
640 }
641
726f6388
JA
642 GET_ORIGINAL_SIGNAL (sig);
643
644 /* A signal ignored on entry to the shell cannot be trapped or reset.
ccc6cda3 645 No error is reported when the user attempts to do so. */
726f6388
JA
646 if (sigmodes[sig] & SIG_HARD_IGNORE)
647 return;
648
649 /* If already trapped and ignored, no change necessary. */
ccc6cda3 650 if (sigmodes[sig] & SIG_IGNORED)
726f6388
JA
651 return;
652
653 /* Only change the signal handler for SIG if it allows it. */
ccc6cda3 654 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
726f6388
JA
655 set_signal_handler (sig, SIG_IGN);
656
657 /* Change the trap command in either case. */
658 change_signal (sig, (char *)IGNORE_SIG);
659}
660
661/* Handle the calling of "trap 0". The only sticky situation is when
662 the command to be executed includes an "exit". This is why we have
663 to provide our own place for top_level to jump to. */
664int
665run_exit_trap ()
666{
ccc6cda3 667 char *trap_command;
b80f6443 668 int code, function_code, retval;
726f6388 669
b80f6443
JA
670 trap_saved_exit_value = last_command_exit_value;
671 function_code = 0;
726f6388 672
ccc6cda3
JA
673 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
674 currently running in the trap handler (call to exit in the list of
675 commands given to trap 0). */
676 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
677 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
726f6388 678 {
ccc6cda3
JA
679 trap_command = savestring (trap_list[EXIT_TRAP]);
680 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
681 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
726f6388 682
b80f6443
JA
683 retval = trap_saved_exit_value;
684 running_trap = 1;
685
726f6388
JA
686 code = setjmp (top_level);
687
b80f6443
JA
688 /* If we're in a function, make sure return longjmps come here, too. */
689 if (return_catch_flag)
690 function_code = setjmp (return_catch);
691
692 if (code == 0 && function_code == 0)
cce855bc
JA
693 {
694 reset_parser ();
17345e5a 695 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
cce855bc 696 }
b80f6443
JA
697 else if (code == ERREXIT)
698 retval = last_command_exit_value;
726f6388 699 else if (code == EXITPROG)
b80f6443
JA
700 retval = last_command_exit_value;
701 else if (function_code != 0)
702 retval = return_catch_value;
726f6388 703 else
b80f6443
JA
704 retval = trap_saved_exit_value;
705
706 running_trap = 0;
707 return retval;
726f6388
JA
708 }
709
b80f6443 710 return (trap_saved_exit_value);
726f6388
JA
711}
712
ccc6cda3
JA
713void
714run_trap_cleanup (sig)
715 int sig;
716{
717 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
718}
719
720/* Run a trap command for SIG. SIG is one of the signals the shell treats
b80f6443
JA
721 specially. Returns the exit status of the executed trap command list. */
722static int
ccc6cda3 723_run_trap_internal (sig, tag)
726f6388 724 int sig;
ccc6cda3 725 char *tag;
726f6388 726{
ccc6cda3 727 char *trap_command, *old_trap;
b80f6443 728 int trap_exit_value, *token_state;
17345e5a 729 int save_return_catch_flag, function_code, flags;
b80f6443 730 procenv_t save_return_catch;
ccc6cda3 731
b80f6443 732 trap_exit_value = function_code = 0;
ccc6cda3
JA
733 /* Run the trap only if SIG is trapped and not ignored, and we are not
734 currently executing in the trap handler. */
735 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
736 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
737 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
738 {
739 old_trap = trap_list[sig];
740 sigmodes[sig] |= SIG_INPROGRESS;
741 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
742 trap_command = savestring (old_trap);
743
744 running_trap = sig + 1;
b80f6443 745 trap_saved_exit_value = last_command_exit_value;
bb70624e
JA
746
747 token_state = save_token_state ();
b80f6443
JA
748
749 /* If we're in a function, make sure return longjmps come here, too. */
750 save_return_catch_flag = return_catch_flag;
751 if (return_catch_flag)
752 {
753 COPY_PROCENV (return_catch, save_return_catch);
754 function_code = setjmp (return_catch);
755 }
756
17345e5a 757 flags = SEVAL_NONINT|SEVAL_NOHIST;
89a92869 758 if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
17345e5a 759 flags |= SEVAL_RESETLINE;
b80f6443 760 if (function_code == 0)
17345e5a 761 parse_and_execute (trap_command, tag, flags);
b80f6443 762
bb70624e
JA
763 restore_token_state (token_state);
764 free (token_state);
765
b80f6443
JA
766 trap_exit_value = last_command_exit_value;
767 last_command_exit_value = trap_saved_exit_value;
ccc6cda3
JA
768 running_trap = 0;
769
770 sigmodes[sig] &= ~SIG_INPROGRESS;
771
772 if (sigmodes[sig] & SIG_CHANGED)
773 {
b80f6443
JA
774#if 0
775 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
776 the places where they can be changed using unwind-protects. For
777 example, look at execute_cmd.c:execute_function(). */
778 if (SPECIAL_TRAP (sig) == 0)
779#endif
780 free (old_trap);
ccc6cda3
JA
781 sigmodes[sig] &= ~SIG_CHANGED;
782 }
b80f6443
JA
783
784 if (save_return_catch_flag)
785 {
786 return_catch_flag = save_return_catch_flag;
787 return_catch_value = trap_exit_value;
788 COPY_PROCENV (save_return_catch, return_catch);
789 if (function_code)
790 longjmp (return_catch, 1);
791 }
ccc6cda3 792 }
b80f6443
JA
793
794 return trap_exit_value;
ccc6cda3
JA
795}
796
b80f6443 797int
ccc6cda3
JA
798run_debug_trap ()
799{
b80f6443 800 int trap_exit_value;
89a92869
CR
801 pid_t save_pgrp;
802 int save_pipe[2];
b80f6443
JA
803
804 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
805 trap_exit_value = 0;
806 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
807 {
89a92869
CR
808#if defined (JOB_CONTROL)
809 save_pgrp = pipeline_pgrp;
810 pipeline_pgrp = 0;
811 save_pipeline (1);
812# if defined (PGRP_PIPE)
813 save_pgrp_pipe (save_pipe, 1);
814# endif
815 stop_making_children ();
816#endif
817
b80f6443 818 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
89a92869
CR
819
820#if defined (JOB_CONTROL)
821 pipeline_pgrp = save_pgrp;
822 restore_pipeline (1);
823# if defined (PGRP_PIPE)
824 close_pgrp_pipe ();
825 restore_pgrp_pipe (save_pipe);
826# endif
827 if (pipeline_pgrp > 0)
828 give_terminal_to (pipeline_pgrp, 1);
829 notify_and_cleanup ();
830#endif
b80f6443
JA
831
832#if defined (DEBUGGER)
833 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
834 a function or sourced script, we force a `return'. */
835 if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
836 {
837 return_catch_value = trap_exit_value;
838 longjmp (return_catch, 1);
839 }
840#endif
841 }
842 return trap_exit_value;
ccc6cda3
JA
843}
844
f73dda09
JA
845void
846run_error_trap ()
847{
b80f6443 848 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
f73dda09
JA
849 _run_trap_internal (ERROR_TRAP, "error trap");
850}
851
b80f6443
JA
852void
853run_return_trap ()
854{
855 int old_exit_value;
856
95732b49
JA
857#if 0
858 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
859 return;
860#endif
861
b80f6443
JA
862 if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
863 {
864 old_exit_value = last_command_exit_value;
865 _run_trap_internal (RETURN_TRAP, "return trap");
866 last_command_exit_value = old_exit_value;
867 }
868}
869
ccc6cda3
JA
870/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
871 declared here to localize the trap functions. */
872void
873run_interrupt_trap ()
874{
875 _run_trap_internal (SIGINT, "interrupt trap");
726f6388
JA
876}
877
cce855bc 878#ifdef INCLUDE_UNUSED
726f6388
JA
879/* Free all the allocated strings in the list of traps and reset the trap
880 values to the default. */
881void
882free_trap_strings ()
883{
884 register int i;
885
f73dda09 886 for (i = 0; i < BASH_NSIG; i++)
726f6388
JA
887 {
888 free_trap_command (i);
889 trap_list[i] = (char *)DEFAULT_SIG;
890 sigmodes[i] &= ~SIG_TRAPPED;
891 }
b80f6443 892 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
726f6388 893}
cce855bc 894#endif
726f6388
JA
895
896/* Reset the handler for SIG to the original value. */
897static void
898reset_signal (sig)
899 int sig;
900{
901 set_signal_handler (sig, original_signals[sig]);
7117c2d2 902 sigmodes[sig] &= ~SIG_TRAPPED;
726f6388
JA
903}
904
ccc6cda3
JA
905/* Set the handler signal SIG to the original and free any trap
906 command associated with it. */
907static void
908restore_signal (sig)
909 int sig;
726f6388 910{
ccc6cda3
JA
911 set_signal_handler (sig, original_signals[sig]);
912 change_signal (sig, (char *)DEFAULT_SIG);
913 sigmodes[sig] &= ~SIG_TRAPPED;
726f6388
JA
914}
915
ccc6cda3
JA
916static void
917reset_or_restore_signal_handlers (reset)
f73dda09 918 sh_resetsig_func_t *reset;
726f6388
JA
919{
920 register int i;
921
ccc6cda3
JA
922 /* Take care of the exit trap first */
923 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
726f6388 924 {
ccc6cda3 925 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
95732b49
JA
926 if (reset != reset_signal)
927 {
928 free_trap_command (EXIT_TRAP);
929 trap_list[EXIT_TRAP] = (char *)NULL;
930 }
726f6388 931 }
b80f6443 932
726f6388
JA
933 for (i = 1; i < NSIG; i++)
934 {
ccc6cda3 935 if (sigmodes[i] & SIG_TRAPPED)
726f6388
JA
936 {
937 if (trap_list[i] == (char *)IGNORE_SIG)
938 set_signal_handler (i, SIG_IGN);
939 else
ccc6cda3 940 (*reset) (i);
726f6388 941 }
ccc6cda3
JA
942 else if (sigmodes[i] & SIG_SPECIAL)
943 (*reset) (i);
726f6388 944 }
f73dda09
JA
945
946 /* Command substitution and other child processes don't inherit the
b80f6443
JA
947 debug, error, or return traps. If we're in the debugger, and the
948 `functrace' or `errtrace' options have been set, then let command
949 substitutions inherit them. Let command substitution inherit the
950 RETURN trap if we're in the debugger and tracing functions. */
0628567a
JA
951 if (function_trace_mode == 0)
952 {
953 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
954 sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
955 }
956 if (error_trace_mode == 0)
b80f6443 957 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
726f6388
JA
958}
959
f73dda09
JA
960/* Reset trapped signals to their original values, but don't free the
961 trap strings. Called by the command substitution code. */
726f6388 962void
ccc6cda3 963reset_signal_handlers ()
726f6388 964{
ccc6cda3
JA
965 reset_or_restore_signal_handlers (reset_signal);
966}
726f6388 967
ccc6cda3
JA
968/* Reset all trapped signals to their original values. Signals set to be
969 ignored with trap '' SIGNAL should be ignored, so we make sure that they
970 are. Called by child processes after they are forked. */
971void
972restore_original_signals ()
973{
974 reset_or_restore_signal_handlers (restore_signal);
726f6388
JA
975}
976
977/* If a trap handler exists for signal SIG, then call it; otherwise just
978 return failure. */
979int
980maybe_call_trap_handler (sig)
981 int sig;
982{
983 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
ccc6cda3 984 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
726f6388
JA
985 {
986 switch (sig)
987 {
988 case SIGINT:
989 run_interrupt_trap ();
990 break;
ccc6cda3 991 case EXIT_TRAP:
726f6388
JA
992 run_exit_trap ();
993 break;
ccc6cda3
JA
994 case DEBUG_TRAP:
995 run_debug_trap ();
996 break;
f73dda09
JA
997 case ERROR_TRAP:
998 run_error_trap ();
999 break;
726f6388
JA
1000 default:
1001 trap_handler (sig);
1002 break;
1003 }
1004 return (1);
1005 }
1006 else
1007 return (0);
1008}
1009
1010int
1011signal_is_trapped (sig)
1012 int sig;
1013{
1014 return (sigmodes[sig] & SIG_TRAPPED);
1015}
1016
1017int
1018signal_is_special (sig)
1019 int sig;
1020{
1021 return (sigmodes[sig] & SIG_SPECIAL);
1022}
1023
1024int
1025signal_is_ignored (sig)
1026 int sig;
1027{
1028 return (sigmodes[sig] & SIG_IGNORED);
1029}
1030
1031void
1032set_signal_ignored (sig)
1033 int sig;
1034{
1035 sigmodes[sig] |= SIG_HARD_IGNORE;
ccc6cda3 1036 original_signals[sig] = SIG_IGN;
726f6388 1037}
95732b49
JA
1038
1039int
1040signal_in_progress (sig)
1041 int sig;
1042{
1043 return (sigmodes[sig] & SIG_INPROGRESS);
1044}