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