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