]> git.ipfire.org Git - thirdparty/bash.git/blame - trap.c
Imported from ../bash-2.05b.tar.gz.
[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
7117c2d2 4/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
726f6388
JA
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
bb70624e 10 Software Foundation; either version 2, or (at your option) any later
726f6388
JA
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
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
JA
33
34#include "trap.h"
35
726f6388 36#include "shell.h"
bb70624e 37#include "input.h" /* for save_token_state, restore_token_state */
726f6388 38#include "signames.h"
7117c2d2 39#include "builtins.h"
ccc6cda3 40#include "builtins/common.h"
7117c2d2 41#include "builtins/builtext.h"
726f6388 42
bb70624e
JA
43#ifndef errno
44extern int errno;
45#endif
46
726f6388
JA
47/* Flags which describe the current handling state of a signal. */
48#define SIG_INHERITED 0x0 /* Value inherited from parent. */
49#define SIG_TRAPPED 0x1 /* Currently trapped. */
50#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
51#define SIG_SPECIAL 0x4 /* Treat this signal specially. */
52#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
ccc6cda3
JA
53#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
54#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
55#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
726f6388 56
f73dda09
JA
57#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP)
58
726f6388 59/* An array of such flags, one for each signal, describing what the
ccc6cda3
JA
60 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
61 assumes this. */
f73dda09
JA
62static int sigmodes[BASH_NSIG];
63
64static void free_trap_command __P((int));
65static void change_signal __P((int, char *));
66
67static void get_original_signal __P((int));
68
69static void _run_trap_internal __P((int, char *));
726f6388 70
f73dda09
JA
71static void reset_signal __P((int));
72static void restore_signal __P((int));
73static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
726f6388
JA
74
75/* Variables used here but defined in other files. */
726f6388
JA
76extern int interrupt_immediately;
77extern int last_command_exit_value;
d166f048 78extern int line_number;
726f6388 79
7117c2d2
JA
80extern sh_builtin_func_t *this_shell_builtin;
81extern procenv_t wait_intr_buf;
82
726f6388
JA
83/* The list of things to do originally, before we started trapping. */
84SigHandler *original_signals[NSIG];
85
86/* For each signal, a slot for a string, which is a command to be
87 executed when that signal is recieved. The slot can also contain
88 DEFAULT_SIG, which means do whatever you were going to do before
89 you were so rudely interrupted, or IGNORE_SIG, which says ignore
90 this signal. */
f73dda09 91char *trap_list[BASH_NSIG];
726f6388
JA
92
93/* A bitmap of signals received for which we have trap handlers. */
94int pending_traps[NSIG];
95
ccc6cda3
JA
96/* Set to the number of the signal we're running the trap for + 1.
97 Used in execute_cmd.c and builtins/common.c to clean up when
98 parse_and_execute does not return normally after executing the
99 trap command (e.g., when `return' is executed in the trap command). */
100int running_trap;
101
d166f048
JA
102/* The value of line_number when the trap started executing, since
103 parse_and_execute resets it to 1 and the trap command might want
104 it. */
105int trap_line_number;
106
7117c2d2
JA
107/* The (trapped) signal received while executing in the `wait' builtin */
108int wait_signal_received;
109
726f6388
JA
110/* A value which can never be the target of a trap handler. */
111#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
112
113void
114initialize_traps ()
115{
116 register int i;
117
f73dda09
JA
118 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = (char *)NULL;
119 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = SIG_INHERITED;
ccc6cda3 120 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
726f6388
JA
121
122 for (i = 1; i < NSIG; i++)
123 {
124 pending_traps[i] = 0;
125 trap_list[i] = (char *)DEFAULT_SIG;
126 sigmodes[i] = SIG_INHERITED;
127 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
128 }
129
130 /* Show which signals are treated specially by the shell. */
131#if defined (SIGCHLD)
ccc6cda3
JA
132 original_signals[SIGCHLD] =
133 (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
726f6388
JA
134 set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
135 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
136#endif /* SIGCHLD */
137
138 original_signals[SIGINT] =
139 (SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
140 set_signal_handler (SIGINT, original_signals[SIGINT]);
141 sigmodes[SIGINT] |= SIG_SPECIAL;
142
b72432fd
JA
143#if defined (__BEOS__)
144 /* BeOS sets SIGINT to SIG_IGN! */
145 original_signals[SIGINT] = SIG_DFL;
146#endif
147
726f6388
JA
148 original_signals[SIGQUIT] =
149 (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
150 set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
151 sigmodes[SIGQUIT] |= SIG_SPECIAL;
152
153 if (interactive)
154 {
ccc6cda3
JA
155 original_signals[SIGTERM] =
156 (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
726f6388
JA
157 set_signal_handler (SIGTERM, original_signals[SIGTERM]);
158 sigmodes[SIGTERM] |= SIG_SPECIAL;
159 }
160}
161
bb70624e
JA
162#ifdef INCLUDE_UNUSED
163/* Return a printable representation of the trap handler for SIG. */
164static char *
165trap_handler_string (sig)
166 int sig;
167{
168 if (trap_list[sig] == (char *)DEFAULT_SIG)
169 return "DEFAULT_SIG";
170 else if (trap_list[sig] == (char *)IGNORE_SIG)
171 return "IGNORE_SIG";
172 else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
173 return "IMPOSSIBLE_TRAP_HANDLER";
174 else if (trap_list[sig])
175 return trap_list[sig];
176 else
177 return "NULL";
178}
179#endif
180
726f6388
JA
181/* Return the print name of this signal. */
182char *
183signal_name (sig)
184 int sig;
185{
cce855bc
JA
186 char *ret;
187
188 /* on cygwin32, signal_names[sig] could be null */
7117c2d2 189 ret = (sig >= BASH_NSIG || sig < 0) ? "bad signal number" : signal_names[sig];
cce855bc
JA
190 if (ret == NULL)
191 ret = "unrecognized signal number";
192 return ret;
726f6388
JA
193}
194
195/* Turn a string into a signal number, or a number into
196 a signal number. If STRING is "2", "SIGINT", or "INT",
197 then (int)2 is returned. Return NO_SIG if STRING doesn't
198 contain a valid signal descriptor. */
199int
200decode_signal (string)
201 char *string;
202{
7117c2d2 203 intmax_t sig;
726f6388 204
ccc6cda3 205 if (legal_number (string, &sig))
f73dda09 206 return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
726f6388 207
e8ce775d 208 /* A leading `SIG' may be omitted. */
f73dda09 209 for (sig = 0; sig < BASH_NSIG; sig++)
b72432fd
JA
210 {
211 if (signal_names[sig] == 0 || signal_names[sig][0] == '\0')
212 continue;
213 if (strcasecmp (string, signal_names[sig]) == 0 ||
214 (STREQN (signal_names[sig], "SIG", 3) &&
215 strcasecmp (string, &(signal_names[sig])[3]) == 0))
216 return ((int)sig);
217 }
726f6388
JA
218
219 return (NO_SIG);
220}
221
222/* Non-zero when we catch a trapped signal. */
ccc6cda3 223static int catch_flag;
726f6388
JA
224
225void
226run_pending_traps ()
227{
228 register int sig;
bb70624e 229 int old_exit_value, *token_state;
726f6388
JA
230
231 if (catch_flag == 0) /* simple optimization */
232 return;
233
234 catch_flag = 0;
235
236 /* Preserve $? when running trap. */
237 old_exit_value = last_command_exit_value;
238
239 for (sig = 1; sig < NSIG; sig++)
240 {
241 /* XXX this could be made into a counter by using
28ef6c31 242 while (pending_traps[sig]--) instead of the if statement. */
726f6388
JA
243 if (pending_traps[sig])
244 {
ccc6cda3 245#if defined (HAVE_POSIX_SIGNALS)
726f6388
JA
246 sigset_t set, oset;
247
248 sigemptyset (&set);
249 sigemptyset (&oset);
250
251 sigaddset (&set, sig);
252 sigprocmask (SIG_BLOCK, &set, &oset);
253#else
254# if defined (HAVE_BSD_SIGNALS)
255 int oldmask = sigblock (sigmask (sig));
256# endif
ccc6cda3 257#endif /* HAVE_POSIX_SIGNALS */
726f6388
JA
258
259 if (sig == SIGINT)
260 {
261 run_interrupt_trap ();
ccc6cda3 262 CLRINTERRUPT;
726f6388 263 }
bb70624e
JA
264 else if (trap_list[sig] == (char *)DEFAULT_SIG ||
265 trap_list[sig] == (char *)IGNORE_SIG ||
266 trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
267 {
268 /* This is possible due to a race condition. Say a bash
269 process has SIGTERM trapped. A subshell is spawned
270 using { list; } & and the parent does something and kills
271 the subshell with SIGTERM. It's possible for the subshell
272 to set pending_traps[SIGTERM] to 1 before the code in
273 execute_cmd.c eventually calls restore_original_signals
274 to reset the SIGTERM signal handler in the subshell. The
275 next time run_pending_traps is called, pending_traps[SIGTERM]
276 will be 1, but the trap handler in trap_list[SIGTERM] will
277 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
278 Unless we catch this, the subshell will dump core when
279 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
280 usually 0x0. */
f73dda09
JA
281 internal_warning ("run_pending_traps: bad value in trap_list[%d]: %p",
282 sig, trap_list[sig]);
bb70624e
JA
283 if (trap_list[sig] == (char *)DEFAULT_SIG)
284 {
285 internal_warning ("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself", sig, signal_name (sig));
286 kill (getpid (), sig);
287 }
288 }
726f6388 289 else
bb70624e
JA
290 {
291 token_state = save_token_state ();
292 parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST);
293 restore_token_state (token_state);
294 free (token_state);
295 }
726f6388
JA
296
297 pending_traps[sig] = 0;
298
ccc6cda3 299#if defined (HAVE_POSIX_SIGNALS)
726f6388
JA
300 sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
301#else
302# if defined (HAVE_BSD_SIGNALS)
303 sigsetmask (oldmask);
304# endif
305#endif /* POSIX_VERSION */
306 }
307 }
308
309 last_command_exit_value = old_exit_value;
310}
311
312sighandler
313trap_handler (sig)
314 int sig;
315{
bb70624e
JA
316 int oerrno;
317
726f6388
JA
318 if ((sig >= NSIG) ||
319 (trap_list[sig] == (char *)DEFAULT_SIG) ||
320 (trap_list[sig] == (char *)IGNORE_SIG))
ccc6cda3 321 programming_error ("trap_handler: bad signal %d", sig);
726f6388
JA
322 else
323 {
28ef6c31 324 oerrno = errno;
ccc6cda3 325#if defined (MUST_REINSTALL_SIGHANDLERS)
726f6388 326 set_signal_handler (sig, trap_handler);
ccc6cda3 327#endif /* MUST_REINSTALL_SIGHANDLERS */
726f6388
JA
328
329 catch_flag = 1;
330 pending_traps[sig]++;
331
7117c2d2
JA
332 if (interrupt_immediately && this_shell_builtin && (this_shell_builtin == wait_builtin))
333 {
334 wait_signal_received = sig;
335 longjmp (wait_intr_buf, 1);
336 }
337
726f6388
JA
338 if (interrupt_immediately)
339 run_pending_traps ();
bb70624e
JA
340
341 errno = oerrno;
726f6388 342 }
ccc6cda3
JA
343
344 SIGRETURN (0);
726f6388
JA
345}
346
347#if defined (JOB_CONTROL) && defined (SIGCHLD)
cce855bc
JA
348
349#ifdef INCLUDE_UNUSED
726f6388
JA
350/* Make COMMAND_STRING be executed when SIGCHLD is caught. */
351void
352set_sigchld_trap (command_string)
353 char *command_string;
354{
726f6388
JA
355 set_signal (SIGCHLD, command_string);
356}
cce855bc 357#endif
726f6388
JA
358
359/* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
360 SIGCHLD trap handler is DEFAULT_SIG. */
361void
362maybe_set_sigchld_trap (command_string)
363 char *command_string;
364{
726f6388
JA
365 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
366 set_signal (SIGCHLD, command_string);
367}
368#endif /* JOB_CONTROL && SIGCHLD */
369
ccc6cda3
JA
370void
371set_debug_trap (command)
726f6388
JA
372 char *command;
373{
ccc6cda3
JA
374 set_signal (DEBUG_TRAP, command);
375}
726f6388 376
f73dda09
JA
377void
378set_error_trap (command)
379 char *command;
380{
381 set_signal (ERROR_TRAP, command);
382}
383
cce855bc 384#ifdef INCLUDE_UNUSED
ccc6cda3
JA
385void
386set_sigint_trap (command)
387 char *command;
388{
726f6388
JA
389 set_signal (SIGINT, command);
390}
cce855bc 391#endif
726f6388
JA
392
393/* Reset the SIGINT handler so that subshells that are doing `shellsy'
394 things, like waiting for command substitution or executing commands
395 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
396SigHandler *
397set_sigint_handler ()
398{
399 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
400 return ((SigHandler *)SIG_IGN);
401
402 else if (sigmodes[SIGINT] & SIG_IGNORED)
ccc6cda3
JA
403 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
404
726f6388
JA
405 else if (sigmodes[SIGINT] & SIG_TRAPPED)
406 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
407
408 /* The signal is not trapped, so set the handler to the shell's special
409 interrupt handler. */
410 else if (interactive) /* XXX - was interactive_shell */
411 return (set_signal_handler (SIGINT, sigint_sighandler));
412 else
413 return (set_signal_handler (SIGINT, termination_unwind_protect));
414}
415
e8ce775d
JA
416/* Return the correct handler for signal SIG according to the values in
417 sigmodes[SIG]. */
418SigHandler *
419trap_to_sighandler (sig)
420 int sig;
421{
422 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
423 return (SIG_IGN);
424 else if (sigmodes[sig] & SIG_TRAPPED)
425 return (trap_handler);
426 else
427 return (SIG_DFL);
428}
429
726f6388
JA
430/* Set SIG to call STRING as a command. */
431void
432set_signal (sig, string)
433 int sig;
434 char *string;
435{
f73dda09 436 if (SPECIAL_TRAP (sig))
ccc6cda3
JA
437 {
438 change_signal (sig, savestring (string));
d166f048
JA
439 if (sig == EXIT_TRAP && interactive == 0)
440 initialize_terminating_signals ();
ccc6cda3
JA
441 return;
442 }
443
726f6388
JA
444 /* A signal ignored on entry to the shell cannot be trapped or reset, but
445 no error is reported when attempting to do so. -- Posix.2 */
446 if (sigmodes[sig] & SIG_HARD_IGNORE)
447 return;
448
449 /* Make sure we have original_signals[sig] if the signal has not yet
450 been trapped. */
451 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
452 {
453 /* If we aren't sure of the original value, check it. */
454 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
455 {
456 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL);
457 set_signal_handler (sig, original_signals[sig]);
458 }
459
460 /* Signals ignored on entry to the shell cannot be trapped or reset. */
461 if (original_signals[sig] == SIG_IGN)
462 {
463 sigmodes[sig] |= SIG_HARD_IGNORE;
464 return;
465 }
466 }
467
468 /* Only change the system signal handler if SIG_NO_TRAP is not set.
469 The trap command string is changed in either case. The shell signal
470 handlers for SIGINT and SIGCHLD run the user specified traps in an
471 environment in which it is safe to do so. */
472 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
473 {
474 set_signal_handler (sig, SIG_IGN);
475 change_signal (sig, savestring (string));
476 set_signal_handler (sig, trap_handler);
477 }
478 else
479 change_signal (sig, savestring (string));
480}
481
482static void
483free_trap_command (sig)
484 int sig;
485{
486 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
487 (trap_list[sig] != (char *)IGNORE_SIG) &&
488 (trap_list[sig] != (char *)DEFAULT_SIG) &&
489 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
490 free (trap_list[sig]);
491}
ccc6cda3 492
726f6388
JA
493/* If SIG has a string assigned to it, get rid of it. Then give it
494 VALUE. */
495static void
496change_signal (sig, value)
497 int sig;
498 char *value;
499{
d166f048
JA
500 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
501 free_trap_command (sig);
726f6388
JA
502 trap_list[sig] = value;
503
504 sigmodes[sig] |= SIG_TRAPPED;
505 if (value == (char *)IGNORE_SIG)
506 sigmodes[sig] |= SIG_IGNORED;
507 else
508 sigmodes[sig] &= ~SIG_IGNORED;
509 if (sigmodes[sig] & SIG_INPROGRESS)
510 sigmodes[sig] |= SIG_CHANGED;
511}
512
513#define GET_ORIGINAL_SIGNAL(sig) \
514 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
515 get_original_signal (sig)
516
517static void
518get_original_signal (sig)
519 int sig;
520{
521 /* If we aren't sure the of the original value, then get it. */
522 if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
523 {
524 original_signals[sig] =
525 (SigHandler *) set_signal_handler (sig, SIG_DFL);
526 set_signal_handler (sig, original_signals[sig]);
527
528 /* Signals ignored on entry to the shell cannot be trapped. */
529 if (original_signals[sig] == SIG_IGN)
530 sigmodes[sig] |= SIG_HARD_IGNORE;
531 }
532}
533
534/* Restore the default action for SIG; i.e., the action the shell
535 would have taken before you used the trap command. This is called
536 from trap_builtin (), which takes care to restore the handlers for
537 the signals the shell treats specially. */
538void
539restore_default_signal (sig)
540 int sig;
541{
f73dda09 542 if (SPECIAL_TRAP (sig))
726f6388 543 {
f73dda09 544 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP) || (sigmodes[sig] & SIG_INPROGRESS) == 0)
d166f048 545 free_trap_command (sig);
726f6388
JA
546 trap_list[sig] = (char *)NULL;
547 sigmodes[sig] &= ~SIG_TRAPPED;
d166f048
JA
548 if (sigmodes[sig] & SIG_INPROGRESS)
549 sigmodes[sig] |= SIG_CHANGED;
726f6388
JA
550 return;
551 }
552
553 GET_ORIGINAL_SIGNAL (sig);
554
555 /* A signal ignored on entry to the shell cannot be trapped or reset, but
556 no error is reported when attempting to do so. Thanks Posix.2. */
557 if (sigmodes[sig] & SIG_HARD_IGNORE)
558 return;
559
560 /* If we aren't trapping this signal, don't bother doing anything else. */
ccc6cda3 561 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
726f6388
JA
562 return;
563
564 /* Only change the signal handler for SIG if it allows it. */
ccc6cda3 565 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
726f6388
JA
566 set_signal_handler (sig, original_signals[sig]);
567
568 /* Change the trap command in either case. */
569 change_signal (sig, (char *)DEFAULT_SIG);
570
571 /* Mark the signal as no longer trapped. */
572 sigmodes[sig] &= ~SIG_TRAPPED;
573}
574
575/* Make this signal be ignored. */
576void
577ignore_signal (sig)
578 int sig;
579{
f73dda09 580 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
ccc6cda3
JA
581 {
582 change_signal (sig, (char *)IGNORE_SIG);
583 return;
584 }
585
726f6388
JA
586 GET_ORIGINAL_SIGNAL (sig);
587
588 /* A signal ignored on entry to the shell cannot be trapped or reset.
ccc6cda3 589 No error is reported when the user attempts to do so. */
726f6388
JA
590 if (sigmodes[sig] & SIG_HARD_IGNORE)
591 return;
592
593 /* If already trapped and ignored, no change necessary. */
ccc6cda3 594 if (sigmodes[sig] & SIG_IGNORED)
726f6388
JA
595 return;
596
597 /* Only change the signal handler for SIG if it allows it. */
ccc6cda3 598 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
726f6388
JA
599 set_signal_handler (sig, SIG_IGN);
600
601 /* Change the trap command in either case. */
602 change_signal (sig, (char *)IGNORE_SIG);
603}
604
605/* Handle the calling of "trap 0". The only sticky situation is when
606 the command to be executed includes an "exit". This is why we have
607 to provide our own place for top_level to jump to. */
608int
609run_exit_trap ()
610{
ccc6cda3
JA
611 char *trap_command;
612 int code, old_exit_value;
726f6388
JA
613
614 old_exit_value = last_command_exit_value;
615
ccc6cda3
JA
616 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
617 currently running in the trap handler (call to exit in the list of
618 commands given to trap 0). */
619 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
620 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
726f6388 621 {
ccc6cda3
JA
622 trap_command = savestring (trap_list[EXIT_TRAP]);
623 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
624 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
726f6388
JA
625
626 code = setjmp (top_level);
627
628 if (code == 0)
cce855bc
JA
629 {
630 reset_parser ();
631 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST);
632 }
726f6388 633 else if (code == EXITPROG)
28ef6c31 634 return (last_command_exit_value);
726f6388
JA
635 else
636 return (old_exit_value);
637 }
638
639 return (old_exit_value);
640}
641
ccc6cda3
JA
642void
643run_trap_cleanup (sig)
644 int sig;
645{
646 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
647}
648
649/* Run a trap command for SIG. SIG is one of the signals the shell treats
650 specially. */
726f6388 651static void
ccc6cda3 652_run_trap_internal (sig, tag)
726f6388 653 int sig;
ccc6cda3 654 char *tag;
726f6388 655{
ccc6cda3 656 char *trap_command, *old_trap;
f73dda09 657 int old_exit_value, *token_state;
ccc6cda3
JA
658
659 /* Run the trap only if SIG is trapped and not ignored, and we are not
660 currently executing in the trap handler. */
661 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
662 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
663 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
664 {
665 old_trap = trap_list[sig];
666 sigmodes[sig] |= SIG_INPROGRESS;
667 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
668 trap_command = savestring (old_trap);
669
670 running_trap = sig + 1;
671 old_exit_value = last_command_exit_value;
d166f048
JA
672 /* Need to copy the value of line_number because parse_and_execute
673 resets it to 1, and the trap command might want it. */
674 trap_line_number = line_number;
bb70624e
JA
675
676 token_state = save_token_state ();
d166f048 677 parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST);
bb70624e
JA
678 restore_token_state (token_state);
679 free (token_state);
680
ccc6cda3
JA
681 last_command_exit_value = old_exit_value;
682 running_trap = 0;
683
684 sigmodes[sig] &= ~SIG_INPROGRESS;
685
686 if (sigmodes[sig] & SIG_CHANGED)
687 {
688 free (old_trap);
689 sigmodes[sig] &= ~SIG_CHANGED;
690 }
691 }
692}
693
694void
695run_debug_trap ()
696{
7117c2d2 697 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
ccc6cda3
JA
698 _run_trap_internal (DEBUG_TRAP, "debug trap");
699}
700
f73dda09
JA
701void
702run_error_trap ()
703{
704 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
705 _run_trap_internal (ERROR_TRAP, "error trap");
706}
707
ccc6cda3
JA
708/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
709 declared here to localize the trap functions. */
710void
711run_interrupt_trap ()
712{
713 _run_trap_internal (SIGINT, "interrupt trap");
726f6388
JA
714}
715
cce855bc 716#ifdef INCLUDE_UNUSED
726f6388
JA
717/* Free all the allocated strings in the list of traps and reset the trap
718 values to the default. */
719void
720free_trap_strings ()
721{
722 register int i;
723
f73dda09 724 for (i = 0; i < BASH_NSIG; i++)
726f6388
JA
725 {
726 free_trap_command (i);
727 trap_list[i] = (char *)DEFAULT_SIG;
728 sigmodes[i] &= ~SIG_TRAPPED;
729 }
f73dda09 730 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = (char *)NULL;
726f6388 731}
cce855bc 732#endif
726f6388
JA
733
734/* Reset the handler for SIG to the original value. */
735static void
736reset_signal (sig)
737 int sig;
738{
739 set_signal_handler (sig, original_signals[sig]);
7117c2d2 740 sigmodes[sig] &= ~SIG_TRAPPED;
726f6388
JA
741}
742
ccc6cda3
JA
743/* Set the handler signal SIG to the original and free any trap
744 command associated with it. */
745static void
746restore_signal (sig)
747 int sig;
726f6388 748{
ccc6cda3
JA
749 set_signal_handler (sig, original_signals[sig]);
750 change_signal (sig, (char *)DEFAULT_SIG);
751 sigmodes[sig] &= ~SIG_TRAPPED;
726f6388
JA
752}
753
ccc6cda3
JA
754static void
755reset_or_restore_signal_handlers (reset)
f73dda09 756 sh_resetsig_func_t *reset;
726f6388
JA
757{
758 register int i;
759
ccc6cda3
JA
760 /* Take care of the exit trap first */
761 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
726f6388 762 {
ccc6cda3
JA
763 free_trap_command (EXIT_TRAP);
764 trap_list[EXIT_TRAP] = (char *)NULL;
765 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
726f6388 766 }
726f6388
JA
767 for (i = 1; i < NSIG; i++)
768 {
ccc6cda3 769 if (sigmodes[i] & SIG_TRAPPED)
726f6388
JA
770 {
771 if (trap_list[i] == (char *)IGNORE_SIG)
772 set_signal_handler (i, SIG_IGN);
773 else
ccc6cda3 774 (*reset) (i);
726f6388 775 }
ccc6cda3
JA
776 else if (sigmodes[i] & SIG_SPECIAL)
777 (*reset) (i);
726f6388 778 }
f73dda09
JA
779
780 /* Command substitution and other child processes don't inherit the
781 debug or error traps. */
782 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
783 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
726f6388
JA
784}
785
f73dda09
JA
786/* Reset trapped signals to their original values, but don't free the
787 trap strings. Called by the command substitution code. */
726f6388 788void
ccc6cda3 789reset_signal_handlers ()
726f6388 790{
ccc6cda3
JA
791 reset_or_restore_signal_handlers (reset_signal);
792}
726f6388 793
ccc6cda3
JA
794/* Reset all trapped signals to their original values. Signals set to be
795 ignored with trap '' SIGNAL should be ignored, so we make sure that they
796 are. Called by child processes after they are forked. */
797void
798restore_original_signals ()
799{
800 reset_or_restore_signal_handlers (restore_signal);
726f6388
JA
801}
802
803/* If a trap handler exists for signal SIG, then call it; otherwise just
804 return failure. */
805int
806maybe_call_trap_handler (sig)
807 int sig;
808{
809 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
ccc6cda3 810 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
726f6388
JA
811 {
812 switch (sig)
813 {
814 case SIGINT:
815 run_interrupt_trap ();
816 break;
ccc6cda3 817 case EXIT_TRAP:
726f6388
JA
818 run_exit_trap ();
819 break;
ccc6cda3
JA
820 case DEBUG_TRAP:
821 run_debug_trap ();
822 break;
f73dda09
JA
823 case ERROR_TRAP:
824 run_error_trap ();
825 break;
726f6388
JA
826 default:
827 trap_handler (sig);
828 break;
829 }
830 return (1);
831 }
832 else
833 return (0);
834}
835
836int
837signal_is_trapped (sig)
838 int sig;
839{
840 return (sigmodes[sig] & SIG_TRAPPED);
841}
842
843int
844signal_is_special (sig)
845 int sig;
846{
847 return (sigmodes[sig] & SIG_SPECIAL);
848}
849
850int
851signal_is_ignored (sig)
852 int sig;
853{
854 return (sigmodes[sig] & SIG_IGNORED);
855}
856
857void
858set_signal_ignored (sig)
859 int sig;
860{
861 sigmodes[sig] |= SIG_HARD_IGNORE;
ccc6cda3 862 original_signals[sig] = SIG_IGN;
726f6388 863}