]>
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 | ||
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 JA |
31 | #include <stdio.h> |
32 | ||
33 | #include "trap.h" | |
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 | { | |
cce855bc JA |
138 | char *ret; |
139 | ||
140 | /* on cygwin32, signal_names[sig] could be null */ | |
141 | ret = (sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]; | |
142 | if (ret == NULL) | |
143 | ret = "unrecognized signal number"; | |
144 | return ret; | |
726f6388 JA |
145 | } |
146 | ||
147 | /* Turn a string into a signal number, or a number into | |
148 | a signal number. If STRING is "2", "SIGINT", or "INT", | |
149 | then (int)2 is returned. Return NO_SIG if STRING doesn't | |
150 | contain a valid signal descriptor. */ | |
151 | int | |
152 | decode_signal (string) | |
153 | char *string; | |
154 | { | |
ccc6cda3 | 155 | long sig; |
726f6388 | 156 | |
ccc6cda3 JA |
157 | if (legal_number (string, &sig)) |
158 | return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG); | |
726f6388 | 159 | |
e8ce775d | 160 | /* A leading `SIG' may be omitted. */ |
ccc6cda3 JA |
161 | for (sig = 0; sig <= NSIG; sig++) |
162 | if (strcasecmp (string, signal_names[sig]) == 0 || | |
e8ce775d JA |
163 | (STREQN (signal_names[sig], "SIG", 3) && |
164 | strcasecmp (string, &(signal_names[sig])[3]) == 0)) | |
ccc6cda3 | 165 | return ((int)sig); |
726f6388 JA |
166 | |
167 | return (NO_SIG); | |
168 | } | |
169 | ||
170 | /* Non-zero when we catch a trapped signal. */ | |
ccc6cda3 | 171 | static int catch_flag; |
726f6388 JA |
172 | |
173 | void | |
174 | run_pending_traps () | |
175 | { | |
176 | register int sig; | |
177 | int old_exit_value; | |
178 | ||
179 | if (catch_flag == 0) /* simple optimization */ | |
180 | return; | |
181 | ||
182 | catch_flag = 0; | |
183 | ||
184 | /* Preserve $? when running trap. */ | |
185 | old_exit_value = last_command_exit_value; | |
186 | ||
187 | for (sig = 1; sig < NSIG; sig++) | |
188 | { | |
189 | /* XXX this could be made into a counter by using | |
190 | while (pending_traps[sig]--) instead of the if statement. */ | |
191 | if (pending_traps[sig]) | |
192 | { | |
ccc6cda3 | 193 | #if defined (HAVE_POSIX_SIGNALS) |
726f6388 JA |
194 | sigset_t set, oset; |
195 | ||
196 | sigemptyset (&set); | |
197 | sigemptyset (&oset); | |
198 | ||
199 | sigaddset (&set, sig); | |
200 | sigprocmask (SIG_BLOCK, &set, &oset); | |
201 | #else | |
202 | # if defined (HAVE_BSD_SIGNALS) | |
203 | int oldmask = sigblock (sigmask (sig)); | |
204 | # endif | |
ccc6cda3 | 205 | #endif /* HAVE_POSIX_SIGNALS */ |
726f6388 JA |
206 | |
207 | if (sig == SIGINT) | |
208 | { | |
209 | run_interrupt_trap (); | |
ccc6cda3 | 210 | CLRINTERRUPT; |
726f6388 JA |
211 | } |
212 | else | |
d166f048 | 213 | parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST); |
726f6388 JA |
214 | |
215 | pending_traps[sig] = 0; | |
216 | ||
ccc6cda3 | 217 | #if defined (HAVE_POSIX_SIGNALS) |
726f6388 JA |
218 | sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); |
219 | #else | |
220 | # if defined (HAVE_BSD_SIGNALS) | |
221 | sigsetmask (oldmask); | |
222 | # endif | |
223 | #endif /* POSIX_VERSION */ | |
224 | } | |
225 | } | |
226 | ||
227 | last_command_exit_value = old_exit_value; | |
228 | } | |
229 | ||
230 | sighandler | |
231 | trap_handler (sig) | |
232 | int sig; | |
233 | { | |
234 | if ((sig >= NSIG) || | |
235 | (trap_list[sig] == (char *)DEFAULT_SIG) || | |
236 | (trap_list[sig] == (char *)IGNORE_SIG)) | |
ccc6cda3 | 237 | programming_error ("trap_handler: bad signal %d", sig); |
726f6388 JA |
238 | else |
239 | { | |
ccc6cda3 | 240 | #if defined (MUST_REINSTALL_SIGHANDLERS) |
726f6388 | 241 | set_signal_handler (sig, trap_handler); |
ccc6cda3 | 242 | #endif /* MUST_REINSTALL_SIGHANDLERS */ |
726f6388 JA |
243 | |
244 | catch_flag = 1; | |
245 | pending_traps[sig]++; | |
246 | ||
247 | if (interrupt_immediately) | |
248 | run_pending_traps (); | |
249 | } | |
ccc6cda3 JA |
250 | |
251 | SIGRETURN (0); | |
726f6388 JA |
252 | } |
253 | ||
254 | #if defined (JOB_CONTROL) && defined (SIGCHLD) | |
cce855bc JA |
255 | |
256 | #ifdef INCLUDE_UNUSED | |
726f6388 JA |
257 | /* Make COMMAND_STRING be executed when SIGCHLD is caught. */ |
258 | void | |
259 | set_sigchld_trap (command_string) | |
260 | char *command_string; | |
261 | { | |
726f6388 JA |
262 | set_signal (SIGCHLD, command_string); |
263 | } | |
cce855bc | 264 | #endif |
726f6388 JA |
265 | |
266 | /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current | |
267 | SIGCHLD trap handler is DEFAULT_SIG. */ | |
268 | void | |
269 | maybe_set_sigchld_trap (command_string) | |
270 | char *command_string; | |
271 | { | |
726f6388 JA |
272 | if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0) |
273 | set_signal (SIGCHLD, command_string); | |
274 | } | |
275 | #endif /* JOB_CONTROL && SIGCHLD */ | |
276 | ||
ccc6cda3 JA |
277 | void |
278 | set_debug_trap (command) | |
726f6388 JA |
279 | char *command; |
280 | { | |
ccc6cda3 JA |
281 | set_signal (DEBUG_TRAP, command); |
282 | } | |
726f6388 | 283 | |
cce855bc | 284 | #ifdef INCLUDE_UNUSED |
ccc6cda3 JA |
285 | void |
286 | set_sigint_trap (command) | |
287 | char *command; | |
288 | { | |
726f6388 JA |
289 | set_signal (SIGINT, command); |
290 | } | |
cce855bc | 291 | #endif |
726f6388 JA |
292 | |
293 | /* Reset the SIGINT handler so that subshells that are doing `shellsy' | |
294 | things, like waiting for command substitution or executing commands | |
295 | in explicit subshells ( ( cmd ) ), can catch interrupts properly. */ | |
296 | SigHandler * | |
297 | set_sigint_handler () | |
298 | { | |
299 | if (sigmodes[SIGINT] & SIG_HARD_IGNORE) | |
300 | return ((SigHandler *)SIG_IGN); | |
301 | ||
302 | else if (sigmodes[SIGINT] & SIG_IGNORED) | |
ccc6cda3 JA |
303 | return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */ |
304 | ||
726f6388 JA |
305 | else if (sigmodes[SIGINT] & SIG_TRAPPED) |
306 | return ((SigHandler *)set_signal_handler (SIGINT, trap_handler)); | |
307 | ||
308 | /* The signal is not trapped, so set the handler to the shell's special | |
309 | interrupt handler. */ | |
310 | else if (interactive) /* XXX - was interactive_shell */ | |
311 | return (set_signal_handler (SIGINT, sigint_sighandler)); | |
312 | else | |
313 | return (set_signal_handler (SIGINT, termination_unwind_protect)); | |
314 | } | |
315 | ||
e8ce775d JA |
316 | /* Return the correct handler for signal SIG according to the values in |
317 | sigmodes[SIG]. */ | |
318 | SigHandler * | |
319 | trap_to_sighandler (sig) | |
320 | int sig; | |
321 | { | |
322 | if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE)) | |
323 | return (SIG_IGN); | |
324 | else if (sigmodes[sig] & SIG_TRAPPED) | |
325 | return (trap_handler); | |
326 | else | |
327 | return (SIG_DFL); | |
328 | } | |
329 | ||
726f6388 JA |
330 | /* Set SIG to call STRING as a command. */ |
331 | void | |
332 | set_signal (sig, string) | |
333 | int sig; | |
334 | char *string; | |
335 | { | |
ccc6cda3 JA |
336 | if (sig == DEBUG_TRAP || sig == EXIT_TRAP) |
337 | { | |
338 | change_signal (sig, savestring (string)); | |
d166f048 JA |
339 | if (sig == EXIT_TRAP && interactive == 0) |
340 | initialize_terminating_signals (); | |
ccc6cda3 JA |
341 | return; |
342 | } | |
343 | ||
726f6388 JA |
344 | /* A signal ignored on entry to the shell cannot be trapped or reset, but |
345 | no error is reported when attempting to do so. -- Posix.2 */ | |
346 | if (sigmodes[sig] & SIG_HARD_IGNORE) | |
347 | return; | |
348 | ||
349 | /* Make sure we have original_signals[sig] if the signal has not yet | |
350 | been trapped. */ | |
351 | if ((sigmodes[sig] & SIG_TRAPPED) == 0) | |
352 | { | |
353 | /* If we aren't sure of the original value, check it. */ | |
354 | if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) | |
355 | { | |
356 | original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); | |
357 | set_signal_handler (sig, original_signals[sig]); | |
358 | } | |
359 | ||
360 | /* Signals ignored on entry to the shell cannot be trapped or reset. */ | |
361 | if (original_signals[sig] == SIG_IGN) | |
362 | { | |
363 | sigmodes[sig] |= SIG_HARD_IGNORE; | |
364 | return; | |
365 | } | |
366 | } | |
367 | ||
368 | /* Only change the system signal handler if SIG_NO_TRAP is not set. | |
369 | The trap command string is changed in either case. The shell signal | |
370 | handlers for SIGINT and SIGCHLD run the user specified traps in an | |
371 | environment in which it is safe to do so. */ | |
372 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) | |
373 | { | |
374 | set_signal_handler (sig, SIG_IGN); | |
375 | change_signal (sig, savestring (string)); | |
376 | set_signal_handler (sig, trap_handler); | |
377 | } | |
378 | else | |
379 | change_signal (sig, savestring (string)); | |
380 | } | |
381 | ||
382 | static void | |
383 | free_trap_command (sig) | |
384 | int sig; | |
385 | { | |
386 | if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] && | |
387 | (trap_list[sig] != (char *)IGNORE_SIG) && | |
388 | (trap_list[sig] != (char *)DEFAULT_SIG) && | |
389 | (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) | |
390 | free (trap_list[sig]); | |
391 | } | |
ccc6cda3 | 392 | |
726f6388 JA |
393 | /* If SIG has a string assigned to it, get rid of it. Then give it |
394 | VALUE. */ | |
395 | static void | |
396 | change_signal (sig, value) | |
397 | int sig; | |
398 | char *value; | |
399 | { | |
d166f048 JA |
400 | if ((sigmodes[sig] & SIG_INPROGRESS) == 0) |
401 | free_trap_command (sig); | |
726f6388 JA |
402 | trap_list[sig] = value; |
403 | ||
404 | sigmodes[sig] |= SIG_TRAPPED; | |
405 | if (value == (char *)IGNORE_SIG) | |
406 | sigmodes[sig] |= SIG_IGNORED; | |
407 | else | |
408 | sigmodes[sig] &= ~SIG_IGNORED; | |
409 | if (sigmodes[sig] & SIG_INPROGRESS) | |
410 | sigmodes[sig] |= SIG_CHANGED; | |
411 | } | |
412 | ||
413 | #define GET_ORIGINAL_SIGNAL(sig) \ | |
414 | if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ | |
415 | get_original_signal (sig) | |
416 | ||
417 | static void | |
418 | get_original_signal (sig) | |
419 | int sig; | |
420 | { | |
421 | /* If we aren't sure the of the original value, then get it. */ | |
422 | if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) | |
423 | { | |
424 | original_signals[sig] = | |
425 | (SigHandler *) set_signal_handler (sig, SIG_DFL); | |
426 | set_signal_handler (sig, original_signals[sig]); | |
427 | ||
428 | /* Signals ignored on entry to the shell cannot be trapped. */ | |
429 | if (original_signals[sig] == SIG_IGN) | |
430 | sigmodes[sig] |= SIG_HARD_IGNORE; | |
431 | } | |
432 | } | |
433 | ||
434 | /* Restore the default action for SIG; i.e., the action the shell | |
435 | would have taken before you used the trap command. This is called | |
436 | from trap_builtin (), which takes care to restore the handlers for | |
437 | the signals the shell treats specially. */ | |
438 | void | |
439 | restore_default_signal (sig) | |
440 | int sig; | |
441 | { | |
ccc6cda3 | 442 | if (sig == DEBUG_TRAP || sig == EXIT_TRAP) |
726f6388 | 443 | { |
d166f048 JA |
444 | if ((sig != DEBUG_TRAP) || (sigmodes[sig] & SIG_INPROGRESS) == 0) |
445 | free_trap_command (sig); | |
726f6388 JA |
446 | trap_list[sig] = (char *)NULL; |
447 | sigmodes[sig] &= ~SIG_TRAPPED; | |
d166f048 JA |
448 | if (sigmodes[sig] & SIG_INPROGRESS) |
449 | sigmodes[sig] |= SIG_CHANGED; | |
726f6388 JA |
450 | return; |
451 | } | |
452 | ||
453 | GET_ORIGINAL_SIGNAL (sig); | |
454 | ||
455 | /* A signal ignored on entry to the shell cannot be trapped or reset, but | |
456 | no error is reported when attempting to do so. Thanks Posix.2. */ | |
457 | if (sigmodes[sig] & SIG_HARD_IGNORE) | |
458 | return; | |
459 | ||
460 | /* If we aren't trapping this signal, don't bother doing anything else. */ | |
ccc6cda3 | 461 | if ((sigmodes[sig] & SIG_TRAPPED) == 0) |
726f6388 JA |
462 | return; |
463 | ||
464 | /* Only change the signal handler for SIG if it allows it. */ | |
ccc6cda3 | 465 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) |
726f6388 JA |
466 | set_signal_handler (sig, original_signals[sig]); |
467 | ||
468 | /* Change the trap command in either case. */ | |
469 | change_signal (sig, (char *)DEFAULT_SIG); | |
470 | ||
471 | /* Mark the signal as no longer trapped. */ | |
472 | sigmodes[sig] &= ~SIG_TRAPPED; | |
473 | } | |
474 | ||
475 | /* Make this signal be ignored. */ | |
476 | void | |
477 | ignore_signal (sig) | |
478 | int sig; | |
479 | { | |
ccc6cda3 JA |
480 | if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0)) |
481 | { | |
482 | change_signal (sig, (char *)IGNORE_SIG); | |
483 | return; | |
484 | } | |
485 | ||
726f6388 JA |
486 | GET_ORIGINAL_SIGNAL (sig); |
487 | ||
488 | /* A signal ignored on entry to the shell cannot be trapped or reset. | |
ccc6cda3 | 489 | No error is reported when the user attempts to do so. */ |
726f6388 JA |
490 | if (sigmodes[sig] & SIG_HARD_IGNORE) |
491 | return; | |
492 | ||
493 | /* If already trapped and ignored, no change necessary. */ | |
ccc6cda3 | 494 | if (sigmodes[sig] & SIG_IGNORED) |
726f6388 JA |
495 | return; |
496 | ||
497 | /* Only change the signal handler for SIG if it allows it. */ | |
ccc6cda3 | 498 | if ((sigmodes[sig] & SIG_NO_TRAP) == 0) |
726f6388 JA |
499 | set_signal_handler (sig, SIG_IGN); |
500 | ||
501 | /* Change the trap command in either case. */ | |
502 | change_signal (sig, (char *)IGNORE_SIG); | |
503 | } | |
504 | ||
505 | /* Handle the calling of "trap 0". The only sticky situation is when | |
506 | the command to be executed includes an "exit". This is why we have | |
507 | to provide our own place for top_level to jump to. */ | |
508 | int | |
509 | run_exit_trap () | |
510 | { | |
ccc6cda3 JA |
511 | char *trap_command; |
512 | int code, old_exit_value; | |
726f6388 JA |
513 | |
514 | old_exit_value = last_command_exit_value; | |
515 | ||
ccc6cda3 JA |
516 | /* Run the trap only if signal 0 is trapped and not ignored, and we are not |
517 | currently running in the trap handler (call to exit in the list of | |
518 | commands given to trap 0). */ | |
519 | if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) && | |
520 | (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0) | |
726f6388 | 521 | { |
ccc6cda3 JA |
522 | trap_command = savestring (trap_list[EXIT_TRAP]); |
523 | sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; | |
524 | sigmodes[EXIT_TRAP] |= SIG_INPROGRESS; | |
726f6388 JA |
525 | |
526 | code = setjmp (top_level); | |
527 | ||
528 | if (code == 0) | |
cce855bc JA |
529 | { |
530 | reset_parser (); | |
531 | parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST); | |
532 | } | |
726f6388 | 533 | else if (code == EXITPROG) |
ccc6cda3 | 534 | return (last_command_exit_value); |
726f6388 JA |
535 | else |
536 | return (old_exit_value); | |
537 | } | |
538 | ||
539 | return (old_exit_value); | |
540 | } | |
541 | ||
ccc6cda3 JA |
542 | void |
543 | run_trap_cleanup (sig) | |
544 | int sig; | |
545 | { | |
546 | sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); | |
547 | } | |
548 | ||
549 | /* Run a trap command for SIG. SIG is one of the signals the shell treats | |
550 | specially. */ | |
726f6388 | 551 | static void |
ccc6cda3 | 552 | _run_trap_internal (sig, tag) |
726f6388 | 553 | int sig; |
ccc6cda3 | 554 | char *tag; |
726f6388 | 555 | { |
ccc6cda3 | 556 | char *trap_command, *old_trap; |
d166f048 | 557 | int old_exit_value, old_line_number; |
ccc6cda3 JA |
558 | |
559 | /* Run the trap only if SIG is trapped and not ignored, and we are not | |
560 | currently executing in the trap handler. */ | |
561 | if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && | |
562 | (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && | |
563 | ((sigmodes[sig] & SIG_INPROGRESS) == 0)) | |
564 | { | |
565 | old_trap = trap_list[sig]; | |
566 | sigmodes[sig] |= SIG_INPROGRESS; | |
567 | sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ | |
568 | trap_command = savestring (old_trap); | |
569 | ||
570 | running_trap = sig + 1; | |
571 | old_exit_value = last_command_exit_value; | |
d166f048 JA |
572 | /* Need to copy the value of line_number because parse_and_execute |
573 | resets it to 1, and the trap command might want it. */ | |
574 | trap_line_number = line_number; | |
575 | parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST); | |
ccc6cda3 JA |
576 | last_command_exit_value = old_exit_value; |
577 | running_trap = 0; | |
578 | ||
579 | sigmodes[sig] &= ~SIG_INPROGRESS; | |
580 | ||
581 | if (sigmodes[sig] & SIG_CHANGED) | |
582 | { | |
583 | free (old_trap); | |
584 | sigmodes[sig] &= ~SIG_CHANGED; | |
585 | } | |
586 | } | |
587 | } | |
588 | ||
589 | void | |
590 | run_debug_trap () | |
591 | { | |
592 | if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0) | |
593 | _run_trap_internal (DEBUG_TRAP, "debug trap"); | |
594 | } | |
595 | ||
596 | /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and | |
597 | declared here to localize the trap functions. */ | |
598 | void | |
599 | run_interrupt_trap () | |
600 | { | |
601 | _run_trap_internal (SIGINT, "interrupt trap"); | |
726f6388 JA |
602 | } |
603 | ||
cce855bc | 604 | #ifdef INCLUDE_UNUSED |
726f6388 JA |
605 | /* Free all the allocated strings in the list of traps and reset the trap |
606 | values to the default. */ | |
607 | void | |
608 | free_trap_strings () | |
609 | { | |
610 | register int i; | |
611 | ||
ccc6cda3 | 612 | for (i = 0; i < NSIG+1; i++) |
726f6388 JA |
613 | { |
614 | free_trap_command (i); | |
615 | trap_list[i] = (char *)DEFAULT_SIG; | |
616 | sigmodes[i] &= ~SIG_TRAPPED; | |
617 | } | |
ccc6cda3 | 618 | trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL; |
726f6388 | 619 | } |
cce855bc | 620 | #endif |
726f6388 JA |
621 | |
622 | /* Reset the handler for SIG to the original value. */ | |
623 | static void | |
624 | reset_signal (sig) | |
625 | int sig; | |
626 | { | |
627 | set_signal_handler (sig, original_signals[sig]); | |
628 | } | |
629 | ||
ccc6cda3 JA |
630 | /* Set the handler signal SIG to the original and free any trap |
631 | command associated with it. */ | |
632 | static void | |
633 | restore_signal (sig) | |
634 | int sig; | |
726f6388 | 635 | { |
ccc6cda3 JA |
636 | set_signal_handler (sig, original_signals[sig]); |
637 | change_signal (sig, (char *)DEFAULT_SIG); | |
638 | sigmodes[sig] &= ~SIG_TRAPPED; | |
726f6388 JA |
639 | } |
640 | ||
ccc6cda3 JA |
641 | static void |
642 | reset_or_restore_signal_handlers (reset) | |
643 | VFunction *reset; | |
726f6388 JA |
644 | { |
645 | register int i; | |
646 | ||
ccc6cda3 JA |
647 | /* Take care of the exit trap first */ |
648 | if (sigmodes[EXIT_TRAP] & SIG_TRAPPED) | |
726f6388 | 649 | { |
ccc6cda3 JA |
650 | free_trap_command (EXIT_TRAP); |
651 | trap_list[EXIT_TRAP] = (char *)NULL; | |
652 | sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; | |
726f6388 | 653 | } |
726f6388 JA |
654 | for (i = 1; i < NSIG; i++) |
655 | { | |
ccc6cda3 | 656 | if (sigmodes[i] & SIG_TRAPPED) |
726f6388 JA |
657 | { |
658 | if (trap_list[i] == (char *)IGNORE_SIG) | |
659 | set_signal_handler (i, SIG_IGN); | |
660 | else | |
ccc6cda3 | 661 | (*reset) (i); |
726f6388 | 662 | } |
ccc6cda3 JA |
663 | else if (sigmodes[i] & SIG_SPECIAL) |
664 | (*reset) (i); | |
726f6388 JA |
665 | } |
666 | } | |
667 | ||
726f6388 | 668 | void |
ccc6cda3 | 669 | reset_signal_handlers () |
726f6388 | 670 | { |
ccc6cda3 JA |
671 | reset_or_restore_signal_handlers (reset_signal); |
672 | } | |
726f6388 | 673 | |
ccc6cda3 JA |
674 | /* Reset all trapped signals to their original values. Signals set to be |
675 | ignored with trap '' SIGNAL should be ignored, so we make sure that they | |
676 | are. Called by child processes after they are forked. */ | |
677 | void | |
678 | restore_original_signals () | |
679 | { | |
680 | reset_or_restore_signal_handlers (restore_signal); | |
726f6388 JA |
681 | } |
682 | ||
683 | /* If a trap handler exists for signal SIG, then call it; otherwise just | |
684 | return failure. */ | |
685 | int | |
686 | maybe_call_trap_handler (sig) | |
687 | int sig; | |
688 | { | |
689 | /* Call the trap handler for SIG if the signal is trapped and not ignored. */ | |
ccc6cda3 | 690 | if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0)) |
726f6388 JA |
691 | { |
692 | switch (sig) | |
693 | { | |
694 | case SIGINT: | |
695 | run_interrupt_trap (); | |
696 | break; | |
ccc6cda3 | 697 | case EXIT_TRAP: |
726f6388 JA |
698 | run_exit_trap (); |
699 | break; | |
ccc6cda3 JA |
700 | case DEBUG_TRAP: |
701 | run_debug_trap (); | |
702 | break; | |
726f6388 JA |
703 | default: |
704 | trap_handler (sig); | |
705 | break; | |
706 | } | |
707 | return (1); | |
708 | } | |
709 | else | |
710 | return (0); | |
711 | } | |
712 | ||
713 | int | |
714 | signal_is_trapped (sig) | |
715 | int sig; | |
716 | { | |
717 | return (sigmodes[sig] & SIG_TRAPPED); | |
718 | } | |
719 | ||
720 | int | |
721 | signal_is_special (sig) | |
722 | int sig; | |
723 | { | |
724 | return (sigmodes[sig] & SIG_SPECIAL); | |
725 | } | |
726 | ||
727 | int | |
728 | signal_is_ignored (sig) | |
729 | int sig; | |
730 | { | |
731 | return (sigmodes[sig] & SIG_IGNORED); | |
732 | } | |
733 | ||
734 | void | |
735 | set_signal_ignored (sig) | |
736 | int sig; | |
737 | { | |
738 | sigmodes[sig] |= SIG_HARD_IGNORE; | |
ccc6cda3 | 739 | original_signals[sig] = SIG_IGN; |
726f6388 | 740 | } |