]> git.ipfire.org Git - thirdparty/bash.git/blob - trap.c
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[thirdparty/bash.git] / trap.c
1 /* trap.c -- Not the trap command, but useful functions for manipulating
2 those objects. The trap command is in builtins/trap.def. */
3
4 /* Copyright (C) 1987-2018 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #if defined (HAVE_UNISTD_H)
25 # include <unistd.h>
26 #endif
27
28 #include "bashtypes.h"
29 #include "bashansi.h"
30
31 #include <stdio.h>
32 #include <errno.h>
33
34 #include "bashintl.h"
35
36 #include <signal.h>
37
38 #include "trap.h"
39
40 #include "shell.h"
41 #include "execute_cmd.h"
42 #include "flags.h"
43 #include "parser.h"
44 #include "input.h" /* for save_token_state, restore_token_state */
45 #include "jobs.h"
46 #include "signames.h"
47 #include "builtins.h"
48 #include "builtins/common.h"
49 #include "builtins/builtext.h"
50
51 #if defined (READLINE)
52 # include <readline/readline.h>
53 # include "bashline.h"
54 #endif
55
56 #ifndef errno
57 extern int errno;
58 #endif
59
60 /* Flags which describe the current handling state of a signal. */
61 #define SIG_INHERITED 0x0 /* Value inherited from parent. */
62 #define SIG_TRAPPED 0x1 /* Currently trapped. */
63 #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
64 #define SIG_SPECIAL 0x4 /* Treat this signal specially. */
65 #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
66 #define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
67 #define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
68 #define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
69
70 #define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
71
72 /* An array of such flags, one for each signal, describing what the
73 shell will do with a signal. DEBUG_TRAP == NSIG; some code below
74 assumes this. */
75 static int sigmodes[BASH_NSIG];
76
77 static void free_trap_command (int);
78 static void change_signal (int, char *);
79
80 static int _run_trap_internal (int, char *);
81
82 static void free_trap_string (int);
83 static void reset_signal (int);
84 static void restore_signal (int);
85 static void reset_or_restore_signal_handlers (sh_resetsig_func_t *);
86
87 static void trap_if_untrapped (int, char *);
88
89 /* Variables used here but defined in other files. */
90 extern procenv_t alrmbuf;
91
92 extern volatile int from_return_trap;
93
94 extern WORD_LIST *subst_assign_varlist;
95
96 /* The list of things to do originally, before we started trapping. */
97 SigHandler *original_signals[NSIG];
98
99 /* For each signal, a slot for a string, which is a command to be
100 executed when that signal is received. The slot can also contain
101 DEFAULT_SIG, which means do whatever you were going to do before
102 you were so rudely interrupted, or IGNORE_SIG, which says ignore
103 this signal. */
104 char *trap_list[BASH_NSIG];
105
106 /* A bitmap of signals received for which we have trap handlers. */
107 int pending_traps[NSIG];
108
109 /* Set to the number of the signal we're running the trap for + 1.
110 Used in execute_cmd.c and builtins/common.c to clean up when
111 parse_and_execute does not return normally after executing the
112 trap command (e.g., when `return' is executed in the trap command). */
113 int running_trap;
114
115 /* Set to last_command_exit_value before running a trap. */
116 int trap_saved_exit_value;
117
118 /* The (trapped) signal received while executing in the `wait' builtin */
119 int wait_signal_received;
120
121 int trapped_signal_received;
122
123 #define GETORIGSIG(sig) \
124 do { \
125 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
126 set_signal_handler (sig, original_signals[sig]); \
127 if (original_signals[sig] == SIG_IGN) \
128 sigmodes[sig] |= SIG_HARD_IGNORE; \
129 } while (0)
130
131 #define SETORIGSIG(sig,handler) \
132 do { \
133 original_signals[sig] = handler; \
134 if (original_signals[sig] == SIG_IGN) \
135 sigmodes[sig] |= SIG_HARD_IGNORE; \
136 } while (0)
137
138 #define GET_ORIGINAL_SIGNAL(sig) \
139 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
140 GETORIGSIG(sig)
141
142 void
143 initialize_traps ()
144 {
145 register int i;
146
147 initialize_signames();
148
149 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
150 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED;
151 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
152
153 for (i = 1; i < NSIG; i++)
154 {
155 pending_traps[i] = 0;
156 trap_list[i] = (char *)DEFAULT_SIG;
157 sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
158 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
159 }
160
161 /* Show which signals are treated specially by the shell. */
162 #if defined (SIGCHLD)
163 GETORIGSIG (SIGCHLD);
164 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
165 #endif /* SIGCHLD */
166
167 GETORIGSIG (SIGINT);
168 sigmodes[SIGINT] |= SIG_SPECIAL;
169
170 #if defined (__BEOS__)
171 /* BeOS sets SIGINT to SIG_IGN! */
172 original_signals[SIGINT] = SIG_DFL;
173 sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
174 #endif
175
176 GETORIGSIG (SIGQUIT);
177 sigmodes[SIGQUIT] |= SIG_SPECIAL;
178
179 if (interactive)
180 {
181 GETORIGSIG (SIGTERM);
182 sigmodes[SIGTERM] |= SIG_SPECIAL;
183 }
184
185 get_original_tty_job_signals ();
186 }
187
188 #ifdef DEBUG
189 /* Return a printable representation of the trap handler for SIG. */
190 static char *
191 trap_handler_string (sig)
192 int sig;
193 {
194 if (trap_list[sig] == (char *)DEFAULT_SIG)
195 return "DEFAULT_SIG";
196 else if (trap_list[sig] == (char *)IGNORE_SIG)
197 return "IGNORE_SIG";
198 else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
199 return "IMPOSSIBLE_TRAP_HANDLER";
200 else if (trap_list[sig])
201 return trap_list[sig];
202 else
203 return "NULL";
204 }
205 #endif
206
207 /* Return the print name of this signal. */
208 char *
209 signal_name (sig)
210 int sig;
211 {
212 char *ret;
213
214 /* on cygwin32, signal_names[sig] could be null */
215 ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL)
216 ? _("invalid signal number")
217 : signal_names[sig];
218
219 return ret;
220 }
221
222 /* Turn a string into a signal number, or a number into
223 a signal number. If STRING is "2", "SIGINT", or "INT",
224 then (int)2 is returned. Return NO_SIG if STRING doesn't
225 contain a valid signal descriptor. */
226 int
227 decode_signal (string, flags)
228 char *string;
229 int flags;
230 {
231 intmax_t sig;
232 char *name;
233
234 if (legal_number (string, &sig))
235 return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
236
237 #if defined (SIGRTMIN) && defined (SIGRTMAX)
238 if (STREQN (string, "SIGRTMIN+", 9) || ((flags & DSIG_NOCASE) && strncasecmp (string, "SIGRTMIN+", 9) == 0))
239 {
240 if (legal_number (string+9, &sig) && sig >= 0 && sig <= SIGRTMAX - SIGRTMIN)
241 return (SIGRTMIN + sig);
242 else
243 return NO_SIG;
244 }
245 else if (STREQN (string, "RTMIN+", 6) || ((flags & DSIG_NOCASE) && strncasecmp (string, "RTMIN+", 6) == 0))
246 {
247 if (legal_number (string+6, &sig) && sig >= 0 && sig <= SIGRTMAX - SIGRTMIN)
248 return (SIGRTMIN + sig);
249 else
250 return NO_SIG;
251 }
252 #endif /* SIGRTMIN && SIGRTMAX */
253
254 /* A leading `SIG' may be omitted. */
255 for (sig = 0; sig < BASH_NSIG; sig++)
256 {
257 name = signal_names[sig];
258 if (name == 0 || name[0] == '\0')
259 continue;
260
261 /* Check name without the SIG prefix first case sensitively or
262 insensitively depending on whether flags includes DSIG_NOCASE */
263 if (STREQN (name, "SIG", 3))
264 {
265 name += 3;
266
267 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
268 return ((int)sig);
269 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
270 return ((int)sig);
271 /* If we can't use the `SIG' prefix to match, punt on this
272 name now. */
273 else if ((flags & DSIG_SIGPREFIX) == 0)
274 continue;
275 }
276
277 /* Check name with SIG prefix case sensitively or insensitively
278 depending on whether flags includes DSIG_NOCASE */
279 name = signal_names[sig];
280 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
281 return ((int)sig);
282 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
283 return ((int)sig);
284 }
285
286 return (NO_SIG);
287 }
288
289 /* Non-zero when we catch a trapped signal. */
290 static int catch_flag;
291
292 void
293 run_pending_traps ()
294 {
295 register int sig;
296 int old_exit_value, x;
297 WORD_LIST *save_subst_varlist;
298 HASH_TABLE *save_tempenv;
299 sh_parser_state_t pstate;
300 #if defined (ARRAY_VARS)
301 ARRAY *ps;
302 #endif
303
304 if (catch_flag == 0) /* simple optimization */
305 return;
306
307 if (running_trap > 0)
308 {
309 #if defined (DEBUG)
310 internal_warning ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap-1);
311 #endif
312 #if defined (SIGWINCH)
313 if (running_trap == SIGWINCH+1 && pending_traps[SIGWINCH])
314 return; /* no recursive SIGWINCH trap invocations */
315 #endif
316 /* could check for running the trap handler for the same signal here
317 (running_trap == sig+1) */
318 if (evalnest_max > 0 && evalnest > evalnest_max)
319 {
320 internal_error (_("trap handler: maximum trap handler level exceeded (%d)"), evalnest_max);
321 evalnest = 0;
322 jump_to_top_level (DISCARD);
323 }
324 }
325
326 catch_flag = trapped_signal_received = 0;
327
328 /* Preserve $? when running trap. */
329 trap_saved_exit_value = old_exit_value = last_command_exit_value;
330 #if defined (ARRAY_VARS)
331 ps = save_pipestatus_array ();
332 #endif
333
334 for (sig = 1; sig < NSIG; sig++)
335 {
336 /* XXX this could be made into a counter by using
337 while (pending_traps[sig]--) instead of the if statement. */
338 if (pending_traps[sig])
339 {
340 if (running_trap == sig+1)
341 /*continue*/;
342
343 running_trap = sig + 1;
344
345 if (sig == SIGINT)
346 {
347 pending_traps[sig] = 0; /* XXX */
348 /* We don't modify evalnest here, since run_interrupt_trap() calls
349 _run_trap_internal, which does. */
350 run_interrupt_trap (0);
351 CLRINTERRUPT; /* interrupts don't stack */
352 }
353 #if defined (JOB_CONTROL) && defined (SIGCHLD)
354 else if (sig == SIGCHLD &&
355 trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER &&
356 (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0)
357 {
358 sigmodes[SIGCHLD] |= SIG_INPROGRESS;
359 /* We modify evalnest here even though run_sigchld_trap can run
360 the trap action more than once */
361 evalnest++;
362 x = pending_traps[sig];
363 pending_traps[sig] = 0;
364 run_sigchld_trap (x); /* use as counter */
365 running_trap = 0;
366 evalnest--;
367 sigmodes[SIGCHLD] &= ~SIG_INPROGRESS;
368 /* continue here rather than reset pending_traps[SIGCHLD] below in
369 case there are recursive calls to run_pending_traps and children
370 have been reaped while run_sigchld_trap was running. */
371 continue;
372 }
373 else if (sig == SIGCHLD &&
374 trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER &&
375 (sigmodes[SIGCHLD] & SIG_INPROGRESS) != 0)
376 {
377 /* This can happen when run_pending_traps is called while
378 running a SIGCHLD trap handler. */
379 running_trap = 0;
380 /* want to leave pending_traps[SIGCHLD] alone here */
381 continue; /* XXX */
382 }
383 else if (sig == SIGCHLD && (sigmodes[SIGCHLD] & SIG_INPROGRESS))
384 {
385 /* whoops -- print warning? */
386 running_trap = 0; /* XXX */
387 /* want to leave pending_traps[SIGCHLD] alone here */
388 continue;
389 }
390 #endif
391 else if (trap_list[sig] == (char *)DEFAULT_SIG ||
392 trap_list[sig] == (char *)IGNORE_SIG ||
393 trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
394 {
395 /* This is possible due to a race condition. Say a bash
396 process has SIGTERM trapped. A subshell is spawned
397 using { list; } & and the parent does something and kills
398 the subshell with SIGTERM. It's possible for the subshell
399 to set pending_traps[SIGTERM] to 1 before the code in
400 execute_cmd.c eventually calls restore_original_signals
401 to reset the SIGTERM signal handler in the subshell. The
402 next time run_pending_traps is called, pending_traps[SIGTERM]
403 will be 1, but the trap handler in trap_list[SIGTERM] will
404 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
405 Unless we catch this, the subshell will dump core when
406 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
407 usually 0x0. */
408 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
409 sig, trap_list[sig]);
410 if (trap_list[sig] == (char *)DEFAULT_SIG)
411 {
412 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig));
413 kill (getpid (), sig);
414 }
415 }
416 else
417 {
418 /* XXX - should we use save_parser_state/restore_parser_state? */
419 save_parser_state (&pstate);
420 save_subst_varlist = subst_assign_varlist;
421 subst_assign_varlist = 0;
422 save_tempenv = temporary_env;
423 temporary_env = 0; /* traps should not run with temporary env */
424
425 #if defined (JOB_CONTROL)
426 save_pipeline (1); /* XXX only provides one save level */
427 #endif
428 /* XXX - set pending_traps[sig] = 0 here? */
429 pending_traps[sig] = 0;
430 evalnest++;
431 evalstring (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
432 evalnest--;
433 #if defined (JOB_CONTROL)
434 restore_pipeline (1);
435 #endif
436
437 subst_assign_varlist = save_subst_varlist;
438 restore_parser_state (&pstate);
439 temporary_env = save_tempenv;
440 }
441
442 pending_traps[sig] = 0; /* XXX - move before evalstring? */
443 running_trap = 0;
444 }
445 }
446
447 #if defined (ARRAY_VARS)
448 restore_pipestatus_array (ps);
449 #endif
450 last_command_exit_value = old_exit_value;
451 }
452
453 sighandler
454 trap_handler (sig)
455 int sig;
456 {
457 int oerrno;
458
459 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
460 {
461 #if defined (DEBUG)
462 internal_warning ("trap_handler: signal %d: signal not trapped", sig);
463 #endif
464 SIGRETURN (0);
465 }
466
467 if ((sig >= NSIG) ||
468 (trap_list[sig] == (char *)DEFAULT_SIG) ||
469 (trap_list[sig] == (char *)IGNORE_SIG))
470 programming_error (_("trap_handler: bad signal %d"), sig);
471 else
472 {
473 oerrno = errno;
474 #if defined (MUST_REINSTALL_SIGHANDLERS)
475 # if defined (JOB_CONTROL) && defined (SIGCHLD)
476 if (sig != SIGCHLD)
477 # endif /* JOB_CONTROL && SIGCHLD */
478 set_signal_handler (sig, trap_handler);
479 #endif /* MUST_REINSTALL_SIGHANDLERS */
480
481 catch_flag = 1;
482 pending_traps[sig]++;
483 trapped_signal_received = sig;
484
485 if (this_shell_builtin && (this_shell_builtin == wait_builtin))
486 {
487 wait_signal_received = sig;
488 if (interrupt_immediately && wait_intr_flag)
489 sh_longjmp (wait_intr_buf, 1);
490 }
491
492 #if defined (READLINE)
493 /* Set the event hook so readline will call it after the signal handlers
494 finish executing, so if this interrupted character input we can get
495 quick response. */
496 if (RL_ISSTATE (RL_STATE_SIGHANDLER) && interrupt_immediately == 0)
497 bashline_set_event_hook ();
498 #endif
499
500 if (interrupt_immediately)
501 run_pending_traps ();
502
503 errno = oerrno;
504 }
505
506 SIGRETURN (0);
507 }
508
509 int
510 first_pending_trap ()
511 {
512 register int i;
513
514 for (i = 1; i < NSIG; i++)
515 if (pending_traps[i])
516 return i;
517 return -1;
518 }
519
520 /* Return > 0 if any of the "real" signals (not fake signals like EXIT) are
521 trapped. */
522 int
523 any_signals_trapped ()
524 {
525 register int i;
526
527 for (i = 1; i < NSIG; i++)
528 if (sigmodes[i] & SIG_TRAPPED)
529 return i;
530 return -1;
531 }
532
533 void
534 check_signals ()
535 {
536 CHECK_ALRM; /* set by the read builtin */
537 QUIT;
538 }
539
540 /* Convenience functions the rest of the shell can use */
541 void
542 check_signals_and_traps ()
543 {
544 check_signals ();
545
546 run_pending_traps ();
547 }
548
549 #if defined (JOB_CONTROL) && defined (SIGCHLD)
550
551 #ifdef INCLUDE_UNUSED
552 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
553 void
554 set_sigchld_trap (command_string)
555 char *command_string;
556 {
557 set_signal (SIGCHLD, command_string);
558 }
559 #endif
560
561 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
562 is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
563 to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
564 reset the disposition to the default and not have the original signal
565 accidentally restored, undoing the user's command. */
566 void
567 maybe_set_sigchld_trap (command_string)
568 char *command_string;
569 {
570 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
571 set_signal (SIGCHLD, command_string);
572 }
573
574 /* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
575 as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
576 or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
577 void
578 set_impossible_sigchld_trap ()
579 {
580 restore_default_signal (SIGCHLD);
581 change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER);
582 sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */
583 }
584
585 /* Act as if we received SIGCHLD NCHILD times and increment
586 pending_traps[SIGCHLD] by that amount. This allows us to still run the
587 SIGCHLD trap once for each exited child. */
588 void
589 queue_sigchld_trap (nchild)
590 int nchild;
591 {
592 if (nchild > 0)
593 {
594 catch_flag = 1;
595 pending_traps[SIGCHLD] += nchild;
596 trapped_signal_received = SIGCHLD;
597 }
598 }
599 #endif /* JOB_CONTROL && SIGCHLD */
600
601 /* Set a trap for SIG only if SIG is not already trapped. */
602 static inline void
603 trap_if_untrapped (sig, command)
604 int sig;
605 char *command;
606 {
607 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
608 set_signal (sig, command);
609 }
610
611 void
612 set_debug_trap (command)
613 char *command;
614 {
615 set_signal (DEBUG_TRAP, command);
616 }
617
618 /* Separate function to call when functions and sourced files want to restore
619 the original version of the DEBUG trap before returning. Unless the -T
620 option is set, source and shell function execution save the old debug trap
621 and unset the trap. If the function or sourced file changes the DEBUG trap,
622 SIG_TRAPPED will be set and we don't bother restoring the original trap string.
623 This is used by both functions and the source builtin. */
624 void
625 maybe_set_debug_trap (command)
626 char *command;
627 {
628 trap_if_untrapped (DEBUG_TRAP, command);
629 }
630
631 void
632 set_error_trap (command)
633 char *command;
634 {
635 set_signal (ERROR_TRAP, command);
636 }
637
638 void
639 maybe_set_error_trap (command)
640 char *command;
641 {
642 trap_if_untrapped (ERROR_TRAP, command);
643 }
644
645 void
646 set_return_trap (command)
647 char *command;
648 {
649 set_signal (RETURN_TRAP, command);
650 }
651
652 void
653 maybe_set_return_trap (command)
654 char *command;
655 {
656 trap_if_untrapped (RETURN_TRAP, command);
657 }
658
659 #ifdef INCLUDE_UNUSED
660 void
661 set_sigint_trap (command)
662 char *command;
663 {
664 set_signal (SIGINT, command);
665 }
666 #endif
667
668 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
669 things, like waiting for command substitution or executing commands
670 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
671 SigHandler *
672 set_sigint_handler ()
673 {
674 if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
675 return ((SigHandler *)SIG_IGN);
676
677 else if (sigmodes[SIGINT] & SIG_IGNORED)
678 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
679
680 else if (sigmodes[SIGINT] & SIG_TRAPPED)
681 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
682
683 /* The signal is not trapped, so set the handler to the shell's special
684 interrupt handler. */
685 else if (interactive) /* XXX - was interactive_shell */
686 return (set_signal_handler (SIGINT, sigint_sighandler));
687 else
688 return (set_signal_handler (SIGINT, termsig_sighandler));
689 }
690
691 /* Return the correct handler for signal SIG according to the values in
692 sigmodes[SIG]. */
693 SigHandler *
694 trap_to_sighandler (sig)
695 int sig;
696 {
697 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
698 return (SIG_IGN);
699 else if (sigmodes[sig] & SIG_TRAPPED)
700 return (trap_handler);
701 else
702 return (SIG_DFL);
703 }
704
705 /* Set SIG to call STRING as a command. */
706 void
707 set_signal (sig, string)
708 int sig;
709 char *string;
710 {
711 sigset_t set, oset;
712
713 if (SPECIAL_TRAP (sig))
714 {
715 change_signal (sig, savestring (string));
716 if (sig == EXIT_TRAP && interactive == 0)
717 initialize_terminating_signals ();
718 return;
719 }
720
721 /* A signal ignored on entry to the shell cannot be trapped or reset, but
722 no error is reported when attempting to do so. -- Posix.2 */
723 if (sigmodes[sig] & SIG_HARD_IGNORE)
724 return;
725
726 /* Make sure we have original_signals[sig] if the signal has not yet
727 been trapped. */
728 if ((sigmodes[sig] & SIG_TRAPPED) == 0)
729 {
730 /* If we aren't sure of the original value, check it. */
731 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
732 GETORIGSIG (sig);
733 if (original_signals[sig] == SIG_IGN)
734 return;
735 }
736
737 /* Only change the system signal handler if SIG_NO_TRAP is not set.
738 The trap command string is changed in either case. The shell signal
739 handlers for SIGINT and SIGCHLD run the user specified traps in an
740 environment in which it is safe to do so. */
741 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
742 {
743 BLOCK_SIGNAL (sig, set, oset);
744 change_signal (sig, savestring (string));
745 set_signal_handler (sig, trap_handler);
746 UNBLOCK_SIGNAL (oset);
747 }
748 else
749 change_signal (sig, savestring (string));
750 }
751
752 static void
753 free_trap_command (sig)
754 int sig;
755 {
756 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
757 (trap_list[sig] != (char *)IGNORE_SIG) &&
758 (trap_list[sig] != (char *)DEFAULT_SIG) &&
759 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
760 free (trap_list[sig]);
761 }
762
763 /* If SIG has a string assigned to it, get rid of it. Then give it
764 VALUE. */
765 static void
766 change_signal (sig, value)
767 int sig;
768 char *value;
769 {
770 if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
771 free_trap_command (sig);
772 trap_list[sig] = value;
773
774 sigmodes[sig] |= SIG_TRAPPED;
775 if (value == (char *)IGNORE_SIG)
776 sigmodes[sig] |= SIG_IGNORED;
777 else
778 sigmodes[sig] &= ~SIG_IGNORED;
779 if (sigmodes[sig] & SIG_INPROGRESS)
780 sigmodes[sig] |= SIG_CHANGED;
781 }
782
783 void
784 get_original_signal (sig)
785 int sig;
786 {
787 /* If we aren't sure the of the original value, then get it. */
788 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
789 GETORIGSIG (sig);
790 }
791
792 void
793 get_all_original_signals ()
794 {
795 register int i;
796
797 for (i = 1; i < NSIG; i++)
798 GET_ORIGINAL_SIGNAL (i);
799 }
800
801 void
802 set_original_signal (sig, handler)
803 int sig;
804 SigHandler *handler;
805 {
806 if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
807 SETORIGSIG (sig, handler);
808 }
809
810 /* Restore the default action for SIG; i.e., the action the shell
811 would have taken before you used the trap command. This is called
812 from trap_builtin (), which takes care to restore the handlers for
813 the signals the shell treats specially. */
814 void
815 restore_default_signal (sig)
816 int sig;
817 {
818 if (SPECIAL_TRAP (sig))
819 {
820 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
821 (sigmodes[sig] & SIG_INPROGRESS) == 0)
822 free_trap_command (sig);
823 trap_list[sig] = (char *)NULL;
824 sigmodes[sig] &= ~SIG_TRAPPED;
825 if (sigmodes[sig] & SIG_INPROGRESS)
826 sigmodes[sig] |= SIG_CHANGED;
827 return;
828 }
829
830 GET_ORIGINAL_SIGNAL (sig);
831
832 /* A signal ignored on entry to the shell cannot be trapped or reset, but
833 no error is reported when attempting to do so. Thanks Posix.2. */
834 if (sigmodes[sig] & SIG_HARD_IGNORE)
835 return;
836
837 /* If we aren't trapping this signal, don't bother doing anything else. */
838 /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
839 sentinel to determine whether or not disposition is reset to the default
840 while the trap handler is executing. */
841 if (((sigmodes[sig] & SIG_TRAPPED) == 0) &&
842 (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
843 return;
844
845 /* Only change the signal handler for SIG if it allows it. */
846 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
847 set_signal_handler (sig, original_signals[sig]);
848
849 /* Change the trap command in either case. */
850 change_signal (sig, (char *)DEFAULT_SIG);
851
852 /* Mark the signal as no longer trapped. */
853 sigmodes[sig] &= ~SIG_TRAPPED;
854 }
855
856 /* Make this signal be ignored. */
857 void
858 ignore_signal (sig)
859 int sig;
860 {
861 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
862 {
863 change_signal (sig, (char *)IGNORE_SIG);
864 return;
865 }
866
867 GET_ORIGINAL_SIGNAL (sig);
868
869 /* A signal ignored on entry to the shell cannot be trapped or reset.
870 No error is reported when the user attempts to do so. */
871 if (sigmodes[sig] & SIG_HARD_IGNORE)
872 return;
873
874 /* If already trapped and ignored, no change necessary. */
875 if (sigmodes[sig] & SIG_IGNORED)
876 return;
877
878 /* Only change the signal handler for SIG if it allows it. */
879 if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
880 set_signal_handler (sig, SIG_IGN);
881
882 /* Change the trap command in either case. */
883 change_signal (sig, (char *)IGNORE_SIG);
884 }
885
886 /* Handle the calling of "trap 0". The only sticky situation is when
887 the command to be executed includes an "exit". This is why we have
888 to provide our own place for top_level to jump to. */
889 int
890 run_exit_trap ()
891 {
892 char *trap_command;
893 int code, function_code, retval;
894 #if defined (ARRAY_VARS)
895 ARRAY *ps;
896 #endif
897
898 trap_saved_exit_value = last_command_exit_value;
899 #if defined (ARRAY_VARS)
900 ps = save_pipestatus_array ();
901 #endif
902 function_code = 0;
903
904 /* Run the trap only if signal 0 is trapped and not ignored, and we are not
905 currently running in the trap handler (call to exit in the list of
906 commands given to trap 0). */
907 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
908 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
909 {
910 trap_command = savestring (trap_list[EXIT_TRAP]);
911 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
912 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
913
914 retval = trap_saved_exit_value;
915 running_trap = 1;
916
917 code = setjmp_nosigs (top_level);
918
919 /* If we're in a function, make sure return longjmps come here, too. */
920 if (return_catch_flag)
921 function_code = setjmp_nosigs (return_catch);
922
923 if (code == 0 && function_code == 0)
924 {
925 reset_parser ();
926 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
927 }
928 else if (code == ERREXIT)
929 retval = last_command_exit_value;
930 else if (code == EXITPROG)
931 retval = last_command_exit_value;
932 else if (function_code != 0)
933 retval = return_catch_value;
934 else
935 retval = trap_saved_exit_value;
936
937 running_trap = 0;
938 #if defined (ARRAY_VARS)
939 array_dispose (ps);
940 #endif
941
942 return retval;
943 }
944
945 #if defined (ARRAY_VARS)
946 restore_pipestatus_array (ps);
947 #endif
948 return (trap_saved_exit_value);
949 }
950
951 void
952 run_trap_cleanup (sig)
953 int sig;
954 {
955 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
956 }
957
958 #define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
959
960 /* Run a trap command for SIG. SIG is one of the signals the shell treats
961 specially. Returns the exit status of the executed trap command list. */
962 static int
963 _run_trap_internal (sig, tag)
964 int sig;
965 char *tag;
966 {
967 char *trap_command, *old_trap;
968 int trap_exit_value;
969 volatile int save_return_catch_flag, function_code, old_int;
970 int flags;
971 procenv_t save_return_catch;
972 WORD_LIST *save_subst_varlist;
973 HASH_TABLE *save_tempenv;
974 sh_parser_state_t pstate;
975 #if defined (ARRAY_VARS)
976 ARRAY *ps;
977 #endif
978
979 trap_exit_value = function_code = 0;
980 trap_saved_exit_value = last_command_exit_value;
981 /* Run the trap only if SIG is trapped and not ignored, and we are not
982 currently executing in the trap handler. */
983 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
984 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
985 #if 0
986 /* Uncomment this to allow some special signals to recursively execute
987 trap handlers. */
988 (RECURSIVE_SIG (sig) || (sigmodes[sig] & SIG_INPROGRESS) == 0))
989 #else
990 ((sigmodes[sig] & SIG_INPROGRESS) == 0))
991 #endif
992 {
993 old_trap = trap_list[sig];
994 sigmodes[sig] |= SIG_INPROGRESS;
995 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
996 trap_command = savestring (old_trap);
997
998 running_trap = sig + 1;
999
1000 old_int = interrupt_state; /* temporarily suppress pending interrupts */
1001 CLRINTERRUPT;
1002
1003 #if defined (ARRAY_VARS)
1004 ps = save_pipestatus_array ();
1005 #endif
1006
1007 save_parser_state (&pstate);
1008 save_subst_varlist = subst_assign_varlist;
1009 subst_assign_varlist = 0;
1010 save_tempenv = temporary_env;
1011 temporary_env = 0; /* traps should not run with temporary env */
1012
1013 #if defined (JOB_CONTROL)
1014 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1015 save_pipeline (1); /* XXX only provides one save level */
1016 #endif
1017
1018 /* If we're in a function, make sure return longjmps come here, too. */
1019 save_return_catch_flag = return_catch_flag;
1020 if (return_catch_flag)
1021 {
1022 COPY_PROCENV (return_catch, save_return_catch);
1023 function_code = setjmp_nosigs (return_catch);
1024 }
1025
1026 flags = SEVAL_NONINT|SEVAL_NOHIST;
1027 if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
1028 flags |= SEVAL_RESETLINE;
1029 evalnest++;
1030 if (function_code == 0)
1031 {
1032 parse_and_execute (trap_command, tag, flags);
1033 trap_exit_value = last_command_exit_value;
1034 }
1035 else
1036 trap_exit_value = return_catch_value;
1037 evalnest--;
1038
1039 #if defined (JOB_CONTROL)
1040 if (sig != DEBUG_TRAP) /* run_debug_trap does this */
1041 restore_pipeline (1);
1042 #endif
1043
1044 subst_assign_varlist = save_subst_varlist;
1045 restore_parser_state (&pstate);
1046
1047 #if defined (ARRAY_VARS)
1048 restore_pipestatus_array (ps);
1049 #endif
1050
1051 temporary_env = save_tempenv;
1052
1053 sigmodes[sig] &= ~SIG_INPROGRESS;
1054 running_trap = 0;
1055 interrupt_state = old_int;
1056
1057 if (sigmodes[sig] & SIG_CHANGED)
1058 {
1059 #if 0
1060 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
1061 the places where they can be changed using unwind-protects. For
1062 example, look at execute_cmd.c:execute_function(). */
1063 if (SPECIAL_TRAP (sig) == 0)
1064 #endif
1065 free (old_trap);
1066 sigmodes[sig] &= ~SIG_CHANGED;
1067
1068 CHECK_TERMSIG; /* some pathological conditions lead here */
1069 }
1070
1071 if (save_return_catch_flag)
1072 {
1073 return_catch_flag = save_return_catch_flag;
1074 return_catch_value = trap_exit_value;
1075 COPY_PROCENV (save_return_catch, return_catch);
1076 if (function_code)
1077 {
1078 #if 0
1079 from_return_trap = sig == RETURN_TRAP;
1080 #endif
1081 sh_longjmp (return_catch, 1);
1082 }
1083 }
1084 }
1085
1086 return trap_exit_value;
1087 }
1088
1089 int
1090 run_debug_trap ()
1091 {
1092 int trap_exit_value, old_verbose;
1093 pid_t save_pgrp;
1094 #if defined (PGRP_PIPE)
1095 int save_pipe[2];
1096 #endif
1097
1098 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
1099 trap_exit_value = 0;
1100 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
1101 {
1102 #if defined (JOB_CONTROL)
1103 save_pgrp = pipeline_pgrp;
1104 pipeline_pgrp = 0;
1105 save_pipeline (1);
1106 # if defined (PGRP_PIPE)
1107 save_pgrp_pipe (save_pipe, 1);
1108 # endif
1109 stop_making_children ();
1110 #endif
1111
1112 old_verbose = echo_input_at_read;
1113 #if 0 /* not yet */
1114 echo_input_at_read = 0;
1115 #endif
1116
1117 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
1118
1119 echo_input_at_read = old_verbose;
1120
1121 #if defined (JOB_CONTROL)
1122 pipeline_pgrp = save_pgrp;
1123 restore_pipeline (1);
1124 # if defined (PGRP_PIPE)
1125 close_pgrp_pipe ();
1126 restore_pgrp_pipe (save_pipe);
1127 # endif
1128 if (pipeline_pgrp > 0 && ((subshell_environment & (SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0))
1129 give_terminal_to (pipeline_pgrp, 1);
1130
1131 notify_and_cleanup ();
1132 #endif
1133
1134 #if defined (DEBUGGER)
1135 /* If we're in the debugger and the DEBUG trap returns 2 while we're in
1136 a function or sourced script, we force a `return'. */
1137 if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
1138 {
1139 return_catch_value = trap_exit_value;
1140 sh_longjmp (return_catch, 1);
1141 }
1142 #endif
1143 }
1144 return trap_exit_value;
1145 }
1146
1147 void
1148 run_error_trap ()
1149 {
1150 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
1151 _run_trap_internal (ERROR_TRAP, "error trap");
1152 }
1153
1154 void
1155 run_return_trap ()
1156 {
1157 int old_exit_value;
1158
1159 #if 0
1160 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
1161 return;
1162 #endif
1163
1164 if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
1165 {
1166 old_exit_value = last_command_exit_value;
1167 _run_trap_internal (RETURN_TRAP, "return trap");
1168 last_command_exit_value = old_exit_value;
1169 }
1170 }
1171
1172 /* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
1173 declared here to localize the trap functions. */
1174 void
1175 run_interrupt_trap (will_throw)
1176 int will_throw; /* from throw_to_top_level? */
1177 {
1178 if (will_throw && running_trap > 0)
1179 run_trap_cleanup (running_trap - 1);
1180 _run_trap_internal (SIGINT, "interrupt trap");
1181 }
1182
1183 /* Free all the allocated strings in the list of traps and reset the trap
1184 values to the default. Intended to be called from subshells that want
1185 to complete work done by reset_signal_handlers upon execution of a
1186 subsequent `trap' command that changes a signal's disposition. We need
1187 to make sure that we duplicate the behavior of
1188 reset_or_restore_signal_handlers and not change the disposition of signals
1189 that are set to be ignored. */
1190 void
1191 free_trap_strings ()
1192 {
1193 register int i;
1194
1195 for (i = 0; i < NSIG; i++)
1196 {
1197 if (trap_list[i] != (char *)IGNORE_SIG)
1198 free_trap_string (i);
1199 }
1200 for (i = NSIG; i < BASH_NSIG; i++)
1201 {
1202 /* Don't free the trap string if the subshell inherited the trap */
1203 if ((sigmodes[i] & SIG_TRAPPED) == 0)
1204 {
1205 free_trap_string (i);
1206 trap_list[i] = (char *)NULL;
1207 }
1208 }
1209 }
1210
1211 /* Free a trap command string associated with SIG without changing signal
1212 disposition. Intended to be called from free_trap_strings() */
1213 static void
1214 free_trap_string (sig)
1215 int sig;
1216 {
1217 change_signal (sig, (char *)DEFAULT_SIG);
1218 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1219 }
1220
1221 /* Reset the handler for SIG to the original value but leave the trap string
1222 in place. */
1223 static void
1224 reset_signal (sig)
1225 int sig;
1226 {
1227 set_signal_handler (sig, original_signals[sig]);
1228 sigmodes[sig] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1229 }
1230
1231 /* Set the handler signal SIG to the original and free any trap
1232 command associated with it. */
1233 static void
1234 restore_signal (sig)
1235 int sig;
1236 {
1237 set_signal_handler (sig, original_signals[sig]);
1238 change_signal (sig, (char *)DEFAULT_SIG);
1239 sigmodes[sig] &= ~SIG_TRAPPED;
1240 }
1241
1242 static void
1243 reset_or_restore_signal_handlers (reset)
1244 sh_resetsig_func_t *reset;
1245 {
1246 register int i;
1247
1248 /* Take care of the exit trap first */
1249 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
1250 {
1251 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; /* XXX - SIG_INPROGRESS? */
1252 if (reset != reset_signal)
1253 {
1254 free_trap_command (EXIT_TRAP);
1255 trap_list[EXIT_TRAP] = (char *)NULL;
1256 }
1257 }
1258
1259 for (i = 1; i < NSIG; i++)
1260 {
1261 if (sigmodes[i] & SIG_TRAPPED)
1262 {
1263 if (trap_list[i] == (char *)IGNORE_SIG)
1264 set_signal_handler (i, SIG_IGN);
1265 else
1266 (*reset) (i);
1267 }
1268 else if (sigmodes[i] & SIG_SPECIAL)
1269 (*reset) (i);
1270 pending_traps[i] = 0; /* XXX */
1271 }
1272
1273 /* Command substitution and other child processes don't inherit the
1274 debug, error, or return traps. If we're in the debugger, and the
1275 `functrace' or `errtrace' options have been set, then let command
1276 substitutions inherit them. Let command substitution inherit the
1277 RETURN trap if we're in the debugger and tracing functions. */
1278 if (function_trace_mode == 0)
1279 {
1280 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
1281 sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
1282 }
1283 if (error_trace_mode == 0)
1284 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
1285 }
1286
1287 /* Reset trapped signals to their original values, but don't free the
1288 trap strings. Called by the command substitution code and other places
1289 that create a "subshell environment". */
1290 void
1291 reset_signal_handlers ()
1292 {
1293 reset_or_restore_signal_handlers (reset_signal);
1294 }
1295
1296 /* Reset all trapped signals to their original values. Signals set to be
1297 ignored with trap '' SIGNAL should be ignored, so we make sure that they
1298 are. Called by child processes after they are forked. */
1299 void
1300 restore_original_signals ()
1301 {
1302 reset_or_restore_signal_handlers (restore_signal);
1303 }
1304
1305 /* If a trap handler exists for signal SIG, then call it; otherwise just
1306 return failure. Returns 1 if it called the trap handler. */
1307 int
1308 maybe_call_trap_handler (sig)
1309 int sig;
1310 {
1311 /* Call the trap handler for SIG if the signal is trapped and not ignored. */
1312 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
1313 {
1314 switch (sig)
1315 {
1316 case SIGINT:
1317 run_interrupt_trap (0);
1318 break;
1319 case EXIT_TRAP:
1320 run_exit_trap ();
1321 break;
1322 case DEBUG_TRAP:
1323 run_debug_trap ();
1324 break;
1325 case ERROR_TRAP:
1326 run_error_trap ();
1327 break;
1328 default:
1329 trap_handler (sig);
1330 break;
1331 }
1332 return (1);
1333 }
1334 else
1335 return (0);
1336 }
1337
1338 int
1339 signal_is_trapped (sig)
1340 int sig;
1341 {
1342 return (sigmodes[sig] & SIG_TRAPPED);
1343 }
1344
1345 int
1346 signal_is_pending (sig)
1347 int sig;
1348 {
1349 return (pending_traps[sig]);
1350 }
1351
1352 int
1353 signal_is_special (sig)
1354 int sig;
1355 {
1356 return (sigmodes[sig] & SIG_SPECIAL);
1357 }
1358
1359 int
1360 signal_is_ignored (sig)
1361 int sig;
1362 {
1363 return (sigmodes[sig] & SIG_IGNORED);
1364 }
1365
1366 int
1367 signal_is_hard_ignored (sig)
1368 int sig;
1369 {
1370 return (sigmodes[sig] & SIG_HARD_IGNORE);
1371 }
1372
1373 void
1374 set_signal_hard_ignored (sig)
1375 int sig;
1376 {
1377 sigmodes[sig] |= SIG_HARD_IGNORE;
1378 original_signals[sig] = SIG_IGN;
1379 }
1380
1381 void
1382 set_signal_ignored (sig)
1383 int sig;
1384 {
1385 original_signals[sig] = SIG_IGN;
1386 }
1387
1388 int
1389 signal_in_progress (sig)
1390 int sig;
1391 {
1392 return (sigmodes[sig] & SIG_INPROGRESS);
1393 }