blob: 139dc2a6fa6b6bc20c1c10c48529f52a85dde454 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001/* 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
Jari Aaltoccc6cda1996-12-23 17:02:34 +000022#include "config.h"
23
Jari Aalto726f6381996-08-26 18:22:31 +000024#include <stdio.h>
25
26#include "bashtypes.h"
27#include "trap.h"
28
29#if defined (HAVE_STRING_H)
30# include <string.h>
31#else /* !HAVE_STRING_H */
32# include <strings.h>
33#endif /* !HAVE_STRING_H */
34
Jari Aaltoccc6cda1996-12-23 17:02:34 +000035#if defined (HAVE_UNISTD_H)
36# include <unistd.h>
37#endif
38
Jari Aalto726f6381996-08-26 18:22:31 +000039#include "shell.h"
40#include "signames.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000041#include "builtins/common.h"
Jari Aalto726f6381996-08-26 18:22:31 +000042
43/* Flags which describe the current handling state of a signal. */
44#define SIG_INHERITED 0x0 /* Value inherited from parent. */
45#define SIG_TRAPPED 0x1 /* Currently trapped. */
46#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
47#define SIG_SPECIAL 0x4 /* Treat this signal specially. */
48#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +000049#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
50#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
51#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
Jari Aalto726f6381996-08-26 18:22:31 +000052
53/* An array of such flags, one for each signal, describing what the
Jari Aaltoccc6cda1996-12-23 17:02:34 +000054 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
55 assumes this. */
56static int sigmodes[NSIG+1];
Jari Aalto726f6381996-08-26 18:22:31 +000057
58static void change_signal (), restore_signal ();
59
60/* Variables used here but defined in other files. */
61extern int interactive_shell, interactive;
62extern int interrupt_immediately;
63extern int last_command_exit_value;
64
65/* The list of things to do originally, before we started trapping. */
66SigHandler *original_signals[NSIG];
67
68/* For each signal, a slot for a string, which is a command to be
69 executed when that signal is recieved. The slot can also contain
70 DEFAULT_SIG, which means do whatever you were going to do before
71 you were so rudely interrupted, or IGNORE_SIG, which says ignore
72 this signal. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +000073char *trap_list[NSIG+1];
Jari Aalto726f6381996-08-26 18:22:31 +000074
75/* A bitmap of signals received for which we have trap handlers. */
76int pending_traps[NSIG];
77
Jari Aaltoccc6cda1996-12-23 17:02:34 +000078/* Set to the number of the signal we're running the trap for + 1.
79 Used in execute_cmd.c and builtins/common.c to clean up when
80 parse_and_execute does not return normally after executing the
81 trap command (e.g., when `return' is executed in the trap command). */
82int running_trap;
83
Jari Aalto726f6381996-08-26 18:22:31 +000084/* A value which can never be the target of a trap handler. */
85#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
86
87void
88initialize_traps ()
89{
90 register int i;
91
Jari Aaltoccc6cda1996-12-23 17:02:34 +000092 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = (char *)NULL;
93 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = SIG_INHERITED;
94 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
Jari Aalto726f6381996-08-26 18:22:31 +000095
96 for (i = 1; i < NSIG; i++)
97 {
98 pending_traps[i] = 0;
99 trap_list[i] = (char *)DEFAULT_SIG;
100 sigmodes[i] = SIG_INHERITED;
101 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
102 }
103
104 /* Show which signals are treated specially by the shell. */
105#if defined (SIGCHLD)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000106 original_signals[SIGCHLD] =
107 (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
Jari Aalto726f6381996-08-26 18:22:31 +0000108 set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
109 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
110#endif /* SIGCHLD */
111
112 original_signals[SIGINT] =
113 (SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
114 set_signal_handler (SIGINT, original_signals[SIGINT]);
115 sigmodes[SIGINT] |= SIG_SPECIAL;
116
117 original_signals[SIGQUIT] =
118 (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
119 set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
120 sigmodes[SIGQUIT] |= SIG_SPECIAL;
121
122 if (interactive)
123 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000124 original_signals[SIGTERM] =
125 (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
Jari Aalto726f6381996-08-26 18:22:31 +0000126 set_signal_handler (SIGTERM, original_signals[SIGTERM]);
127 sigmodes[SIGTERM] |= SIG_SPECIAL;
128 }
129}
130
131/* Return the print name of this signal. */
132char *
133signal_name (sig)
134 int sig;
135{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000136 return ((sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]);
Jari Aalto726f6381996-08-26 18:22:31 +0000137}
138
139/* Turn a string into a signal number, or a number into
140 a signal number. If STRING is "2", "SIGINT", or "INT",
141 then (int)2 is returned. Return NO_SIG if STRING doesn't
142 contain a valid signal descriptor. */
143int
144decode_signal (string)
145 char *string;
146{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000147 long sig;
Jari Aalto726f6381996-08-26 18:22:31 +0000148
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000149 if (legal_number (string, &sig))
150 return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG);
Jari Aalto726f6381996-08-26 18:22:31 +0000151
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000152 for (sig = 0; sig <= NSIG; sig++)
153 if (strcasecmp (string, signal_names[sig]) == 0 ||
154 strcasecmp (string, &(signal_names[sig])[3]) == 0)
155 return ((int)sig);
Jari Aalto726f6381996-08-26 18:22:31 +0000156
157 return (NO_SIG);
158}
159
160/* Non-zero when we catch a trapped signal. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000161static int catch_flag;
Jari Aalto726f6381996-08-26 18:22:31 +0000162
163void
164run_pending_traps ()
165{
166 register int sig;
167 int old_exit_value;
168
169 if (catch_flag == 0) /* simple optimization */
170 return;
171
172 catch_flag = 0;
173
174 /* Preserve $? when running trap. */
175 old_exit_value = last_command_exit_value;
176
177 for (sig = 1; sig < NSIG; sig++)
178 {
179 /* XXX this could be made into a counter by using
180 while (pending_traps[sig]--) instead of the if statement. */
181 if (pending_traps[sig])
182 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000183#if defined (HAVE_POSIX_SIGNALS)
Jari Aalto726f6381996-08-26 18:22:31 +0000184 sigset_t set, oset;
185
186 sigemptyset (&set);
187 sigemptyset (&oset);
188
189 sigaddset (&set, sig);
190 sigprocmask (SIG_BLOCK, &set, &oset);
191#else
192# if defined (HAVE_BSD_SIGNALS)
193 int oldmask = sigblock (sigmask (sig));
194# endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000195#endif /* HAVE_POSIX_SIGNALS */
Jari Aalto726f6381996-08-26 18:22:31 +0000196
197 if (sig == SIGINT)
198 {
199 run_interrupt_trap ();
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000200 CLRINTERRUPT;
Jari Aalto726f6381996-08-26 18:22:31 +0000201 }
202 else
203 parse_and_execute (savestring (trap_list[sig]), "trap", 0);
204
205 pending_traps[sig] = 0;
206
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000207#if defined (HAVE_POSIX_SIGNALS)
Jari Aalto726f6381996-08-26 18:22:31 +0000208 sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
209#else
210# if defined (HAVE_BSD_SIGNALS)
211 sigsetmask (oldmask);
212# endif
213#endif /* POSIX_VERSION */
214 }
215 }
216
217 last_command_exit_value = old_exit_value;
218}
219
220sighandler
221trap_handler (sig)
222 int sig;
223{
224 if ((sig >= NSIG) ||
225 (trap_list[sig] == (char *)DEFAULT_SIG) ||
226 (trap_list[sig] == (char *)IGNORE_SIG))
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000227 programming_error ("trap_handler: bad signal %d", sig);
Jari Aalto726f6381996-08-26 18:22:31 +0000228 else
229 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000230#if defined (MUST_REINSTALL_SIGHANDLERS)
Jari Aalto726f6381996-08-26 18:22:31 +0000231 set_signal_handler (sig, trap_handler);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000232#endif /* MUST_REINSTALL_SIGHANDLERS */
Jari Aalto726f6381996-08-26 18:22:31 +0000233
234 catch_flag = 1;
235 pending_traps[sig]++;
236
237 if (interrupt_immediately)
238 run_pending_traps ();
239 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000240
241 SIGRETURN (0);
Jari Aalto726f6381996-08-26 18:22:31 +0000242}
243
244#if defined (JOB_CONTROL) && defined (SIGCHLD)
245/* Make COMMAND_STRING be executed when SIGCHLD is caught. */
246void
247set_sigchld_trap (command_string)
248 char *command_string;
249{
Jari Aalto726f6381996-08-26 18:22:31 +0000250 set_signal (SIGCHLD, command_string);
251}
252
253/* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
254 SIGCHLD trap handler is DEFAULT_SIG. */
255void
256maybe_set_sigchld_trap (command_string)
257 char *command_string;
258{
Jari Aalto726f6381996-08-26 18:22:31 +0000259 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
260 set_signal (SIGCHLD, command_string);
261}
262#endif /* JOB_CONTROL && SIGCHLD */
263
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000264void
265set_debug_trap (command)
266 char *command;
267{
268 set_signal (DEBUG_TRAP, command);
269}
270
271void
Jari Aalto726f6381996-08-26 18:22:31 +0000272set_sigint_trap (command)
273 char *command;
274{
Jari Aalto726f6381996-08-26 18:22:31 +0000275 set_signal (SIGINT, command);
276}
277
278/* Reset the SIGINT handler so that subshells that are doing `shellsy'
279 things, like waiting for command substitution or executing commands
280 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
281SigHandler *
282set_sigint_handler ()
283{
284 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
285 return ((SigHandler *)SIG_IGN);
286
287 else if (sigmodes[SIGINT] & SIG_IGNORED)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000288 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
289
Jari Aalto726f6381996-08-26 18:22:31 +0000290 else if (sigmodes[SIGINT] & SIG_TRAPPED)
291 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
292
293 /* The signal is not trapped, so set the handler to the shell's special
294 interrupt handler. */
295 else if (interactive) /* XXX - was interactive_shell */
296 return (set_signal_handler (SIGINT, sigint_sighandler));
297 else
298 return (set_signal_handler (SIGINT, termination_unwind_protect));
299}
300
301/* Set SIG to call STRING as a command. */
302void
303set_signal (sig, string)
304 int sig;
305 char *string;
306{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000307 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
308 {
309 change_signal (sig, savestring (string));
310 return;
311 }
312
Jari Aalto726f6381996-08-26 18:22:31 +0000313 /* A signal ignored on entry to the shell cannot be trapped or reset, but
314 no error is reported when attempting to do so. -- Posix.2 */
315 if (sigmodes[sig] & SIG_HARD_IGNORE)
316 return;
317
318 /* Make sure we have original_signals[sig] if the signal has not yet
319 been trapped. */
320 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
321 {
322 /* If we aren't sure of the original value, check it. */
323 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
324 {
325 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL);
326 set_signal_handler (sig, original_signals[sig]);
327 }
328
329 /* Signals ignored on entry to the shell cannot be trapped or reset. */
330 if (original_signals[sig] == SIG_IGN)
331 {
332 sigmodes[sig] |= SIG_HARD_IGNORE;
333 return;
334 }
335 }
336
337 /* Only change the system signal handler if SIG_NO_TRAP is not set.
338 The trap command string is changed in either case. The shell signal
339 handlers for SIGINT and SIGCHLD run the user specified traps in an
340 environment in which it is safe to do so. */
341 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
342 {
343 set_signal_handler (sig, SIG_IGN);
344 change_signal (sig, savestring (string));
345 set_signal_handler (sig, trap_handler);
346 }
347 else
348 change_signal (sig, savestring (string));
349}
350
351static void
352free_trap_command (sig)
353 int sig;
354{
355 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
356 (trap_list[sig] != (char *)IGNORE_SIG) &&
357 (trap_list[sig] != (char *)DEFAULT_SIG) &&
358 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
359 free (trap_list[sig]);
360}
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000361
Jari Aalto726f6381996-08-26 18:22:31 +0000362/* If SIG has a string assigned to it, get rid of it. Then give it
363 VALUE. */
364static void
365change_signal (sig, value)
366 int sig;
367 char *value;
368{
369 free_trap_command (sig);
370 trap_list[sig] = value;
371
372 sigmodes[sig] |= SIG_TRAPPED;
373 if (value == (char *)IGNORE_SIG)
374 sigmodes[sig] |= SIG_IGNORED;
375 else
376 sigmodes[sig] &= ~SIG_IGNORED;
377 if (sigmodes[sig] & SIG_INPROGRESS)
378 sigmodes[sig] |= SIG_CHANGED;
379}
380
381#define GET_ORIGINAL_SIGNAL(sig) \
382 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
383 get_original_signal (sig)
384
385static void
386get_original_signal (sig)
387 int sig;
388{
389 /* If we aren't sure the of the original value, then get it. */
390 if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
391 {
392 original_signals[sig] =
393 (SigHandler *) set_signal_handler (sig, SIG_DFL);
394 set_signal_handler (sig, original_signals[sig]);
395
396 /* Signals ignored on entry to the shell cannot be trapped. */
397 if (original_signals[sig] == SIG_IGN)
398 sigmodes[sig] |= SIG_HARD_IGNORE;
399 }
400}
401
402/* Restore the default action for SIG; i.e., the action the shell
403 would have taken before you used the trap command. This is called
404 from trap_builtin (), which takes care to restore the handlers for
405 the signals the shell treats specially. */
406void
407restore_default_signal (sig)
408 int sig;
409{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000410 if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
Jari Aalto726f6381996-08-26 18:22:31 +0000411 {
412 free_trap_command (sig);
413 trap_list[sig] = (char *)NULL;
414 sigmodes[sig] &= ~SIG_TRAPPED;
415 return;
416 }
417
418 GET_ORIGINAL_SIGNAL (sig);
419
420 /* A signal ignored on entry to the shell cannot be trapped or reset, but
421 no error is reported when attempting to do so. Thanks Posix.2. */
422 if (sigmodes[sig] & SIG_HARD_IGNORE)
423 return;
424
425 /* If we aren't trapping this signal, don't bother doing anything else. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000426 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000427 return;
428
429 /* Only change the signal handler for SIG if it allows it. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000430 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000431 set_signal_handler (sig, original_signals[sig]);
432
433 /* Change the trap command in either case. */
434 change_signal (sig, (char *)DEFAULT_SIG);
435
436 /* Mark the signal as no longer trapped. */
437 sigmodes[sig] &= ~SIG_TRAPPED;
438}
439
440/* Make this signal be ignored. */
441void
442ignore_signal (sig)
443 int sig;
444{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000445 if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0))
446 {
447 change_signal (sig, (char *)IGNORE_SIG);
448 return;
449 }
450
Jari Aalto726f6381996-08-26 18:22:31 +0000451 GET_ORIGINAL_SIGNAL (sig);
452
453 /* A signal ignored on entry to the shell cannot be trapped or reset.
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000454 No error is reported when the user attempts to do so. */
Jari Aalto726f6381996-08-26 18:22:31 +0000455 if (sigmodes[sig] & SIG_HARD_IGNORE)
456 return;
457
458 /* If already trapped and ignored, no change necessary. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000459 if (sigmodes[sig] & SIG_IGNORED)
Jari Aalto726f6381996-08-26 18:22:31 +0000460 return;
461
462 /* Only change the signal handler for SIG if it allows it. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000463 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000464 set_signal_handler (sig, SIG_IGN);
465
466 /* Change the trap command in either case. */
467 change_signal (sig, (char *)IGNORE_SIG);
468}
469
470/* Handle the calling of "trap 0". The only sticky situation is when
471 the command to be executed includes an "exit". This is why we have
472 to provide our own place for top_level to jump to. */
473int
474run_exit_trap ()
475{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000476 char *trap_command;
477 int code, old_exit_value;
Jari Aalto726f6381996-08-26 18:22:31 +0000478
479 old_exit_value = last_command_exit_value;
480
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000481 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
482 currently running in the trap handler (call to exit in the list of
483 commands given to trap 0). */
484 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
485 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000486 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000487 trap_command = savestring (trap_list[EXIT_TRAP]);
488 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
489 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
Jari Aalto726f6381996-08-26 18:22:31 +0000490
491 code = setjmp (top_level);
492
493 if (code == 0)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000494 parse_and_execute (trap_command, "exit trap", 0);
Jari Aalto726f6381996-08-26 18:22:31 +0000495 else if (code == EXITPROG)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000496 return (last_command_exit_value);
Jari Aalto726f6381996-08-26 18:22:31 +0000497 else
498 return (old_exit_value);
499 }
500
501 return (old_exit_value);
502}
503
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000504void
505run_trap_cleanup (sig)
Jari Aalto726f6381996-08-26 18:22:31 +0000506 int sig;
507{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000508 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
509}
510
511/* Run a trap command for SIG. SIG is one of the signals the shell treats
512 specially. */
513static void
514_run_trap_internal (sig, tag)
515 int sig;
516 char *tag;
517{
518 char *trap_command, *old_trap;
519 int old_exit_value;
520
521 /* Run the trap only if SIG is trapped and not ignored, and we are not
522 currently executing in the trap handler. */
523 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
524 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
525 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
526 {
527 old_trap = trap_list[sig];
528 sigmodes[sig] |= SIG_INPROGRESS;
529 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
530 trap_command = savestring (old_trap);
531
532 running_trap = sig + 1;
533 old_exit_value = last_command_exit_value;
534 parse_and_execute (trap_command, tag, 0);
535 last_command_exit_value = old_exit_value;
536 running_trap = 0;
537
538 sigmodes[sig] &= ~SIG_INPROGRESS;
539
540 if (sigmodes[sig] & SIG_CHANGED)
541 {
542 free (old_trap);
543 sigmodes[sig] &= ~SIG_CHANGED;
544 }
545 }
546}
547
548void
549run_debug_trap ()
550{
551 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)
552 _run_trap_internal (DEBUG_TRAP, "debug trap");
553}
554
555/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
556 declared here to localize the trap functions. */
557void
558run_interrupt_trap ()
559{
560 _run_trap_internal (SIGINT, "interrupt trap");
Jari Aalto726f6381996-08-26 18:22:31 +0000561}
562
563/* Free all the allocated strings in the list of traps and reset the trap
564 values to the default. */
565void
566free_trap_strings ()
567{
568 register int i;
569
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000570 for (i = 0; i < NSIG+1; i++)
Jari Aalto726f6381996-08-26 18:22:31 +0000571 {
572 free_trap_command (i);
573 trap_list[i] = (char *)DEFAULT_SIG;
574 sigmodes[i] &= ~SIG_TRAPPED;
575 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000576 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL;
Jari Aalto726f6381996-08-26 18:22:31 +0000577}
578
579/* Reset the handler for SIG to the original value. */
580static void
581reset_signal (sig)
582 int sig;
583{
584 set_signal_handler (sig, original_signals[sig]);
585}
586
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000587/* Set the handler signal SIG to the original and free any trap
588 command associated with it. */
589static void
590restore_signal (sig)
591 int sig;
592{
593 set_signal_handler (sig, original_signals[sig]);
594 change_signal (sig, (char *)DEFAULT_SIG);
595 sigmodes[sig] &= ~SIG_TRAPPED;
596}
597
598static void
599reset_or_restore_signal_handlers (reset)
600 VFunction *reset;
Jari Aalto726f6381996-08-26 18:22:31 +0000601{
602 register int i;
603
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000604 /* Take care of the exit trap first */
605 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
Jari Aalto726f6381996-08-26 18:22:31 +0000606 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000607 free_trap_command (EXIT_TRAP);
608 trap_list[EXIT_TRAP] = (char *)NULL;
609 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
Jari Aalto726f6381996-08-26 18:22:31 +0000610 }
Jari Aalto726f6381996-08-26 18:22:31 +0000611 for (i = 1; i < NSIG; i++)
612 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000613 if (sigmodes[i] & SIG_TRAPPED)
Jari Aalto726f6381996-08-26 18:22:31 +0000614 {
615 if (trap_list[i] == (char *)IGNORE_SIG)
616 set_signal_handler (i, SIG_IGN);
617 else
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000618 (*reset) (i);
Jari Aalto726f6381996-08-26 18:22:31 +0000619 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000620 else if (sigmodes[i] & SIG_SPECIAL)
621 (*reset) (i);
Jari Aalto726f6381996-08-26 18:22:31 +0000622 }
623}
624
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000625void
626reset_signal_handlers ()
627{
628 reset_or_restore_signal_handlers (reset_signal);
629}
630
Jari Aalto726f6381996-08-26 18:22:31 +0000631/* Reset all trapped signals to their original values. Signals set to be
632 ignored with trap '' SIGNAL should be ignored, so we make sure that they
633 are. Called by child processes after they are forked. */
634void
635restore_original_signals ()
636{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000637 reset_or_restore_signal_handlers (restore_signal);
Jari Aalto726f6381996-08-26 18:22:31 +0000638}
639
640/* If a trap handler exists for signal SIG, then call it; otherwise just
641 return failure. */
642int
643maybe_call_trap_handler (sig)
644 int sig;
645{
646 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000647 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
Jari Aalto726f6381996-08-26 18:22:31 +0000648 {
649 switch (sig)
650 {
651 case SIGINT:
652 run_interrupt_trap ();
653 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000654 case EXIT_TRAP:
Jari Aalto726f6381996-08-26 18:22:31 +0000655 run_exit_trap ();
656 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000657 case DEBUG_TRAP:
658 run_debug_trap ();
659 break;
Jari Aalto726f6381996-08-26 18:22:31 +0000660 default:
661 trap_handler (sig);
662 break;
663 }
664 return (1);
665 }
666 else
667 return (0);
668}
669
670int
671signal_is_trapped (sig)
672 int sig;
673{
674 return (sigmodes[sig] & SIG_TRAPPED);
675}
676
677int
678signal_is_special (sig)
679 int sig;
680{
681 return (sigmodes[sig] & SIG_SPECIAL);
682}
683
684int
685signal_is_ignored (sig)
686 int sig;
687{
688 return (sigmodes[sig] & SIG_IGNORED);
689}
690
691void
692set_signal_ignored (sig)
693 int sig;
694{
695 sigmodes[sig] |= SIG_HARD_IGNORE;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000696 original_signals[sig] = SIG_IGN;
Jari Aalto726f6381996-08-26 18:22:31 +0000697}