]> git.ipfire.org Git - thirdparty/bash.git/blob - trap.c
Bash-4.2 direxpand with patch 27
[thirdparty/bash.git] / trap.c
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-2010 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
48 extern 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. */
66 static int sigmodes[BASH_NSIG];
67
68 static void free_trap_command __P((int));
69 static void change_signal __P((int, char *));
70
71 static void get_original_signal __P((int));
72
73 static int _run_trap_internal __P((int, char *));
74
75 static void free_trap_string __P((int));
76 static void reset_signal __P((int));
77 static void restore_signal __P((int));
78 static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
79
80 /* Variables used here but defined in other files. */
81 extern int last_command_exit_value;
82 extern int line_number;
83
84 extern char *this_command_name;
85 extern sh_builtin_func_t *this_shell_builtin;
86 extern procenv_t wait_intr_buf;
87 extern int return_catch_flag, return_catch_value;
88 extern int subshell_level;
89 extern WORD_LIST *subst_assign_varlist;
90
91 /* The list of things to do originally, before we started trapping. */
92 SigHandler *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. */
99 char *trap_list[BASH_NSIG];
100
101 /* A bitmap of signals received for which we have trap handlers. */
102 int 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). */
108 int running_trap;
109
110 /* Set to last_command_exit_value before running a trap. */
111 int trap_saved_exit_value;
112
113 /* The (trapped) signal received while executing in the `wait' builtin */
114 int 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
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
131 #define GET_ORIGINAL_SIGNAL(sig) \
132 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
133 GETORIGSIG(sig)
134
135 void
136 initialize_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;
150 sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
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. */
181 static char *
182 trap_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. */
199 char *
200 signal_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. */
217 int
218 decode_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. */
264 static int catch_flag;
265
266 void
267 run_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
376 sighandler
377 trap_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. */
426 void
427 set_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. */
439 void
440 maybe_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. */
450 void
451 set_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
459 void
460 set_debug_trap (command)
461 char *command;
462 {
463 set_signal (DEBUG_TRAP, command);
464 }
465
466 void
467 set_error_trap (command)
468 char *command;
469 {
470 set_signal (ERROR_TRAP, command);
471 }
472
473 void
474 set_return_trap (command)
475 char *command;
476 {
477 set_signal (RETURN_TRAP, command);
478 }
479
480 #ifdef INCLUDE_UNUSED
481 void
482 set_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. */
492 SigHandler *
493 set_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]. */
514 SigHandler *
515 trap_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. */
527 void
528 set_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
570 static void
571 free_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. */
583 static void
584 change_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
601 static void
602 get_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
610 void
611 get_all_original_signals ()
612 {
613 register int i;
614
615 for (i = 1; i < NSIG; i++)
616 GET_ORIGINAL_SIGNAL (i);
617 }
618
619 void
620 set_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
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. */
632 void
633 restore_default_signal (sig)
634 int sig;
635 {
636 if (SPECIAL_TRAP (sig))
637 {
638 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
639 (sigmodes[sig] & SIG_INPROGRESS) == 0)
640 free_trap_command (sig);
641 trap_list[sig] = (char *)NULL;
642 sigmodes[sig] &= ~SIG_TRAPPED;
643 if (sigmodes[sig] & SIG_INPROGRESS)
644 sigmodes[sig] |= SIG_CHANGED;
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. */
656 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
657 return;
658
659 /* Only change the signal handler for SIG if it allows it. */
660 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
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. */
671 void
672 ignore_signal (sig)
673 int sig;
674 {
675 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
676 {
677 change_signal (sig, (char *)IGNORE_SIG);
678 return;
679 }
680
681 GET_ORIGINAL_SIGNAL (sig);
682
683 /* A signal ignored on entry to the shell cannot be trapped or reset.
684 No error is reported when the user attempts to do so. */
685 if (sigmodes[sig] & SIG_HARD_IGNORE)
686 return;
687
688 /* If already trapped and ignored, no change necessary. */
689 if (sigmodes[sig] & SIG_IGNORED)
690 return;
691
692 /* Only change the signal handler for SIG if it allows it. */
693 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
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. */
703 int
704 run_exit_trap ()
705 {
706 char *trap_command;
707 int code, function_code, retval;
708 #if defined (ARRAY_VARS)
709 ARRAY *ps;
710 #endif
711
712 trap_saved_exit_value = last_command_exit_value;
713 #if defined (ARRAY_VARS)
714 ps = save_pipestatus_array ();
715 #endif
716 function_code = 0;
717
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)
723 {
724 trap_command = savestring (trap_list[EXIT_TRAP]);
725 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
726 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
727
728 retval = trap_saved_exit_value;
729 running_trap = 1;
730
731 code = setjmp (top_level);
732
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)
738 {
739 reset_parser ();
740 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
741 }
742 else if (code == ERREXIT)
743 retval = last_command_exit_value;
744 else if (code == EXITPROG)
745 retval = last_command_exit_value;
746 else if (function_code != 0)
747 retval = return_catch_value;
748 else
749 retval = trap_saved_exit_value;
750
751 running_trap = 0;
752 return retval;
753 }
754
755 #if defined (ARRAY_VARS)
756 restore_pipestatus_array (ps);
757 #endif
758 return (trap_saved_exit_value);
759 }
760
761 void
762 run_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
769 specially. Returns the exit status of the executed trap command list. */
770 static int
771 _run_trap_internal (sig, tag)
772 int sig;
773 char *tag;
774 {
775 char *trap_command, *old_trap;
776 int trap_exit_value, *token_state;
777 int save_return_catch_flag, function_code, flags;
778 procenv_t save_return_catch;
779 WORD_LIST *save_subst_varlist;
780 #if defined (ARRAY_VARS)
781 ARRAY *ps;
782 #endif
783
784 trap_exit_value = function_code = 0;
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;
797 trap_saved_exit_value = last_command_exit_value;
798 #if defined (ARRAY_VARS)
799 ps = save_pipestatus_array ();
800 #endif
801
802 token_state = save_token_state ();
803 save_subst_varlist = subst_assign_varlist;
804 subst_assign_varlist = 0;
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
814 flags = SEVAL_NONINT|SEVAL_NOHIST;
815 if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
816 flags |= SEVAL_RESETLINE;
817 if (function_code == 0)
818 parse_and_execute (trap_command, tag, flags);
819
820 restore_token_state (token_state);
821 free (token_state);
822
823 subst_assign_varlist = save_subst_varlist;
824
825 trap_exit_value = last_command_exit_value;
826 last_command_exit_value = trap_saved_exit_value;
827 #if defined (ARRAY_VARS)
828 restore_pipestatus_array (ps);
829 #endif
830 running_trap = 0;
831
832 sigmodes[sig] &= ~SIG_INPROGRESS;
833
834 if (sigmodes[sig] & SIG_CHANGED)
835 {
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);
843 sigmodes[sig] &= ~SIG_CHANGED;
844 }
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 }
854 }
855
856 return trap_exit_value;
857 }
858
859 int
860 run_debug_trap ()
861 {
862 int trap_exit_value;
863 pid_t save_pgrp;
864 int save_pipe[2];
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 {
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
880 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
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
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;
905 }
906
907 void
908 run_error_trap ()
909 {
910 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
911 _run_trap_internal (ERROR_TRAP, "error trap");
912 }
913
914 void
915 run_return_trap ()
916 {
917 int old_exit_value;
918
919 #if 0
920 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
921 return;
922 #endif
923
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
932 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
933 declared here to localize the trap functions. */
934 void
935 run_interrupt_trap ()
936 {
937 _run_trap_internal (SIGINT, "interrupt trap");
938 }
939
940 /* Free all the allocated strings in the list of traps and reset the trap
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. */
944 void
945 free_trap_strings ()
946 {
947 register int i;
948
949 for (i = 0; i < BASH_NSIG; i++)
950 free_trap_string (i);
951 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
952 }
953
954 /* Free a trap command string associated with SIG without changing signal
955 disposition. Intended to be called from free_trap_strings() */
956 static void
957 free_trap_string (sig)
958 int sig;
959 {
960 change_signal (sig, (char *)DEFAULT_SIG);
961 sigmodes[sig] &= ~SIG_TRAPPED;
962 }
963
964 /* Reset the handler for SIG to the original value but leave the trap string
965 in place. */
966 static void
967 reset_signal (sig)
968 int sig;
969 {
970 set_signal_handler (sig, original_signals[sig]);
971 sigmodes[sig] &= ~SIG_TRAPPED;
972 }
973
974 /* Set the handler signal SIG to the original and free any trap
975 command associated with it. */
976 static void
977 restore_signal (sig)
978 int sig;
979 {
980 set_signal_handler (sig, original_signals[sig]);
981 change_signal (sig, (char *)DEFAULT_SIG);
982 sigmodes[sig] &= ~SIG_TRAPPED;
983 }
984
985 static void
986 reset_or_restore_signal_handlers (reset)
987 sh_resetsig_func_t *reset;
988 {
989 register int i;
990
991 /* Take care of the exit trap first */
992 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
993 {
994 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
995 if (reset != reset_signal)
996 {
997 free_trap_command (EXIT_TRAP);
998 trap_list[EXIT_TRAP] = (char *)NULL;
999 }
1000 }
1001
1002 for (i = 1; i < NSIG; i++)
1003 {
1004 if (sigmodes[i] & SIG_TRAPPED)
1005 {
1006 if (trap_list[i] == (char *)IGNORE_SIG)
1007 set_signal_handler (i, SIG_IGN);
1008 else
1009 (*reset) (i);
1010 }
1011 else if (sigmodes[i] & SIG_SPECIAL)
1012 (*reset) (i);
1013 }
1014
1015 /* Command substitution and other child processes don't inherit the
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. */
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)
1026 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
1027 }
1028
1029 /* Reset trapped signals to their original values, but don't free the
1030 trap strings. Called by the command substitution code and other places
1031 that create a "subshell environment". */
1032 void
1033 reset_signal_handlers ()
1034 {
1035 reset_or_restore_signal_handlers (reset_signal);
1036 }
1037
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. */
1041 void
1042 restore_original_signals ()
1043 {
1044 reset_or_restore_signal_handlers (restore_signal);
1045 }
1046
1047 /* If a trap handler exists for signal SIG, then call it; otherwise just
1048 return failure. */
1049 int
1050 maybe_call_trap_handler (sig)
1051 int sig;
1052 {
1053 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1054 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
1055 {
1056 switch (sig)
1057 {
1058 case SIGINT:
1059 run_interrupt_trap ();
1060 break;
1061 case EXIT_TRAP:
1062 run_exit_trap ();
1063 break;
1064 case DEBUG_TRAP:
1065 run_debug_trap ();
1066 break;
1067 case ERROR_TRAP:
1068 run_error_trap ();
1069 break;
1070 default:
1071 trap_handler (sig);
1072 break;
1073 }
1074 return (1);
1075 }
1076 else
1077 return (0);
1078 }
1079
1080 int
1081 signal_is_trapped (sig)
1082 int sig;
1083 {
1084 return (sigmodes[sig] & SIG_TRAPPED);
1085 }
1086
1087 int
1088 signal_is_special (sig)
1089 int sig;
1090 {
1091 return (sigmodes[sig] & SIG_SPECIAL);
1092 }
1093
1094 int
1095 signal_is_ignored (sig)
1096 int sig;
1097 {
1098 return (sigmodes[sig] & SIG_IGNORED);
1099 }
1100
1101 int
1102 signal_is_hard_ignored (sig)
1103 int sig;
1104 {
1105 return (sigmodes[sig] & SIG_HARD_IGNORE);
1106 }
1107
1108 void
1109 set_signal_ignored (sig)
1110 int sig;
1111 {
1112 sigmodes[sig] |= SIG_HARD_IGNORE;
1113 original_signals[sig] = SIG_IGN;
1114 }
1115
1116 int
1117 signal_in_progress (sig)
1118 int sig;
1119 {
1120 return (sigmodes[sig] & SIG_INPROGRESS);
1121 }