1 /* sig.c - interface for shell signal handlers and signal initialization. */
3 /* Copyright (C) 1994 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #include "bashtypes.h"
25 #if defined (HAVE_UNISTD_H)
27 # include <sys/types.h>
36 #if defined (JOB_CONTROL)
38 #endif /* JOB_CONTROL */
43 #include "builtins/common.h"
45 #if defined (READLINE)
46 # include "bashline.h"
50 # include "bashhist.h"
53 extern int last_command_exit_value
;
54 extern int return_catch_flag
;
55 extern int loop_level
, continuing
, breaking
;
56 extern int parse_and_execute_level
, shell_initialized
;
58 /* Non-zero after SIGINT. */
61 /* The environment at the top-level R-E loop. We use this in
62 the case of error return. */
65 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
66 /* The signal masks that this shell runs with. */
67 sigset_t top_level_mask
;
68 #endif /* JOB_CONTROL */
70 /* When non-zero, we throw_to_top_level (). */
71 int interrupt_immediately
= 0;
73 static void initialize_shell_signals
__P((void));
76 initialize_signals (reinit
)
79 initialize_shell_signals ();
80 initialize_job_signals ();
81 #if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
83 initialize_siglist ();
84 #endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
87 /* A structure describing a signal that terminates the shell if not
88 caught. The orig_handler member is present so children can reset
89 these signals back to their original handlers. */
92 SigHandler
*orig_handler
;
95 #define NULL_HANDLER (SigHandler *)SIG_DFL
97 /* The list of signals that would terminate the shell if not caught.
98 We catch them, but just so that we can write the history file,
100 static struct termsig terminating_signals
[] = {
102 { SIGHUP
, NULL_HANDLER
},
106 { SIGINT
, NULL_HANDLER
},
110 { SIGILL
, NULL_HANDLER
},
114 { SIGTRAP
, NULL_HANDLER
},
118 { SIGIOT
, NULL_HANDLER
},
122 { SIGDANGER
, NULL_HANDLER
},
126 { SIGEMT
, NULL_HANDLER
},
130 { SIGFPE
, NULL_HANDLER
},
134 { SIGBUS
, NULL_HANDLER
},
138 { SIGSEGV
, NULL_HANDLER
},
142 { SIGSYS
, NULL_HANDLER
},
146 { SIGPIPE
, NULL_HANDLER
},
150 { SIGALRM
, NULL_HANDLER
},
154 { SIGTERM
, NULL_HANDLER
},
158 { SIGXCPU
, NULL_HANDLER
},
162 { SIGXFSZ
, NULL_HANDLER
},
166 { SIGVTALRM
, NULL_HANDLER
},
171 { SIGPROF
, NULL_HANDLER
},
176 { SIGLOST
, NULL_HANDLER
},
180 { SIGUSR1
, NULL_HANDLER
},
184 { SIGUSR2
, NULL_HANDLER
},
188 #define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
190 #define XSIG(x) (terminating_signals[x].signum)
191 #define XHANDLER(x) (terminating_signals[x].orig_handler)
193 static int termsigs_initialized
= 0;
195 /* Initialize signals that will terminate the shell to do some
196 unwind protection. For non-interactive shells, we only call
197 this when a trap is defined for EXIT (0). */
199 initialize_terminating_signals ()
202 #if defined (HAVE_POSIX_SIGNALS)
203 struct sigaction act
, oact
;
206 if (termsigs_initialized
)
209 /* The following code is to avoid an expensive call to
210 set_signal_handler () for each terminating_signals. Fortunately,
211 this is possible in Posix. Unfortunately, we have to call signal ()
212 on non-Posix systems for each signal in terminating_signals. */
213 #if defined (HAVE_POSIX_SIGNALS)
214 act
.sa_handler
= termination_unwind_protect
;
216 sigemptyset (&act
.sa_mask
);
217 sigemptyset (&oact
.sa_mask
);
218 for (i
= 0; i
< TERMSIGS_LENGTH
; i
++)
219 sigaddset (&act
.sa_mask
, XSIG (i
));
220 for (i
= 0; i
< TERMSIGS_LENGTH
; i
++)
222 /* If we've already trapped it, don't do anything. */
223 if (signal_is_trapped (XSIG (i
)))
226 sigaction (XSIG (i
), &act
, &oact
);
227 XHANDLER(i
) = oact
.sa_handler
;
228 /* Don't do anything with signals that are ignored at shell entry
229 if the shell is not interactive. */
230 if (!interactive_shell
&& XHANDLER (i
) == SIG_IGN
)
232 sigaction (XSIG (i
), &oact
, &act
);
233 set_signal_ignored (XSIG (i
));
235 #if defined (SIGPROF) && !defined (_MINIX)
236 if (XSIG (i
) == SIGPROF
&& XHANDLER (i
) != SIG_DFL
&& XHANDLER (i
) != SIG_IGN
)
237 sigaction (XSIG (i
), &oact
, (struct sigaction
*)NULL
);
238 #endif /* SIGPROF && !_MINIX */
241 #else /* !HAVE_POSIX_SIGNALS */
243 for (i
= 0; i
< TERMSIGS_LENGTH
; i
++)
245 /* If we've already trapped it, don't do anything. */
246 if (signal_is_trapped (XSIG (i
)))
249 XHANDLER(i
) = signal (XSIG (i
), termination_unwind_protect
);
250 /* Don't do anything with signals that are ignored at shell entry
251 if the shell is not interactive. */
252 if (!interactive_shell
&& XHANDLER (i
) == SIG_IGN
)
254 signal (XSIG (i
), SIG_IGN
);
255 set_signal_ignored (XSIG (i
));
258 if (XSIG (i
) == SIGPROF
&& XHANDLER (i
) != SIG_DFL
&& XHANDLER (i
) != SIG_IGN
)
259 signal (XSIG (i
), XHANDLER (i
));
263 #endif /* !HAVE_POSIX_SIGNALS */
265 termsigs_initialized
= 1;
269 initialize_shell_signals ()
272 initialize_terminating_signals ();
274 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
275 /* All shells use the signal mask they inherit, and pass it along
276 to child processes. Children will never block SIGCHLD, though. */
277 sigemptyset (&top_level_mask
);
278 sigprocmask (SIG_BLOCK
, (sigset_t
*)NULL
, &top_level_mask
);
279 # if defined (SIGCHLD)
280 sigdelset (&top_level_mask
, SIGCHLD
);
282 #endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
284 /* And, some signals that are specifically ignored by the shell. */
285 set_signal_handler (SIGQUIT
, SIG_IGN
);
289 set_signal_handler (SIGINT
, sigint_sighandler
);
290 set_signal_handler (SIGTERM
, SIG_IGN
);
295 reset_terminating_signals ()
298 #if defined (HAVE_POSIX_SIGNALS)
299 struct sigaction act
;
302 if (termsigs_initialized
== 0)
305 #if defined (HAVE_POSIX_SIGNALS)
307 sigemptyset (&act
.sa_mask
);
308 for (i
= 0; i
< TERMSIGS_LENGTH
; i
++)
310 /* Skip a signal if it's trapped or handled specially, because the
311 trap code will restore the correct value. */
312 if (signal_is_trapped (XSIG (i
)) || signal_is_special (XSIG (i
)))
315 act
.sa_handler
= XHANDLER (i
);
316 sigaction (XSIG (i
), &act
, (struct sigaction
*) NULL
);
318 #else /* !HAVE_POSIX_SIGNALS */
319 for (i
= 0; i
< TERMSIGS_LENGTH
; i
++)
321 if (signal_is_trapped (XSIG (i
)) || signal_is_special (XSIG (i
)))
324 signal (XSIG (i
), XHANDLER (i
));
326 #endif /* !HAVE_POSIX_SIGNALS */
331 /* What to do when we've been interrupted, and it is safe to handle it. */
333 throw_to_top_level ()
335 int print_newline
= 0;
346 last_command_exit_value
|= 128;
348 /* Run any traps set on SIGINT. */
349 run_interrupt_trap ();
351 /* Cleanup string parser environment. */
352 while (parse_and_execute_level
)
353 parse_and_execute_cleanup ();
355 #if defined (JOB_CONTROL)
356 give_terminal_to (shell_pgrp
, 0);
357 #endif /* JOB_CONTROL */
359 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
360 /* This should not be necessary on systems using sigsetjmp/siglongjmp. */
361 sigprocmask (SIG_SETMASK
, &top_level_mask
, (sigset_t
*)NULL
);
366 #if defined (READLINE)
368 bashline_reinitialize ();
369 #endif /* READLINE */
371 #if defined (PROCESS_SUBSTITUTION)
373 #endif /* PROCESS_SUBSTITUTION */
375 run_unwind_protects ();
376 loop_level
= continuing
= breaking
= 0;
377 return_catch_flag
= 0;
379 if (interactive
&& print_newline
)
382 fprintf (stderr
, "\n");
386 /* An interrupted `wait' command in a script does not exit the script. */
387 if (interactive
|| (interactive_shell
&& !shell_initialized
) ||
388 (print_newline
&& signal_is_trapped (SIGINT
)))
389 jump_to_top_level (DISCARD
);
391 jump_to_top_level (EXITPROG
);
394 /* This is just here to isolate the longjmp calls. */
396 jump_to_top_level (value
)
399 longjmp (top_level
, value
);
403 termination_unwind_protect (sig
)
406 if (sig
== SIGINT
&& signal_is_trapped (SIGINT
))
407 run_interrupt_trap ();
409 #if defined (HISTORY)
410 if (interactive_shell
&& sig
!= SIGABRT
)
411 maybe_save_shell_history ();
414 #if defined (JOB_CONTROL)
415 if (interactive
&& sig
== SIGHUP
)
418 #endif /* JOB_CONTROL */
420 #if defined (PROCESS_SUBSTITUTION)
422 #endif /* PROCESS_SUBSTITUTION */
425 set_signal_handler (sig
, SIG_DFL
);
426 kill (getpid (), sig
);
431 /* What we really do when SIGINT occurs. */
433 sigint_sighandler (sig
)
436 #if defined (MUST_REINSTALL_SIGHANDLERS)
437 signal (sig
, sigint_sighandler
);
440 /* interrupt_state needs to be set for the stack of interrupts to work
441 right. Should it be set unconditionally? */
442 if (interrupt_state
== 0)
445 if (interrupt_immediately
)
447 interrupt_immediately
= 0;
448 throw_to_top_level ();
454 /* Signal functions used by the rest of the code. */
455 #if !defined (HAVE_POSIX_SIGNALS)
457 #if defined (JOB_CONTROL)
458 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
459 sigprocmask (operation
, newset
, oldset
)
460 int operation
, *newset
, *oldset
;
472 old
= sigblock (new);
480 internal_error ("Bad code in sig.c: sigprocmask");
486 #endif /* JOB_CONTROL */
490 #if !defined (SA_INTERRUPT)
491 # define SA_INTERRUPT 0
494 #if !defined (SA_RESTART)
495 # define SA_RESTART 0
499 set_signal_handler (sig
, handler
)
503 struct sigaction act
, oact
;
505 act
.sa_handler
= handler
;
509 act
.sa_flags
|= SA_INTERRUPT
; /* XXX */
511 act
.sa_flags
|= SA_RESTART
; /* XXX */
513 sigemptyset (&act
.sa_mask
);
514 sigemptyset (&oact
.sa_mask
);
515 sigaction (sig
, &act
, &oact
);
516 return (oact
.sa_handler
);
518 #endif /* HAVE_POSIX_SIGNALS */