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