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