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