]> git.ipfire.org Git - thirdparty/bash.git/blame - trap.c~
commit bash-20100325 snapshot
[thirdparty/bash.git] / trap.c~
CommitLineData
64419627
CR
1/* trap.c -- Not the trap command, but useful functions for manipulating
2 those objects. The trap command is in builtins/trap.def. */
3
4/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
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
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.
12
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.
17
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*/
21
22#include "config.h"
23
24#if defined (HAVE_UNISTD_H)
25# include <unistd.h>
26#endif
27
28#include "bashtypes.h"
29#include "bashansi.h"
30
31#include <stdio.h>
32#include <errno.h>
33
34#include "bashintl.h"
35
36#include "trap.h"
37
38#include "shell.h"
39#include "flags.h"
40#include "input.h" /* for save_token_state, restore_token_state */
41#include "jobs.h"
42#include "signames.h"
43#include "builtins.h"
44#include "builtins/common.h"
45#include "builtins/builtext.h"
46
47#ifndef errno
48extern int errno;
49#endif
50
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. */
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. */
60
61#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
62
63/* An array of such flags, one for each signal, describing what the
64 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
65 assumes this. */
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
73static int _run_trap_internal __P((int, char *));
74
75static void free_trap_string __P((int));
76static void reset_signal __P((int));
77static void restore_signal __P((int));
78static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
79
80/* Variables used here but defined in other files. */
81extern int last_command_exit_value;
82extern int line_number;
83
84extern char *this_command_name;
85extern sh_builtin_func_t *this_shell_builtin;
86extern procenv_t wait_intr_buf;
87extern int return_catch_flag, return_catch_value;
88extern int subshell_level;
89extern WORD_LIST *subst_assign_varlist;
90
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. */
99char *trap_list[BASH_NSIG];
100
101/* A bitmap of signals received for which we have trap handlers. */
102int pending_traps[NSIG];
103
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
110/* Set to last_command_exit_value before running a trap. */
111int trap_saved_exit_value;
112
113/* The (trapped) signal received while executing in the `wait' builtin */
114int wait_signal_received;
115
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
9e51a74d
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
64419627
CR
131#define GET_ORIGINAL_SIGNAL(sig) \
132 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
133 GETORIGSIG(sig)
134
135void
136initialize_traps ()
137{
138 register int i;
139
140 initialize_signames();
141
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;
144 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
145
146 for (i = 1; i < NSIG; i++)
147 {
148 pending_traps[i] = 0;
149 trap_list[i] = (char *)DEFAULT_SIG;
9e51a74d 150 sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
64419627
CR
151 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
152 }
153
154 /* Show which signals are treated specially by the shell. */
155#if defined (SIGCHLD)
156 GETORIGSIG (SIGCHLD);
157 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
158#endif /* SIGCHLD */
159
160 GETORIGSIG (SIGINT);
161 sigmodes[SIGINT] |= SIG_SPECIAL;
162
163#if defined (__BEOS__)
164 /* BeOS sets SIGINT to SIG_IGN! */
165 original_signals[SIGINT] = SIG_DFL;
166 sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
167#endif
168
169 GETORIGSIG (SIGQUIT);
170 sigmodes[SIGQUIT] |= SIG_SPECIAL;
171
172 if (interactive)
173 {
174 GETORIGSIG (SIGTERM);
175 sigmodes[SIGTERM] |= SIG_SPECIAL;
176 }
177}
178
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
198/* Return the print name of this signal. */
199char *
200signal_name (sig)
201 int sig;
202{
203 char *ret;
204
205 /* on cygwin32, signal_names[sig] could be null */
206 ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL)
207 ? _("invalid signal number")
208 : signal_names[sig];
209
210 return ret;
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
218decode_signal (string, flags)
219 char *string;
220 int flags;
221{
222 intmax_t sig;
223 char *name;
224
225 if (legal_number (string, &sig))
226 return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
227
228 /* A leading `SIG' may be omitted. */
229 for (sig = 0; sig < BASH_NSIG; sig++)
230 {
231 name = signal_names[sig];
232 if (name == 0 || name[0] == '\0')
233 continue;
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)
257 return ((int)sig);
258 }
259
260 return (NO_SIG);
261}
262
263/* Non-zero when we catch a trapped signal. */
264static int catch_flag;
265
266void
267run_pending_traps ()
268{
269 register int sig;
270 int old_exit_value, *token_state;
271 WORD_LIST *save_subst_varlist;
272#if defined (ARRAY_VARS)
273 ARRAY *ps;
274#endif
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;
283#if defined (ARRAY_VARS)
284 ps = save_pipestatus_array ();
285#endif
286
287 for (sig = 1; sig < NSIG; sig++)
288 {
289 /* XXX this could be made into a counter by using
290 while (pending_traps[sig]--) instead of the if statement. */
291 if (pending_traps[sig])
292 {
293#if defined (HAVE_POSIX_SIGNALS)
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
305#endif /* HAVE_POSIX_SIGNALS */
306
307 if (sig == SIGINT)
308 {
309 run_interrupt_trap ();
310 CLRINTERRUPT;
311 }
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
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. */
337 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
338 sig, trap_list[sig]);
339 if (trap_list[sig] == (char *)DEFAULT_SIG)
340 {
341 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig));
342 kill (getpid (), sig);
343 }
344 }
345 else
346 {
347 token_state = save_token_state ();
348 save_subst_varlist = subst_assign_varlist;
349 subst_assign_varlist = 0;
350
351 parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
352 restore_token_state (token_state);
353 free (token_state);
354
355 subst_assign_varlist = save_subst_varlist;
356 }
357
358 pending_traps[sig] = 0;
359
360#if defined (HAVE_POSIX_SIGNALS)
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
370#if defined (ARRAY_VARS)
371 restore_pipestatus_array (ps);
372#endif
373 last_command_exit_value = old_exit_value;
374}
375
376sighandler
377trap_handler (sig)
378 int sig;
379{
380 int oerrno;
381
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
390 if ((sig >= NSIG) ||
391 (trap_list[sig] == (char *)DEFAULT_SIG) ||
392 (trap_list[sig] == (char *)IGNORE_SIG))
393 programming_error (_("trap_handler: bad signal %d"), sig);
394 else
395 {
396 oerrno = errno;
397#if defined (MUST_REINSTALL_SIGHANDLERS)
398# if defined (JOB_CONTROL) && defined (SIGCHLD)
399 if (sig != SIGCHLD)
400# endif /* JOB_CONTROL && SIGCHLD */
401 set_signal_handler (sig, trap_handler);
402#endif /* MUST_REINSTALL_SIGHANDLERS */
403
404 catch_flag = 1;
405 pending_traps[sig]++;
406
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
413 if (interrupt_immediately)
414 run_pending_traps ();
415
416 errno = oerrno;
417 }
418
419 SIGRETURN (0);
420}
421
422#if defined (JOB_CONTROL) && defined (SIGCHLD)
423
424#ifdef INCLUDE_UNUSED
425/* Make COMMAND_STRING be executed when SIGCHLD is caught. */
426void
427set_sigchld_trap (command_string)
428 char *command_string;
429{
430 set_signal (SIGCHLD, command_string);
431}
432#endif
433
434/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
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. */
439void
440maybe_set_sigchld_trap (command_string)
441 char *command_string;
442{
443 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
444 set_signal (SIGCHLD, command_string);
445}
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}
457#endif /* JOB_CONTROL && SIGCHLD */
458
459void
460set_debug_trap (command)
461 char *command;
462{
463 set_signal (DEBUG_TRAP, command);
464}
465
466void
467set_error_trap (command)
468 char *command;
469{
470 set_signal (ERROR_TRAP, command);
471}
472
473void
474set_return_trap (command)
475 char *command;
476{
477 set_signal (RETURN_TRAP, command);
478}
479
480#ifdef INCLUDE_UNUSED
481void
482set_sigint_trap (command)
483 char *command;
484{
485 set_signal (SIGINT, command);
486}
487#endif
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)
499 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
500
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
509 return (set_signal_handler (SIGINT, termsig_sighandler));
510}
511
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
526/* Set SIG to call STRING as a command. */
527void
528set_signal (sig, string)
529 int sig;
530 char *string;
531{
532 if (SPECIAL_TRAP (sig))
533 {
534 change_signal (sig, savestring (string));
535 if (sig == EXIT_TRAP && interactive == 0)
536 initialize_terminating_signals ();
537 return;
538 }
539
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)
551 GETORIGSIG (sig);
552 if (original_signals[sig] == SIG_IGN)
553 return;
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}
580
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{
588 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
589 free_trap_command (sig);
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
601static void
602get_original_signal (sig)
603 int sig;
604{
605 /* If we aren't sure the of the original value, then get it. */
606 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
607 GETORIGSIG (sig);
608}
609
9e51a74d
CR
610void
611set_original_signal (sig, handler)
612 int sig;
613 SigHandler *handler;
614{
615 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
616 SETORIGSIG (sig, handler);
617}
618
64419627
CR
619/* Restore the default action for SIG; i.e., the action the shell
620 would have taken before you used the trap command. This is called
621 from trap_builtin (), which takes care to restore the handlers for
622 the signals the shell treats specially. */
623void
624restore_default_signal (sig)
625 int sig;
626{
627 if (SPECIAL_TRAP (sig))
628 {
629 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
630 (sigmodes[sig] & SIG_INPROGRESS) == 0)
631 free_trap_command (sig);
632 trap_list[sig] = (char *)NULL;
633 sigmodes[sig] &= ~SIG_TRAPPED;
634 if (sigmodes[sig] & SIG_INPROGRESS)
635 sigmodes[sig] |= SIG_CHANGED;
636 return;
637 }
638
639 GET_ORIGINAL_SIGNAL (sig);
640
641 /* A signal ignored on entry to the shell cannot be trapped or reset, but
642 no error is reported when attempting to do so. Thanks Posix.2. */
643 if (sigmodes[sig] & SIG_HARD_IGNORE)
644 return;
645
646 /* If we aren't trapping this signal, don't bother doing anything else. */
647 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
648 return;
649
650 /* Only change the signal handler for SIG if it allows it. */
651 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
652 set_signal_handler (sig, original_signals[sig]);
653
654 /* Change the trap command in either case. */
655 change_signal (sig, (char *)DEFAULT_SIG);
656
657 /* Mark the signal as no longer trapped. */
658 sigmodes[sig] &= ~SIG_TRAPPED;
659}
660
661/* Make this signal be ignored. */
662void
663ignore_signal (sig)
664 int sig;
665{
666 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
667 {
668 change_signal (sig, (char *)IGNORE_SIG);
669 return;
670 }
671
672 GET_ORIGINAL_SIGNAL (sig);
673
674 /* A signal ignored on entry to the shell cannot be trapped or reset.
675 No error is reported when the user attempts to do so. */
676 if (sigmodes[sig] & SIG_HARD_IGNORE)
677 return;
678
679 /* If already trapped and ignored, no change necessary. */
680 if (sigmodes[sig] & SIG_IGNORED)
681 return;
682
683 /* Only change the signal handler for SIG if it allows it. */
684 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
685 set_signal_handler (sig, SIG_IGN);
686
687 /* Change the trap command in either case. */
688 change_signal (sig, (char *)IGNORE_SIG);
689}
690
691/* Handle the calling of "trap 0". The only sticky situation is when
692 the command to be executed includes an "exit". This is why we have
693 to provide our own place for top_level to jump to. */
694int
695run_exit_trap ()
696{
697 char *trap_command;
698 int code, function_code, retval;
699#if defined (ARRAY_VARS)
700 ARRAY *ps;
701#endif
702
703 trap_saved_exit_value = last_command_exit_value;
704#if defined (ARRAY_VARS)
705 ps = save_pipestatus_array ();
706#endif
707 function_code = 0;
708
709 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
710 currently running in the trap handler (call to exit in the list of
711 commands given to trap 0). */
712 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
713 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
714 {
715 trap_command = savestring (trap_list[EXIT_TRAP]);
716 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
717 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
718
719 retval = trap_saved_exit_value;
720 running_trap = 1;
721
722 code = setjmp (top_level);
723
724 /* If we're in a function, make sure return longjmps come here, too. */
725 if (return_catch_flag)
726 function_code = setjmp (return_catch);
727
728 if (code == 0 && function_code == 0)
729 {
730 reset_parser ();
731 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
732 }
733 else if (code == ERREXIT)
734 retval = last_command_exit_value;
735 else if (code == EXITPROG)
736 retval = last_command_exit_value;
737 else if (function_code != 0)
738 retval = return_catch_value;
739 else
740 retval = trap_saved_exit_value;
741
742 running_trap = 0;
743 return retval;
744 }
745
746#if defined (ARRAY_VARS)
747 restore_pipestatus_array (ps);
748#endif
749 return (trap_saved_exit_value);
750}
751
752void
753run_trap_cleanup (sig)
754 int sig;
755{
756 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
757}
758
759/* Run a trap command for SIG. SIG is one of the signals the shell treats
760 specially. Returns the exit status of the executed trap command list. */
761static int
762_run_trap_internal (sig, tag)
763 int sig;
764 char *tag;
765{
766 char *trap_command, *old_trap;
767 int trap_exit_value, *token_state;
768 int save_return_catch_flag, function_code, flags;
769 procenv_t save_return_catch;
770 WORD_LIST *save_subst_varlist;
771#if defined (ARRAY_VARS)
772 ARRAY *ps;
773#endif
774
775 trap_exit_value = function_code = 0;
776 /* Run the trap only if SIG is trapped and not ignored, and we are not
777 currently executing in the trap handler. */
778 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
779 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
780 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
781 {
782 old_trap = trap_list[sig];
783 sigmodes[sig] |= SIG_INPROGRESS;
784 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
785 trap_command = savestring (old_trap);
786
787 running_trap = sig + 1;
788 trap_saved_exit_value = last_command_exit_value;
789#if defined (ARRAY_VARS)
790 ps = save_pipestatus_array ();
791#endif
792
793 token_state = save_token_state ();
794 save_subst_varlist = subst_assign_varlist;
795 subst_assign_varlist = 0;
796
797 /* If we're in a function, make sure return longjmps come here, too. */
798 save_return_catch_flag = return_catch_flag;
799 if (return_catch_flag)
800 {
801 COPY_PROCENV (return_catch, save_return_catch);
802 function_code = setjmp (return_catch);
803 }
804
805 flags = SEVAL_NONINT|SEVAL_NOHIST;
806 if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
807 flags |= SEVAL_RESETLINE;
808 if (function_code == 0)
809 parse_and_execute (trap_command, tag, flags);
810
811 restore_token_state (token_state);
812 free (token_state);
813
814 subst_assign_varlist = save_subst_varlist;
815
816 trap_exit_value = last_command_exit_value;
817 last_command_exit_value = trap_saved_exit_value;
818#if defined (ARRAY_VARS)
819 restore_pipestatus_array (ps);
820#endif
821 running_trap = 0;
822
823 sigmodes[sig] &= ~SIG_INPROGRESS;
824
825 if (sigmodes[sig] & SIG_CHANGED)
826 {
827#if 0
828 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
829 the places where they can be changed using unwind-protects. For
830 example, look at execute_cmd.c:execute_function(). */
831 if (SPECIAL_TRAP (sig) == 0)
832#endif
833 free (old_trap);
834 sigmodes[sig] &= ~SIG_CHANGED;
835 }
836
837 if (save_return_catch_flag)
838 {
839 return_catch_flag = save_return_catch_flag;
840 return_catch_value = trap_exit_value;
841 COPY_PROCENV (save_return_catch, return_catch);
842 if (function_code)
843 longjmp (return_catch, 1);
844 }
845 }
846
847 return trap_exit_value;
848}
849
850int
851run_debug_trap ()
852{
853 int trap_exit_value;
854 pid_t save_pgrp;
855 int save_pipe[2];
856
857 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
858 trap_exit_value = 0;
859 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
860 {
861#if defined (JOB_CONTROL)
862 save_pgrp = pipeline_pgrp;
863 pipeline_pgrp = 0;
864 save_pipeline (1);
865# if defined (PGRP_PIPE)
866 save_pgrp_pipe (save_pipe, 1);
867# endif
868 stop_making_children ();
869#endif
870
871 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
872
873#if defined (JOB_CONTROL)
874 pipeline_pgrp = save_pgrp;
875 restore_pipeline (1);
876# if defined (PGRP_PIPE)
877 close_pgrp_pipe ();
878 restore_pgrp_pipe (save_pipe);
879# endif
880 if (pipeline_pgrp > 0)
881 give_terminal_to (pipeline_pgrp, 1);
882 notify_and_cleanup ();
883#endif
884
885#if defined (DEBUGGER)
886 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
887 a function or sourced script, we force a `return'. */
888 if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
889 {
890 return_catch_value = trap_exit_value;
891 longjmp (return_catch, 1);
892 }
893#endif
894 }
895 return trap_exit_value;
896}
897
898void
899run_error_trap ()
900{
901 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
902 _run_trap_internal (ERROR_TRAP, "error trap");
903}
904
905void
906run_return_trap ()
907{
908 int old_exit_value;
909
910#if 0
911 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
912 return;
913#endif
914
915 if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
916 {
917 old_exit_value = last_command_exit_value;
918 _run_trap_internal (RETURN_TRAP, "return trap");
919 last_command_exit_value = old_exit_value;
920 }
921}
922
923/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
924 declared here to localize the trap functions. */
925void
926run_interrupt_trap ()
927{
928 _run_trap_internal (SIGINT, "interrupt trap");
929}
930
64419627
CR
931/* Free all the allocated strings in the list of traps and reset the trap
932 values to the default. Intended to be called from subshells that want
933 to complete work done by reset_signal_handlers upon execution of a
934 subsequent `trap' command that changes a signal's disposition. */
935void
936free_trap_strings ()
937{
938 register int i;
939
940 for (i = 0; i < BASH_NSIG; i++)
941 free_trap_string (i);
942 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
943}
944
945/* Free a trap command string associated with SIG without changing signal
946 disposition. Intended to be called from free_trap_strings() */
947static void
948free_trap_string (sig)
949 int sig;
950{
951 change_signal (sig, (char *)DEFAULT_SIG);
952 sigmodes[sig] &= ~SIG_TRAPPED;
953}
64419627
CR
954
955/* Reset the handler for SIG to the original value. */
956static void
957reset_signal (sig)
958 int sig;
959{
960 set_signal_handler (sig, original_signals[sig]);
961 sigmodes[sig] &= ~SIG_TRAPPED;
962}
963
964/* Set the handler signal SIG to the original and free any trap
965 command associated with it. */
966static void
967restore_signal (sig)
968 int sig;
969{
970 set_signal_handler (sig, original_signals[sig]);
971 change_signal (sig, (char *)DEFAULT_SIG);
972 sigmodes[sig] &= ~SIG_TRAPPED;
973}
974
975static void
976reset_or_restore_signal_handlers (reset)
977 sh_resetsig_func_t *reset;
978{
979 register int i;
980
981 /* Take care of the exit trap first */
982 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
983 {
984 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
985 if (reset != reset_signal)
986 {
987 free_trap_command (EXIT_TRAP);
988 trap_list[EXIT_TRAP] = (char *)NULL;
989 }
990 }
991
992 for (i = 1; i < NSIG; i++)
993 {
994 if (sigmodes[i] & SIG_TRAPPED)
995 {
996 if (trap_list[i] == (char *)IGNORE_SIG)
997 set_signal_handler (i, SIG_IGN);
998 else
999 (*reset) (i);
1000 }
1001 else if (sigmodes[i] & SIG_SPECIAL)
1002 (*reset) (i);
1003 }
1004
1005 /* Command substitution and other child processes don't inherit the
1006 debug, error, or return traps. If we're in the debugger, and the
1007 `functrace' or `errtrace' options have been set, then let command
1008 substitutions inherit them. Let command substitution inherit the
1009 RETURN trap if we're in the debugger and tracing functions. */
1010 if (function_trace_mode == 0)
1011 {
1012 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
1013 sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
1014 }
1015 if (error_trace_mode == 0)
1016 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
1017}
1018
1019/* Reset trapped signals to their original values, but don't free the
1020 trap strings. Called by the command substitution code. */
1021void
1022reset_signal_handlers ()
1023{
1024 reset_or_restore_signal_handlers (reset_signal);
1025}
1026
1027/* Reset all trapped signals to their original values. Signals set to be
1028 ignored with trap '' SIGNAL should be ignored, so we make sure that they
1029 are. Called by child processes after they are forked. */
1030void
1031restore_original_signals ()
1032{
1033 reset_or_restore_signal_handlers (restore_signal);
1034}
1035
1036/* If a trap handler exists for signal SIG, then call it; otherwise just
1037 return failure. */
1038int
1039maybe_call_trap_handler (sig)
1040 int sig;
1041{
1042 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1043 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
1044 {
1045 switch (sig)
1046 {
1047 case SIGINT:
1048 run_interrupt_trap ();
1049 break;
1050 case EXIT_TRAP:
1051 run_exit_trap ();
1052 break;
1053 case DEBUG_TRAP:
1054 run_debug_trap ();
1055 break;
1056 case ERROR_TRAP:
1057 run_error_trap ();
1058 break;
1059 default:
1060 trap_handler (sig);
1061 break;
1062 }
1063 return (1);
1064 }
1065 else
1066 return (0);
1067}
1068
1069int
1070signal_is_trapped (sig)
1071 int sig;
1072{
1073 return (sigmodes[sig] & SIG_TRAPPED);
1074}
1075
1076int
1077signal_is_special (sig)
1078 int sig;
1079{
1080 return (sigmodes[sig] & SIG_SPECIAL);
1081}
1082
1083int
1084signal_is_ignored (sig)
1085 int sig;
1086{
1087 return (sigmodes[sig] & SIG_IGNORED);
1088}
1089
9e51a74d
CR
1090int
1091signal_is_hard_ignored (sig)
1092{
1093 return (sigmodes[sig] & SIG_HARD_IGNORE);
1094}
1095
64419627
CR
1096void
1097set_signal_ignored (sig)
1098 int sig;
1099{
9e51a74d 1100itrace("set_signal_ignored: %d set to SIG_HARD_IGNORE", sig);
64419627
CR
1101 sigmodes[sig] |= SIG_HARD_IGNORE;
1102 original_signals[sig] = SIG_IGN;
1103}
1104
1105int
1106signal_in_progress (sig)
1107 int sig;
1108{
1109 return (sigmodes[sig] & SIG_INPROGRESS);
1110}