]> git.ipfire.org Git - thirdparty/bash.git/blob - sig.c
Bash-5.0 patch 4: the wait builtin without arguments only waits for known children...
[thirdparty/bash.git] / sig.c
1 /* sig.c - interface for shell signal handlers and signal initialization. */
2
3 /* Copyright (C) 1994-2018 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 # 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 ();
59
60 #if !defined (JOB_CONTROL)
61 extern void initialize_job_signals __P((void));
62 #endif
63
64 /* Non-zero after SIGINT. */
65 volatile sig_atomic_t interrupt_state = 0;
66
67 /* Non-zero after SIGWINCH */
68 volatile sig_atomic_t sigwinch_received = 0;
69
70 /* Non-zero after SIGTERM */
71 volatile sig_atomic_t sigterm_received = 0;
72
73 /* Set to the value of any terminating signal received. */
74 volatile sig_atomic_t terminating_signal = 0;
75
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
88 /* When non-zero, we call the terminating signal handler immediately. */
89 int terminate_immediately = 0;
90
91 #if defined (SIGWINCH)
92 static SigHandler *old_winch = (SigHandler *)SIG_DFL;
93 #endif
94
95 static void initialize_shell_signals __P((void));
96
97 void
98 initialize_signals (reinit)
99 int reinit;
100 {
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 */
107 }
108
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;
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
126 { SIGHUP, NULL_HANDLER, 0 },
127 #endif
128
129 #ifdef SIGINT
130 { SIGINT, NULL_HANDLER, 0 },
131 #endif
132
133 #ifdef SIGILL
134 { SIGILL, NULL_HANDLER, 0, 1},
135 #endif
136
137 #ifdef SIGTRAP
138 { SIGTRAP, NULL_HANDLER, 0, 1 },
139 #endif
140
141 #ifdef SIGIOT
142 { SIGIOT, NULL_HANDLER, 0, 1 },
143 #endif
144
145 #ifdef SIGDANGER
146 { SIGDANGER, NULL_HANDLER, 0 },
147 #endif
148
149 #ifdef SIGEMT
150 { SIGEMT, NULL_HANDLER, 0 },
151 #endif
152
153 #ifdef SIGFPE
154 { SIGFPE, NULL_HANDLER, 0, 1 },
155 #endif
156
157 #ifdef SIGBUS
158 { SIGBUS, NULL_HANDLER, 0, 1 },
159 #endif
160
161 #ifdef SIGSEGV
162 { SIGSEGV, NULL_HANDLER, 0, 1 },
163 #endif
164
165 #ifdef SIGSYS
166 { SIGSYS, NULL_HANDLER, 0, 1 },
167 #endif
168
169 #ifdef SIGPIPE
170 { SIGPIPE, NULL_HANDLER, 0 },
171 #endif
172
173 #ifdef SIGALRM
174 { SIGALRM, NULL_HANDLER, 0 },
175 #endif
176
177 #ifdef SIGTERM
178 { SIGTERM, NULL_HANDLER, 0 },
179 #endif
180
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
186
187 #ifdef SIGXFSZ
188 { SIGXFSZ, NULL_HANDLER, 0, 1 },
189 #endif
190
191 #ifdef SIGVTALRM
192 { SIGVTALRM, NULL_HANDLER, 0 },
193 #endif
194
195 #if 0
196 #ifdef SIGPROF
197 { SIGPROF, NULL_HANDLER, 0 },
198 #endif
199 #endif
200
201 #ifdef SIGLOST
202 { SIGLOST, NULL_HANDLER, 0 },
203 #endif
204
205 #ifdef SIGUSR1
206 { SIGUSR1, NULL_HANDLER, 0 },
207 #endif
208
209 #ifdef SIGUSR2
210 { SIGUSR2, NULL_HANDLER, 0 },
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)
218 #define XSAFLAGS(x) (terminating_signals[x].orig_flags)
219 #define XCOREDUMP(x) (terminating_signals[x].core_dump)
220
221 static int termsigs_initialized = 0;
222
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 ()
229 {
230 register int i;
231 #if defined (HAVE_POSIX_SIGNALS)
232 struct sigaction act, oact;
233 #endif
234
235 if (termsigs_initialized)
236 return;
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)
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++)
250 {
251 /* If we've already trapped it, don't do anything. */
252 if (signal_is_trapped (XSIG (i)))
253 continue;
254
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)
262 {
263 sigaction (XSIG (i), &oact, &act);
264 set_signal_hard_ignored (XSIG (i));
265 }
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 */
270 }
271 #else /* !HAVE_POSIX_SIGNALS */
272
273 for (i = 0; i < TERMSIGS_LENGTH; i++)
274 {
275 /* If we've already trapped it, don't do anything. */
276 if (signal_is_trapped (XSIG (i)))
277 continue;
278
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)
285 {
286 signal (XSIG (i), SIG_IGN);
287 set_signal_hard_ignored (XSIG (i));
288 }
289 #ifdef SIGPROF
290 if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
291 signal (XSIG (i), XHANDLER (i));
292 #endif
293 }
294
295 #endif /* !HAVE_POSIX_SIGNALS */
296
297 termsigs_initialized = 1;
298 }
299
300 static void
301 initialize_shell_signals ()
302 {
303 if (interactive)
304 initialize_terminating_signals ();
305
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 sigdelset (&top_level_mask, SIGCHLD);
313 # endif
314 #endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
315
316 /* And, some signals that are specifically ignored by the shell. */
317 set_signal_handler (SIGQUIT, SIG_IGN);
318
319 if (interactive)
320 {
321 set_signal_handler (SIGINT, sigint_sighandler);
322 get_original_signal (SIGTERM);
323 if (signal_is_hard_ignored (SIGTERM) == 0)
324 set_signal_handler (SIGTERM, sigterm_sighandler);
325 set_sigwinch_handler ();
326 }
327 }
328
329 void
330 reset_terminating_signals ()
331 {
332 register int i;
333 #if defined (HAVE_POSIX_SIGNALS)
334 struct sigaction act;
335 #endif
336
337 if (termsigs_initialized == 0)
338 return;
339
340 #if defined (HAVE_POSIX_SIGNALS)
341 act.sa_flags = 0;
342 sigemptyset (&act.sa_mask);
343 for (i = 0; i < TERMSIGS_LENGTH; i++)
344 {
345 /* Skip a signal if it's trapped or handled specially, because the
346 trap code will restore the correct value. */
347 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
348 continue;
349
350 act.sa_handler = XHANDLER (i);
351 act.sa_flags = XSAFLAGS (i);
352 sigaction (XSIG (i), &act, (struct sigaction *) NULL);
353 }
354 #else /* !HAVE_POSIX_SIGNALS */
355 for (i = 0; i < TERMSIGS_LENGTH; i++)
356 {
357 if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
358 continue;
359
360 signal (XSIG (i), XHANDLER (i));
361 }
362 #endif /* !HAVE_POSIX_SIGNALS */
363
364 termsigs_initialized = 0;
365 }
366 #undef XHANDLER
367
368 /* Run some of the cleanups that should be performed when we run
369 jump_to_top_level from a builtin command context. XXX - might want to
370 also call reset_parser here. */
371 void
372 top_level_cleanup ()
373 {
374 /* Clean up string parser environment. */
375 while (parse_and_execute_level)
376 parse_and_execute_cleanup (-1);
377
378 #if defined (PROCESS_SUBSTITUTION)
379 unlink_fifo_list ();
380 #endif /* PROCESS_SUBSTITUTION */
381
382 run_unwind_protects ();
383 loop_level = continuing = breaking = funcnest = 0;
384 executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
385 }
386
387 /* What to do when we've been interrupted, and it is safe to handle it. */
388 void
389 throw_to_top_level ()
390 {
391 int print_newline = 0;
392
393 if (interrupt_state)
394 {
395 if (last_command_exit_value < 128)
396 last_command_exit_value = 128 + SIGINT;
397 print_newline = 1;
398 DELINTERRUPT;
399 }
400
401 if (interrupt_state)
402 return;
403
404 last_command_exit_signal = (last_command_exit_value > 128) ?
405 (last_command_exit_value - 128) : 0;
406 last_command_exit_value |= 128;
407
408 /* Run any traps set on SIGINT, mostly for interactive shells */
409 if (signal_is_trapped (SIGINT))
410 run_interrupt_trap (1);
411
412 /* Clean up string parser environment. */
413 while (parse_and_execute_level)
414 parse_and_execute_cleanup (-1);
415
416 if (running_trap > 0)
417 run_trap_cleanup (running_trap - 1);
418
419 #if defined (JOB_CONTROL)
420 give_terminal_to (shell_pgrp, 0);
421 #endif /* JOB_CONTROL */
422
423 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
424 /* This needs to stay because jobs.c:make_child() uses it without resetting
425 the signal mask. */
426 sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
427 #endif
428
429 reset_parser ();
430
431 #if defined (READLINE)
432 if (interactive)
433 bashline_reset ();
434 #endif /* READLINE */
435
436 #if defined (PROCESS_SUBSTITUTION)
437 unlink_fifo_list ();
438 #endif /* PROCESS_SUBSTITUTION */
439
440 run_unwind_protects ();
441 loop_level = continuing = breaking = funcnest = 0;
442 executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
443
444 if (interactive && print_newline)
445 {
446 fflush (stdout);
447 fprintf (stderr, "\n");
448 fflush (stderr);
449 }
450
451 /* An interrupted `wait' command in a script does not exit the script. */
452 if (interactive || (interactive_shell && !shell_initialized) ||
453 (print_newline && signal_is_trapped (SIGINT)))
454 jump_to_top_level (DISCARD);
455 else
456 jump_to_top_level (EXITPROG);
457 }
458
459 /* This is just here to isolate the longjmp calls. */
460 void
461 jump_to_top_level (value)
462 int value;
463 {
464 sh_longjmp (top_level, value);
465 }
466
467 sighandler
468 termsig_sighandler (sig)
469 int sig;
470 {
471 /* If we get called twice with the same signal before handling it,
472 terminate right away. */
473 if (
474 #ifdef SIGHUP
475 sig != SIGHUP &&
476 #endif
477 #ifdef SIGINT
478 sig != SIGINT &&
479 #endif
480 #ifdef SIGDANGER
481 sig != SIGDANGER &&
482 #endif
483 #ifdef SIGPIPE
484 sig != SIGPIPE &&
485 #endif
486 #ifdef SIGALRM
487 sig != SIGALRM &&
488 #endif
489 #ifdef SIGTERM
490 sig != SIGTERM &&
491 #endif
492 #ifdef SIGXCPU
493 sig != SIGXCPU &&
494 #endif
495 #ifdef SIGXFSZ
496 sig != SIGXFSZ &&
497 #endif
498 #ifdef SIGVTALRM
499 sig != SIGVTALRM &&
500 #endif
501 #ifdef SIGLOST
502 sig != SIGLOST &&
503 #endif
504 #ifdef SIGUSR1
505 sig != SIGUSR1 &&
506 #endif
507 #ifdef SIGUSR2
508 sig != SIGUSR2 &&
509 #endif
510 sig == terminating_signal)
511 terminate_immediately = 1;
512
513 terminating_signal = sig;
514
515 /* XXX - should this also trigger when interrupt_immediately is set? */
516 if (terminate_immediately)
517 {
518 #if defined (HISTORY)
519 /* XXX - will inhibit history file being written */
520 # if defined (READLINE)
521 if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0))
522 # endif
523 history_lines_this_session = 0;
524 #endif
525 terminate_immediately = 0;
526 termsig_handler (sig);
527 }
528
529 #if defined (READLINE)
530 /* Set the event hook so readline will call it after the signal handlers
531 finish executing, so if this interrupted character input we can get
532 quick response. If readline is active or has modified the terminal we
533 need to set this no matter what the signal is, though the check for
534 RL_STATE_TERMPREPPED is possibly redundant. */
535 if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED))
536 bashline_set_event_hook ();
537 #endif
538
539 SIGRETURN (0);
540 }
541
542 void
543 termsig_handler (sig)
544 int sig;
545 {
546 static int handling_termsig = 0;
547 int i, core;
548 sigset_t mask;
549
550 /* Simple semaphore to keep this function from being executed multiple
551 times. Since we no longer are running as a signal handler, we don't
552 block multiple occurrences of the terminating signals while running. */
553 if (handling_termsig)
554 return;
555 handling_termsig = 1;
556 terminating_signal = 0; /* keep macro from re-testing true. */
557
558 /* I don't believe this condition ever tests true. */
559 if (sig == SIGINT && signal_is_trapped (SIGINT))
560 run_interrupt_trap (0);
561
562 #if defined (HISTORY)
563 /* If we don't do something like this, the history will not be saved when
564 an interactive shell is running in a terminal window that gets closed
565 with the `close' button. We can't test for RL_STATE_READCMD because
566 readline no longer handles SIGTERM synchronously. */
567 if (interactive_shell && interactive && (sig == SIGHUP || sig == SIGTERM) && remember_on_history)
568 maybe_save_shell_history ();
569 #endif /* HISTORY */
570
571 if (this_shell_builtin == read_builtin)
572 read_tty_cleanup ();
573
574 #if defined (JOB_CONTROL)
575 if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
576 hangup_all_jobs ();
577
578 if ((subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)) == 0)
579 end_job_control ();
580 #endif /* JOB_CONTROL */
581
582 #if defined (PROCESS_SUBSTITUTION)
583 unlink_fifo_list ();
584 #endif /* PROCESS_SUBSTITUTION */
585
586 /* Reset execution context */
587 loop_level = continuing = breaking = funcnest = 0;
588 executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
589
590 run_exit_trap (); /* XXX - run exit trap possibly in signal context? */
591
592 /* We don't change the set of blocked signals. If a user starts the shell
593 with a terminating signal blocked, we won't get here (and if by some
594 magic chance we do, we'll exit below). */
595 set_signal_handler (sig, SIG_DFL);
596
597 kill (getpid (), sig);
598
599 if (dollar_dollar_pid != 1)
600 exit (128+sig); /* just in case the kill fails? */
601
602 /* We get here only under extraordinary circumstances. */
603
604 /* We are PID 1, and the kill above failed to kill the process. We assume
605 this means that we are running as an init process in a pid namespace
606 on Linux. In this case, we can't send ourselves a fatal signal, so we
607 determine whether or not we should have generated a core dump with the
608 kill call and attempt to trick the kernel into generating one if
609 necessary. */
610 sigprocmask (SIG_SETMASK, (sigset_t *)NULL, &mask);
611 for (i = core = 0; i < TERMSIGS_LENGTH; i++)
612 {
613 set_signal_handler (XSIG (i), SIG_DFL);
614 sigdelset (&mask, XSIG (i));
615 if (sig == XSIG (i))
616 core = XCOREDUMP (i);
617 }
618 sigprocmask (SIG_SETMASK, &mask, (sigset_t *)NULL);
619
620 if (core)
621 *((volatile unsigned long *) NULL) = 0xdead0000 + sig; /* SIGSEGV */
622
623 exit (128+sig);
624 }
625 #undef XSIG
626
627 /* What we really do when SIGINT occurs. */
628 sighandler
629 sigint_sighandler (sig)
630 int sig;
631 {
632 #if defined (MUST_REINSTALL_SIGHANDLERS)
633 signal (sig, sigint_sighandler);
634 #endif
635
636 /* interrupt_state needs to be set for the stack of interrupts to work
637 right. Should it be set unconditionally? */
638 if (interrupt_state == 0)
639 ADDINTERRUPT;
640
641 /* We will get here in interactive shells with job control active; allow
642 an interactive wait to be interrupted. wait_intr_flag is only set during
643 the execution of the wait builtin and when wait_intr_buf is valid. */
644 if (wait_intr_flag)
645 {
646 last_command_exit_value = 128 + sig;
647 wait_signal_received = sig;
648 SIGRETURN (0);
649 }
650
651 if (interrupt_immediately)
652 {
653 interrupt_immediately = 0;
654 last_command_exit_value = 128 + sig;
655 throw_to_top_level ();
656 }
657 #if defined (READLINE)
658 /* Set the event hook so readline will call it after the signal handlers
659 finish executing, so if this interrupted character input we can get
660 quick response. */
661 else if (RL_ISSTATE (RL_STATE_SIGHANDLER))
662 bashline_set_event_hook ();
663 #endif
664
665 SIGRETURN (0);
666 }
667
668 #if defined (SIGWINCH)
669 sighandler
670 sigwinch_sighandler (sig)
671 int sig;
672 {
673 #if defined (MUST_REINSTALL_SIGHANDLERS)
674 set_signal_handler (SIGWINCH, sigwinch_sighandler);
675 #endif /* MUST_REINSTALL_SIGHANDLERS */
676 sigwinch_received = 1;
677 SIGRETURN (0);
678 }
679 #endif /* SIGWINCH */
680
681 void
682 set_sigwinch_handler ()
683 {
684 #if defined (SIGWINCH)
685 old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler);
686 #endif
687 }
688
689 void
690 unset_sigwinch_handler ()
691 {
692 #if defined (SIGWINCH)
693 set_signal_handler (SIGWINCH, old_winch);
694 #endif
695 }
696
697 sighandler
698 sigterm_sighandler (sig)
699 int sig;
700 {
701 sigterm_received = 1; /* XXX - counter? */
702 SIGRETURN (0);
703 }
704
705 /* Signal functions used by the rest of the code. */
706 #if !defined (HAVE_POSIX_SIGNALS)
707
708 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
709 sigprocmask (operation, newset, oldset)
710 int operation, *newset, *oldset;
711 {
712 int old, new;
713
714 if (newset)
715 new = *newset;
716 else
717 new = 0;
718
719 switch (operation)
720 {
721 case SIG_BLOCK:
722 old = sigblock (new);
723 break;
724
725 case SIG_SETMASK:
726 old = sigsetmask (new);
727 break;
728
729 default:
730 internal_error (_("sigprocmask: %d: invalid operation"), operation);
731 }
732
733 if (oldset)
734 *oldset = old;
735 }
736
737 #else
738
739 #if !defined (SA_INTERRUPT)
740 # define SA_INTERRUPT 0
741 #endif
742
743 #if !defined (SA_RESTART)
744 # define SA_RESTART 0
745 #endif
746
747 SigHandler *
748 set_signal_handler (sig, handler)
749 int sig;
750 SigHandler *handler;
751 {
752 struct sigaction act, oact;
753
754 act.sa_handler = handler;
755 act.sa_flags = 0;
756
757 /* XXX - bash-4.2 */
758 /* We don't want a child death to interrupt interruptible system calls, even
759 if we take the time to reap children */
760 #if defined (SIGCHLD)
761 if (sig == SIGCHLD)
762 act.sa_flags |= SA_RESTART; /* XXX */
763 #endif
764 /* Let's see if we can keep SIGWINCH from interrupting interruptible system
765 calls, like open(2)/read(2)/write(2) */
766 #if defined (SIGWINCH)
767 if (sig == SIGWINCH)
768 act.sa_flags |= SA_RESTART; /* XXX */
769 #endif
770 /* If we're installing a SIGTERM handler for interactive shells, we want
771 it to be as close to SIG_IGN as possible. */
772 if (sig == SIGTERM && handler == sigterm_sighandler)
773 act.sa_flags |= SA_RESTART; /* XXX */
774
775 sigemptyset (&act.sa_mask);
776 sigemptyset (&oact.sa_mask);
777 if (sigaction (sig, &act, &oact) == 0)
778 return (oact.sa_handler);
779 else
780 return (SIG_DFL);
781 }
782 #endif /* HAVE_POSIX_SIGNALS */