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