1/* sig.c - interface for shell signal handlers and signal initialization. */
2
3/* Copyright (C) 1994-2006 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 it under
8   the terms of the GNU General Public License as published by the Free
9   Software Foundation; either version 2, or (at your option) any later
10   version.
11
12   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or
14   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   for more details.
16
17   You should have received a copy of the GNU General Public License along
18   with Bash; see the file COPYING.  If not, write to the Free Software
19   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
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
47#if defined (READLINE)
48#  include "bashline.h"
49#endif
50
51#if defined (HISTORY)
52#  include "bashhist.h"
53#endif
54
55extern int last_command_exit_value;
56extern int last_command_exit_signal;
57extern int return_catch_flag;
58extern int loop_level, continuing, breaking;
59extern int parse_and_execute_level, shell_initialized;
60
61/* Non-zero after SIGINT. */
62volatile int interrupt_state = 0;
63
64/* Non-zero after SIGWINCH */
65volatile int sigwinch_received = 0;
66
67/* Set to the value of any terminating signal received. */
68volatile int terminating_signal = 0;
69
70/* The environment at the top-level R-E loop.  We use this in
71   the case of error return. */
72procenv_t top_level;
73
74#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
75/* The signal masks that this shell runs with. */
76sigset_t top_level_mask;
77#endif /* JOB_CONTROL */
78
79/* When non-zero, we throw_to_top_level (). */
80int interrupt_immediately = 0;
81
82/* When non-zero, we call the terminating signal handler immediately. */
83int terminate_immediately = 0;
84
85#if defined (SIGWINCH)
86static SigHandler *old_winch = (SigHandler *)SIG_DFL;
87#endif
88
89static void initialize_shell_signals __P((void));
90
91void
92initialize_signals (reinit)
93     int reinit;
94{
95  initialize_shell_signals ();
96  initialize_job_signals ();
97#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
98  if (reinit == 0)
99    initialize_siglist ();
100#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
101}
102
103/* A structure describing a signal that terminates the shell if not
104   caught.  The orig_handler member is present so children can reset
105   these signals back to their original handlers. */
106struct termsig {
107     int signum;
108     SigHandler *orig_handler;
109     int orig_flags;
110};
111
112#define NULL_HANDLER (SigHandler *)SIG_DFL
113
114/* The list of signals that would terminate the shell if not caught.
115   We catch them, but just so that we can write the history file,
116   and so forth. */
117static struct termsig terminating_signals[] = {
118#ifdef SIGHUP
119{  SIGHUP, NULL_HANDLER, 0 },
120#endif
121
122#ifdef SIGINT
123{  SIGINT, NULL_HANDLER, 0 },
124#endif
125
126#ifdef SIGILL
127{  SIGILL, NULL_HANDLER, 0 },
128#endif
129
130#ifdef SIGTRAP
131{  SIGTRAP, NULL_HANDLER, 0 },
132#endif
133
134#ifdef SIGIOT
135{  SIGIOT, NULL_HANDLER, 0 },
136#endif
137
138#ifdef SIGDANGER
139{  SIGDANGER, NULL_HANDLER, 0 },
140#endif
141
142#ifdef SIGEMT
143{  SIGEMT, NULL_HANDLER, 0 },
144#endif
145
146#ifdef SIGFPE
147{  SIGFPE, NULL_HANDLER, 0 },
148#endif
149
150#ifdef SIGBUS
151{  SIGBUS, NULL_HANDLER, 0 },
152#endif
153
154#ifdef SIGSEGV
155{  SIGSEGV, NULL_HANDLER, 0 },
156#endif
157
158#ifdef SIGSYS
159{  SIGSYS, NULL_HANDLER, 0 },
160#endif
161
162#ifdef SIGPIPE
163{  SIGPIPE, NULL_HANDLER, 0 },
164#endif
165
166#ifdef SIGALRM
167{  SIGALRM, NULL_HANDLER, 0 },
168#endif
169
170#ifdef SIGTERM
171{  SIGTERM, NULL_HANDLER, 0 },
172#endif
173
174#ifdef SIGXCPU
175{  SIGXCPU, NULL_HANDLER, 0 },
176#endif
177
178#ifdef SIGXFSZ
179{  SIGXFSZ, NULL_HANDLER, 0 },
180#endif
181
182#ifdef SIGVTALRM
183{  SIGVTALRM, NULL_HANDLER, 0 },
184#endif
185
186#if 0
187#ifdef SIGPROF
188{  SIGPROF, NULL_HANDLER, 0 },
189#endif
190#endif
191
192#ifdef SIGLOST
193{  SIGLOST, NULL_HANDLER, 0 },
194#endif
195
196#ifdef SIGUSR1
197{  SIGUSR1, NULL_HANDLER, 0 },
198#endif
199
200#ifdef SIGUSR2
201{  SIGUSR2, NULL_HANDLER, 0 },
202#endif
203};
204
205#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
206
207#define XSIG(x) (terminating_signals[x].signum)
208#define XHANDLER(x) (terminating_signals[x].orig_handler)
209#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
210
211static int termsigs_initialized = 0;
212
213/* Initialize signals that will terminate the shell to do some
214   unwind protection.  For non-interactive shells, we only call
215   this when a trap is defined for EXIT (0). */
216void
217initialize_terminating_signals ()
218{
219  register int i;
220#if defined (HAVE_POSIX_SIGNALS)
221  struct sigaction act, oact;
222#endif
223
224  if (termsigs_initialized)
225    return;
226
227  /* The following code is to avoid an expensive call to
228     set_signal_handler () for each terminating_signals.  Fortunately,
229     this is possible in Posix.  Unfortunately, we have to call signal ()
230     on non-Posix systems for each signal in terminating_signals. */
231#if defined (HAVE_POSIX_SIGNALS)
232  act.sa_handler = termsig_sighandler;
233  act.sa_flags = 0;
234  sigemptyset (&act.sa_mask);
235  sigemptyset (&oact.sa_mask);
236  for (i = 0; i < TERMSIGS_LENGTH; i++)
237    sigaddset (&act.sa_mask, XSIG (i));
238  for (i = 0; i < TERMSIGS_LENGTH; i++)
239    {
240      /* If we've already trapped it, don't do anything. */
241      if (signal_is_trapped (XSIG (i)))
242	continue;
243
244      sigaction (XSIG (i), &act, &oact);
245      XHANDLER(i) = oact.sa_handler;
246      XSAFLAGS(i) = oact.sa_flags;
247      /* Don't do anything with signals that are ignored at shell entry
248	 if the shell is not interactive. */
249      if (!interactive_shell && XHANDLER (i) == SIG_IGN)
250	{
251	  sigaction (XSIG (i), &oact, &act);
252	  set_signal_ignored (XSIG (i));
253	}
254#if defined (SIGPROF) && !defined (_MINIX)
255      if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
256	sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
257#endif /* SIGPROF && !_MINIX */
258    }
259
260#else /* !HAVE_POSIX_SIGNALS */
261
262  for (i = 0; i < TERMSIGS_LENGTH; i++)
263    {
264      /* If we've already trapped it, don't do anything. */
265      if (signal_is_trapped (XSIG (i)))
266	continue;
267
268      XHANDLER(i) = signal (XSIG (i), termsig_sighandler);
269      XSAFLAGS(i) = 0;
270      /* Don't do anything with signals that are ignored at shell entry
271	 if the shell is not interactive. */
272      if (!interactive_shell && XHANDLER (i) == SIG_IGN)
273	{
274	  signal (XSIG (i), SIG_IGN);
275	  set_signal_ignored (XSIG (i));
276	}
277#ifdef SIGPROF
278      if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
279	signal (XSIG (i), XHANDLER (i));
280#endif
281    }
282
283#endif /* !HAVE_POSIX_SIGNALS */
284
285  termsigs_initialized = 1;
286}
287
288static void
289initialize_shell_signals ()
290{
291  if (interactive)
292    initialize_terminating_signals ();
293
294#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
295  /* All shells use the signal mask they inherit, and pass it along
296     to child processes.  Children will never block SIGCHLD, though. */
297  sigemptyset (&top_level_mask);
298  sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
299#  if defined (SIGCHLD)
300  sigdelset (&top_level_mask, SIGCHLD);
301#  endif
302#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
303
304  /* And, some signals that are specifically ignored by the shell. */
305  set_signal_handler (SIGQUIT, SIG_IGN);
306
307  if (interactive)
308    {
309      set_signal_handler (SIGINT, sigint_sighandler);
310      set_signal_handler (SIGTERM, SIG_IGN);
311      set_sigwinch_handler ();
312    }
313}
314
315void
316reset_terminating_signals ()
317{
318  register int i;
319#if defined (HAVE_POSIX_SIGNALS)
320  struct sigaction act;
321#endif
322
323  if (termsigs_initialized == 0)
324    return;
325
326#if defined (HAVE_POSIX_SIGNALS)
327  act.sa_flags = 0;
328  sigemptyset (&act.sa_mask);
329  for (i = 0; i < TERMSIGS_LENGTH; i++)
330    {
331      /* Skip a signal if it's trapped or handled specially, because the
332	 trap code will restore the correct value. */
333      if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
334	continue;
335
336      act.sa_handler = XHANDLER (i);
337      act.sa_flags = XSAFLAGS (i);
338      sigaction (XSIG (i), &act, (struct sigaction *) NULL);
339    }
340#else /* !HAVE_POSIX_SIGNALS */
341  for (i = 0; i < TERMSIGS_LENGTH; i++)
342    {
343      if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
344	continue;
345
346      signal (XSIG (i), XHANDLER (i));
347    }
348#endif /* !HAVE_POSIX_SIGNALS */
349}
350#undef XSIG
351#undef XHANDLER
352
353/* Run some of the cleanups that should be performed when we run
354   jump_to_top_level from a builtin command context.  XXX - might want to
355   also call reset_parser here. */
356void
357top_level_cleanup ()
358{
359  /* Clean up string parser environment. */
360  while (parse_and_execute_level)
361    parse_and_execute_cleanup ();
362
363#if defined (PROCESS_SUBSTITUTION)
364  unlink_fifo_list ();
365#endif /* PROCESS_SUBSTITUTION */
366
367  run_unwind_protects ();
368  loop_level = continuing = breaking = 0;
369  return_catch_flag = 0;
370}
371
372/* What to do when we've been interrupted, and it is safe to handle it. */
373void
374throw_to_top_level ()
375{
376  int print_newline = 0;
377
378  if (interrupt_state)
379    {
380      print_newline = 1;
381      DELINTERRUPT;
382    }
383
384  if (interrupt_state)
385    return;
386
387  last_command_exit_signal = (last_command_exit_value > 128) ?
388				(last_command_exit_value - 128) : 0;
389  last_command_exit_value |= 128;
390
391  /* Run any traps set on SIGINT. */
392  run_interrupt_trap ();
393
394  /* Cleanup string parser environment. */
395  while (parse_and_execute_level)
396    parse_and_execute_cleanup ();
397
398#if defined (JOB_CONTROL)
399  give_terminal_to (shell_pgrp, 0);
400#endif /* JOB_CONTROL */
401
402#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
403  /* This should not be necessary on systems using sigsetjmp/siglongjmp. */
404  sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
405#endif
406
407  reset_parser ();
408
409#if defined (READLINE)
410  if (interactive)
411    bashline_reinitialize ();
412#endif /* READLINE */
413
414#if defined (PROCESS_SUBSTITUTION)
415  unlink_fifo_list ();
416#endif /* PROCESS_SUBSTITUTION */
417
418  run_unwind_protects ();
419  loop_level = continuing = breaking = 0;
420  return_catch_flag = 0;
421
422  if (interactive && print_newline)
423    {
424      fflush (stdout);
425      fprintf (stderr, "\n");
426      fflush (stderr);
427    }
428
429  /* An interrupted `wait' command in a script does not exit the script. */
430  if (interactive || (interactive_shell && !shell_initialized) ||
431      (print_newline && signal_is_trapped (SIGINT)))
432    jump_to_top_level (DISCARD);
433  else
434    jump_to_top_level (EXITPROG);
435}
436
437/* This is just here to isolate the longjmp calls. */
438void
439jump_to_top_level (value)
440     int value;
441{
442  longjmp (top_level, value);
443}
444
445sighandler
446termsig_sighandler (sig)
447     int sig;
448{
449  terminating_signal = sig;
450
451  if (terminate_immediately)
452    {
453      terminate_immediately = 0;
454      termsig_handler (sig);
455    }
456
457  SIGRETURN (0);
458}
459
460void
461termsig_handler (sig)
462     int sig;
463{
464  static int handling_termsig = 0;
465
466  /* Simple semaphore to keep this function from being executed multiple
467     times.  Since we no longer are running as a signal handler, we don't
468     block multiple occurrences of the terminating signals while running. */
469  if (handling_termsig)
470    return;
471  handling_termsig = 1;
472  terminating_signal = 0;	/* keep macro from re-testing true. */
473
474  /* I don't believe this condition ever tests true. */
475  if (sig == SIGINT && signal_is_trapped (SIGINT))
476    run_interrupt_trap ();
477
478#if defined (HISTORY)
479  if (interactive_shell && sig != SIGABRT)
480    maybe_save_shell_history ();
481#endif /* HISTORY */
482
483#if defined (JOB_CONTROL)
484  if (interactive && sig == SIGHUP)
485    hangup_all_jobs ();
486  end_job_control ();
487#endif /* JOB_CONTROL */
488
489#if defined (PROCESS_SUBSTITUTION)
490  unlink_fifo_list ();
491#endif /* PROCESS_SUBSTITUTION */
492
493  run_exit_trap ();
494  set_signal_handler (sig, SIG_DFL);
495  kill (getpid (), sig);
496}
497
498/* What we really do when SIGINT occurs. */
499sighandler
500sigint_sighandler (sig)
501     int sig;
502{
503#if defined (MUST_REINSTALL_SIGHANDLERS)
504  signal (sig, sigint_sighandler);
505#endif
506
507  /* interrupt_state needs to be set for the stack of interrupts to work
508     right.  Should it be set unconditionally? */
509  if (interrupt_state == 0)
510    ADDINTERRUPT;
511
512  if (interrupt_immediately)
513    {
514      interrupt_immediately = 0;
515      throw_to_top_level ();
516    }
517
518  SIGRETURN (0);
519}
520
521#if defined (SIGWINCH)
522sighandler
523sigwinch_sighandler (sig)
524     int sig;
525{
526#if defined (MUST_REINSTALL_SIGHANDLERS)
527  set_signal_handler (SIGWINCH, sigwinch_sighandler);
528#endif /* MUST_REINSTALL_SIGHANDLERS */
529  sigwinch_received = 1;
530  SIGRETURN (0);
531}
532#endif /* SIGWINCH */
533
534void
535set_sigwinch_handler ()
536{
537#if defined (SIGWINCH)
538 old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler);
539#endif
540}
541
542void
543unset_sigwinch_handler ()
544{
545#if defined (SIGWINCH)
546  set_signal_handler (SIGWINCH, old_winch);
547#endif
548}
549
550/* Signal functions used by the rest of the code. */
551#if !defined (HAVE_POSIX_SIGNALS)
552
553#if defined (JOB_CONTROL)
554/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
555sigprocmask (operation, newset, oldset)
556     int operation, *newset, *oldset;
557{
558  int old, new;
559
560  if (newset)
561    new = *newset;
562  else
563    new = 0;
564
565  switch (operation)
566    {
567    case SIG_BLOCK:
568      old = sigblock (new);
569      break;
570
571    case SIG_SETMASK:
572      sigsetmask (new);
573      break;
574
575    default:
576      internal_error (_("sigprocmask: %d: invalid operation"), operation);
577    }
578
579  if (oldset)
580    *oldset = old;
581}
582#endif /* JOB_CONTROL */
583
584#else
585
586#if !defined (SA_INTERRUPT)
587#  define SA_INTERRUPT 0
588#endif
589
590#if !defined (SA_RESTART)
591#  define SA_RESTART 0
592#endif
593
594SigHandler *
595set_signal_handler (sig, handler)
596     int sig;
597     SigHandler *handler;
598{
599  struct sigaction act, oact;
600
601  act.sa_handler = handler;
602  act.sa_flags = 0;
603#if 0
604  if (sig == SIGALRM)
605    act.sa_flags |= SA_INTERRUPT;	/* XXX */
606  else
607    act.sa_flags |= SA_RESTART;		/* XXX */
608#endif
609  sigemptyset (&act.sa_mask);
610  sigemptyset (&oact.sa_mask);
611  sigaction (sig, &act, &oact);
612  return (oact.sa_handler);
613}
614#endif /* HAVE_POSIX_SIGNALS */
615