]>
Commit | Line | Data |
---|---|---|
ccc6cda3 JA |
1 | /* sig.c - interface for shell signal handlers and signal initialization. */ |
2 | ||
ac50fbac | 3 | /* Copyright (C) 1994-2013 Free Software Foundation, Inc. |
ccc6cda3 JA |
4 | |
5 | This file is part of GNU Bash, the Bourne Again SHell. | |
6 | ||
3185942a JA |
7 | Bash is free software: you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation, either version 3 of the License, or | |
10 | (at your option) any later version. | |
ccc6cda3 | 11 | |
3185942a JA |
12 | Bash is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
ccc6cda3 | 16 | |
3185942a JA |
17 | You should have received a copy of the GNU General Public License |
18 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
ccc6cda3 JA |
20 | |
21 | #include "config.h" | |
22 | ||
23 | #include "bashtypes.h" | |
24 | ||
25 | #if defined (HAVE_UNISTD_H) | |
cce855bc JA |
26 | # ifdef _MINIX |
27 | # include <sys/types.h> | |
28 | # endif | |
ccc6cda3 JA |
29 | # include <unistd.h> |
30 | #endif | |
31 | ||
32 | #include <stdio.h> | |
33 | #include <signal.h> | |
34 | ||
b80f6443 JA |
35 | #include "bashintl.h" |
36 | ||
ccc6cda3 JA |
37 | #include "shell.h" |
38 | #if defined (JOB_CONTROL) | |
39 | #include "jobs.h" | |
40 | #endif /* JOB_CONTROL */ | |
41 | #include "siglist.h" | |
42 | #include "sig.h" | |
43 | #include "trap.h" | |
44 | ||
45 | #include "builtins/common.h" | |
ac50fbac | 46 | #include "builtins/builtext.h" |
ccc6cda3 JA |
47 | |
48 | #if defined (READLINE) | |
49 | # include "bashline.h" | |
d5d00961 | 50 | # include <readline/readline.h> |
ccc6cda3 JA |
51 | #endif |
52 | ||
53 | #if defined (HISTORY) | |
54 | # include "bashhist.h" | |
55 | #endif | |
56 | ||
57 | extern int last_command_exit_value; | |
b80f6443 | 58 | extern int last_command_exit_signal; |
ccc6cda3 | 59 | extern int return_catch_flag; |
495aee44 | 60 | extern int loop_level, continuing, breaking, funcnest; |
3185942a JA |
61 | extern int executing_list; |
62 | extern int comsub_ignore_return; | |
ccc6cda3 | 63 | extern int parse_and_execute_level, shell_initialized; |
495aee44 CR |
64 | #if defined (HISTORY) |
65 | extern int history_lines_this_session; | |
66 | #endif | |
d5d00961 | 67 | extern int no_line_editing; |
ac50fbac CR |
68 | extern int wait_signal_received; |
69 | extern sh_builtin_func_t *this_shell_builtin; | |
495aee44 CR |
70 | |
71 | extern void initialize_siglist (); | |
ccc6cda3 JA |
72 | |
73 | /* Non-zero after SIGINT. */ | |
ac50fbac | 74 | volatile sig_atomic_t interrupt_state = 0; |
ccc6cda3 | 75 | |
95732b49 | 76 | /* Non-zero after SIGWINCH */ |
ac50fbac CR |
77 | volatile sig_atomic_t sigwinch_received = 0; |
78 | ||
79 | /* Non-zero after SIGTERM */ | |
80 | volatile sig_atomic_t sigterm_received = 0; | |
95732b49 | 81 | |
0628567a | 82 | /* Set to the value of any terminating signal received. */ |
ac50fbac | 83 | volatile sig_atomic_t terminating_signal = 0; |
0628567a | 84 | |
ccc6cda3 JA |
85 | /* The environment at the top-level R-E loop. We use this in |
86 | the case of error return. */ | |
87 | procenv_t top_level; | |
88 | ||
89 | #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) | |
90 | /* The signal masks that this shell runs with. */ | |
91 | sigset_t top_level_mask; | |
92 | #endif /* JOB_CONTROL */ | |
93 | ||
94 | /* When non-zero, we throw_to_top_level (). */ | |
95 | int interrupt_immediately = 0; | |
96 | ||
0628567a JA |
97 | /* When non-zero, we call the terminating signal handler immediately. */ |
98 | int terminate_immediately = 0; | |
99 | ||
95732b49 JA |
100 | #if defined (SIGWINCH) |
101 | static SigHandler *old_winch = (SigHandler *)SIG_DFL; | |
102 | #endif | |
103 | ||
f73dda09 | 104 | static void initialize_shell_signals __P((void)); |
ccc6cda3 JA |
105 | |
106 | void | |
7117c2d2 JA |
107 | initialize_signals (reinit) |
108 | int reinit; | |
ccc6cda3 | 109 | { |
d166f048 | 110 | initialize_shell_signals (); |
ccc6cda3 | 111 | initialize_job_signals (); |
e8ce775d | 112 | #if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) |
7117c2d2 JA |
113 | if (reinit == 0) |
114 | initialize_siglist (); | |
e8ce775d | 115 | #endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */ |
ccc6cda3 JA |
116 | } |
117 | ||
ccc6cda3 JA |
118 | /* A structure describing a signal that terminates the shell if not |
119 | caught. The orig_handler member is present so children can reset | |
120 | these signals back to their original handlers. */ | |
121 | struct termsig { | |
122 | int signum; | |
123 | SigHandler *orig_handler; | |
95732b49 | 124 | int orig_flags; |
ccc6cda3 JA |
125 | }; |
126 | ||
127 | #define NULL_HANDLER (SigHandler *)SIG_DFL | |
128 | ||
129 | /* The list of signals that would terminate the shell if not caught. | |
130 | We catch them, but just so that we can write the history file, | |
131 | and so forth. */ | |
132 | static struct termsig terminating_signals[] = { | |
133 | #ifdef SIGHUP | |
95732b49 | 134 | { SIGHUP, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
135 | #endif |
136 | ||
137 | #ifdef SIGINT | |
95732b49 | 138 | { SIGINT, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
139 | #endif |
140 | ||
141 | #ifdef SIGILL | |
95732b49 | 142 | { SIGILL, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
143 | #endif |
144 | ||
145 | #ifdef SIGTRAP | |
95732b49 | 146 | { SIGTRAP, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
147 | #endif |
148 | ||
149 | #ifdef SIGIOT | |
95732b49 | 150 | { SIGIOT, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
151 | #endif |
152 | ||
153 | #ifdef SIGDANGER | |
95732b49 | 154 | { SIGDANGER, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
155 | #endif |
156 | ||
157 | #ifdef SIGEMT | |
95732b49 | 158 | { SIGEMT, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
159 | #endif |
160 | ||
161 | #ifdef SIGFPE | |
95732b49 | 162 | { SIGFPE, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
163 | #endif |
164 | ||
165 | #ifdef SIGBUS | |
95732b49 | 166 | { SIGBUS, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
167 | #endif |
168 | ||
169 | #ifdef SIGSEGV | |
95732b49 | 170 | { SIGSEGV, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
171 | #endif |
172 | ||
173 | #ifdef SIGSYS | |
95732b49 | 174 | { SIGSYS, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
175 | #endif |
176 | ||
177 | #ifdef SIGPIPE | |
95732b49 | 178 | { SIGPIPE, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
179 | #endif |
180 | ||
181 | #ifdef SIGALRM | |
95732b49 | 182 | { SIGALRM, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
183 | #endif |
184 | ||
185 | #ifdef SIGTERM | |
95732b49 | 186 | { SIGTERM, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
187 | #endif |
188 | ||
189 | #ifdef SIGXCPU | |
95732b49 | 190 | { SIGXCPU, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
191 | #endif |
192 | ||
193 | #ifdef SIGXFSZ | |
95732b49 | 194 | { SIGXFSZ, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
195 | #endif |
196 | ||
197 | #ifdef SIGVTALRM | |
95732b49 | 198 | { SIGVTALRM, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
199 | #endif |
200 | ||
bb70624e | 201 | #if 0 |
ccc6cda3 | 202 | #ifdef SIGPROF |
95732b49 | 203 | { SIGPROF, NULL_HANDLER, 0 }, |
ccc6cda3 | 204 | #endif |
bb70624e | 205 | #endif |
ccc6cda3 JA |
206 | |
207 | #ifdef SIGLOST | |
95732b49 | 208 | { SIGLOST, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
209 | #endif |
210 | ||
211 | #ifdef SIGUSR1 | |
95732b49 | 212 | { SIGUSR1, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
213 | #endif |
214 | ||
215 | #ifdef SIGUSR2 | |
95732b49 | 216 | { SIGUSR2, NULL_HANDLER, 0 }, |
ccc6cda3 JA |
217 | #endif |
218 | }; | |
219 | ||
220 | #define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig)) | |
221 | ||
222 | #define XSIG(x) (terminating_signals[x].signum) | |
223 | #define XHANDLER(x) (terminating_signals[x].orig_handler) | |
95732b49 | 224 | #define XSAFLAGS(x) (terminating_signals[x].orig_flags) |
ccc6cda3 | 225 | |
d166f048 JA |
226 | static int termsigs_initialized = 0; |
227 | ||
ccc6cda3 | 228 | /* Initialize signals that will terminate the shell to do some |
d166f048 | 229 | unwind protection. For non-interactive shells, we only call |
495aee44 CR |
230 | this when a trap is defined for EXIT (0) or when trap is run |
231 | to display signal dispositions. */ | |
d166f048 | 232 | void |
ccc6cda3 JA |
233 | initialize_terminating_signals () |
234 | { | |
235 | register int i; | |
d166f048 JA |
236 | #if defined (HAVE_POSIX_SIGNALS) |
237 | struct sigaction act, oact; | |
238 | #endif | |
239 | ||
240 | if (termsigs_initialized) | |
241 | return; | |
ccc6cda3 JA |
242 | |
243 | /* The following code is to avoid an expensive call to | |
244 | set_signal_handler () for each terminating_signals. Fortunately, | |
245 | this is possible in Posix. Unfortunately, we have to call signal () | |
246 | on non-Posix systems for each signal in terminating_signals. */ | |
247 | #if defined (HAVE_POSIX_SIGNALS) | |
0628567a | 248 | act.sa_handler = termsig_sighandler; |
ccc6cda3 JA |
249 | act.sa_flags = 0; |
250 | sigemptyset (&act.sa_mask); | |
251 | sigemptyset (&oact.sa_mask); | |
252 | for (i = 0; i < TERMSIGS_LENGTH; i++) | |
253 | sigaddset (&act.sa_mask, XSIG (i)); | |
254 | for (i = 0; i < TERMSIGS_LENGTH; i++) | |
255 | { | |
7117c2d2 JA |
256 | /* If we've already trapped it, don't do anything. */ |
257 | if (signal_is_trapped (XSIG (i))) | |
258 | continue; | |
259 | ||
ccc6cda3 | 260 | sigaction (XSIG (i), &act, &oact); |
d166f048 | 261 | XHANDLER(i) = oact.sa_handler; |
95732b49 | 262 | XSAFLAGS(i) = oact.sa_flags; |
ccc6cda3 JA |
263 | /* Don't do anything with signals that are ignored at shell entry |
264 | if the shell is not interactive. */ | |
495aee44 CR |
265 | /* XXX - should we do this for interactive shells, too? */ |
266 | if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) | |
28ef6c31 | 267 | { |
ccc6cda3 | 268 | sigaction (XSIG (i), &oact, &act); |
ac50fbac | 269 | set_signal_hard_ignored (XSIG (i)); |
28ef6c31 | 270 | } |
cce855bc | 271 | #if defined (SIGPROF) && !defined (_MINIX) |
d166f048 | 272 | if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) |
28ef6c31 | 273 | sigaction (XSIG (i), &oact, (struct sigaction *)NULL); |
cce855bc | 274 | #endif /* SIGPROF && !_MINIX */ |
ccc6cda3 JA |
275 | } |
276 | ||
277 | #else /* !HAVE_POSIX_SIGNALS */ | |
278 | ||
279 | for (i = 0; i < TERMSIGS_LENGTH; i++) | |
280 | { | |
7117c2d2 JA |
281 | /* If we've already trapped it, don't do anything. */ |
282 | if (signal_is_trapped (XSIG (i))) | |
283 | continue; | |
284 | ||
0628567a | 285 | XHANDLER(i) = signal (XSIG (i), termsig_sighandler); |
95732b49 | 286 | XSAFLAGS(i) = 0; |
ccc6cda3 JA |
287 | /* Don't do anything with signals that are ignored at shell entry |
288 | if the shell is not interactive. */ | |
495aee44 CR |
289 | /* XXX - should we do this for interactive shells, too? */ |
290 | if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) | |
ccc6cda3 | 291 | { |
28ef6c31 | 292 | signal (XSIG (i), SIG_IGN); |
ac50fbac | 293 | set_signal_hard_ignored (XSIG (i)); |
ccc6cda3 | 294 | } |
cce855bc | 295 | #ifdef SIGPROF |
d166f048 | 296 | if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) |
28ef6c31 | 297 | signal (XSIG (i), XHANDLER (i)); |
cce855bc | 298 | #endif |
ccc6cda3 JA |
299 | } |
300 | ||
301 | #endif /* !HAVE_POSIX_SIGNALS */ | |
302 | ||
d166f048 JA |
303 | termsigs_initialized = 1; |
304 | } | |
305 | ||
306 | static void | |
307 | initialize_shell_signals () | |
308 | { | |
309 | if (interactive) | |
310 | initialize_terminating_signals (); | |
311 | ||
ccc6cda3 JA |
312 | #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) |
313 | /* All shells use the signal mask they inherit, and pass it along | |
314 | to child processes. Children will never block SIGCHLD, though. */ | |
315 | sigemptyset (&top_level_mask); | |
316 | sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask); | |
bb70624e | 317 | # if defined (SIGCHLD) |
ccc6cda3 | 318 | sigdelset (&top_level_mask, SIGCHLD); |
bb70624e | 319 | # endif |
ccc6cda3 JA |
320 | #endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */ |
321 | ||
322 | /* And, some signals that are specifically ignored by the shell. */ | |
323 | set_signal_handler (SIGQUIT, SIG_IGN); | |
324 | ||
325 | if (interactive) | |
326 | { | |
327 | set_signal_handler (SIGINT, sigint_sighandler); | |
ac50fbac CR |
328 | get_original_signal (SIGTERM); |
329 | if (signal_is_hard_ignored (SIGTERM) == 0) | |
330 | set_signal_handler (SIGTERM, sigterm_sighandler); | |
95732b49 | 331 | set_sigwinch_handler (); |
ccc6cda3 JA |
332 | } |
333 | } | |
334 | ||
335 | void | |
336 | reset_terminating_signals () | |
337 | { | |
338 | register int i; | |
ccc6cda3 JA |
339 | #if defined (HAVE_POSIX_SIGNALS) |
340 | struct sigaction act; | |
d166f048 | 341 | #endif |
ccc6cda3 | 342 | |
d166f048 JA |
343 | if (termsigs_initialized == 0) |
344 | return; | |
345 | ||
346 | #if defined (HAVE_POSIX_SIGNALS) | |
ccc6cda3 JA |
347 | act.sa_flags = 0; |
348 | sigemptyset (&act.sa_mask); | |
349 | for (i = 0; i < TERMSIGS_LENGTH; i++) | |
350 | { | |
351 | /* Skip a signal if it's trapped or handled specially, because the | |
352 | trap code will restore the correct value. */ | |
353 | if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) | |
354 | continue; | |
355 | ||
356 | act.sa_handler = XHANDLER (i); | |
95732b49 | 357 | act.sa_flags = XSAFLAGS (i); |
ccc6cda3 JA |
358 | sigaction (XSIG (i), &act, (struct sigaction *) NULL); |
359 | } | |
360 | #else /* !HAVE_POSIX_SIGNALS */ | |
361 | for (i = 0; i < TERMSIGS_LENGTH; i++) | |
362 | { | |
363 | if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) | |
364 | continue; | |
365 | ||
366 | signal (XSIG (i), XHANDLER (i)); | |
367 | } | |
368 | #endif /* !HAVE_POSIX_SIGNALS */ | |
ac50fbac CR |
369 | |
370 | termsigs_initialized = 0; | |
ccc6cda3 JA |
371 | } |
372 | #undef XSIG | |
373 | #undef XHANDLER | |
374 | ||
f1be666c JA |
375 | /* Run some of the cleanups that should be performed when we run |
376 | jump_to_top_level from a builtin command context. XXX - might want to | |
377 | also call reset_parser here. */ | |
378 | void | |
379 | top_level_cleanup () | |
380 | { | |
381 | /* Clean up string parser environment. */ | |
382 | while (parse_and_execute_level) | |
383 | parse_and_execute_cleanup (); | |
384 | ||
385 | #if defined (PROCESS_SUBSTITUTION) | |
386 | unlink_fifo_list (); | |
387 | #endif /* PROCESS_SUBSTITUTION */ | |
388 | ||
389 | run_unwind_protects (); | |
495aee44 | 390 | loop_level = continuing = breaking = funcnest = 0; |
3185942a | 391 | executing_list = comsub_ignore_return = return_catch_flag = 0; |
f1be666c JA |
392 | } |
393 | ||
ccc6cda3 JA |
394 | /* What to do when we've been interrupted, and it is safe to handle it. */ |
395 | void | |
396 | throw_to_top_level () | |
397 | { | |
398 | int print_newline = 0; | |
399 | ||
400 | if (interrupt_state) | |
401 | { | |
ac50fbac CR |
402 | if (last_command_exit_value < 128) |
403 | last_command_exit_value = 128 + SIGINT; | |
ccc6cda3 JA |
404 | print_newline = 1; |
405 | DELINTERRUPT; | |
406 | } | |
407 | ||
408 | if (interrupt_state) | |
409 | return; | |
410 | ||
b80f6443 JA |
411 | last_command_exit_signal = (last_command_exit_value > 128) ? |
412 | (last_command_exit_value - 128) : 0; | |
ccc6cda3 JA |
413 | last_command_exit_value |= 128; |
414 | ||
415 | /* Run any traps set on SIGINT. */ | |
416 | run_interrupt_trap (); | |
417 | ||
3185942a | 418 | /* Clean up string parser environment. */ |
ccc6cda3 JA |
419 | while (parse_and_execute_level) |
420 | parse_and_execute_cleanup (); | |
421 | ||
422 | #if defined (JOB_CONTROL) | |
28ef6c31 | 423 | give_terminal_to (shell_pgrp, 0); |
ccc6cda3 JA |
424 | #endif /* JOB_CONTROL */ |
425 | ||
426 | #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) | |
ac50fbac CR |
427 | /* This needs to stay because jobs.c:make_child() uses it without resetting |
428 | the signal mask. */ | |
ccc6cda3 JA |
429 | sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); |
430 | #endif | |
431 | ||
432 | reset_parser (); | |
433 | ||
434 | #if defined (READLINE) | |
435 | if (interactive) | |
3185942a | 436 | bashline_reset (); |
ccc6cda3 JA |
437 | #endif /* READLINE */ |
438 | ||
439 | #if defined (PROCESS_SUBSTITUTION) | |
440 | unlink_fifo_list (); | |
441 | #endif /* PROCESS_SUBSTITUTION */ | |
442 | ||
443 | run_unwind_protects (); | |
495aee44 | 444 | loop_level = continuing = breaking = funcnest = 0; |
3185942a | 445 | executing_list = comsub_ignore_return = return_catch_flag = 0; |
ccc6cda3 JA |
446 | |
447 | if (interactive && print_newline) | |
448 | { | |
449 | fflush (stdout); | |
450 | fprintf (stderr, "\n"); | |
451 | fflush (stderr); | |
452 | } | |
453 | ||
454 | /* An interrupted `wait' command in a script does not exit the script. */ | |
455 | if (interactive || (interactive_shell && !shell_initialized) || | |
456 | (print_newline && signal_is_trapped (SIGINT))) | |
457 | jump_to_top_level (DISCARD); | |
458 | else | |
459 | jump_to_top_level (EXITPROG); | |
460 | } | |
461 | ||
462 | /* This is just here to isolate the longjmp calls. */ | |
463 | void | |
464 | jump_to_top_level (value) | |
465 | int value; | |
466 | { | |
467 | longjmp (top_level, value); | |
468 | } | |
469 | ||
470 | sighandler | |
0628567a | 471 | termsig_sighandler (sig) |
ccc6cda3 JA |
472 | int sig; |
473 | { | |
89a92869 CR |
474 | /* If we get called twice with the same signal before handling it, |
475 | terminate right away. */ | |
476 | if ( | |
477 | #ifdef SIGHUP | |
478 | sig != SIGHUP && | |
479 | #endif | |
480 | #ifdef SIGINT | |
481 | sig != SIGINT && | |
482 | #endif | |
483 | #ifdef SIGDANGER | |
484 | sig != SIGDANGER && | |
485 | #endif | |
486 | #ifdef SIGPIPE | |
487 | sig != SIGPIPE && | |
488 | #endif | |
489 | #ifdef SIGALRM | |
490 | sig != SIGALRM && | |
491 | #endif | |
492 | #ifdef SIGTERM | |
493 | sig != SIGTERM && | |
494 | #endif | |
495 | #ifdef SIGXCPU | |
496 | sig != SIGXCPU && | |
497 | #endif | |
498 | #ifdef SIGXFSZ | |
499 | sig != SIGXFSZ && | |
500 | #endif | |
501 | #ifdef SIGVTALRM | |
502 | sig != SIGVTALRM && | |
503 | #endif | |
504 | #ifdef SIGLOST | |
505 | sig != SIGLOST && | |
506 | #endif | |
507 | #ifdef SIGUSR1 | |
508 | sig != SIGUSR1 && | |
509 | #endif | |
510 | #ifdef SIGUSR2 | |
511 | sig != SIGUSR2 && | |
512 | #endif | |
513 | sig == terminating_signal) | |
514 | terminate_immediately = 1; | |
515 | ||
0628567a JA |
516 | terminating_signal = sig; |
517 | ||
3185942a | 518 | /* XXX - should this also trigger when interrupt_immediately is set? */ |
0628567a JA |
519 | if (terminate_immediately) |
520 | { | |
495aee44 CR |
521 | #if defined (HISTORY) |
522 | /* XXX - will inhibit history file being written */ | |
d5d00961 CR |
523 | # if defined (READLINE) |
524 | if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0)) | |
525 | # endif | |
526 | history_lines_this_session = 0; | |
495aee44 | 527 | #endif |
0628567a JA |
528 | terminate_immediately = 0; |
529 | termsig_handler (sig); | |
530 | } | |
531 | ||
ac50fbac CR |
532 | #if defined (READLINE) |
533 | /* Set the event hook so readline will call it after the signal handlers | |
534 | finish executing, so if this interrupted character input we can get | |
535 | quick response. */ | |
536 | if (interactive_shell && interactive && no_line_editing == 0) | |
537 | bashline_set_event_hook (); | |
538 | #endif | |
539 | ||
0628567a JA |
540 | SIGRETURN (0); |
541 | } | |
542 | ||
543 | void | |
544 | termsig_handler (sig) | |
545 | int sig; | |
546 | { | |
547 | static int handling_termsig = 0; | |
548 | ||
549 | /* Simple semaphore to keep this function from being executed multiple | |
550 | times. Since we no longer are running as a signal handler, we don't | |
551 | block multiple occurrences of the terminating signals while running. */ | |
552 | if (handling_termsig) | |
553 | return; | |
554 | handling_termsig = 1; | |
555 | terminating_signal = 0; /* keep macro from re-testing true. */ | |
556 | ||
95732b49 | 557 | /* I don't believe this condition ever tests true. */ |
ccc6cda3 JA |
558 | if (sig == SIGINT && signal_is_trapped (SIGINT)) |
559 | run_interrupt_trap (); | |
560 | ||
561 | #if defined (HISTORY) | |
ac50fbac CR |
562 | /* If we don't do something like this, the history will not be saved when |
563 | an interactive shell is running in a terminal window that gets closed | |
564 | with the `close' button. We can't test for RL_STATE_READCMD because | |
565 | readline no longer handles SIGTERM synchronously. */ | |
566 | if (interactive_shell && interactive && (sig == SIGHUP || sig == SIGTERM) && remember_on_history) | |
ccc6cda3 JA |
567 | maybe_save_shell_history (); |
568 | #endif /* HISTORY */ | |
569 | ||
570 | #if defined (JOB_CONTROL) | |
0001803f | 571 | if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)))) |
ccc6cda3 JA |
572 | hangup_all_jobs (); |
573 | end_job_control (); | |
574 | #endif /* JOB_CONTROL */ | |
575 | ||
576 | #if defined (PROCESS_SUBSTITUTION) | |
577 | unlink_fifo_list (); | |
578 | #endif /* PROCESS_SUBSTITUTION */ | |
579 | ||
3185942a | 580 | /* Reset execution context */ |
495aee44 | 581 | loop_level = continuing = breaking = funcnest = 0; |
3185942a JA |
582 | executing_list = comsub_ignore_return = return_catch_flag = 0; |
583 | ||
ac50fbac | 584 | run_exit_trap (); /* XXX - run exit trap possibly in signal context? */ |
ccc6cda3 JA |
585 | set_signal_handler (sig, SIG_DFL); |
586 | kill (getpid (), sig); | |
ccc6cda3 JA |
587 | } |
588 | ||
589 | /* What we really do when SIGINT occurs. */ | |
590 | sighandler | |
591 | sigint_sighandler (sig) | |
592 | int sig; | |
593 | { | |
594 | #if defined (MUST_REINSTALL_SIGHANDLERS) | |
595 | signal (sig, sigint_sighandler); | |
596 | #endif | |
597 | ||
598 | /* interrupt_state needs to be set for the stack of interrupts to work | |
599 | right. Should it be set unconditionally? */ | |
600 | if (interrupt_state == 0) | |
601 | ADDINTERRUPT; | |
602 | ||
ac50fbac CR |
603 | /* We will get here in interactive shells with job control active; allow |
604 | an interactive wait to be interrupted. */ | |
605 | if (this_shell_builtin && this_shell_builtin == wait_builtin) | |
606 | { | |
607 | last_command_exit_value = 128 + sig; | |
608 | wait_signal_received = sig; | |
609 | SIGRETURN (0); | |
610 | } | |
611 | ||
ccc6cda3 JA |
612 | if (interrupt_immediately) |
613 | { | |
614 | interrupt_immediately = 0; | |
0001803f | 615 | last_command_exit_value = 128 + sig; |
ccc6cda3 JA |
616 | throw_to_top_level (); |
617 | } | |
ac50fbac CR |
618 | #if defined (READLINE) |
619 | /* Set the event hook so readline will call it after the signal handlers | |
620 | finish executing, so if this interrupted character input we can get | |
621 | quick response. */ | |
622 | else if (RL_ISSTATE (RL_STATE_SIGHANDLER)) | |
623 | bashline_set_event_hook (); | |
624 | #endif | |
ccc6cda3 JA |
625 | |
626 | SIGRETURN (0); | |
627 | } | |
628 | ||
95732b49 JA |
629 | #if defined (SIGWINCH) |
630 | sighandler | |
631 | sigwinch_sighandler (sig) | |
632 | int sig; | |
633 | { | |
634 | #if defined (MUST_REINSTALL_SIGHANDLERS) | |
635 | set_signal_handler (SIGWINCH, sigwinch_sighandler); | |
636 | #endif /* MUST_REINSTALL_SIGHANDLERS */ | |
637 | sigwinch_received = 1; | |
638 | SIGRETURN (0); | |
639 | } | |
640 | #endif /* SIGWINCH */ | |
641 | ||
642 | void | |
643 | set_sigwinch_handler () | |
644 | { | |
645 | #if defined (SIGWINCH) | |
646 | old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); | |
647 | #endif | |
648 | } | |
649 | ||
650 | void | |
651 | unset_sigwinch_handler () | |
652 | { | |
653 | #if defined (SIGWINCH) | |
654 | set_signal_handler (SIGWINCH, old_winch); | |
655 | #endif | |
656 | } | |
657 | ||
ac50fbac CR |
658 | sighandler |
659 | sigterm_sighandler (sig) | |
660 | int sig; | |
661 | { | |
662 | sigterm_received = 1; /* XXX - counter? */ | |
663 | SIGRETURN (0); | |
664 | } | |
665 | ||
ccc6cda3 JA |
666 | /* Signal functions used by the rest of the code. */ |
667 | #if !defined (HAVE_POSIX_SIGNALS) | |
668 | ||
ccc6cda3 JA |
669 | /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ |
670 | sigprocmask (operation, newset, oldset) | |
671 | int operation, *newset, *oldset; | |
672 | { | |
673 | int old, new; | |
674 | ||
675 | if (newset) | |
676 | new = *newset; | |
677 | else | |
678 | new = 0; | |
679 | ||
680 | switch (operation) | |
681 | { | |
682 | case SIG_BLOCK: | |
683 | old = sigblock (new); | |
684 | break; | |
685 | ||
686 | case SIG_SETMASK: | |
ac50fbac | 687 | old = sigsetmask (new); |
ccc6cda3 JA |
688 | break; |
689 | ||
690 | default: | |
b80f6443 | 691 | internal_error (_("sigprocmask: %d: invalid operation"), operation); |
ccc6cda3 JA |
692 | } |
693 | ||
694 | if (oldset) | |
695 | *oldset = old; | |
696 | } | |
ccc6cda3 JA |
697 | |
698 | #else | |
699 | ||
700 | #if !defined (SA_INTERRUPT) | |
701 | # define SA_INTERRUPT 0 | |
702 | #endif | |
703 | ||
704 | #if !defined (SA_RESTART) | |
705 | # define SA_RESTART 0 | |
706 | #endif | |
707 | ||
708 | SigHandler * | |
709 | set_signal_handler (sig, handler) | |
710 | int sig; | |
711 | SigHandler *handler; | |
712 | { | |
713 | struct sigaction act, oact; | |
714 | ||
715 | act.sa_handler = handler; | |
716 | act.sa_flags = 0; | |
495aee44 CR |
717 | |
718 | /* XXX - bash-4.2 */ | |
719 | /* We don't want a child death to interrupt interruptible system calls, even | |
720 | if we take the time to reap children */ | |
ac50fbac | 721 | #if defined (SIGCHLD) |
30d188c2 | 722 | if (sig == SIGCHLD) |
495aee44 | 723 | act.sa_flags |= SA_RESTART; /* XXX */ |
ac50fbac CR |
724 | #endif |
725 | /* If we're installing a SIGTERM handler for interactive shells, we want | |
726 | it to be as close to SIG_IGN as possible. */ | |
727 | if (sig == SIGTERM && handler == sigterm_sighandler) | |
728 | act.sa_flags |= SA_RESTART; /* XXX */ | |
495aee44 | 729 | |
ccc6cda3 JA |
730 | sigemptyset (&act.sa_mask); |
731 | sigemptyset (&oact.sa_mask); | |
ac50fbac CR |
732 | if (sigaction (sig, &act, &oact) == 0) |
733 | return (oact.sa_handler); | |
734 | else | |
735 | return (SIG_DFL); | |
ccc6cda3 JA |
736 | } |
737 | #endif /* HAVE_POSIX_SIGNALS */ |