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