improve of cmpl.
[bush.git] / src / sig.c
blob3cf299117e9dae4c48bde668eff43b7c5d2cb28a
1 /* sig.c - interface for shell signal handlers and signal initialization. */
3 /* Copyright (C) 1994-2020 Free Software Foundation, Inc.
5 This file is part of GNU Bush, the Bourne Again SHell.
7 Bush 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.
12 Bush 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.
17 You should have received a copy of the GNU General Public License
18 along with Bush. If not, see <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include "bushtypes.h"
25 #if defined (HAVE_UNISTD_H)
26 # ifdef _MINIX
27 # include <sys/types.h>
28 # endif
29 # include <unistd.h>
30 #endif
32 #include <stdio.h>
33 #include <signal.h>
35 #include "bushintl.h"
37 #include "shell.h"
38 #include "runner/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"
46 #include "builtins/common.h"
47 #include "builtins/builtext.h"
49 #if defined (READLINE)
50 # include "input/bushline.h"
51 # include <readline/readline.h>
52 #endif
54 #if defined (HISTORY)
55 # include "bushhist.h"
56 #endif
58 extern void initialize_siglist ();
60 #if !defined (JOB_CONTROL)
61 extern void initialize_job_signals PARAMS((void));
62 #endif
64 /* Non-zero after SIGINT. */
65 volatile sig_atomic_t interrupt_state = 0;
67 /* Non-zero after SIGWINCH */
68 volatile sig_atomic_t sigwinch_received = 0;
70 /* Non-zero after SIGTERM */
71 volatile sig_atomic_t sigterm_received = 0;
73 /* Set to the value of any terminating signal received. */
74 volatile sig_atomic_t terminating_signal = 0;
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;
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 */
85 /* When non-zero, we throw_to_top_level (). */
86 int interrupt_immediately = 0;
88 /* When non-zero, we call the terminating signal handler immediately. */
89 int terminate_immediately = 0;
91 #if defined (SIGWINCH)
92 static SigHandler *old_winch = (SigHandler *)SIG_DFL;
93 #endif
95 static void initialize_shell_signals PARAMS((void));
97 void
98 initialize_signals (reinit)
99 int reinit;
101 initialize_shell_signals ();
102 initialize_job_signals ();
103 #if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
104 if (reinit == 0)
105 initialize_siglist ();
106 #endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
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;
115 int orig_flags;
116 int core_dump;
119 #define NULL_HANDLER (SigHandler *)SIG_DFL
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
126 { SIGHUP, NULL_HANDLER, 0 },
127 #endif
129 #ifdef SIGINT
130 { SIGINT, NULL_HANDLER, 0 },
131 #endif
133 #ifdef SIGILL
134 { SIGILL, NULL_HANDLER, 0, 1},
135 #endif
137 #ifdef SIGTRAP
138 { SIGTRAP, NULL_HANDLER, 0, 1 },
139 #endif
141 #ifdef SIGIOT
142 { SIGIOT, NULL_HANDLER, 0, 1 },
143 #endif
145 #ifdef SIGDANGER
146 { SIGDANGER, NULL_HANDLER, 0 },
147 #endif
149 #ifdef SIGEMT
150 { SIGEMT, NULL_HANDLER, 0 },
151 #endif
153 #ifdef SIGFPE
154 { SIGFPE, NULL_HANDLER, 0, 1 },
155 #endif
157 #ifdef SIGBUS
158 { SIGBUS, NULL_HANDLER, 0, 1 },
159 #endif
161 #ifdef SIGSEGV
162 { SIGSEGV, NULL_HANDLER, 0, 1 },
163 #endif
165 #ifdef SIGSYS
166 { SIGSYS, NULL_HANDLER, 0, 1 },
167 #endif
169 #ifdef SIGPIPE
170 { SIGPIPE, NULL_HANDLER, 0 },
171 #endif
173 #ifdef SIGALRM
174 { SIGALRM, NULL_HANDLER, 0 },
175 #endif
177 #ifdef SIGTERM
178 { SIGTERM, NULL_HANDLER, 0 },
179 #endif
181 /* These don't generate core dumps on anything but Linux, but we're doing
182 this just for Linux anyway. */
183 #ifdef SIGXCPU
184 { SIGXCPU, NULL_HANDLER, 0, 1 },
185 #endif
187 #ifdef SIGXFSZ
188 { SIGXFSZ, NULL_HANDLER, 0, 1 },
189 #endif
191 #ifdef SIGVTALRM
192 { SIGVTALRM, NULL_HANDLER, 0 },
193 #endif
195 #if 0
196 #ifdef SIGPROF
197 { SIGPROF, NULL_HANDLER, 0 },
198 #endif
199 #endif
201 #ifdef SIGLOST
202 { SIGLOST, NULL_HANDLER, 0 },
203 #endif
205 #ifdef SIGUSR1
206 { SIGUSR1, NULL_HANDLER, 0 },
207 #endif
209 #ifdef SIGUSR2
210 { SIGUSR2, NULL_HANDLER, 0 },
211 #endif
214 #define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
216 #define XSIG(x) (terminating_signals[x].signum)
217 #define XHANDLER(x) (terminating_signals[x].orig_handler)
218 #define XSAFLAGS(x) (terminating_signals[x].orig_flags)
219 #define XCOREDUMP(x) (terminating_signals[x].core_dump)
221 static int termsigs_initialized = 0;
223 /* Initialize signals that will terminate the shell to do some
224 unwind protection. For non-interactive shells, we only call
225 this when a trap is defined for EXIT (0) or when trap is run
226 to display signal dispositions. */
227 void
228 initialize_terminating_signals ()
230 register int i;
231 #if defined (HAVE_POSIX_SIGNALS)
232 struct sigaction act, oact;
233 #endif
235 if (termsigs_initialized)
236 return;
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)
243 act.sa_handler = termsig_sighandler;
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++)
251 /* If we've already trapped it, don't do anything. */
252 if (signal_is_trapped (XSIG (i)))
253 continue;
255 sigaction (XSIG (i), &act, &oact);
256 XHANDLER(i) = oact.sa_handler;
257 XSAFLAGS(i) = oact.sa_flags;
258 /* Don't do anything with signals that are ignored at shell entry
259 if the shell is not interactive. */
260 /* XXX - should we do this for interactive shells, too? */
261 if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
263 sigaction (XSIG (i), &oact, &act);
264 set_signal_hard_ignored (XSIG (i));
266 #if defined (SIGPROF) && !defined (_MINIX)
267 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
268 sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
269 #endif /* SIGPROF && !_MINIX */
271 #else /* !HAVE_POSIX_SIGNALS */
273 for (i = 0; i < TERMSIGS_LENGTH; i++)
275 /* If we've already trapped it, don't do anything. */
276 if (signal_is_trapped (XSIG (i)))
277 continue;
279 XHANDLER(i) = signal (XSIG (i), termsig_sighandler);
280 XSAFLAGS(i) = 0;
281 /* Don't do anything with signals that are ignored at shell entry
282 if the shell is not interactive. */
283 /* XXX - should we do this for interactive shells, too? */
284 if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
286 signal (XSIG (i), SIG_IGN);
287 set_signal_hard_ignored (XSIG (i));
289 #ifdef SIGPROF
290 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
291 signal (XSIG (i), XHANDLER (i));
292 #endif
295 #endif /* !HAVE_POSIX_SIGNALS */
297 termsigs_initialized = 1;
300 static void
301 initialize_shell_signals ()
303 if (interactive)
304 initialize_terminating_signals ();
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);
311 # if defined (SIGCHLD)
312 if (sigismember (&top_level_mask, SIGCHLD))
314 sigdelset (&top_level_mask, SIGCHLD);
315 sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
317 # endif
318 #endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
320 /* And, some signals that are specifically ignored by the shell. */
321 set_signal_handler (SIGQUIT, SIG_IGN);
323 if (interactive)
325 set_signal_handler (SIGINT, sigint_sighandler);
326 get_original_signal (SIGTERM);
327 set_signal_handler (SIGTERM, SIG_IGN);
328 set_sigwinch_handler ();
332 void
333 reset_terminating_signals ()
335 register int i;
336 #if defined (HAVE_POSIX_SIGNALS)
337 struct sigaction act;
338 #endif
340 if (termsigs_initialized == 0)
341 return;
343 #if defined (HAVE_POSIX_SIGNALS)
344 act.sa_flags = 0;
345 sigemptyset (&act.sa_mask);
346 for (i = 0; i < TERMSIGS_LENGTH; i++)
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;
353 act.sa_handler = XHANDLER (i);
354 act.sa_flags = XSAFLAGS (i);
355 sigaction (XSIG (i), &act, (struct sigaction *) NULL);
357 #else /* !HAVE_POSIX_SIGNALS */
358 for (i = 0; i < TERMSIGS_LENGTH; i++)
360 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
361 continue;
363 signal (XSIG (i), XHANDLER (i));
365 #endif /* !HAVE_POSIX_SIGNALS */
367 termsigs_initialized = 0;
369 #undef XHANDLER
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 ()
377 /* Clean up string parser environment. */
378 while (parse_and_execute_level)
379 parse_and_execute_cleanup (-1);
381 #if defined (PROCESS_SUBSTITUTION)
382 unlink_fifo_list ();
383 #endif /* PROCESS_SUBSTITUTION */
385 run_unwind_protects ();
386 loop_level = continuing = breaking = funcnest = 0;
387 executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
390 /* What to do when we've been interrupted, and it is safe to handle it. */
391 void
392 throw_to_top_level ()
394 int print_newline = 0;
396 if (interrupt_state)
398 if (last_command_exit_value < 128)
399 last_command_exit_value = 128 + SIGINT;
400 set_pipestatus_from_exit (last_command_exit_value);
401 print_newline = 1;
402 DELINTERRUPT;
405 if (interrupt_state)
406 return;
408 last_command_exit_signal = (last_command_exit_value > 128) ?
409 (last_command_exit_value - 128) : 0;
410 last_command_exit_value |= 128;
411 set_pipestatus_from_exit (last_command_exit_value);
413 /* Run any traps set on SIGINT, mostly for interactive shells */
414 if (signal_is_trapped (SIGINT) && signal_is_pending (SIGINT))
415 run_interrupt_trap (1);
417 /* Clean up string parser environment. */
418 while (parse_and_execute_level)
419 parse_and_execute_cleanup (-1);
421 if (running_trap > 0)
423 run_trap_cleanup (running_trap - 1);
424 running_trap = 0;
427 #if defined (JOB_CONTROL)
428 give_terminal_to (shell_pgrp, 0);
429 #endif /* JOB_CONTROL */
431 /* This needs to stay because jobs.c:make_child() uses it without resetting
432 the signal mask. */
433 restore_sigmask ();
435 reset_parser ();
437 #if defined (READLINE)
438 if (interactive)
439 bushline_reset ();
440 #endif /* READLINE */
442 #if defined (PROCESS_SUBSTITUTION)
443 unlink_fifo_list ();
444 #endif /* PROCESS_SUBSTITUTION */
446 run_unwind_protects ();
447 loop_level = continuing = breaking = funcnest = 0;
448 executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
450 if (interactive && print_newline)
452 fflush (stdout);
453 fprintf (stderr, "\n");
454 fflush (stderr);
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);
465 /* This is just here to isolate the longjmp calls. */
466 void
467 jump_to_top_level (value)
468 int value;
470 sh_longjmp (top_level, value);
473 void
474 restore_sigmask ()
476 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
477 sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
478 #endif
481 sighandler
482 termsig_sighandler (sig)
483 int sig;
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;
527 terminating_signal = sig;
529 if (terminate_immediately)
531 #if defined (HISTORY)
532 /* XXX - will inhibit history file being written */
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;
537 #endif
538 terminate_immediately = 0;
539 termsig_handler (sig);
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
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))
549 bushline_set_event_hook ();
550 #endif
552 SIGRETURN (0);
555 void
556 termsig_handler (sig)
557 int sig;
559 static int handling_termsig = 0;
560 int i, core;
561 sigset_t mask;
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. */
571 /* I don't believe this condition ever tests true. */
572 if (sig == SIGINT && signal_is_trapped (SIGINT))
573 run_interrupt_trap (0);
575 #if defined (HISTORY)
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)
581 maybe_save_shell_history ();
582 #endif /* HISTORY */
584 if (this_shell_builtin == read_builtin)
585 read_tty_cleanup ();
587 #if defined (JOB_CONTROL)
588 if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
589 hangup_all_jobs ();
591 if ((subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)) == 0)
592 end_job_control ();
593 #endif /* JOB_CONTROL */
595 #if defined (PROCESS_SUBSTITUTION)
596 unlink_all_fifos ();
597 # if defined (JOB_CONTROL)
598 procsub_clear ();
599 # endif
600 #endif /* PROCESS_SUBSTITUTION */
602 /* Reset execution context */
603 loop_level = continuing = breaking = funcnest = 0;
604 executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
606 run_exit_trap (); /* XXX - run exit trap possibly in signal context? */
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
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 ();
615 set_signal_handler (sig, SIG_DFL);
617 kill (getpid (), sig);
619 if (dollar_dollar_pid != 1)
620 exit (128+sig); /* just in case the kill fails? */
622 /* We get here only under extraordinary circumstances. */
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++)
633 set_signal_handler (XSIG (i), SIG_DFL);
634 sigdelset (&mask, XSIG (i));
635 if (sig == XSIG (i))
636 core = XCOREDUMP (i);
638 sigprocmask (SIG_SETMASK, &mask, (sigset_t *)NULL);
640 if (core)
641 *((volatile unsigned long *) NULL) = 0xdead0000 + sig; /* SIGSEGV */
643 exit (128+sig);
645 #undef XSIG
647 /* What we really do when SIGINT occurs. */
648 sighandler
649 sigint_sighandler (sig)
650 int sig;
652 #if defined (MUST_REINSTALL_SIGHANDLERS)
653 signal (sig, sigint_sighandler);
654 #endif
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;
661 /* We will get here in interactive shells with job control active; allow
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)
666 last_command_exit_value = 128 + sig;
667 set_pipestatus_from_exit (last_command_exit_value);
668 wait_signal_received = sig;
669 SIGRETURN (0);
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);
677 /* This is no longer used, but this code block remains as a reminder. */
678 if (interrupt_immediately)
680 interrupt_immediately = 0;
681 set_exit_status (128 + sig);
682 throw_to_top_level ();
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 bushline_set_event_hook ();
690 #endif
692 SIGRETURN (0);
695 #if defined (SIGWINCH)
696 sighandler
697 sigwinch_sighandler (sig)
698 int sig;
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);
706 #endif /* SIGWINCH */
708 void
709 set_sigwinch_handler ()
711 #if defined (SIGWINCH)
712 old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler);
713 #endif
716 void
717 unset_sigwinch_handler ()
719 #if defined (SIGWINCH)
720 set_signal_handler (SIGWINCH, old_winch);
721 #endif
724 sighandler
725 sigterm_sighandler (sig)
726 int sig;
728 sigterm_received = 1; /* XXX - counter? */
729 SIGRETURN (0);
732 /* Signal functions used by the rest of the code. */
733 #if !defined (HAVE_POSIX_SIGNALS)
735 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
736 sigprocmask (operation, newset, oldset)
737 int operation, *newset, *oldset;
739 int old, new;
741 if (newset)
742 new = *newset;
743 else
744 new = 0;
746 switch (operation)
748 case SIG_BLOCK:
749 old = sigblock (new);
750 break;
752 case SIG_SETMASK:
753 old = sigsetmask (new);
754 break;
756 default:
757 internal_error (_("sigprocmask: %d: invalid operation"), operation);
760 if (oldset)
761 *oldset = old;
764 #else
766 #if !defined (SA_INTERRUPT)
767 # define SA_INTERRUPT 0
768 #endif
770 #if !defined (SA_RESTART)
771 # define SA_RESTART 0
772 #endif
774 SigHandler *
775 set_signal_handler (sig, handler)
776 int sig;
777 SigHandler *handler;
779 struct sigaction act, oact;
781 act.sa_handler = handler;
782 act.sa_flags = 0;
784 /* XXX - bush-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 */
787 #if defined (SIGCHLD)
788 if (sig == SIGCHLD)
789 act.sa_flags |= SA_RESTART; /* XXX */
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 */
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 */
802 sigemptyset (&act.sa_mask);
803 sigemptyset (&oact.sa_mask);
804 if (sigaction (sig, &act, &oact) == 0)
805 return (oact.sa_handler);
806 else
807 return (SIG_DFL);
809 #endif /* HAVE_POSIX_SIGNALS */