]>
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 | ||
a0c0a00f | 4 | /* Copyright (C) 1987-2015 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
3185942a JA |
8 | Bash is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation, either version 3 of the License, or | |
11 | (at your option) any later version. | |
726f6388 | 12 | |
3185942a JA |
13 | Bash is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
726f6388 | 17 | |
3185942a JA |
18 | You should have received a copy of the GNU General Public License |
19 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
20 | */ | |
726f6388 | 21 | |
ccc6cda3 JA |
22 | #include "config.h" |
23 | ||
e8ce775d JA |
24 | #if defined (HAVE_UNISTD_H) |
25 | # include <unistd.h> | |
26 | #endif | |
27 | ||
726f6388 | 28 | #include "bashtypes.h" |
d166f048 | 29 | #include "bashansi.h" |
726f6388 | 30 | |
cce855bc | 31 | #include <stdio.h> |
bb70624e | 32 | #include <errno.h> |
cce855bc | 33 | |
b80f6443 JA |
34 | #include "bashintl.h" |
35 | ||
ac50fbac CR |
36 | #include <signal.h> |
37 | ||
cce855bc JA |
38 | #include "trap.h" |
39 | ||
726f6388 | 40 | #include "shell.h" |
b80f6443 | 41 | #include "flags.h" |
bb70624e | 42 | #include "input.h" /* for save_token_state, restore_token_state */ |
3185942a | 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 | |
ac50fbac 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 | |
b80f6443 | 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 | ||
a0c0a00f CR |
75 | static void free_trap_command (int); |
76 | static void change_signal (int, char *); | |
f73dda09 | 77 | |
a0c0a00f | 78 | static int _run_trap_internal (int, char *); |
726f6388 | 79 | |
a0c0a00f CR |
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 *); | |
726f6388 JA |
86 | |
87 | /* Variables used here but defined in other files. */ | |
726f6388 | 88 | extern int last_command_exit_value; |
d166f048 | 89 | extern int line_number; |
726f6388 | 90 | |
ac50fbac CR |
91 | extern int sigalrm_seen; |
92 | extern procenv_t alrmbuf; | |
93 | ||
a0c0a00f CR |
94 | extern volatile int from_return_trap; |
95 | ||
b80f6443 | 96 | extern char *this_command_name; |
7117c2d2 JA |
97 | extern sh_builtin_func_t *this_shell_builtin; |
98 | extern procenv_t wait_intr_buf; | |
a0c0a00f | 99 | extern int wait_intr_flag; |
b80f6443 JA |
100 | extern int return_catch_flag, return_catch_value; |
101 | extern int subshell_level; | |
0001803f | 102 | extern WORD_LIST *subst_assign_varlist; |
7117c2d2 | 103 | |
726f6388 JA |
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 | |
ac50fbac | 108 | executed when that signal is received. The slot can also contain |
726f6388 JA |
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. */ | |
f73dda09 | 112 | char *trap_list[BASH_NSIG]; |
726f6388 JA |
113 | |
114 | /* A bitmap of signals received for which we have trap handlers. */ | |
115 | int pending_traps[NSIG]; | |
116 | ||
ccc6cda3 JA |
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 | ||
b80f6443 JA |
123 | /* Set to last_command_exit_value before running a trap. */ |
124 | int trap_saved_exit_value; | |
d166f048 | 125 | |
7117c2d2 JA |
126 | /* The (trapped) signal received while executing in the `wait' builtin */ |
127 | int wait_signal_received; | |
128 | ||
ac50fbac CR |
129 | int trapped_signal_received; |
130 | ||
0628567a JA |
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 | ||
495aee44 CR |
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 | ||
0628567a JA |
146 | #define GET_ORIGINAL_SIGNAL(sig) \ |
147 | if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ | |
148 | GETORIGSIG(sig) | |
149 | ||
726f6388 JA |
150 | void |
151 | initialize_traps () | |
152 | { | |
153 | register int i; | |
154 | ||
0628567a JA |
155 | initialize_signames(); |
156 | ||
b80f6443 JA |
157 | trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; |
158 | sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED; | |
ccc6cda3 | 159 | original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER; |
726f6388 JA |
160 | |
161 | for (i = 1; i < NSIG; i++) | |
162 | { | |
163 | pending_traps[i] = 0; | |
164 | trap_list[i] = (char *)DEFAULT_SIG; | |
495aee44 | 165 | sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */ |
726f6388 JA |
166 | original_signals[i] = IMPOSSIBLE_TRAP_HANDLER; |
167 | } | |
168 | ||
169 | /* Show which signals are treated specially by the shell. */ | |
170 | #if defined (SIGCHLD) | |
0628567a | 171 | GETORIGSIG (SIGCHLD); |
726f6388 JA |
172 | sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP); |
173 | #endif /* SIGCHLD */ | |
174 | ||
0628567a | 175 | GETORIGSIG (SIGINT); |
726f6388 JA |
176 | sigmodes[SIGINT] |= SIG_SPECIAL; |
177 | ||
b72432fd JA |
178 | #if defined (__BEOS__) |
179 | /* BeOS sets SIGINT to SIG_IGN! */ | |
180 | original_signals[SIGINT] = SIG_DFL; | |
0628567a | 181 | sigmodes[SIGINT] &= ~SIG_HARD_IGNORE; |
b72432fd JA |
182 | #endif |
183 | ||
0628567a | 184 | GETORIGSIG (SIGQUIT); |
726f6388 JA |
185 | sigmodes[SIGQUIT] |= SIG_SPECIAL; |
186 | ||
187 | if (interactive) | |
188 | { | |
0628567a | 189 | GETORIGSIG (SIGTERM); |
726f6388 JA |
190 | sigmodes[SIGTERM] |= SIG_SPECIAL; |
191 | } | |
a0c0a00f CR |
192 | |
193 | get_original_tty_job_signals (); | |
726f6388 JA |
194 | } |
195 | ||
ac50fbac | 196 | #ifdef DEBUG |
bb70624e JA |
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 | ||
726f6388 JA |
215 | /* Return the print name of this signal. */ |
216 | char * | |
217 | signal_name (sig) | |
218 | int sig; | |
219 | { | |
cce855bc JA |
220 | char *ret; |
221 | ||
222 | /* on cygwin32, signal_names[sig] could be null */ | |
b80f6443 JA |
223 | ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL) |
224 | ? _("invalid signal number") | |
225 | : signal_names[sig]; | |
226 | ||
cce855bc | 227 | return ret; |
726f6388 JA |
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 | |
b80f6443 | 235 | decode_signal (string, flags) |
726f6388 | 236 | char *string; |
b80f6443 | 237 | int flags; |
726f6388 | 238 | { |
7117c2d2 | 239 | intmax_t sig; |
b80f6443 | 240 | char *name; |
726f6388 | 241 | |
ccc6cda3 | 242 | if (legal_number (string, &sig)) |
f73dda09 | 243 | return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG); |
726f6388 | 244 | |
e8ce775d | 245 | /* A leading `SIG' may be omitted. */ |
f73dda09 | 246 | for (sig = 0; sig < BASH_NSIG; sig++) |
b72432fd | 247 | { |
b80f6443 JA |
248 | name = signal_names[sig]; |
249 | if (name == 0 || name[0] == '\0') | |
b72432fd | 250 | continue; |
b80f6443 | 251 | |
ac50fbac | 252 | /* Check name without the SIG prefix first case sensitively or |
b80f6443 JA |
253 | insensitively depending on whether flags includes DSIG_NOCASE */ |
254 | if (STREQN (name, "SIG", 3)) | |
255 | { | |
256 | name += 3; | |
257 | ||
258 | if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) | |
259 | return ((int)sig); | |
260 | else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) | |
261 | return ((int)sig); | |
262 | /* If we can't use the `SIG' prefix to match, punt on this | |
263 | name now. */ | |
264 | 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 | name = signal_names[sig]; | |
271 | if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) | |
272 | return ((int)sig); | |
273 | else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) | |
b72432fd JA |
274 | return ((int)sig); |
275 | } | |
726f6388 JA |
276 | |
277 | return (NO_SIG); | |
278 | } | |
279 | ||
280 | /* Non-zero when we catch a trapped signal. */ | |
ccc6cda3 | 281 | static int catch_flag; |
726f6388 JA |
282 | |
283 | void | |
284 | run_pending_traps () | |
285 | { | |
286 | register int sig; | |
a0c0a00f | 287 | int old_exit_value, x; |
0001803f | 288 | WORD_LIST *save_subst_varlist; |
a0c0a00f | 289 | HASH_TABLE *save_tempenv; |
ac50fbac | 290 | sh_parser_state_t pstate; |
495aee44 CR |
291 | #if defined (ARRAY_VARS) |
292 | ARRAY *ps; | |
293 | #endif | |
726f6388 JA |
294 | |
295 | if (catch_flag == 0) /* simple optimization */ | |
296 | return; | |
297 | ||
ac50fbac CR |
298 | 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 | |
a0c0a00f CR |
303 | #if defined (SIGWINCH) |
304 | if (running_trap == SIGWINCH+1 && pending_traps[SIGWINCH]) | |
305 | return; /* no recursive SIGWINCH trap invocations */ | |
ac50fbac CR |
306 | #else |
307 | ; | |
308 | #endif | |
309 | } | |
310 | ||
311 | catch_flag = trapped_signal_received = 0; | |
726f6388 JA |
312 | |
313 | /* Preserve $? when running trap. */ | |
a0c0a00f | 314 | trap_saved_exit_value = old_exit_value = last_command_exit_value; |
495aee44 CR |
315 | #if defined (ARRAY_VARS) |
316 | ps = save_pipestatus_array (); | |
317 | #endif | |
726f6388 JA |
318 | |
319 | for (sig = 1; sig < NSIG; sig++) | |
320 | { | |
321 | /* XXX this could be made into a counter by using | |
28ef6c31 | 322 | while (pending_traps[sig]--) instead of the if statement. */ |
726f6388 JA |
323 | if (pending_traps[sig]) |
324 | { | |
ac50fbac CR |
325 | if (running_trap == sig+1) |
326 | /*continue*/; | |
726f6388 | 327 | |
ac50fbac | 328 | running_trap = sig + 1; |
726f6388 JA |
329 | |
330 | if (sig == SIGINT) | |
331 | { | |
ac50fbac | 332 | pending_traps[sig] = 0; /* XXX */ |
a0c0a00f | 333 | run_interrupt_trap (0); |
ccc6cda3 | 334 | CLRINTERRUPT; |
726f6388 | 335 | } |
3185942a JA |
336 | #if defined (JOB_CONTROL) && defined (SIGCHLD) |
337 | else if (sig == SIGCHLD && | |
338 | trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER && | |
339 | (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0) | |
340 | { | |
ac50fbac | 341 | sigmodes[SIGCHLD] |= SIG_INPROGRESS; |
a0c0a00f CR |
342 | x = pending_traps[sig]; |
343 | pending_traps[sig] = 0; | |
344 | run_sigchld_trap (x); /* use as counter */ | |
345 | running_trap = 0; | |
ac50fbac | 346 | sigmodes[SIGCHLD] &= ~SIG_INPROGRESS; |
a0c0a00f CR |
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 | continue; | |
ac50fbac CR |
351 | } |
352 | else if (sig == SIGCHLD && | |
353 | trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER && | |
354 | (sigmodes[SIGCHLD] & SIG_INPROGRESS) != 0) | |
355 | { | |
356 | /* This can happen when run_pending_traps is called while | |
357 | running a SIGCHLD trap handler. */ | |
358 | running_trap = 0; | |
359 | /* want to leave pending_traps[SIGCHLD] alone here */ | |
360 | continue; /* XXX */ | |
361 | } | |
362 | else if (sig == SIGCHLD && (sigmodes[SIGCHLD] & SIG_INPROGRESS)) | |
363 | { | |
364 | /* whoops -- print warning? */ | |
365 | running_trap = 0; /* XXX */ | |
366 | /* want to leave pending_traps[SIGCHLD] alone here */ | |
367 | continue; | |
3185942a JA |
368 | } |
369 | #endif | |
bb70624e JA |
370 | else if (trap_list[sig] == (char *)DEFAULT_SIG || |
371 | 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. */ | |
b80f6443 | 387 | internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"), |
f73dda09 | 388 | sig, trap_list[sig]); |
bb70624e JA |
389 | if (trap_list[sig] == (char *)DEFAULT_SIG) |
390 | { | |
b80f6443 | 391 | internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig)); |
bb70624e JA |
392 | kill (getpid (), sig); |
393 | } | |
394 | } | |
726f6388 | 395 | else |
bb70624e | 396 | { |
ac50fbac CR |
397 | /* XXX - should we use save_parser_state/restore_parser_state? */ |
398 | save_parser_state (&pstate); | |
0001803f CR |
399 | save_subst_varlist = subst_assign_varlist; |
400 | subst_assign_varlist = 0; | |
a0c0a00f CR |
401 | save_tempenv = temporary_env; |
402 | temporary_env = 0; /* traps should not run with temporary env */ | |
0001803f | 403 | |
ac50fbac CR |
404 | #if defined (JOB_CONTROL) |
405 | save_pipeline (1); /* XXX only provides one save level */ | |
406 | #endif | |
407 | /* XXX - set pending_traps[sig] = 0 here? */ | |
408 | pending_traps[sig] = 0; | |
409 | evalstring (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE); | |
410 | #if defined (JOB_CONTROL) | |
411 | restore_pipeline (1); | |
412 | #endif | |
0001803f CR |
413 | |
414 | subst_assign_varlist = save_subst_varlist; | |
ac50fbac | 415 | restore_parser_state (&pstate); |
a0c0a00f | 416 | temporary_env = save_tempenv; |
bb70624e | 417 | } |
726f6388 | 418 | |
ac50fbac CR |
419 | pending_traps[sig] = 0; /* XXX - move before evalstring? */ |
420 | running_trap = 0; | |
726f6388 JA |
421 | } |
422 | } | |
423 | ||
495aee44 CR |
424 | #if defined (ARRAY_VARS) |
425 | restore_pipestatus_array (ps); | |
426 | #endif | |
726f6388 JA |
427 | last_command_exit_value = old_exit_value; |
428 | } | |
429 | ||
430 | sighandler | |
431 | trap_handler (sig) | |
432 | int sig; | |
433 | { | |
bb70624e JA |
434 | int oerrno; |
435 | ||
3185942a JA |
436 | 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 | ||
726f6388 JA |
444 | if ((sig >= NSIG) || |
445 | (trap_list[sig] == (char *)DEFAULT_SIG) || | |
446 | (trap_list[sig] == (char *)IGNORE_SIG)) | |
b80f6443 | 447 | programming_error (_("trap_handler: bad signal %d"), sig); |
726f6388 JA |
448 | else |
449 | { | |
28ef6c31 | 450 | oerrno = errno; |
ccc6cda3 | 451 | #if defined (MUST_REINSTALL_SIGHANDLERS) |
3185942a JA |
452 | # if defined (JOB_CONTROL) && defined (SIGCHLD) |
453 | if (sig != SIGCHLD) | |
454 | # endif /* JOB_CONTROL && SIGCHLD */ | |
726f6388 | 455 | set_signal_handler (sig, trap_handler); |
ccc6cda3 | 456 | #endif /* MUST_REINSTALL_SIGHANDLERS */ |
726f6388 JA |
457 | |
458 | catch_flag = 1; | |
459 | pending_traps[sig]++; | |
ac50fbac CR |
460 | trapped_signal_received = sig; |
461 | ||
462 | if (this_shell_builtin && (this_shell_builtin == wait_builtin)) | |
7117c2d2 JA |
463 | { |
464 | wait_signal_received = sig; | |
a0c0a00f CR |
465 | if (interrupt_immediately && wait_intr_flag) |
466 | sh_longjmp (wait_intr_buf, 1); | |
7117c2d2 JA |
467 | } |
468 | ||
ac50fbac CR |
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 | if (RL_ISSTATE (RL_STATE_SIGHANDLER) && interrupt_immediately == 0) | |
474 | bashline_set_event_hook (); | |
475 | #endif | |
476 | ||
726f6388 JA |
477 | if (interrupt_immediately) |
478 | run_pending_traps (); | |
bb70624e JA |
479 | |
480 | errno = oerrno; | |
726f6388 | 481 | } |
ccc6cda3 JA |
482 | |
483 | SIGRETURN (0); | |
726f6388 JA |
484 | } |
485 | ||
ac50fbac CR |
486 | int |
487 | first_pending_trap () | |
488 | { | |
489 | register int i; | |
490 | ||
491 | for (i = 1; i < NSIG; i++) | |
492 | if (pending_traps[i]) | |
493 | return i; | |
494 | return -1; | |
495 | } | |
496 | ||
497 | int | |
498 | any_signals_trapped () | |
499 | { | |
500 | register int i; | |
501 | ||
502 | for (i = 1; i < NSIG; i++) | |
503 | if (sigmodes[i] & SIG_TRAPPED) | |
504 | return i; | |
505 | return -1; | |
506 | } | |
507 | ||
508 | void | |
509 | check_signals () | |
510 | { | |
511 | CHECK_ALRM; /* set by the read builtin */ | |
512 | QUIT; | |
513 | } | |
514 | ||
515 | /* Convenience functions the rest of the shell can use */ | |
516 | void | |
517 | check_signals_and_traps () | |
518 | { | |
519 | check_signals (); | |
520 | ||
521 | run_pending_traps (); | |
522 | } | |
523 | ||
726f6388 | 524 | #if defined (JOB_CONTROL) && defined (SIGCHLD) |
cce855bc JA |
525 | |
526 | #ifdef INCLUDE_UNUSED | |
726f6388 JA |
527 | /* Make COMMAND_STRING be executed when SIGCHLD is caught. */ |
528 | void | |
529 | set_sigchld_trap (command_string) | |
530 | char *command_string; | |
531 | { | |
726f6388 JA |
532 | set_signal (SIGCHLD, command_string); |
533 | } | |
cce855bc | 534 | #endif |
726f6388 | 535 | |
95732b49 | 536 | /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD |
3185942a JA |
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. */ | |
726f6388 JA |
541 | void |
542 | maybe_set_sigchld_trap (command_string) | |
543 | char *command_string; | |
544 | { | |
3185942a | 545 | if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER) |
726f6388 JA |
546 | set_signal (SIGCHLD, command_string); |
547 | } | |
3185942a JA |
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 | set_impossible_sigchld_trap () | |
554 | { | |
555 | restore_default_signal (SIGCHLD); | |
556 | change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER); | |
557 | sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */ | |
558 | } | |
ac50fbac CR |
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 | queue_sigchld_trap (nchild) | |
565 | int nchild; | |
566 | { | |
567 | if (nchild > 0) | |
568 | { | |
569 | catch_flag = 1; | |
570 | pending_traps[SIGCHLD] += nchild; | |
571 | trapped_signal_received = SIGCHLD; | |
572 | } | |
573 | } | |
726f6388 JA |
574 | #endif /* JOB_CONTROL && SIGCHLD */ |
575 | ||
a0c0a00f CR |
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 | if ((sigmodes[sig] & SIG_TRAPPED) == 0) | |
583 | set_signal (sig, command); | |
584 | } | |
585 | ||
ccc6cda3 JA |
586 | void |
587 | set_debug_trap (command) | |
726f6388 JA |
588 | char *command; |
589 | { | |
ccc6cda3 JA |
590 | set_signal (DEBUG_TRAP, command); |
591 | } | |
726f6388 | 592 | |
a0c0a00f CR |
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 | maybe_set_debug_trap (command) | |
601 | char *command; | |
602 | { | |
603 | trap_if_untrapped (DEBUG_TRAP, command); | |
604 | } | |
605 | ||
f73dda09 JA |
606 | void |
607 | set_error_trap (command) | |
608 | char *command; | |
609 | { | |
610 | set_signal (ERROR_TRAP, command); | |
611 | } | |
612 | ||
a0c0a00f CR |
613 | void |
614 | maybe_set_error_trap (command) | |
615 | char *command; | |
616 | { | |
617 | trap_if_untrapped (ERROR_TRAP, command); | |
618 | } | |
619 | ||
b80f6443 JA |
620 | void |
621 | set_return_trap (command) | |
622 | char *command; | |
623 | { | |
624 | set_signal (RETURN_TRAP, command); | |
625 | } | |
626 | ||
a0c0a00f CR |
627 | void |
628 | maybe_set_return_trap (command) | |
629 | char *command; | |
630 | { | |
631 | trap_if_untrapped (RETURN_TRAP, command); | |
632 | } | |
633 | ||
cce855bc | 634 | #ifdef INCLUDE_UNUSED |
ccc6cda3 JA |
635 | void |
636 | set_sigint_trap (command) | |
637 | char *command; | |
638 | { | |
726f6388 JA |
639 | set_signal (SIGINT, command); |
640 | } | |
cce855bc | 641 | #endif |
726f6388 JA |
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 | set_sigint_handler () | |
648 | { | |
649 | if (sigmodes[SIGINT] & SIG_HARD_IGNORE) | |
650 | return ((SigHandler *)SIG_IGN); | |
651 | ||
652 | else if (sigmodes[SIGINT] & SIG_IGNORED) | |
ccc6cda3 JA |
653 | return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */ |
654 | ||
726f6388 JA |
655 | else if (sigmodes[SIGINT] & SIG_TRAPPED) |
656 | 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 | else if (interactive) /* XXX - was interactive_shell */ | |
661 | return (set_signal_handler (SIGINT, sigint_sighandler)); | |
662 | else | |
0628567a | 663 | return (set_signal_handler (SIGINT, termsig_sighandler)); |
726f6388 JA |
664 | } |
665 | ||
e8ce775d JA |
666 | /* Return the correct handler for signal SIG according to the values in |
667 | sigmodes[SIG]. */ | |
668 | SigHandler * | |
669 | trap_to_sighandler (sig) | |
670 | int sig; | |
671 | { | |
672 | if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE)) | |
673 | return (SIG_IGN); | |
674 | else if (sigmodes[sig] & SIG_TRAPPED) | |
675 | return (trap_handler); | |
676 | else | |
677 | return (SIG_DFL); | |
678 | } | |
679 | ||
726f6388 JA |
680 | /* Set SIG to call STRING as a command. */ |
681 | void | |
682 | set_signal (sig, string) | |
683 | int sig; | |
684 | char *string; | |
685 | { | |
ac50fbac CR |
686 | sigset_t set, oset; |
687 | ||
f73dda09 | 688 | if (SPECIAL_TRAP (sig)) |
ccc6cda3 JA |
689 | { |
690 | change_signal (sig, savestring (string)); | |
d166f048 JA |
691 | if (sig == EXIT_TRAP && interactive == 0) |
692 | initialize_terminating_signals (); | |
ccc6cda3 JA |
693 | return; |
694 | } | |
695 | ||
726f6388 JA |
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 | 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 | if ((sigmodes[sig] & SIG_TRAPPED) == 0) | |
704 | { | |
705 | /* If we aren't sure of the original value, check it. */ | |
706 | if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) | |
0628567a | 707 | GETORIGSIG (sig); |
726f6388 | 708 | if (original_signals[sig] == SIG_IGN) |
0628567a | 709 | return; |
726f6388 JA |
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 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) | |
717 | { | |
ac50fbac | 718 | BLOCK_SIGNAL (sig, set, oset); |
726f6388 JA |
719 | change_signal (sig, savestring (string)); |
720 | set_signal_handler (sig, trap_handler); | |
ac50fbac | 721 | UNBLOCK_SIGNAL (oset); |
726f6388 JA |
722 | } |
723 | else | |
724 | change_signal (sig, savestring (string)); | |
725 | } | |
726 | ||
727 | static void | |
728 | free_trap_command (sig) | |
729 | int sig; | |
730 | { | |
731 | if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] && | |
732 | (trap_list[sig] != (char *)IGNORE_SIG) && | |
733 | (trap_list[sig] != (char *)DEFAULT_SIG) && | |
734 | (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) | |
735 | free (trap_list[sig]); | |
736 | } | |
ccc6cda3 | 737 | |
726f6388 JA |
738 | /* If SIG has a string assigned to it, get rid of it. Then give it |
739 | VALUE. */ | |
740 | static void | |
741 | change_signal (sig, value) | |
742 | int sig; | |
743 | char *value; | |
744 | { | |
d166f048 JA |
745 | if ((sigmodes[sig] & SIG_INPROGRESS) == 0) |
746 | free_trap_command (sig); | |
726f6388 JA |
747 | trap_list[sig] = value; |
748 | ||
749 | sigmodes[sig] |= SIG_TRAPPED; | |
750 | if (value == (char *)IGNORE_SIG) | |
751 | sigmodes[sig] |= SIG_IGNORED; | |
752 | else | |
753 | sigmodes[sig] &= ~SIG_IGNORED; | |
754 | if (sigmodes[sig] & SIG_INPROGRESS) | |
755 | sigmodes[sig] |= SIG_CHANGED; | |
756 | } | |
757 | ||
ac50fbac | 758 | void |
726f6388 JA |
759 | get_original_signal (sig) |
760 | int sig; | |
761 | { | |
762 | /* If we aren't sure the of the original value, then get it. */ | |
0001803f | 763 | if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) |
0628567a | 764 | GETORIGSIG (sig); |
726f6388 JA |
765 | } |
766 | ||
495aee44 CR |
767 | void |
768 | get_all_original_signals () | |
769 | { | |
770 | register int i; | |
771 | ||
772 | for (i = 1; i < NSIG; i++) | |
773 | GET_ORIGINAL_SIGNAL (i); | |
774 | } | |
775 | ||
776 | void | |
777 | set_original_signal (sig, handler) | |
778 | int sig; | |
779 | SigHandler *handler; | |
780 | { | |
781 | if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) | |
782 | SETORIGSIG (sig, handler); | |
783 | } | |
784 | ||
726f6388 JA |
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 | restore_default_signal (sig) | |
791 | int sig; | |
792 | { | |
f73dda09 | 793 | if (SPECIAL_TRAP (sig)) |
726f6388 | 794 | { |
b80f6443 JA |
795 | if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) || |
796 | (sigmodes[sig] & SIG_INPROGRESS) == 0) | |
d166f048 | 797 | free_trap_command (sig); |
726f6388 JA |
798 | trap_list[sig] = (char *)NULL; |
799 | sigmodes[sig] &= ~SIG_TRAPPED; | |
d166f048 JA |
800 | if (sigmodes[sig] & SIG_INPROGRESS) |
801 | sigmodes[sig] |= SIG_CHANGED; | |
726f6388 JA |
802 | return; |
803 | } | |
804 | ||
805 | 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 | if (sigmodes[sig] & SIG_HARD_IGNORE) | |
810 | return; | |
811 | ||
812 | /* If we aren't trapping this signal, don't bother doing anything else. */ | |
ac50fbac CR |
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 | if (((sigmodes[sig] & SIG_TRAPPED) == 0) && | |
817 | (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) | |
726f6388 JA |
818 | return; |
819 | ||
820 | /* Only change the signal handler for SIG if it allows it. */ | |
ccc6cda3 | 821 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) |
726f6388 JA |
822 | set_signal_handler (sig, original_signals[sig]); |
823 | ||
824 | /* Change the trap command in either case. */ | |
825 | change_signal (sig, (char *)DEFAULT_SIG); | |
826 | ||
827 | /* Mark the signal as no longer trapped. */ | |
828 | sigmodes[sig] &= ~SIG_TRAPPED; | |
829 | } | |
830 | ||
831 | /* Make this signal be ignored. */ | |
832 | void | |
833 | ignore_signal (sig) | |
834 | int sig; | |
835 | { | |
f73dda09 | 836 | if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0)) |
ccc6cda3 JA |
837 | { |
838 | change_signal (sig, (char *)IGNORE_SIG); | |
839 | return; | |
840 | } | |
841 | ||
726f6388 JA |
842 | GET_ORIGINAL_SIGNAL (sig); |
843 | ||
844 | /* A signal ignored on entry to the shell cannot be trapped or reset. | |
ccc6cda3 | 845 | No error is reported when the user attempts to do so. */ |
726f6388 JA |
846 | if (sigmodes[sig] & SIG_HARD_IGNORE) |
847 | return; | |
848 | ||
849 | /* If already trapped and ignored, no change necessary. */ | |
ccc6cda3 | 850 | if (sigmodes[sig] & SIG_IGNORED) |
726f6388 JA |
851 | return; |
852 | ||
853 | /* Only change the signal handler for SIG if it allows it. */ | |
ccc6cda3 | 854 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) |
726f6388 JA |
855 | set_signal_handler (sig, SIG_IGN); |
856 | ||
857 | /* Change the trap command in either case. */ | |
858 | 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 | run_exit_trap () | |
866 | { | |
ccc6cda3 | 867 | char *trap_command; |
b80f6443 | 868 | int code, function_code, retval; |
495aee44 CR |
869 | #if defined (ARRAY_VARS) |
870 | ARRAY *ps; | |
871 | #endif | |
726f6388 | 872 | |
b80f6443 | 873 | trap_saved_exit_value = last_command_exit_value; |
495aee44 CR |
874 | #if defined (ARRAY_VARS) |
875 | ps = save_pipestatus_array (); | |
876 | #endif | |
b80f6443 | 877 | function_code = 0; |
726f6388 | 878 | |
ccc6cda3 JA |
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 | if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) && | |
883 | (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0) | |
726f6388 | 884 | { |
ccc6cda3 JA |
885 | trap_command = savestring (trap_list[EXIT_TRAP]); |
886 | sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; | |
887 | sigmodes[EXIT_TRAP] |= SIG_INPROGRESS; | |
726f6388 | 888 | |
b80f6443 JA |
889 | retval = trap_saved_exit_value; |
890 | running_trap = 1; | |
891 | ||
ac50fbac | 892 | code = setjmp_nosigs (top_level); |
726f6388 | 893 | |
b80f6443 JA |
894 | /* If we're in a function, make sure return longjmps come here, too. */ |
895 | if (return_catch_flag) | |
ac50fbac | 896 | function_code = setjmp_nosigs (return_catch); |
b80f6443 JA |
897 | |
898 | if (code == 0 && function_code == 0) | |
cce855bc JA |
899 | { |
900 | reset_parser (); | |
17345e5a | 901 | parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE); |
cce855bc | 902 | } |
b80f6443 JA |
903 | else if (code == ERREXIT) |
904 | retval = last_command_exit_value; | |
726f6388 | 905 | else if (code == EXITPROG) |
b80f6443 JA |
906 | retval = last_command_exit_value; |
907 | else if (function_code != 0) | |
908 | retval = return_catch_value; | |
726f6388 | 909 | else |
b80f6443 JA |
910 | retval = trap_saved_exit_value; |
911 | ||
912 | running_trap = 0; | |
a0c0a00f CR |
913 | #if defined (ARRAY_VARS) |
914 | array_dispose (ps); | |
915 | #endif | |
916 | ||
b80f6443 | 917 | return retval; |
726f6388 JA |
918 | } |
919 | ||
495aee44 CR |
920 | #if defined (ARRAY_VARS) |
921 | restore_pipestatus_array (ps); | |
922 | #endif | |
b80f6443 | 923 | return (trap_saved_exit_value); |
726f6388 JA |
924 | } |
925 | ||
ccc6cda3 JA |
926 | void |
927 | run_trap_cleanup (sig) | |
928 | int sig; | |
929 | { | |
930 | sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); | |
931 | } | |
932 | ||
ac50fbac CR |
933 | #define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0) |
934 | ||
ccc6cda3 | 935 | /* Run a trap command for SIG. SIG is one of the signals the shell treats |
b80f6443 JA |
936 | specially. Returns the exit status of the executed trap command list. */ |
937 | static int | |
ccc6cda3 | 938 | _run_trap_internal (sig, tag) |
726f6388 | 939 | int sig; |
ccc6cda3 | 940 | char *tag; |
726f6388 | 941 | { |
ccc6cda3 | 942 | char *trap_command, *old_trap; |
b80f6443 | 943 | int trap_exit_value, *token_state; |
a0c0a00f | 944 | volatile int save_return_catch_flag, function_code, top_level_code, old_int; |
ac50fbac | 945 | int flags; |
b80f6443 | 946 | procenv_t save_return_catch; |
0001803f | 947 | WORD_LIST *save_subst_varlist; |
a0c0a00f | 948 | HASH_TABLE *save_tempenv; |
ac50fbac | 949 | sh_parser_state_t pstate; |
495aee44 CR |
950 | #if defined (ARRAY_VARS) |
951 | ARRAY *ps; | |
952 | #endif | |
ccc6cda3 | 953 | |
b80f6443 | 954 | trap_exit_value = function_code = 0; |
a0c0a00f | 955 | trap_saved_exit_value = last_command_exit_value; |
ccc6cda3 JA |
956 | /* Run the trap only if SIG is trapped and not ignored, and we are not |
957 | currently executing in the trap handler. */ | |
958 | if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && | |
959 | (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && | |
ac50fbac CR |
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 | |
ccc6cda3 | 965 | ((sigmodes[sig] & SIG_INPROGRESS) == 0)) |
ac50fbac | 966 | #endif |
ccc6cda3 JA |
967 | { |
968 | old_trap = trap_list[sig]; | |
969 | sigmodes[sig] |= SIG_INPROGRESS; | |
970 | sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ | |
971 | trap_command = savestring (old_trap); | |
972 | ||
973 | running_trap = sig + 1; | |
ac50fbac | 974 | |
a0c0a00f CR |
975 | old_int = interrupt_state; /* temporarily suppress pending interrupts */ |
976 | CLRINTERRUPT; | |
977 | ||
495aee44 CR |
978 | #if defined (ARRAY_VARS) |
979 | ps = save_pipestatus_array (); | |
980 | #endif | |
bb70624e | 981 | |
ac50fbac | 982 | save_parser_state (&pstate); |
0001803f CR |
983 | save_subst_varlist = subst_assign_varlist; |
984 | subst_assign_varlist = 0; | |
a0c0a00f CR |
985 | save_tempenv = temporary_env; |
986 | temporary_env = 0; /* traps should not run with temporary env */ | |
b80f6443 | 987 | |
ac50fbac | 988 | #if defined (JOB_CONTROL) |
7f89f4cd CR |
989 | if (sig != DEBUG_TRAP) /* run_debug_trap does this */ |
990 | save_pipeline (1); /* XXX only provides one save level */ | |
ac50fbac CR |
991 | #endif |
992 | ||
b80f6443 JA |
993 | /* If we're in a function, make sure return longjmps come here, too. */ |
994 | save_return_catch_flag = return_catch_flag; | |
995 | if (return_catch_flag) | |
996 | { | |
997 | COPY_PROCENV (return_catch, save_return_catch); | |
ac50fbac | 998 | function_code = setjmp_nosigs (return_catch); |
b80f6443 JA |
999 | } |
1000 | ||
17345e5a | 1001 | flags = SEVAL_NONINT|SEVAL_NOHIST; |
89a92869 | 1002 | if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP) |
17345e5a | 1003 | flags |= SEVAL_RESETLINE; |
b80f6443 | 1004 | if (function_code == 0) |
a0c0a00f CR |
1005 | { |
1006 | parse_and_execute (trap_command, tag, flags); | |
1007 | trap_exit_value = last_command_exit_value; | |
1008 | } | |
1009 | else | |
1010 | trap_exit_value = return_catch_value; | |
ac50fbac CR |
1011 | |
1012 | #if defined (JOB_CONTROL) | |
7f89f4cd CR |
1013 | if (sig != DEBUG_TRAP) /* run_debug_trap does this */ |
1014 | restore_pipeline (1); | |
ac50fbac | 1015 | #endif |
bb70624e | 1016 | |
0001803f | 1017 | subst_assign_varlist = save_subst_varlist; |
ac50fbac | 1018 | restore_parser_state (&pstate); |
0001803f | 1019 | |
495aee44 CR |
1020 | #if defined (ARRAY_VARS) |
1021 | restore_pipestatus_array (ps); | |
1022 | #endif | |
a0c0a00f CR |
1023 | |
1024 | temporary_env = save_tempenv; | |
ccc6cda3 JA |
1025 | |
1026 | sigmodes[sig] &= ~SIG_INPROGRESS; | |
a0c0a00f CR |
1027 | running_trap = 0; |
1028 | interrupt_state = old_int; | |
ccc6cda3 JA |
1029 | |
1030 | if (sigmodes[sig] & SIG_CHANGED) | |
1031 | { | |
b80f6443 JA |
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 | free (old_trap); | |
ccc6cda3 JA |
1039 | sigmodes[sig] &= ~SIG_CHANGED; |
1040 | } | |
b80f6443 JA |
1041 | |
1042 | if (save_return_catch_flag) | |
1043 | { | |
1044 | return_catch_flag = save_return_catch_flag; | |
1045 | return_catch_value = trap_exit_value; | |
1046 | COPY_PROCENV (save_return_catch, return_catch); | |
1047 | if (function_code) | |
a0c0a00f CR |
1048 | { |
1049 | #if 0 | |
1050 | from_return_trap = sig == RETURN_TRAP; | |
1051 | #endif | |
1052 | sh_longjmp (return_catch, 1); | |
1053 | } | |
b80f6443 | 1054 | } |
ccc6cda3 | 1055 | } |
b80f6443 JA |
1056 | |
1057 | return trap_exit_value; | |
ccc6cda3 JA |
1058 | } |
1059 | ||
b80f6443 | 1060 | int |
ccc6cda3 JA |
1061 | run_debug_trap () |
1062 | { | |
b80f6443 | 1063 | int trap_exit_value; |
89a92869 CR |
1064 | pid_t save_pgrp; |
1065 | int save_pipe[2]; | |
b80f6443 JA |
1066 | |
1067 | /* XXX - question: should the DEBUG trap inherit the RETURN trap? */ | |
1068 | trap_exit_value = 0; | |
1069 | if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)) | |
1070 | { | |
89a92869 CR |
1071 | #if defined (JOB_CONTROL) |
1072 | save_pgrp = pipeline_pgrp; | |
1073 | pipeline_pgrp = 0; | |
1074 | save_pipeline (1); | |
1075 | # if defined (PGRP_PIPE) | |
1076 | save_pgrp_pipe (save_pipe, 1); | |
1077 | # endif | |
1078 | stop_making_children (); | |
1079 | #endif | |
1080 | ||
b80f6443 | 1081 | trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap"); |
89a92869 CR |
1082 | |
1083 | #if defined (JOB_CONTROL) | |
1084 | pipeline_pgrp = save_pgrp; | |
1085 | restore_pipeline (1); | |
1086 | # if defined (PGRP_PIPE) | |
1087 | close_pgrp_pipe (); | |
1088 | restore_pgrp_pipe (save_pipe); | |
1089 | # endif | |
1090 | if (pipeline_pgrp > 0) | |
1091 | give_terminal_to (pipeline_pgrp, 1); | |
1092 | notify_and_cleanup (); | |
1093 | #endif | |
b80f6443 JA |
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 | if (debugging_mode && trap_exit_value == 2 && return_catch_flag) | |
1099 | { | |
1100 | return_catch_value = trap_exit_value; | |
a0c0a00f | 1101 | sh_longjmp (return_catch, 1); |
b80f6443 JA |
1102 | } |
1103 | #endif | |
1104 | } | |
1105 | return trap_exit_value; | |
ccc6cda3 JA |
1106 | } |
1107 | ||
f73dda09 JA |
1108 | void |
1109 | run_error_trap () | |
1110 | { | |
b80f6443 | 1111 | if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0) |
f73dda09 JA |
1112 | _run_trap_internal (ERROR_TRAP, "error trap"); |
1113 | } | |
1114 | ||
b80f6443 JA |
1115 | void |
1116 | run_return_trap () | |
1117 | { | |
1118 | int old_exit_value; | |
1119 | ||
95732b49 JA |
1120 | #if 0 |
1121 | if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS)) | |
1122 | return; | |
1123 | #endif | |
1124 | ||
b80f6443 JA |
1125 | if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0) |
1126 | { | |
1127 | old_exit_value = last_command_exit_value; | |
1128 | _run_trap_internal (RETURN_TRAP, "return trap"); | |
1129 | last_command_exit_value = old_exit_value; | |
1130 | } | |
1131 | } | |
1132 | ||
ccc6cda3 JA |
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 | |
a0c0a00f CR |
1136 | run_interrupt_trap (will_throw) |
1137 | int will_throw; /* from throw_to_top_level? */ | |
ccc6cda3 | 1138 | { |
a0c0a00f CR |
1139 | if (will_throw && running_trap > 0) |
1140 | run_trap_cleanup (running_trap - 1); | |
ccc6cda3 | 1141 | _run_trap_internal (SIGINT, "interrupt trap"); |
726f6388 JA |
1142 | } |
1143 | ||
1144 | /* Free all the allocated strings in the list of traps and reset the trap | |
0001803f CR |
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 | |
ac50fbac CR |
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. */ | |
726f6388 JA |
1151 | void |
1152 | free_trap_strings () | |
1153 | { | |
1154 | register int i; | |
1155 | ||
a0c0a00f | 1156 | for (i = 0; i < NSIG; i++) |
ac50fbac CR |
1157 | { |
1158 | if (trap_list[i] != (char *)IGNORE_SIG) | |
1159 | free_trap_string (i); | |
1160 | } | |
a0c0a00f CR |
1161 | for (i = NSIG; i < BASH_NSIG; i++) |
1162 | { | |
1163 | /* Don't free the trap string if the subshell inherited the trap */ | |
1164 | if ((sigmodes[i] & SIG_TRAPPED) == 0) | |
1165 | { | |
1166 | free_trap_string (i); | |
1167 | trap_list[i] = (char *)NULL; | |
1168 | } | |
1169 | } | |
726f6388 | 1170 | } |
0001803f CR |
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 | change_signal (sig, (char *)DEFAULT_SIG); | |
1179 | sigmodes[sig] &= ~SIG_TRAPPED; | |
1180 | } | |
726f6388 | 1181 | |
495aee44 CR |
1182 | /* Reset the handler for SIG to the original value but leave the trap string |
1183 | in place. */ | |
726f6388 JA |
1184 | static void |
1185 | reset_signal (sig) | |
1186 | int sig; | |
1187 | { | |
1188 | set_signal_handler (sig, original_signals[sig]); | |
7117c2d2 | 1189 | sigmodes[sig] &= ~SIG_TRAPPED; |
726f6388 JA |
1190 | } |
1191 | ||
ccc6cda3 JA |
1192 | /* Set the handler signal SIG to the original and free any trap |
1193 | command associated with it. */ | |
1194 | static void | |
1195 | restore_signal (sig) | |
1196 | int sig; | |
726f6388 | 1197 | { |
ccc6cda3 JA |
1198 | set_signal_handler (sig, original_signals[sig]); |
1199 | change_signal (sig, (char *)DEFAULT_SIG); | |
1200 | sigmodes[sig] &= ~SIG_TRAPPED; | |
726f6388 JA |
1201 | } |
1202 | ||
ccc6cda3 JA |
1203 | static void |
1204 | reset_or_restore_signal_handlers (reset) | |
f73dda09 | 1205 | sh_resetsig_func_t *reset; |
726f6388 JA |
1206 | { |
1207 | register int i; | |
1208 | ||
ccc6cda3 JA |
1209 | /* Take care of the exit trap first */ |
1210 | if (sigmodes[EXIT_TRAP] & SIG_TRAPPED) | |
726f6388 | 1211 | { |
ccc6cda3 | 1212 | sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; |
95732b49 JA |
1213 | if (reset != reset_signal) |
1214 | { | |
1215 | free_trap_command (EXIT_TRAP); | |
1216 | trap_list[EXIT_TRAP] = (char *)NULL; | |
1217 | } | |
726f6388 | 1218 | } |
b80f6443 | 1219 | |
726f6388 JA |
1220 | for (i = 1; i < NSIG; i++) |
1221 | { | |
ccc6cda3 | 1222 | if (sigmodes[i] & SIG_TRAPPED) |
726f6388 JA |
1223 | { |
1224 | if (trap_list[i] == (char *)IGNORE_SIG) | |
1225 | set_signal_handler (i, SIG_IGN); | |
1226 | else | |
ccc6cda3 | 1227 | (*reset) (i); |
726f6388 | 1228 | } |
ccc6cda3 JA |
1229 | else if (sigmodes[i] & SIG_SPECIAL) |
1230 | (*reset) (i); | |
a0c0a00f | 1231 | pending_traps[i] = 0; /* XXX */ |
726f6388 | 1232 | } |
f73dda09 JA |
1233 | |
1234 | /* Command substitution and other child processes don't inherit the | |
b80f6443 JA |
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. */ | |
0628567a JA |
1239 | if (function_trace_mode == 0) |
1240 | { | |
1241 | sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED; | |
1242 | sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED; | |
1243 | } | |
1244 | if (error_trace_mode == 0) | |
b80f6443 | 1245 | sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED; |
726f6388 JA |
1246 | } |
1247 | ||
f73dda09 | 1248 | /* Reset trapped signals to their original values, but don't free the |
495aee44 CR |
1249 | trap strings. Called by the command substitution code and other places |
1250 | that create a "subshell environment". */ | |
726f6388 | 1251 | void |
ccc6cda3 | 1252 | reset_signal_handlers () |
726f6388 | 1253 | { |
ccc6cda3 JA |
1254 | reset_or_restore_signal_handlers (reset_signal); |
1255 | } | |
726f6388 | 1256 | |
ccc6cda3 JA |
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 | restore_original_signals () | |
1262 | { | |
1263 | reset_or_restore_signal_handlers (restore_signal); | |
726f6388 JA |
1264 | } |
1265 | ||
1266 | /* If a trap handler exists for signal SIG, then call it; otherwise just | |
ac50fbac | 1267 | return failure. Returns 1 if it called the trap handler. */ |
726f6388 JA |
1268 | int |
1269 | maybe_call_trap_handler (sig) | |
1270 | int sig; | |
1271 | { | |
1272 | /* Call the trap handler for SIG if the signal is trapped and not ignored. */ | |
ccc6cda3 | 1273 | if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0)) |
726f6388 JA |
1274 | { |
1275 | switch (sig) | |
1276 | { | |
1277 | case SIGINT: | |
a0c0a00f | 1278 | run_interrupt_trap (0); |
726f6388 | 1279 | break; |
ccc6cda3 | 1280 | case EXIT_TRAP: |
726f6388 JA |
1281 | run_exit_trap (); |
1282 | break; | |
ccc6cda3 JA |
1283 | case DEBUG_TRAP: |
1284 | run_debug_trap (); | |
1285 | break; | |
f73dda09 JA |
1286 | case ERROR_TRAP: |
1287 | run_error_trap (); | |
1288 | break; | |
726f6388 JA |
1289 | default: |
1290 | trap_handler (sig); | |
1291 | break; | |
1292 | } | |
1293 | return (1); | |
1294 | } | |
1295 | else | |
1296 | return (0); | |
1297 | } | |
1298 | ||
1299 | int | |
1300 | signal_is_trapped (sig) | |
1301 | int sig; | |
1302 | { | |
1303 | return (sigmodes[sig] & SIG_TRAPPED); | |
1304 | } | |
1305 | ||
ac50fbac CR |
1306 | int |
1307 | signal_is_pending (sig) | |
1308 | int sig; | |
1309 | { | |
1310 | return (pending_traps[sig]); | |
1311 | } | |
1312 | ||
726f6388 JA |
1313 | int |
1314 | signal_is_special (sig) | |
1315 | int sig; | |
1316 | { | |
1317 | return (sigmodes[sig] & SIG_SPECIAL); | |
1318 | } | |
1319 | ||
1320 | int | |
1321 | signal_is_ignored (sig) | |
1322 | int sig; | |
1323 | { | |
1324 | return (sigmodes[sig] & SIG_IGNORED); | |
1325 | } | |
1326 | ||
495aee44 CR |
1327 | int |
1328 | signal_is_hard_ignored (sig) | |
1329 | int sig; | |
1330 | { | |
1331 | return (sigmodes[sig] & SIG_HARD_IGNORE); | |
1332 | } | |
1333 | ||
726f6388 | 1334 | void |
ac50fbac | 1335 | set_signal_hard_ignored (sig) |
726f6388 JA |
1336 | int sig; |
1337 | { | |
1338 | sigmodes[sig] |= SIG_HARD_IGNORE; | |
ccc6cda3 | 1339 | original_signals[sig] = SIG_IGN; |
726f6388 | 1340 | } |
95732b49 | 1341 | |
ac50fbac CR |
1342 | void |
1343 | set_signal_ignored (sig) | |
1344 | int sig; | |
1345 | { | |
1346 | original_signals[sig] = SIG_IGN; | |
1347 | } | |
1348 | ||
95732b49 JA |
1349 | int |
1350 | signal_in_progress (sig) | |
1351 | int sig; | |
1352 | { | |
1353 | return (sigmodes[sig] & SIG_INPROGRESS); | |
1354 | } |