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