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