]>
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 | ||
4 | /* Copyright (C) 1987, 1991 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 it under | |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 1, or (at your option) any later | |
11 | version. | |
12 | ||
13 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License along | |
19 | with Bash; see the file COPYING. If not, write to the Free Software | |
20 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
21 | ||
ccc6cda3 JA |
22 | #include "config.h" |
23 | ||
726f6388 JA |
24 | #include <stdio.h> |
25 | ||
26 | #include "bashtypes.h" | |
27 | #include "trap.h" | |
28 | ||
d166f048 | 29 | #include "bashansi.h" |
726f6388 | 30 | |
ccc6cda3 JA |
31 | #if defined (HAVE_UNISTD_H) |
32 | # include <unistd.h> | |
33 | #endif | |
34 | ||
726f6388 JA |
35 | #include "shell.h" |
36 | #include "signames.h" | |
ccc6cda3 | 37 | #include "builtins/common.h" |
726f6388 JA |
38 | |
39 | /* Flags which describe the current handling state of a signal. */ | |
40 | #define SIG_INHERITED 0x0 /* Value inherited from parent. */ | |
41 | #define SIG_TRAPPED 0x1 /* Currently trapped. */ | |
42 | #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */ | |
43 | #define SIG_SPECIAL 0x4 /* Treat this signal specially. */ | |
44 | #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */ | |
ccc6cda3 JA |
45 | #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */ |
46 | #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */ | |
47 | #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */ | |
726f6388 JA |
48 | |
49 | /* An array of such flags, one for each signal, describing what the | |
ccc6cda3 JA |
50 | shell will do with a signal. DEBUG_TRAP == NSIG; some code below |
51 | assumes this. */ | |
52 | static int sigmodes[NSIG+1]; | |
726f6388 JA |
53 | |
54 | static void change_signal (), restore_signal (); | |
55 | ||
56 | /* Variables used here but defined in other files. */ | |
57 | extern int interactive_shell, interactive; | |
58 | extern int interrupt_immediately; | |
59 | extern int last_command_exit_value; | |
d166f048 | 60 | extern int line_number; |
726f6388 JA |
61 | |
62 | /* The list of things to do originally, before we started trapping. */ | |
63 | SigHandler *original_signals[NSIG]; | |
64 | ||
65 | /* For each signal, a slot for a string, which is a command to be | |
66 | executed when that signal is recieved. The slot can also contain | |
67 | DEFAULT_SIG, which means do whatever you were going to do before | |
68 | you were so rudely interrupted, or IGNORE_SIG, which says ignore | |
69 | this signal. */ | |
ccc6cda3 | 70 | char *trap_list[NSIG+1]; |
726f6388 JA |
71 | |
72 | /* A bitmap of signals received for which we have trap handlers. */ | |
73 | int pending_traps[NSIG]; | |
74 | ||
ccc6cda3 JA |
75 | /* Set to the number of the signal we're running the trap for + 1. |
76 | Used in execute_cmd.c and builtins/common.c to clean up when | |
77 | parse_and_execute does not return normally after executing the | |
78 | trap command (e.g., when `return' is executed in the trap command). */ | |
79 | int running_trap; | |
80 | ||
d166f048 JA |
81 | /* The value of line_number when the trap started executing, since |
82 | parse_and_execute resets it to 1 and the trap command might want | |
83 | it. */ | |
84 | int trap_line_number; | |
85 | ||
726f6388 JA |
86 | /* A value which can never be the target of a trap handler. */ |
87 | #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps | |
88 | ||
89 | void | |
90 | initialize_traps () | |
91 | { | |
92 | register int i; | |
93 | ||
ccc6cda3 JA |
94 | trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = (char *)NULL; |
95 | sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = SIG_INHERITED; | |
96 | original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER; | |
726f6388 JA |
97 | |
98 | for (i = 1; i < NSIG; i++) | |
99 | { | |
100 | pending_traps[i] = 0; | |
101 | trap_list[i] = (char *)DEFAULT_SIG; | |
102 | sigmodes[i] = SIG_INHERITED; | |
103 | original_signals[i] = IMPOSSIBLE_TRAP_HANDLER; | |
104 | } | |
105 | ||
106 | /* Show which signals are treated specially by the shell. */ | |
107 | #if defined (SIGCHLD) | |
ccc6cda3 JA |
108 | original_signals[SIGCHLD] = |
109 | (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL); | |
726f6388 JA |
110 | set_signal_handler (SIGCHLD, original_signals[SIGCHLD]); |
111 | sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP); | |
112 | #endif /* SIGCHLD */ | |
113 | ||
114 | original_signals[SIGINT] = | |
115 | (SigHandler *) set_signal_handler (SIGINT, SIG_DFL); | |
116 | set_signal_handler (SIGINT, original_signals[SIGINT]); | |
117 | sigmodes[SIGINT] |= SIG_SPECIAL; | |
118 | ||
119 | original_signals[SIGQUIT] = | |
120 | (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL); | |
121 | set_signal_handler (SIGQUIT, original_signals[SIGQUIT]); | |
122 | sigmodes[SIGQUIT] |= SIG_SPECIAL; | |
123 | ||
124 | if (interactive) | |
125 | { | |
ccc6cda3 JA |
126 | original_signals[SIGTERM] = |
127 | (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL); | |
726f6388 JA |
128 | set_signal_handler (SIGTERM, original_signals[SIGTERM]); |
129 | sigmodes[SIGTERM] |= SIG_SPECIAL; | |
130 | } | |
131 | } | |
132 | ||
133 | /* Return the print name of this signal. */ | |
134 | char * | |
135 | signal_name (sig) | |
136 | int sig; | |
137 | { | |
ccc6cda3 | 138 | return ((sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]); |
726f6388 JA |
139 | } |
140 | ||
141 | /* Turn a string into a signal number, or a number into | |
142 | a signal number. If STRING is "2", "SIGINT", or "INT", | |
143 | then (int)2 is returned. Return NO_SIG if STRING doesn't | |
144 | contain a valid signal descriptor. */ | |
145 | int | |
146 | decode_signal (string) | |
147 | char *string; | |
148 | { | |
ccc6cda3 | 149 | long sig; |
726f6388 | 150 | |
ccc6cda3 JA |
151 | if (legal_number (string, &sig)) |
152 | return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG); | |
726f6388 | 153 | |
ccc6cda3 JA |
154 | for (sig = 0; sig <= NSIG; sig++) |
155 | if (strcasecmp (string, signal_names[sig]) == 0 || | |
156 | strcasecmp (string, &(signal_names[sig])[3]) == 0) | |
157 | return ((int)sig); | |
726f6388 JA |
158 | |
159 | return (NO_SIG); | |
160 | } | |
161 | ||
162 | /* Non-zero when we catch a trapped signal. */ | |
ccc6cda3 | 163 | static int catch_flag; |
726f6388 JA |
164 | |
165 | void | |
166 | run_pending_traps () | |
167 | { | |
168 | register int sig; | |
169 | int old_exit_value; | |
170 | ||
171 | if (catch_flag == 0) /* simple optimization */ | |
172 | return; | |
173 | ||
174 | catch_flag = 0; | |
175 | ||
176 | /* Preserve $? when running trap. */ | |
177 | old_exit_value = last_command_exit_value; | |
178 | ||
179 | for (sig = 1; sig < NSIG; sig++) | |
180 | { | |
181 | /* XXX this could be made into a counter by using | |
182 | while (pending_traps[sig]--) instead of the if statement. */ | |
183 | if (pending_traps[sig]) | |
184 | { | |
ccc6cda3 | 185 | #if defined (HAVE_POSIX_SIGNALS) |
726f6388 JA |
186 | sigset_t set, oset; |
187 | ||
188 | sigemptyset (&set); | |
189 | sigemptyset (&oset); | |
190 | ||
191 | sigaddset (&set, sig); | |
192 | sigprocmask (SIG_BLOCK, &set, &oset); | |
193 | #else | |
194 | # if defined (HAVE_BSD_SIGNALS) | |
195 | int oldmask = sigblock (sigmask (sig)); | |
196 | # endif | |
ccc6cda3 | 197 | #endif /* HAVE_POSIX_SIGNALS */ |
726f6388 JA |
198 | |
199 | if (sig == SIGINT) | |
200 | { | |
201 | run_interrupt_trap (); | |
ccc6cda3 | 202 | CLRINTERRUPT; |
726f6388 JA |
203 | } |
204 | else | |
d166f048 | 205 | parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST); |
726f6388 JA |
206 | |
207 | pending_traps[sig] = 0; | |
208 | ||
ccc6cda3 | 209 | #if defined (HAVE_POSIX_SIGNALS) |
726f6388 JA |
210 | sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); |
211 | #else | |
212 | # if defined (HAVE_BSD_SIGNALS) | |
213 | sigsetmask (oldmask); | |
214 | # endif | |
215 | #endif /* POSIX_VERSION */ | |
216 | } | |
217 | } | |
218 | ||
219 | last_command_exit_value = old_exit_value; | |
220 | } | |
221 | ||
222 | sighandler | |
223 | trap_handler (sig) | |
224 | int sig; | |
225 | { | |
226 | if ((sig >= NSIG) || | |
227 | (trap_list[sig] == (char *)DEFAULT_SIG) || | |
228 | (trap_list[sig] == (char *)IGNORE_SIG)) | |
ccc6cda3 | 229 | programming_error ("trap_handler: bad signal %d", sig); |
726f6388 JA |
230 | else |
231 | { | |
ccc6cda3 | 232 | #if defined (MUST_REINSTALL_SIGHANDLERS) |
726f6388 | 233 | set_signal_handler (sig, trap_handler); |
ccc6cda3 | 234 | #endif /* MUST_REINSTALL_SIGHANDLERS */ |
726f6388 JA |
235 | |
236 | catch_flag = 1; | |
237 | pending_traps[sig]++; | |
238 | ||
239 | if (interrupt_immediately) | |
240 | run_pending_traps (); | |
241 | } | |
ccc6cda3 JA |
242 | |
243 | SIGRETURN (0); | |
726f6388 JA |
244 | } |
245 | ||
246 | #if defined (JOB_CONTROL) && defined (SIGCHLD) | |
247 | /* Make COMMAND_STRING be executed when SIGCHLD is caught. */ | |
248 | void | |
249 | set_sigchld_trap (command_string) | |
250 | char *command_string; | |
251 | { | |
726f6388 JA |
252 | set_signal (SIGCHLD, command_string); |
253 | } | |
254 | ||
255 | /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current | |
256 | SIGCHLD trap handler is DEFAULT_SIG. */ | |
257 | void | |
258 | maybe_set_sigchld_trap (command_string) | |
259 | char *command_string; | |
260 | { | |
726f6388 JA |
261 | if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0) |
262 | set_signal (SIGCHLD, command_string); | |
263 | } | |
264 | #endif /* JOB_CONTROL && SIGCHLD */ | |
265 | ||
ccc6cda3 JA |
266 | void |
267 | set_debug_trap (command) | |
726f6388 JA |
268 | char *command; |
269 | { | |
ccc6cda3 JA |
270 | set_signal (DEBUG_TRAP, command); |
271 | } | |
726f6388 | 272 | |
ccc6cda3 JA |
273 | void |
274 | set_sigint_trap (command) | |
275 | char *command; | |
276 | { | |
726f6388 JA |
277 | set_signal (SIGINT, command); |
278 | } | |
279 | ||
280 | /* Reset the SIGINT handler so that subshells that are doing `shellsy' | |
281 | things, like waiting for command substitution or executing commands | |
282 | in explicit subshells ( ( cmd ) ), can catch interrupts properly. */ | |
283 | SigHandler * | |
284 | set_sigint_handler () | |
285 | { | |
286 | if (sigmodes[SIGINT] & SIG_HARD_IGNORE) | |
287 | return ((SigHandler *)SIG_IGN); | |
288 | ||
289 | else if (sigmodes[SIGINT] & SIG_IGNORED) | |
ccc6cda3 JA |
290 | return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */ |
291 | ||
726f6388 JA |
292 | else if (sigmodes[SIGINT] & SIG_TRAPPED) |
293 | return ((SigHandler *)set_signal_handler (SIGINT, trap_handler)); | |
294 | ||
295 | /* The signal is not trapped, so set the handler to the shell's special | |
296 | interrupt handler. */ | |
297 | else if (interactive) /* XXX - was interactive_shell */ | |
298 | return (set_signal_handler (SIGINT, sigint_sighandler)); | |
299 | else | |
300 | return (set_signal_handler (SIGINT, termination_unwind_protect)); | |
301 | } | |
302 | ||
303 | /* Set SIG to call STRING as a command. */ | |
304 | void | |
305 | set_signal (sig, string) | |
306 | int sig; | |
307 | char *string; | |
308 | { | |
ccc6cda3 JA |
309 | if (sig == DEBUG_TRAP || sig == EXIT_TRAP) |
310 | { | |
311 | change_signal (sig, savestring (string)); | |
d166f048 JA |
312 | if (sig == EXIT_TRAP && interactive == 0) |
313 | initialize_terminating_signals (); | |
ccc6cda3 JA |
314 | return; |
315 | } | |
316 | ||
726f6388 JA |
317 | /* A signal ignored on entry to the shell cannot be trapped or reset, but |
318 | no error is reported when attempting to do so. -- Posix.2 */ | |
319 | if (sigmodes[sig] & SIG_HARD_IGNORE) | |
320 | return; | |
321 | ||
322 | /* Make sure we have original_signals[sig] if the signal has not yet | |
323 | been trapped. */ | |
324 | if ((sigmodes[sig] & SIG_TRAPPED) == 0) | |
325 | { | |
326 | /* If we aren't sure of the original value, check it. */ | |
327 | if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) | |
328 | { | |
329 | original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); | |
330 | set_signal_handler (sig, original_signals[sig]); | |
331 | } | |
332 | ||
333 | /* Signals ignored on entry to the shell cannot be trapped or reset. */ | |
334 | if (original_signals[sig] == SIG_IGN) | |
335 | { | |
336 | sigmodes[sig] |= SIG_HARD_IGNORE; | |
337 | return; | |
338 | } | |
339 | } | |
340 | ||
341 | /* Only change the system signal handler if SIG_NO_TRAP is not set. | |
342 | The trap command string is changed in either case. The shell signal | |
343 | handlers for SIGINT and SIGCHLD run the user specified traps in an | |
344 | environment in which it is safe to do so. */ | |
345 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) | |
346 | { | |
347 | set_signal_handler (sig, SIG_IGN); | |
348 | change_signal (sig, savestring (string)); | |
349 | set_signal_handler (sig, trap_handler); | |
350 | } | |
351 | else | |
352 | change_signal (sig, savestring (string)); | |
353 | } | |
354 | ||
355 | static void | |
356 | free_trap_command (sig) | |
357 | int sig; | |
358 | { | |
359 | if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] && | |
360 | (trap_list[sig] != (char *)IGNORE_SIG) && | |
361 | (trap_list[sig] != (char *)DEFAULT_SIG) && | |
362 | (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) | |
363 | free (trap_list[sig]); | |
364 | } | |
ccc6cda3 | 365 | |
726f6388 JA |
366 | /* If SIG has a string assigned to it, get rid of it. Then give it |
367 | VALUE. */ | |
368 | static void | |
369 | change_signal (sig, value) | |
370 | int sig; | |
371 | char *value; | |
372 | { | |
d166f048 JA |
373 | if ((sigmodes[sig] & SIG_INPROGRESS) == 0) |
374 | free_trap_command (sig); | |
726f6388 JA |
375 | trap_list[sig] = value; |
376 | ||
377 | sigmodes[sig] |= SIG_TRAPPED; | |
378 | if (value == (char *)IGNORE_SIG) | |
379 | sigmodes[sig] |= SIG_IGNORED; | |
380 | else | |
381 | sigmodes[sig] &= ~SIG_IGNORED; | |
382 | if (sigmodes[sig] & SIG_INPROGRESS) | |
383 | sigmodes[sig] |= SIG_CHANGED; | |
384 | } | |
385 | ||
386 | #define GET_ORIGINAL_SIGNAL(sig) \ | |
387 | if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ | |
388 | get_original_signal (sig) | |
389 | ||
390 | static void | |
391 | get_original_signal (sig) | |
392 | int sig; | |
393 | { | |
394 | /* If we aren't sure the of the original value, then get it. */ | |
395 | if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) | |
396 | { | |
397 | original_signals[sig] = | |
398 | (SigHandler *) set_signal_handler (sig, SIG_DFL); | |
399 | set_signal_handler (sig, original_signals[sig]); | |
400 | ||
401 | /* Signals ignored on entry to the shell cannot be trapped. */ | |
402 | if (original_signals[sig] == SIG_IGN) | |
403 | sigmodes[sig] |= SIG_HARD_IGNORE; | |
404 | } | |
405 | } | |
406 | ||
407 | /* Restore the default action for SIG; i.e., the action the shell | |
408 | would have taken before you used the trap command. This is called | |
409 | from trap_builtin (), which takes care to restore the handlers for | |
410 | the signals the shell treats specially. */ | |
411 | void | |
412 | restore_default_signal (sig) | |
413 | int sig; | |
414 | { | |
ccc6cda3 | 415 | if (sig == DEBUG_TRAP || sig == EXIT_TRAP) |
726f6388 | 416 | { |
d166f048 JA |
417 | if ((sig != DEBUG_TRAP) || (sigmodes[sig] & SIG_INPROGRESS) == 0) |
418 | free_trap_command (sig); | |
726f6388 JA |
419 | trap_list[sig] = (char *)NULL; |
420 | sigmodes[sig] &= ~SIG_TRAPPED; | |
d166f048 JA |
421 | if (sigmodes[sig] & SIG_INPROGRESS) |
422 | sigmodes[sig] |= SIG_CHANGED; | |
726f6388 JA |
423 | return; |
424 | } | |
425 | ||
426 | GET_ORIGINAL_SIGNAL (sig); | |
427 | ||
428 | /* A signal ignored on entry to the shell cannot be trapped or reset, but | |
429 | no error is reported when attempting to do so. Thanks Posix.2. */ | |
430 | if (sigmodes[sig] & SIG_HARD_IGNORE) | |
431 | return; | |
432 | ||
433 | /* If we aren't trapping this signal, don't bother doing anything else. */ | |
ccc6cda3 | 434 | if ((sigmodes[sig] & SIG_TRAPPED) == 0) |
726f6388 JA |
435 | return; |
436 | ||
437 | /* Only change the signal handler for SIG if it allows it. */ | |
ccc6cda3 | 438 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) |
726f6388 JA |
439 | set_signal_handler (sig, original_signals[sig]); |
440 | ||
441 | /* Change the trap command in either case. */ | |
442 | change_signal (sig, (char *)DEFAULT_SIG); | |
443 | ||
444 | /* Mark the signal as no longer trapped. */ | |
445 | sigmodes[sig] &= ~SIG_TRAPPED; | |
446 | } | |
447 | ||
448 | /* Make this signal be ignored. */ | |
449 | void | |
450 | ignore_signal (sig) | |
451 | int sig; | |
452 | { | |
ccc6cda3 JA |
453 | if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0)) |
454 | { | |
455 | change_signal (sig, (char *)IGNORE_SIG); | |
456 | return; | |
457 | } | |
458 | ||
726f6388 JA |
459 | GET_ORIGINAL_SIGNAL (sig); |
460 | ||
461 | /* A signal ignored on entry to the shell cannot be trapped or reset. | |
ccc6cda3 | 462 | No error is reported when the user attempts to do so. */ |
726f6388 JA |
463 | if (sigmodes[sig] & SIG_HARD_IGNORE) |
464 | return; | |
465 | ||
466 | /* If already trapped and ignored, no change necessary. */ | |
ccc6cda3 | 467 | if (sigmodes[sig] & SIG_IGNORED) |
726f6388 JA |
468 | return; |
469 | ||
470 | /* Only change the signal handler for SIG if it allows it. */ | |
ccc6cda3 | 471 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) |
726f6388 JA |
472 | set_signal_handler (sig, SIG_IGN); |
473 | ||
474 | /* Change the trap command in either case. */ | |
475 | change_signal (sig, (char *)IGNORE_SIG); | |
476 | } | |
477 | ||
478 | /* Handle the calling of "trap 0". The only sticky situation is when | |
479 | the command to be executed includes an "exit". This is why we have | |
480 | to provide our own place for top_level to jump to. */ | |
481 | int | |
482 | run_exit_trap () | |
483 | { | |
ccc6cda3 JA |
484 | char *trap_command; |
485 | int code, old_exit_value; | |
726f6388 JA |
486 | |
487 | old_exit_value = last_command_exit_value; | |
488 | ||
ccc6cda3 JA |
489 | /* Run the trap only if signal 0 is trapped and not ignored, and we are not |
490 | currently running in the trap handler (call to exit in the list of | |
491 | commands given to trap 0). */ | |
492 | if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) && | |
493 | (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0) | |
726f6388 | 494 | { |
ccc6cda3 JA |
495 | trap_command = savestring (trap_list[EXIT_TRAP]); |
496 | sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; | |
497 | sigmodes[EXIT_TRAP] |= SIG_INPROGRESS; | |
726f6388 JA |
498 | |
499 | code = setjmp (top_level); | |
500 | ||
501 | if (code == 0) | |
d166f048 | 502 | parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST); |
726f6388 | 503 | else if (code == EXITPROG) |
ccc6cda3 | 504 | return (last_command_exit_value); |
726f6388 JA |
505 | else |
506 | return (old_exit_value); | |
507 | } | |
508 | ||
509 | return (old_exit_value); | |
510 | } | |
511 | ||
ccc6cda3 JA |
512 | void |
513 | run_trap_cleanup (sig) | |
514 | int sig; | |
515 | { | |
516 | sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); | |
517 | } | |
518 | ||
519 | /* Run a trap command for SIG. SIG is one of the signals the shell treats | |
520 | specially. */ | |
726f6388 | 521 | static void |
ccc6cda3 | 522 | _run_trap_internal (sig, tag) |
726f6388 | 523 | int sig; |
ccc6cda3 | 524 | char *tag; |
726f6388 | 525 | { |
ccc6cda3 | 526 | char *trap_command, *old_trap; |
d166f048 | 527 | int old_exit_value, old_line_number; |
ccc6cda3 JA |
528 | |
529 | /* Run the trap only if SIG is trapped and not ignored, and we are not | |
530 | currently executing in the trap handler. */ | |
531 | if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && | |
532 | (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && | |
533 | ((sigmodes[sig] & SIG_INPROGRESS) == 0)) | |
534 | { | |
535 | old_trap = trap_list[sig]; | |
536 | sigmodes[sig] |= SIG_INPROGRESS; | |
537 | sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ | |
538 | trap_command = savestring (old_trap); | |
539 | ||
540 | running_trap = sig + 1; | |
541 | old_exit_value = last_command_exit_value; | |
d166f048 JA |
542 | /* Need to copy the value of line_number because parse_and_execute |
543 | resets it to 1, and the trap command might want it. */ | |
544 | trap_line_number = line_number; | |
545 | parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST); | |
ccc6cda3 JA |
546 | last_command_exit_value = old_exit_value; |
547 | running_trap = 0; | |
548 | ||
549 | sigmodes[sig] &= ~SIG_INPROGRESS; | |
550 | ||
551 | if (sigmodes[sig] & SIG_CHANGED) | |
552 | { | |
553 | free (old_trap); | |
554 | sigmodes[sig] &= ~SIG_CHANGED; | |
555 | } | |
556 | } | |
557 | } | |
558 | ||
559 | void | |
560 | run_debug_trap () | |
561 | { | |
562 | if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0) | |
563 | _run_trap_internal (DEBUG_TRAP, "debug trap"); | |
564 | } | |
565 | ||
566 | /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and | |
567 | declared here to localize the trap functions. */ | |
568 | void | |
569 | run_interrupt_trap () | |
570 | { | |
571 | _run_trap_internal (SIGINT, "interrupt trap"); | |
726f6388 JA |
572 | } |
573 | ||
574 | /* Free all the allocated strings in the list of traps and reset the trap | |
575 | values to the default. */ | |
576 | void | |
577 | free_trap_strings () | |
578 | { | |
579 | register int i; | |
580 | ||
ccc6cda3 | 581 | for (i = 0; i < NSIG+1; i++) |
726f6388 JA |
582 | { |
583 | free_trap_command (i); | |
584 | trap_list[i] = (char *)DEFAULT_SIG; | |
585 | sigmodes[i] &= ~SIG_TRAPPED; | |
586 | } | |
ccc6cda3 | 587 | trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL; |
726f6388 JA |
588 | } |
589 | ||
590 | /* Reset the handler for SIG to the original value. */ | |
591 | static void | |
592 | reset_signal (sig) | |
593 | int sig; | |
594 | { | |
595 | set_signal_handler (sig, original_signals[sig]); | |
596 | } | |
597 | ||
ccc6cda3 JA |
598 | /* Set the handler signal SIG to the original and free any trap |
599 | command associated with it. */ | |
600 | static void | |
601 | restore_signal (sig) | |
602 | int sig; | |
726f6388 | 603 | { |
ccc6cda3 JA |
604 | set_signal_handler (sig, original_signals[sig]); |
605 | change_signal (sig, (char *)DEFAULT_SIG); | |
606 | sigmodes[sig] &= ~SIG_TRAPPED; | |
726f6388 JA |
607 | } |
608 | ||
ccc6cda3 JA |
609 | static void |
610 | reset_or_restore_signal_handlers (reset) | |
611 | VFunction *reset; | |
726f6388 JA |
612 | { |
613 | register int i; | |
614 | ||
ccc6cda3 JA |
615 | /* Take care of the exit trap first */ |
616 | if (sigmodes[EXIT_TRAP] & SIG_TRAPPED) | |
726f6388 | 617 | { |
ccc6cda3 JA |
618 | free_trap_command (EXIT_TRAP); |
619 | trap_list[EXIT_TRAP] = (char *)NULL; | |
620 | sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; | |
726f6388 | 621 | } |
726f6388 JA |
622 | for (i = 1; i < NSIG; i++) |
623 | { | |
ccc6cda3 | 624 | if (sigmodes[i] & SIG_TRAPPED) |
726f6388 JA |
625 | { |
626 | if (trap_list[i] == (char *)IGNORE_SIG) | |
627 | set_signal_handler (i, SIG_IGN); | |
628 | else | |
ccc6cda3 | 629 | (*reset) (i); |
726f6388 | 630 | } |
ccc6cda3 JA |
631 | else if (sigmodes[i] & SIG_SPECIAL) |
632 | (*reset) (i); | |
726f6388 JA |
633 | } |
634 | } | |
635 | ||
726f6388 | 636 | void |
ccc6cda3 | 637 | reset_signal_handlers () |
726f6388 | 638 | { |
ccc6cda3 JA |
639 | reset_or_restore_signal_handlers (reset_signal); |
640 | } | |
726f6388 | 641 | |
ccc6cda3 JA |
642 | /* Reset all trapped signals to their original values. Signals set to be |
643 | ignored with trap '' SIGNAL should be ignored, so we make sure that they | |
644 | are. Called by child processes after they are forked. */ | |
645 | void | |
646 | restore_original_signals () | |
647 | { | |
648 | reset_or_restore_signal_handlers (restore_signal); | |
726f6388 JA |
649 | } |
650 | ||
651 | /* If a trap handler exists for signal SIG, then call it; otherwise just | |
652 | return failure. */ | |
653 | int | |
654 | maybe_call_trap_handler (sig) | |
655 | int sig; | |
656 | { | |
657 | /* Call the trap handler for SIG if the signal is trapped and not ignored. */ | |
ccc6cda3 | 658 | if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0)) |
726f6388 JA |
659 | { |
660 | switch (sig) | |
661 | { | |
662 | case SIGINT: | |
663 | run_interrupt_trap (); | |
664 | break; | |
ccc6cda3 | 665 | case EXIT_TRAP: |
726f6388 JA |
666 | run_exit_trap (); |
667 | break; | |
ccc6cda3 JA |
668 | case DEBUG_TRAP: |
669 | run_debug_trap (); | |
670 | break; | |
726f6388 JA |
671 | default: |
672 | trap_handler (sig); | |
673 | break; | |
674 | } | |
675 | return (1); | |
676 | } | |
677 | else | |
678 | return (0); | |
679 | } | |
680 | ||
681 | int | |
682 | signal_is_trapped (sig) | |
683 | int sig; | |
684 | { | |
685 | return (sigmodes[sig] & SIG_TRAPPED); | |
686 | } | |
687 | ||
688 | int | |
689 | signal_is_special (sig) | |
690 | int sig; | |
691 | { | |
692 | return (sigmodes[sig] & SIG_SPECIAL); | |
693 | } | |
694 | ||
695 | int | |
696 | signal_is_ignored (sig) | |
697 | int sig; | |
698 | { | |
699 | return (sigmodes[sig] & SIG_IGNORED); | |
700 | } | |
701 | ||
702 | void | |
703 | set_signal_ignored (sig) | |
704 | int sig; | |
705 | { | |
706 | sigmodes[sig] |= SIG_HARD_IGNORE; | |
ccc6cda3 | 707 | original_signals[sig] = SIG_IGN; |
726f6388 | 708 | } |