Line data Source code
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-2015 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 <signal.h>
37 :
38 : #include "trap.h"
39 :
40 : #include "shell.h"
41 : #include "flags.h"
42 : #include "input.h" /* for save_token_state, restore_token_state */
43 : #include "jobs.h"
44 : #include "signames.h"
45 : #include "builtins.h"
46 : #include "builtins/common.h"
47 : #include "builtins/builtext.h"
48 :
49 : #if defined (READLINE)
50 : # include <readline/readline.h>
51 : # include "bashline.h"
52 : #endif
53 :
54 : #ifndef errno
55 : extern int errno;
56 : #endif
57 :
58 : /* Flags which describe the current handling state of a signal. */
59 : #define SIG_INHERITED 0x0 /* Value inherited from parent. */
60 : #define SIG_TRAPPED 0x1 /* Currently trapped. */
61 : #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
62 : #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
63 : #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
64 : #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
65 : #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
66 : #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
67 :
68 : #define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
69 :
70 : /* An array of such flags, one for each signal, describing what the
71 : shell will do with a signal. DEBUG_TRAP == NSIG; some code below
72 : assumes this. */
73 : static int sigmodes[BASH_NSIG];
74 :
75 : static void free_trap_command (int);
76 : static void change_signal (int, char *);
77 :
78 : static int _run_trap_internal (int, char *);
79 :
80 : static void free_trap_string (int);
81 : static void reset_signal (int);
82 : static void restore_signal (int);
83 : static void reset_or_restore_signal_handlers (sh_resetsig_func_t *);
84 :
85 : static void trap_if_untrapped (int, char *);
86 :
87 : /* Variables used here but defined in other files. */
88 : extern int last_command_exit_value;
89 : extern int line_number;
90 :
91 : extern int sigalrm_seen;
92 : extern procenv_t alrmbuf;
93 :
94 : extern volatile int from_return_trap;
95 :
96 : extern char *this_command_name;
97 : extern sh_builtin_func_t *this_shell_builtin;
98 : extern procenv_t wait_intr_buf;
99 : extern int wait_intr_flag;
100 : extern int return_catch_flag, return_catch_value;
101 : extern int subshell_level;
102 : extern WORD_LIST *subst_assign_varlist;
103 :
104 : /* The list of things to do originally, before we started trapping. */
105 : SigHandler *original_signals[NSIG];
106 :
107 : /* For each signal, a slot for a string, which is a command to be
108 : executed when that signal is received. The slot can also contain
109 : DEFAULT_SIG, which means do whatever you were going to do before
110 : you were so rudely interrupted, or IGNORE_SIG, which says ignore
111 : this signal. */
112 : char *trap_list[BASH_NSIG];
113 :
114 : /* A bitmap of signals received for which we have trap handlers. */
115 : int pending_traps[NSIG];
116 :
117 : /* Set to the number of the signal we're running the trap for + 1.
118 : Used in execute_cmd.c and builtins/common.c to clean up when
119 : parse_and_execute does not return normally after executing the
120 : trap command (e.g., when `return' is executed in the trap command). */
121 : int running_trap;
122 :
123 : /* Set to last_command_exit_value before running a trap. */
124 : int trap_saved_exit_value;
125 :
126 : /* The (trapped) signal received while executing in the `wait' builtin */
127 : int wait_signal_received;
128 :
129 : int trapped_signal_received;
130 :
131 : #define GETORIGSIG(sig) \
132 : do { \
133 : original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
134 : set_signal_handler (sig, original_signals[sig]); \
135 : if (original_signals[sig] == SIG_IGN) \
136 : sigmodes[sig] |= SIG_HARD_IGNORE; \
137 : } while (0)
138 :
139 : #define SETORIGSIG(sig,handler) \
140 : do { \
141 : original_signals[sig] = handler; \
142 : if (original_signals[sig] == SIG_IGN) \
143 : sigmodes[sig] |= SIG_HARD_IGNORE; \
144 : } while (0)
145 :
146 : #define GET_ORIGINAL_SIGNAL(sig) \
147 : if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
148 : GETORIGSIG(sig)
149 :
150 : void
151 9143244 : initialize_traps ()
152 : {
153 9143244 : register int i;
154 :
155 9143244 : initialize_signames();
156 :
157 9143244 : trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
158 9143244 : sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED;
159 9143244 : original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
160 :
161 594310860 : for (i = 1; i < NSIG; i++)
162 : {
163 585167616 : pending_traps[i] = 0;
164 585167616 : trap_list[i] = (char *)DEFAULT_SIG;
165 585167616 : sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
166 585167616 : original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
167 : }
168 :
169 : /* Show which signals are treated specially by the shell. */
170 : #if defined (SIGCHLD)
171 9143244 : GETORIGSIG (SIGCHLD);
172 9143244 : sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
173 : #endif /* SIGCHLD */
174 :
175 9143244 : GETORIGSIG (SIGINT);
176 9143244 : sigmodes[SIGINT] |= SIG_SPECIAL;
177 :
178 : #if defined (__BEOS__)
179 : /* BeOS sets SIGINT to SIG_IGN! */
180 : original_signals[SIGINT] = SIG_DFL;
181 : sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
182 : #endif
183 :
184 9143244 : GETORIGSIG (SIGQUIT);
185 9143244 : sigmodes[SIGQUIT] |= SIG_SPECIAL;
186 :
187 9143244 : if (interactive)
188 : {
189 0 : GETORIGSIG (SIGTERM);
190 0 : sigmodes[SIGTERM] |= SIG_SPECIAL;
191 : }
192 :
193 9143244 : get_original_tty_job_signals ();
194 9143244 : }
195 :
196 : #ifdef DEBUG
197 : /* Return a printable representation of the trap handler for SIG. */
198 : static char *
199 : trap_handler_string (sig)
200 : int sig;
201 : {
202 : if (trap_list[sig] == (char *)DEFAULT_SIG)
203 : return "DEFAULT_SIG";
204 : else if (trap_list[sig] == (char *)IGNORE_SIG)
205 : return "IGNORE_SIG";
206 : else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
207 : return "IMPOSSIBLE_TRAP_HANDLER";
208 : else if (trap_list[sig])
209 : return trap_list[sig];
210 : else
211 : return "NULL";
212 : }
213 : #endif
214 :
215 : /* Return the print name of this signal. */
216 : char *
217 176 : signal_name (sig)
218 : int sig;
219 : {
220 176 : char *ret;
221 :
222 : /* on cygwin32, signal_names[sig] could be null */
223 176 : ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL)
224 0 : ? _("invalid signal number")
225 176 : : signal_names[sig];
226 :
227 176 : return ret;
228 : }
229 :
230 : /* Turn a string into a signal number, or a number into
231 : a signal number. If STRING is "2", "SIGINT", or "INT",
232 : then (int)2 is returned. Return NO_SIG if STRING doesn't
233 : contain a valid signal descriptor. */
234 : int
235 136 : decode_signal (string, flags)
236 : char *string;
237 : int flags;
238 : {
239 136 : intmax_t sig;
240 136 : char *name;
241 :
242 136 : if (legal_number (string, &sig))
243 9 : return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
244 :
245 : /* A leading `SIG' may be omitted. */
246 8151 : for (sig = 0; sig < BASH_NSIG; sig++)
247 : {
248 8033 : name = signal_names[sig];
249 8033 : if (name == 0 || name[0] == '\0')
250 : continue;
251 :
252 : /* Check name without the SIG prefix first case sensitively or
253 : insensitively depending on whether flags includes DSIG_NOCASE */
254 8033 : if (STREQN (name, "SIG", 3))
255 : {
256 7552 : name += 3;
257 :
258 7552 : if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
259 0 : return ((int)sig);
260 7552 : else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
261 0 : return ((int)sig);
262 : /* If we can't use the `SIG' prefix to match, punt on this
263 : name now. */
264 7552 : else if ((flags & DSIG_SIGPREFIX) == 0)
265 : continue;
266 : }
267 :
268 : /* Check name with SIG prefix case sensitively or insensitively
269 : depending on whether flags includes DSIG_NOCASE */
270 8033 : name = signal_names[sig];
271 8033 : if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
272 9 : return ((int)sig);
273 8024 : else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
274 0 : return ((int)sig);
275 : }
276 :
277 : return (NO_SIG);
278 : }
279 :
280 : /* Non-zero when we catch a trapped signal. */
281 : static int catch_flag;
282 :
283 : void
284 532271564 : run_pending_traps ()
285 : {
286 532271564 : register int sig;
287 532271564 : int old_exit_value, x;
288 532271564 : WORD_LIST *save_subst_varlist;
289 532271564 : HASH_TABLE *save_tempenv;
290 532271564 : sh_parser_state_t pstate;
291 : #if defined (ARRAY_VARS)
292 532271564 : ARRAY *ps;
293 : #endif
294 :
295 532271564 : if (catch_flag == 0) /* simple optimization */
296 532271564 : return;
297 :
298 0 : if (running_trap > 0)
299 : {
300 : #if defined (DEBUG)
301 : internal_warning ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap-1);
302 : #endif
303 : #if defined (SIGWINCH)
304 0 : if (running_trap == SIGWINCH+1 && pending_traps[SIGWINCH])
305 : return; /* no recursive SIGWINCH trap invocations */
306 : #else
307 : ;
308 : #endif
309 : }
310 :
311 0 : catch_flag = trapped_signal_received = 0;
312 :
313 : /* Preserve $? when running trap. */
314 0 : trap_saved_exit_value = old_exit_value = last_command_exit_value;
315 : #if defined (ARRAY_VARS)
316 0 : ps = save_pipestatus_array ();
317 : #endif
318 :
319 0 : for (sig = 1; sig < NSIG; sig++)
320 : {
321 : /* XXX this could be made into a counter by using
322 : while (pending_traps[sig]--) instead of the if statement. */
323 0 : if (pending_traps[sig])
324 : {
325 0 : if (running_trap == sig+1)
326 : /*continue*/;
327 :
328 0 : running_trap = sig + 1;
329 :
330 0 : if (sig == SIGINT)
331 : {
332 0 : pending_traps[sig] = 0; /* XXX */
333 0 : run_interrupt_trap (0);
334 0 : CLRINTERRUPT;
335 : }
336 : #if defined (JOB_CONTROL) && defined (SIGCHLD)
337 0 : else if (sig == SIGCHLD &&
338 0 : trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER &&
339 0 : (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0)
340 : {
341 0 : sigmodes[SIGCHLD] |= SIG_INPROGRESS;
342 0 : x = pending_traps[sig];
343 0 : pending_traps[sig] = 0;
344 0 : run_sigchld_trap (x); /* use as counter */
345 0 : running_trap = 0;
346 0 : sigmodes[SIGCHLD] &= ~SIG_INPROGRESS;
347 : /* continue here rather than reset pending_traps[SIGCHLD] below in
348 : case there are recursive calls to run_pending_traps and children
349 : have been reaped while run_sigchld_trap was running. */
350 0 : continue;
351 : }
352 0 : else if (sig == SIGCHLD &&
353 0 : trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER &&
354 0 : (sigmodes[SIGCHLD] & SIG_INPROGRESS) != 0)
355 : {
356 : /* This can happen when run_pending_traps is called while
357 : running a SIGCHLD trap handler. */
358 0 : running_trap = 0;
359 : /* want to leave pending_traps[SIGCHLD] alone here */
360 0 : continue; /* XXX */
361 : }
362 0 : else if (sig == SIGCHLD && (sigmodes[SIGCHLD] & SIG_INPROGRESS))
363 : {
364 : /* whoops -- print warning? */
365 0 : running_trap = 0; /* XXX */
366 : /* want to leave pending_traps[SIGCHLD] alone here */
367 0 : continue;
368 : }
369 : #endif
370 0 : else if (trap_list[sig] == (char *)DEFAULT_SIG ||
371 0 : trap_list[sig] == (char *)IGNORE_SIG ||
372 : trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
373 : {
374 : /* This is possible due to a race condition. Say a bash
375 : process has SIGTERM trapped. A subshell is spawned
376 : using { list; } & and the parent does something and kills
377 : the subshell with SIGTERM. It's possible for the subshell
378 : to set pending_traps[SIGTERM] to 1 before the code in
379 : execute_cmd.c eventually calls restore_original_signals
380 : to reset the SIGTERM signal handler in the subshell. The
381 : next time run_pending_traps is called, pending_traps[SIGTERM]
382 : will be 1, but the trap handler in trap_list[SIGTERM] will
383 : be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
384 : Unless we catch this, the subshell will dump core when
385 : trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
386 : usually 0x0. */
387 0 : internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
388 : sig, trap_list[sig]);
389 0 : if (trap_list[sig] == (char *)DEFAULT_SIG)
390 : {
391 0 : internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig));
392 0 : kill (getpid (), sig);
393 : }
394 : }
395 : else
396 : {
397 : /* XXX - should we use save_parser_state/restore_parser_state? */
398 0 : save_parser_state (&pstate);
399 0 : save_subst_varlist = subst_assign_varlist;
400 0 : subst_assign_varlist = 0;
401 0 : save_tempenv = temporary_env;
402 0 : temporary_env = 0; /* traps should not run with temporary env */
403 :
404 : #if defined (JOB_CONTROL)
405 0 : save_pipeline (1); /* XXX only provides one save level */
406 : #endif
407 : /* XXX - set pending_traps[sig] = 0 here? */
408 0 : pending_traps[sig] = 0;
409 0 : evalstring (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
410 : #if defined (JOB_CONTROL)
411 0 : restore_pipeline (1);
412 : #endif
413 :
414 0 : subst_assign_varlist = save_subst_varlist;
415 0 : restore_parser_state (&pstate);
416 0 : temporary_env = save_tempenv;
417 : }
418 :
419 0 : pending_traps[sig] = 0; /* XXX - move before evalstring? */
420 0 : running_trap = 0;
421 : }
422 : }
423 :
424 : #if defined (ARRAY_VARS)
425 0 : restore_pipestatus_array (ps);
426 : #endif
427 0 : last_command_exit_value = old_exit_value;
428 : }
429 :
430 : sighandler
431 0 : trap_handler (sig)
432 : int sig;
433 : {
434 0 : int oerrno;
435 :
436 0 : if ((sigmodes[sig] & SIG_TRAPPED) == 0)
437 : {
438 : #if defined (DEBUG)
439 : internal_warning ("trap_handler: signal %d: signal not trapped", sig);
440 : #endif
441 : SIGRETURN (0);
442 : }
443 :
444 0 : if ((sig >= NSIG) ||
445 0 : (trap_list[sig] == (char *)DEFAULT_SIG) ||
446 : (trap_list[sig] == (char *)IGNORE_SIG))
447 0 : programming_error (_("trap_handler: bad signal %d"), sig);
448 : else
449 : {
450 0 : oerrno = errno;
451 : #if defined (MUST_REINSTALL_SIGHANDLERS)
452 : # if defined (JOB_CONTROL) && defined (SIGCHLD)
453 : if (sig != SIGCHLD)
454 : # endif /* JOB_CONTROL && SIGCHLD */
455 : set_signal_handler (sig, trap_handler);
456 : #endif /* MUST_REINSTALL_SIGHANDLERS */
457 :
458 0 : catch_flag = 1;
459 0 : pending_traps[sig]++;
460 0 : trapped_signal_received = sig;
461 :
462 0 : if (this_shell_builtin && (this_shell_builtin == wait_builtin))
463 : {
464 0 : wait_signal_received = sig;
465 0 : if (interrupt_immediately && wait_intr_flag)
466 0 : sh_longjmp (wait_intr_buf, 1);
467 : }
468 :
469 : #if defined (READLINE)
470 : /* Set the event hook so readline will call it after the signal handlers
471 : finish executing, so if this interrupted character input we can get
472 : quick response. */
473 0 : if (RL_ISSTATE (RL_STATE_SIGHANDLER) && interrupt_immediately == 0)
474 0 : bashline_set_event_hook ();
475 : #endif
476 :
477 0 : if (interrupt_immediately)
478 0 : run_pending_traps ();
479 :
480 0 : errno = oerrno;
481 : }
482 :
483 : SIGRETURN (0);
484 : }
485 :
486 : int
487 0 : first_pending_trap ()
488 : {
489 0 : register int i;
490 :
491 0 : for (i = 1; i < NSIG; i++)
492 0 : if (pending_traps[i])
493 0 : return i;
494 : return -1;
495 : }
496 :
497 : int
498 1698 : any_signals_trapped ()
499 : {
500 1698 : register int i;
501 :
502 110370 : for (i = 1; i < NSIG; i++)
503 108672 : if (sigmodes[i] & SIG_TRAPPED)
504 0 : return i;
505 : return -1;
506 : }
507 :
508 : void
509 0 : check_signals ()
510 : {
511 0 : CHECK_ALRM; /* set by the read builtin */
512 0 : QUIT;
513 0 : }
514 :
515 : /* Convenience functions the rest of the shell can use */
516 : void
517 0 : check_signals_and_traps ()
518 : {
519 0 : check_signals ();
520 :
521 0 : run_pending_traps ();
522 0 : }
523 :
524 : #if defined (JOB_CONTROL) && defined (SIGCHLD)
525 :
526 : #ifdef INCLUDE_UNUSED
527 : /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
528 : void
529 : set_sigchld_trap (command_string)
530 : char *command_string;
531 : {
532 : set_signal (SIGCHLD, command_string);
533 : }
534 : #endif
535 :
536 : /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
537 : is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
538 : to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
539 : reset the disposition to the default and not have the original signal
540 : accidentally restored, undoing the user's command. */
541 : void
542 0 : maybe_set_sigchld_trap (command_string)
543 : char *command_string;
544 : {
545 0 : if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
546 0 : set_signal (SIGCHLD, command_string);
547 0 : }
548 :
549 : /* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
550 : as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
551 : or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
552 : void
553 0 : set_impossible_sigchld_trap ()
554 : {
555 0 : restore_default_signal (SIGCHLD);
556 0 : change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER);
557 0 : sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */
558 0 : }
559 :
560 : /* Act as if we received SIGCHLD NCHILD times and increment
561 : pending_traps[SIGCHLD] by that amount. This allows us to still run the
562 : SIGCHLD trap once for each exited child. */
563 : void
564 0 : queue_sigchld_trap (nchild)
565 : int nchild;
566 : {
567 0 : if (nchild > 0)
568 : {
569 0 : catch_flag = 1;
570 0 : pending_traps[SIGCHLD] += nchild;
571 0 : trapped_signal_received = SIGCHLD;
572 : }
573 0 : }
574 : #endif /* JOB_CONTROL && SIGCHLD */
575 :
576 : /* Set a trap for SIG only if SIG is not already trapped. */
577 : static inline void
578 : trap_if_untrapped (sig, command)
579 : int sig;
580 : char *command;
581 : {
582 0 : if ((sigmodes[sig] & SIG_TRAPPED) == 0)
583 0 : set_signal (sig, command);
584 : }
585 :
586 : void
587 0 : set_debug_trap (command)
588 : char *command;
589 : {
590 0 : set_signal (DEBUG_TRAP, command);
591 0 : }
592 :
593 : /* Separate function to call when functions and sourced files want to restore
594 : the original version of the DEBUG trap before returning. Unless the -T
595 : option is set, source and shell function execution save the old debug trap
596 : and unset the trap. If the function or sourced file changes the DEBUG trap,
597 : SIG_TRAPPED will be set and we don't bother restoring the original trap string.
598 : This is used by both functions and the source builtin. */
599 : void
600 0 : maybe_set_debug_trap (command)
601 : char *command;
602 : {
603 0 : trap_if_untrapped (DEBUG_TRAP, command);
604 0 : }
605 :
606 : void
607 0 : set_error_trap (command)
608 : char *command;
609 : {
610 0 : set_signal (ERROR_TRAP, command);
611 0 : }
612 :
613 : void
614 0 : maybe_set_error_trap (command)
615 : char *command;
616 : {
617 0 : trap_if_untrapped (ERROR_TRAP, command);
618 0 : }
619 :
620 : void
621 0 : set_return_trap (command)
622 : char *command;
623 : {
624 0 : set_signal (RETURN_TRAP, command);
625 0 : }
626 :
627 : void
628 0 : maybe_set_return_trap (command)
629 : char *command;
630 : {
631 0 : trap_if_untrapped (RETURN_TRAP, command);
632 0 : }
633 :
634 : #ifdef INCLUDE_UNUSED
635 : void
636 : set_sigint_trap (command)
637 : char *command;
638 : {
639 : set_signal (SIGINT, command);
640 : }
641 : #endif
642 :
643 : /* Reset the SIGINT handler so that subshells that are doing `shellsy'
644 : things, like waiting for command substitution or executing commands
645 : in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
646 : SigHandler *
647 18842 : set_sigint_handler ()
648 : {
649 18842 : if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
650 : return ((SigHandler *)SIG_IGN);
651 :
652 18842 : else if (sigmodes[SIGINT] & SIG_IGNORED)
653 0 : return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
654 :
655 18842 : else if (sigmodes[SIGINT] & SIG_TRAPPED)
656 0 : return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
657 :
658 : /* The signal is not trapped, so set the handler to the shell's special
659 : interrupt handler. */
660 18842 : else if (interactive) /* XXX - was interactive_shell */
661 0 : return (set_signal_handler (SIGINT, sigint_sighandler));
662 : else
663 18842 : return (set_signal_handler (SIGINT, termsig_sighandler));
664 : }
665 :
666 : /* Return the correct handler for signal SIG according to the values in
667 : sigmodes[SIG]. */
668 : SigHandler *
669 0 : trap_to_sighandler (sig)
670 : int sig;
671 : {
672 0 : if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
673 : return (SIG_IGN);
674 0 : else if (sigmodes[sig] & SIG_TRAPPED)
675 : return (trap_handler);
676 : else
677 0 : return (SIG_DFL);
678 : }
679 :
680 : /* Set SIG to call STRING as a command. */
681 : void
682 9 : set_signal (sig, string)
683 : int sig;
684 : char *string;
685 : {
686 9 : sigset_t set, oset;
687 :
688 9 : if (SPECIAL_TRAP (sig))
689 : {
690 9 : change_signal (sig, savestring (string));
691 9 : if (sig == EXIT_TRAP && interactive == 0)
692 9 : initialize_terminating_signals ();
693 9 : return;
694 : }
695 :
696 : /* A signal ignored on entry to the shell cannot be trapped or reset, but
697 : no error is reported when attempting to do so. -- Posix.2 */
698 0 : if (sigmodes[sig] & SIG_HARD_IGNORE)
699 : return;
700 :
701 : /* Make sure we have original_signals[sig] if the signal has not yet
702 : been trapped. */
703 0 : if ((sigmodes[sig] & SIG_TRAPPED) == 0)
704 : {
705 : /* If we aren't sure of the original value, check it. */
706 0 : if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
707 0 : GETORIGSIG (sig);
708 0 : if (original_signals[sig] == SIG_IGN)
709 : return;
710 : }
711 :
712 : /* Only change the system signal handler if SIG_NO_TRAP is not set.
713 : The trap command string is changed in either case. The shell signal
714 : handlers for SIGINT and SIGCHLD run the user specified traps in an
715 : environment in which it is safe to do so. */
716 0 : if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
717 : {
718 0 : BLOCK_SIGNAL (sig, set, oset);
719 0 : change_signal (sig, savestring (string));
720 0 : set_signal_handler (sig, trap_handler);
721 0 : UNBLOCK_SIGNAL (oset);
722 : }
723 : else
724 0 : change_signal (sig, savestring (string));
725 : }
726 :
727 : static void
728 21121455 : free_trap_command (sig)
729 : int sig;
730 : {
731 21121455 : if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
732 : (trap_list[sig] != (char *)IGNORE_SIG) &&
733 0 : (trap_list[sig] != (char *)DEFAULT_SIG) &&
734 : (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
735 0 : free (trap_list[sig]);
736 21121455 : }
737 :
738 : /* If SIG has a string assigned to it, get rid of it. Then give it
739 : VALUE. */
740 : static void
741 21121455 : change_signal (sig, value)
742 : int sig;
743 : char *value;
744 : {
745 21121455 : if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
746 21121455 : free_trap_command (sig);
747 21121455 : trap_list[sig] = value;
748 :
749 21121455 : sigmodes[sig] |= SIG_TRAPPED;
750 21121455 : if (value == (char *)IGNORE_SIG)
751 0 : sigmodes[sig] |= SIG_IGNORED;
752 : else
753 21121455 : sigmodes[sig] &= ~SIG_IGNORED;
754 21121455 : if (sigmodes[sig] & SIG_INPROGRESS)
755 0 : sigmodes[sig] |= SIG_CHANGED;
756 21121455 : }
757 :
758 : void
759 27467745 : get_original_signal (sig)
760 : int sig;
761 : {
762 : /* If we aren't sure the of the original value, then get it. */
763 27467745 : if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
764 27429705 : GETORIGSIG (sig);
765 27467745 : }
766 :
767 : void
768 88 : get_all_original_signals ()
769 : {
770 88 : register int i;
771 :
772 5720 : for (i = 1; i < NSIG; i++)
773 5632 : GET_ORIGINAL_SIGNAL (i);
774 88 : }
775 :
776 : void
777 0 : set_original_signal (sig, handler)
778 : int sig;
779 : SigHandler *handler;
780 : {
781 0 : if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
782 0 : SETORIGSIG (sig, handler);
783 0 : }
784 :
785 : /* Restore the default action for SIG; i.e., the action the shell
786 : would have taken before you used the trap command. This is called
787 : from trap_builtin (), which takes care to restore the handlers for
788 : the signals the shell treats specially. */
789 : void
790 0 : restore_default_signal (sig)
791 : int sig;
792 : {
793 0 : if (SPECIAL_TRAP (sig))
794 : {
795 0 : if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
796 0 : (sigmodes[sig] & SIG_INPROGRESS) == 0)
797 0 : free_trap_command (sig);
798 0 : trap_list[sig] = (char *)NULL;
799 0 : sigmodes[sig] &= ~SIG_TRAPPED;
800 0 : if (sigmodes[sig] & SIG_INPROGRESS)
801 0 : sigmodes[sig] |= SIG_CHANGED;
802 0 : return;
803 : }
804 :
805 0 : GET_ORIGINAL_SIGNAL (sig);
806 :
807 : /* A signal ignored on entry to the shell cannot be trapped or reset, but
808 : no error is reported when attempting to do so. Thanks Posix.2. */
809 0 : if (sigmodes[sig] & SIG_HARD_IGNORE)
810 : return;
811 :
812 : /* If we aren't trapping this signal, don't bother doing anything else. */
813 : /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
814 : sentinel to determine whether or not disposition is reset to the default
815 : while the trap handler is executing. */
816 0 : if (((sigmodes[sig] & SIG_TRAPPED) == 0) &&
817 0 : (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
818 : return;
819 :
820 : /* Only change the signal handler for SIG if it allows it. */
821 0 : if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
822 0 : set_signal_handler (sig, original_signals[sig]);
823 :
824 : /* Change the trap command in either case. */
825 0 : change_signal (sig, (char *)DEFAULT_SIG);
826 :
827 : /* Mark the signal as no longer trapped. */
828 0 : sigmodes[sig] &= ~SIG_TRAPPED;
829 : }
830 :
831 : /* Make this signal be ignored. */
832 : void
833 0 : ignore_signal (sig)
834 : int sig;
835 : {
836 0 : if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
837 : {
838 0 : change_signal (sig, (char *)IGNORE_SIG);
839 0 : return;
840 : }
841 :
842 0 : GET_ORIGINAL_SIGNAL (sig);
843 :
844 : /* A signal ignored on entry to the shell cannot be trapped or reset.
845 : No error is reported when the user attempts to do so. */
846 0 : if (sigmodes[sig] & SIG_HARD_IGNORE)
847 : return;
848 :
849 : /* If already trapped and ignored, no change necessary. */
850 0 : if (sigmodes[sig] & SIG_IGNORED)
851 : return;
852 :
853 : /* Only change the signal handler for SIG if it allows it. */
854 0 : if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
855 0 : set_signal_handler (sig, SIG_IGN);
856 :
857 : /* Change the trap command in either case. */
858 0 : change_signal (sig, (char *)IGNORE_SIG);
859 : }
860 :
861 : /* Handle the calling of "trap 0". The only sticky situation is when
862 : the command to be executed includes an "exit". This is why we have
863 : to provide our own place for top_level to jump to. */
864 : int
865 3976 : run_exit_trap ()
866 : {
867 3976 : char *trap_command;
868 3976 : int code, function_code, retval;
869 : #if defined (ARRAY_VARS)
870 3976 : ARRAY *ps;
871 : #endif
872 :
873 3976 : trap_saved_exit_value = last_command_exit_value;
874 : #if defined (ARRAY_VARS)
875 3976 : ps = save_pipestatus_array ();
876 : #endif
877 3976 : function_code = 0;
878 :
879 : /* Run the trap only if signal 0 is trapped and not ignored, and we are not
880 : currently running in the trap handler (call to exit in the list of
881 : commands given to trap 0). */
882 3976 : if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
883 : (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
884 : {
885 9 : trap_command = savestring (trap_list[EXIT_TRAP]);
886 9 : sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
887 9 : sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
888 :
889 9 : retval = trap_saved_exit_value;
890 9 : running_trap = 1;
891 :
892 18 : code = setjmp_nosigs (top_level);
893 :
894 : /* If we're in a function, make sure return longjmps come here, too. */
895 18 : if (return_catch_flag)
896 0 : function_code = setjmp_nosigs (return_catch);
897 :
898 18 : if (code == 0 && function_code == 0)
899 : {
900 9 : reset_parser ();
901 9 : parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
902 : }
903 9 : else if (code == ERREXIT)
904 0 : retval = last_command_exit_value;
905 9 : else if (code == EXITPROG)
906 9 : retval = last_command_exit_value;
907 0 : else if (function_code != 0)
908 0 : retval = return_catch_value;
909 : else
910 0 : retval = trap_saved_exit_value;
911 :
912 9 : running_trap = 0;
913 : #if defined (ARRAY_VARS)
914 9 : array_dispose (ps);
915 : #endif
916 :
917 9 : return retval;
918 : }
919 :
920 : #if defined (ARRAY_VARS)
921 3967 : restore_pipestatus_array (ps);
922 : #endif
923 3967 : return (trap_saved_exit_value);
924 : }
925 :
926 : void
927 0 : run_trap_cleanup (sig)
928 : int sig;
929 : {
930 0 : sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
931 0 : }
932 :
933 : #define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
934 :
935 : /* Run a trap command for SIG. SIG is one of the signals the shell treats
936 : specially. Returns the exit status of the executed trap command list. */
937 : static int
938 0 : _run_trap_internal (sig, tag)
939 : int sig;
940 : char *tag;
941 : {
942 0 : char *trap_command, *old_trap;
943 0 : int trap_exit_value;
944 0 : volatile int save_return_catch_flag, function_code, old_int;
945 0 : int flags;
946 0 : procenv_t save_return_catch;
947 0 : WORD_LIST *save_subst_varlist;
948 0 : HASH_TABLE *save_tempenv;
949 0 : sh_parser_state_t pstate;
950 : #if defined (ARRAY_VARS)
951 0 : ARRAY *ps;
952 : #endif
953 :
954 0 : trap_exit_value = function_code = 0;
955 0 : trap_saved_exit_value = last_command_exit_value;
956 : /* Run the trap only if SIG is trapped and not ignored, and we are not
957 : currently executing in the trap handler. */
958 0 : if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
959 0 : (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
960 : #if 0
961 : /* Uncomment this to allow some special signals to recursively execute
962 : trap handlers. */
963 : (RECURSIVE_SIG (sig) || (sigmodes[sig] & SIG_INPROGRESS) == 0))
964 : #else
965 0 : ((sigmodes[sig] & SIG_INPROGRESS) == 0))
966 : #endif
967 : {
968 0 : old_trap = trap_list[sig];
969 0 : sigmodes[sig] |= SIG_INPROGRESS;
970 0 : sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
971 0 : trap_command = savestring (old_trap);
972 :
973 0 : running_trap = sig + 1;
974 :
975 0 : old_int = interrupt_state; /* temporarily suppress pending interrupts */
976 0 : CLRINTERRUPT;
977 :
978 : #if defined (ARRAY_VARS)
979 0 : ps = save_pipestatus_array ();
980 : #endif
981 :
982 0 : save_parser_state (&pstate);
983 0 : save_subst_varlist = subst_assign_varlist;
984 0 : subst_assign_varlist = 0;
985 0 : save_tempenv = temporary_env;
986 0 : temporary_env = 0; /* traps should not run with temporary env */
987 :
988 : #if defined (JOB_CONTROL)
989 0 : if (sig != DEBUG_TRAP) /* run_debug_trap does this */
990 0 : save_pipeline (1); /* XXX only provides one save level */
991 : #endif
992 :
993 : /* If we're in a function, make sure return longjmps come here, too. */
994 0 : save_return_catch_flag = return_catch_flag;
995 0 : if (return_catch_flag)
996 : {
997 0 : COPY_PROCENV (return_catch, save_return_catch);
998 0 : function_code = setjmp_nosigs (return_catch);
999 : }
1000 :
1001 0 : flags = SEVAL_NONINT|SEVAL_NOHIST;
1002 0 : if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
1003 0 : flags |= SEVAL_RESETLINE;
1004 0 : if (function_code == 0)
1005 : {
1006 0 : parse_and_execute (trap_command, tag, flags);
1007 0 : trap_exit_value = last_command_exit_value;
1008 : }
1009 : else
1010 0 : trap_exit_value = return_catch_value;
1011 :
1012 : #if defined (JOB_CONTROL)
1013 0 : if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1014 0 : restore_pipeline (1);
1015 : #endif
1016 :
1017 0 : subst_assign_varlist = save_subst_varlist;
1018 0 : restore_parser_state (&pstate);
1019 :
1020 : #if defined (ARRAY_VARS)
1021 0 : restore_pipestatus_array (ps);
1022 : #endif
1023 :
1024 0 : temporary_env = save_tempenv;
1025 :
1026 0 : sigmodes[sig] &= ~SIG_INPROGRESS;
1027 0 : running_trap = 0;
1028 0 : interrupt_state = old_int;
1029 :
1030 0 : if (sigmodes[sig] & SIG_CHANGED)
1031 : {
1032 : #if 0
1033 : /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
1034 : the places where they can be changed using unwind-protects. For
1035 : example, look at execute_cmd.c:execute_function(). */
1036 : if (SPECIAL_TRAP (sig) == 0)
1037 : #endif
1038 0 : free (old_trap);
1039 0 : sigmodes[sig] &= ~SIG_CHANGED;
1040 : }
1041 :
1042 0 : if (save_return_catch_flag)
1043 : {
1044 0 : return_catch_flag = save_return_catch_flag;
1045 0 : return_catch_value = trap_exit_value;
1046 0 : COPY_PROCENV (save_return_catch, return_catch);
1047 0 : if (function_code)
1048 : {
1049 : #if 0
1050 : from_return_trap = sig == RETURN_TRAP;
1051 : #endif
1052 0 : sh_longjmp (return_catch, 1);
1053 : }
1054 : }
1055 : }
1056 :
1057 0 : return trap_exit_value;
1058 : }
1059 :
1060 : int
1061 85272448 : run_debug_trap ()
1062 : {
1063 85272448 : int trap_exit_value;
1064 85272448 : pid_t save_pgrp;
1065 85272448 : int save_pipe[2];
1066 :
1067 : /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
1068 85272448 : trap_exit_value = 0;
1069 85272448 : if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
1070 : {
1071 : #if defined (JOB_CONTROL)
1072 0 : save_pgrp = pipeline_pgrp;
1073 0 : pipeline_pgrp = 0;
1074 0 : save_pipeline (1);
1075 : # if defined (PGRP_PIPE)
1076 0 : save_pgrp_pipe (save_pipe, 1);
1077 : # endif
1078 0 : stop_making_children ();
1079 : #endif
1080 :
1081 0 : trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
1082 :
1083 : #if defined (JOB_CONTROL)
1084 0 : pipeline_pgrp = save_pgrp;
1085 0 : restore_pipeline (1);
1086 : # if defined (PGRP_PIPE)
1087 0 : close_pgrp_pipe ();
1088 0 : restore_pgrp_pipe (save_pipe);
1089 : # endif
1090 0 : if (pipeline_pgrp > 0)
1091 0 : give_terminal_to (pipeline_pgrp, 1);
1092 0 : notify_and_cleanup ();
1093 : #endif
1094 :
1095 : #if defined (DEBUGGER)
1096 : /* If we're in the debugger and the DEBUG trap returns 2 while we're in
1097 : a function or sourced script, we force a `return'. */
1098 0 : if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
1099 : {
1100 0 : return_catch_value = trap_exit_value;
1101 0 : sh_longjmp (return_catch, 1);
1102 : }
1103 : #endif
1104 : }
1105 85272448 : return trap_exit_value;
1106 : }
1107 :
1108 : void
1109 0 : run_error_trap ()
1110 : {
1111 0 : if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
1112 0 : _run_trap_internal (ERROR_TRAP, "error trap");
1113 0 : }
1114 :
1115 : void
1116 16853560 : run_return_trap ()
1117 : {
1118 16853560 : int old_exit_value;
1119 :
1120 : #if 0
1121 : if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
1122 : return;
1123 : #endif
1124 :
1125 16853560 : if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
1126 : {
1127 0 : old_exit_value = last_command_exit_value;
1128 0 : _run_trap_internal (RETURN_TRAP, "return trap");
1129 0 : last_command_exit_value = old_exit_value;
1130 : }
1131 16853560 : }
1132 :
1133 : /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
1134 : declared here to localize the trap functions. */
1135 : void
1136 0 : run_interrupt_trap (will_throw)
1137 : int will_throw; /* from throw_to_top_level? */
1138 : {
1139 0 : if (will_throw && running_trap > 0)
1140 0 : run_trap_cleanup (running_trap - 1);
1141 0 : _run_trap_internal (SIGINT, "interrupt trap");
1142 0 : }
1143 :
1144 : /* Free all the allocated strings in the list of traps and reset the trap
1145 : values to the default. Intended to be called from subshells that want
1146 : to complete work done by reset_signal_handlers upon execution of a
1147 : subsequent `trap' command that changes a signal's disposition. We need
1148 : to make sure that we duplicate the behavior of
1149 : reset_or_restore_signal_handlers and not change the disposition of signals
1150 : that are set to be ignored. */
1151 : void
1152 0 : free_trap_strings ()
1153 : {
1154 0 : register int i;
1155 :
1156 0 : for (i = 0; i < NSIG; i++)
1157 : {
1158 0 : if (trap_list[i] != (char *)IGNORE_SIG)
1159 0 : free_trap_string (i);
1160 : }
1161 0 : for (i = NSIG; i < BASH_NSIG; i++)
1162 : {
1163 : /* Don't free the trap string if the subshell inherited the trap */
1164 0 : if ((sigmodes[i] & SIG_TRAPPED) == 0)
1165 : {
1166 0 : free_trap_string (i);
1167 0 : trap_list[i] = (char *)NULL;
1168 : }
1169 : }
1170 0 : }
1171 :
1172 : /* Free a trap command string associated with SIG without changing signal
1173 : disposition. Intended to be called from free_trap_strings() */
1174 : static void
1175 : free_trap_string (sig)
1176 : int sig;
1177 : {
1178 0 : change_signal (sig, (char *)DEFAULT_SIG);
1179 0 : sigmodes[sig] &= ~SIG_TRAPPED;
1180 : }
1181 :
1182 : /* Reset the handler for SIG to the original value but leave the trap string
1183 : in place. */
1184 : static void
1185 56046 : reset_signal (sig)
1186 : int sig;
1187 : {
1188 56046 : set_signal_handler (sig, original_signals[sig]);
1189 56046 : sigmodes[sig] &= ~SIG_TRAPPED;
1190 56046 : }
1191 :
1192 : /* Set the handler signal SIG to the original and free any trap
1193 : command associated with it. */
1194 : static void
1195 21121446 : restore_signal (sig)
1196 : int sig;
1197 : {
1198 21121446 : set_signal_handler (sig, original_signals[sig]);
1199 21121446 : change_signal (sig, (char *)DEFAULT_SIG);
1200 21121446 : sigmodes[sig] &= ~SIG_TRAPPED;
1201 21121446 : }
1202 :
1203 : static void
1204 7059164 : reset_or_restore_signal_handlers (reset)
1205 : sh_resetsig_func_t *reset;
1206 : {
1207 7059164 : register int i;
1208 :
1209 : /* Take care of the exit trap first */
1210 7059164 : if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
1211 : {
1212 0 : sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
1213 0 : if (reset != reset_signal)
1214 : {
1215 0 : free_trap_command (EXIT_TRAP);
1216 0 : trap_list[EXIT_TRAP] = (char *)NULL;
1217 : }
1218 : }
1219 :
1220 458845660 : for (i = 1; i < NSIG; i++)
1221 : {
1222 451786496 : if (sigmodes[i] & SIG_TRAPPED)
1223 : {
1224 0 : if (trap_list[i] == (char *)IGNORE_SIG)
1225 0 : set_signal_handler (i, SIG_IGN);
1226 : else
1227 0 : (*reset) (i);
1228 : }
1229 451786496 : else if (sigmodes[i] & SIG_SPECIAL)
1230 21177492 : (*reset) (i);
1231 451786496 : pending_traps[i] = 0; /* XXX */
1232 : }
1233 :
1234 : /* Command substitution and other child processes don't inherit the
1235 : debug, error, or return traps. If we're in the debugger, and the
1236 : `functrace' or `errtrace' options have been set, then let command
1237 : substitutions inherit them. Let command substitution inherit the
1238 : RETURN trap if we're in the debugger and tracing functions. */
1239 7059164 : if (function_trace_mode == 0)
1240 : {
1241 7059164 : sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
1242 7059164 : sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
1243 : }
1244 7059164 : if (error_trace_mode == 0)
1245 7059164 : sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
1246 7059164 : }
1247 :
1248 : /* Reset trapped signals to their original values, but don't free the
1249 : trap strings. Called by the command substitution code and other places
1250 : that create a "subshell environment". */
1251 : void
1252 18682 : reset_signal_handlers ()
1253 : {
1254 18682 : reset_or_restore_signal_handlers (reset_signal);
1255 18682 : }
1256 :
1257 : /* Reset all trapped signals to their original values. Signals set to be
1258 : ignored with trap '' SIGNAL should be ignored, so we make sure that they
1259 : are. Called by child processes after they are forked. */
1260 : void
1261 7040482 : restore_original_signals ()
1262 : {
1263 7040482 : reset_or_restore_signal_handlers (restore_signal);
1264 7040482 : }
1265 :
1266 : /* If a trap handler exists for signal SIG, then call it; otherwise just
1267 : return failure. Returns 1 if it called the trap handler. */
1268 : int
1269 0 : maybe_call_trap_handler (sig)
1270 : int sig;
1271 : {
1272 : /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1273 0 : if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
1274 : {
1275 0 : switch (sig)
1276 : {
1277 : case SIGINT:
1278 0 : run_interrupt_trap (0);
1279 : break;
1280 0 : case EXIT_TRAP:
1281 0 : run_exit_trap ();
1282 0 : break;
1283 0 : case DEBUG_TRAP:
1284 0 : run_debug_trap ();
1285 0 : break;
1286 : case ERROR_TRAP:
1287 0 : run_error_trap ();
1288 : break;
1289 0 : default:
1290 0 : trap_handler (sig);
1291 0 : break;
1292 : }
1293 0 : return (1);
1294 : }
1295 : else
1296 : return (0);
1297 : }
1298 :
1299 : int
1300 127307657 : signal_is_trapped (sig)
1301 : int sig;
1302 : {
1303 127307657 : return (sigmodes[sig] & SIG_TRAPPED);
1304 : }
1305 :
1306 : int
1307 25001000 : signal_is_pending (sig)
1308 : int sig;
1309 : {
1310 25001000 : return (pending_traps[sig]);
1311 : }
1312 :
1313 : int
1314 782 : signal_is_special (sig)
1315 : int sig;
1316 : {
1317 782 : return (sigmodes[sig] & SIG_SPECIAL);
1318 : }
1319 :
1320 : int
1321 0 : signal_is_ignored (sig)
1322 : int sig;
1323 : {
1324 0 : return (sigmodes[sig] & SIG_IGNORED);
1325 : }
1326 :
1327 : int
1328 21183577 : signal_is_hard_ignored (sig)
1329 : int sig;
1330 : {
1331 21183577 : return (sigmodes[sig] & SIG_HARD_IGNORE);
1332 : }
1333 :
1334 : void
1335 97 : set_signal_hard_ignored (sig)
1336 : int sig;
1337 : {
1338 97 : sigmodes[sig] |= SIG_HARD_IGNORE;
1339 97 : original_signals[sig] = SIG_IGN;
1340 97 : }
1341 :
1342 : void
1343 0 : set_signal_ignored (sig)
1344 : int sig;
1345 : {
1346 0 : original_signals[sig] = SIG_IGN;
1347 0 : }
1348 :
1349 : int
1350 85264959 : signal_in_progress (sig)
1351 : int sig;
1352 : {
1353 85264959 : return (sigmodes[sig] & SIG_INPROGRESS);
1354 : }
|