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