Imported from ../bash-2.01.1.tar.gz.
[platform/upstream/bash.git] / sig.c
1 /* sig.c - interface for shell signal handlers and signal initialization. */
2
3 /* Copyright (C) 1994 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include "config.h"
22
23 #include "bashtypes.h"
24
25 #if defined (HAVE_UNISTD_H)
26 #  include <unistd.h>
27 #endif
28
29 #include <stdio.h>
30 #include <signal.h>
31
32 #include "shell.h"
33 #if defined (JOB_CONTROL)
34 #include "jobs.h"
35 #endif /* JOB_CONTROL */
36 #include "siglist.h"
37 #include "sig.h"
38 #include "trap.h"
39
40 #include "builtins/common.h"
41
42 #if defined (READLINE)
43 #  include "bashline.h"
44 #endif
45
46 #if defined (HISTORY)
47 #  include "bashhist.h"
48 #endif
49
50 extern int last_command_exit_value;
51 extern int return_catch_flag;
52 extern int loop_level, continuing, breaking;
53 extern int parse_and_execute_level, shell_initialized;
54 extern int interactive, interactive_shell, login_shell, startup_state;
55
56 /* Non-zero after SIGINT. */
57 int interrupt_state;
58
59 /* The environment at the top-level R-E loop.  We use this in
60    the case of error return. */
61 procenv_t top_level;
62
63 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
64 /* The signal masks that this shell runs with. */
65 sigset_t top_level_mask;
66 #endif /* JOB_CONTROL */
67
68 /* When non-zero, we throw_to_top_level (). */
69 int interrupt_immediately = 0;
70
71 static void initialize_shell_signals ();
72
73 void
74 initialize_signals ()
75 {
76   initialize_shell_signals ();
77   initialize_job_signals ();
78 #if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
79   initialize_siglist ();
80 #endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
81 }
82
83 void
84 reinitialize_signals ()
85 {
86   initialize_shell_signals (1);
87   initialize_job_signals ();
88 }
89
90 /* A structure describing a signal that terminates the shell if not
91    caught.  The orig_handler member is present so children can reset
92    these signals back to their original handlers. */
93 struct termsig {
94      int signum;
95      SigHandler *orig_handler;
96 };
97
98 #define NULL_HANDLER (SigHandler *)SIG_DFL
99
100 /* The list of signals that would terminate the shell if not caught.
101    We catch them, but just so that we can write the history file,
102    and so forth. */
103 static struct termsig terminating_signals[] = {
104 #ifdef SIGHUP
105   SIGHUP, NULL_HANDLER,
106 #endif
107
108 #ifdef SIGINT
109   SIGINT, NULL_HANDLER,
110 #endif
111
112 #ifdef SIGILL
113   SIGILL, NULL_HANDLER,
114 #endif
115
116 #ifdef SIGTRAP
117   SIGTRAP, NULL_HANDLER,
118 #endif
119
120 #ifdef SIGIOT
121   SIGIOT, NULL_HANDLER,
122 #endif
123
124 #ifdef SIGDANGER
125   SIGDANGER, NULL_HANDLER,
126 #endif
127
128 #ifdef SIGEMT
129   SIGEMT, NULL_HANDLER,
130 #endif
131
132 #ifdef SIGFPE
133   SIGFPE, NULL_HANDLER,
134 #endif
135
136 #ifdef SIGBUS
137   SIGBUS, NULL_HANDLER,
138 #endif
139
140 #ifdef SIGSEGV
141   SIGSEGV, NULL_HANDLER,
142 #endif
143
144 #ifdef SIGSYS
145   SIGSYS, NULL_HANDLER,
146 #endif
147
148 #ifdef SIGPIPE
149   SIGPIPE, NULL_HANDLER,
150 #endif
151
152 #ifdef SIGALRM
153   SIGALRM, NULL_HANDLER,
154 #endif
155
156 #ifdef SIGTERM
157   SIGTERM, NULL_HANDLER,
158 #endif
159
160 #ifdef SIGXCPU
161   SIGXCPU, NULL_HANDLER,
162 #endif
163
164 #ifdef SIGXFSZ
165   SIGXFSZ, NULL_HANDLER,
166 #endif
167
168 #ifdef SIGVTALRM
169   SIGVTALRM, NULL_HANDLER,
170 #endif
171
172 #ifdef SIGPROF
173   SIGPROF, NULL_HANDLER,
174 #endif
175
176 #ifdef SIGLOST
177   SIGLOST, NULL_HANDLER,
178 #endif
179
180 #ifdef SIGUSR1
181   SIGUSR1, NULL_HANDLER,
182 #endif
183
184 #ifdef SIGUSR2
185   SIGUSR2, NULL_HANDLER,
186 #endif
187 };
188
189 #define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
190
191 #define XSIG(x) (terminating_signals[x].signum)
192 #define XHANDLER(x) (terminating_signals[x].orig_handler)
193
194 static int termsigs_initialized = 0;
195
196 /* Initialize signals that will terminate the shell to do some
197    unwind protection.  For non-interactive shells, we only call
198    this when a trap is defined for EXIT (0). */
199 void
200 initialize_terminating_signals ()
201 {
202   register int i;
203 #if defined (HAVE_POSIX_SIGNALS)
204   struct sigaction act, oact;
205 #endif
206
207   if (termsigs_initialized)
208     return;
209
210   /* The following code is to avoid an expensive call to
211      set_signal_handler () for each terminating_signals.  Fortunately,
212      this is possible in Posix.  Unfortunately, we have to call signal ()
213      on non-Posix systems for each signal in terminating_signals. */
214 #if defined (HAVE_POSIX_SIGNALS)
215   act.sa_handler = termination_unwind_protect;
216   act.sa_flags = 0;
217   sigemptyset (&act.sa_mask);
218   sigemptyset (&oact.sa_mask);
219   for (i = 0; i < TERMSIGS_LENGTH; i++)
220     sigaddset (&act.sa_mask, XSIG (i));
221   for (i = 0; i < TERMSIGS_LENGTH; i++)
222     {
223       sigaction (XSIG (i), &act, &oact);
224       XHANDLER(i) = oact.sa_handler;
225       /* Don't do anything with signals that are ignored at shell entry
226          if the shell is not interactive. */
227       if (!interactive_shell && XHANDLER (i) == SIG_IGN)
228         {
229           sigaction (XSIG (i), &oact, &act);
230           set_signal_ignored (XSIG (i));
231         }
232 #if defined (SIGPROF)
233       if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
234         sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
235 #endif /* SIGPROF */
236     }
237
238 #else /* !HAVE_POSIX_SIGNALS */
239
240   for (i = 0; i < TERMSIGS_LENGTH; i++)
241     {
242       XHANDLER(i) = signal (XSIG (i), termination_unwind_protect);
243       /* Don't do anything with signals that are ignored at shell entry
244          if the shell is not interactive. */
245       if (!interactive_shell && XHANDLER (i) == SIG_IGN)
246         {
247           signal (XSIG (i), SIG_IGN);
248           set_signal_ignored (XSIG (i));
249         }
250       if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
251         signal (XSIG (i), XHANDLER (i));
252     }
253
254 #endif /* !HAVE_POSIX_SIGNALS */
255
256   termsigs_initialized = 1;
257 }
258
259 static void
260 initialize_shell_signals ()
261 {
262   if (interactive)
263     initialize_terminating_signals ();
264
265 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
266   /* All shells use the signal mask they inherit, and pass it along
267      to child processes.  Children will never block SIGCHLD, though. */
268   sigemptyset (&top_level_mask);
269   sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
270   sigdelset (&top_level_mask, SIGCHLD);
271 #endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
272
273   /* And, some signals that are specifically ignored by the shell. */
274   set_signal_handler (SIGQUIT, SIG_IGN);
275
276   if (interactive)
277     {
278       set_signal_handler (SIGINT, sigint_sighandler);
279       set_signal_handler (SIGTERM, SIG_IGN);
280     }
281 }
282
283 void
284 reset_terminating_signals ()
285 {
286   register int i;
287 #if defined (HAVE_POSIX_SIGNALS)
288   struct sigaction act;
289 #endif
290
291   if (termsigs_initialized == 0)
292     return;
293
294 #if defined (HAVE_POSIX_SIGNALS)
295   act.sa_flags = 0;
296   sigemptyset (&act.sa_mask);
297   for (i = 0; i < TERMSIGS_LENGTH; i++)
298     {
299       /* Skip a signal if it's trapped or handled specially, because the
300          trap code will restore the correct value. */
301       if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
302         continue;
303
304       act.sa_handler = XHANDLER (i);
305       sigaction (XSIG (i), &act, (struct sigaction *) NULL);
306     }
307 #else /* !HAVE_POSIX_SIGNALS */
308   for (i = 0; i < TERMSIGS_LENGTH; i++)
309     {
310       if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
311         continue;
312
313       signal (XSIG (i), XHANDLER (i));
314     }
315 #endif /* !HAVE_POSIX_SIGNALS */
316 }
317 #undef XSIG
318 #undef XHANDLER
319
320 /* What to do when we've been interrupted, and it is safe to handle it. */
321 void
322 throw_to_top_level ()
323 {
324   int print_newline = 0;
325
326   if (interrupt_state)
327     {
328       print_newline = 1;
329       DELINTERRUPT;
330     }
331
332   if (interrupt_state)
333     return;
334
335   last_command_exit_value |= 128;
336
337   /* Run any traps set on SIGINT. */
338   run_interrupt_trap ();
339
340   /* Cleanup string parser environment. */
341   while (parse_and_execute_level)
342     parse_and_execute_cleanup ();
343
344 #if defined (JOB_CONTROL)
345   give_terminal_to (shell_pgrp);
346 #endif /* JOB_CONTROL */
347
348 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
349   /* This should not be necessary on systems using sigsetjmp/siglongjmp. */
350   sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
351 #endif
352
353   reset_parser ();
354
355 #if defined (READLINE)
356   if (interactive)
357     bashline_reinitialize ();
358 #endif /* READLINE */
359
360 #if defined (PROCESS_SUBSTITUTION)
361   unlink_fifo_list ();
362 #endif /* PROCESS_SUBSTITUTION */
363
364   run_unwind_protects ();
365   loop_level = continuing = breaking = 0;
366   return_catch_flag = 0;
367
368   if (interactive && print_newline)
369     {
370       fflush (stdout);
371       fprintf (stderr, "\n");
372       fflush (stderr);
373     }
374
375   /* An interrupted `wait' command in a script does not exit the script. */
376   if (interactive || (interactive_shell && !shell_initialized) ||
377       (print_newline && signal_is_trapped (SIGINT)))
378     jump_to_top_level (DISCARD);
379   else
380     jump_to_top_level (EXITPROG);
381 }
382
383 /* This is just here to isolate the longjmp calls. */
384 void
385 jump_to_top_level (value)
386      int value;
387 {
388   longjmp (top_level, value);
389 }
390
391 sighandler
392 termination_unwind_protect (sig)
393      int sig;
394 {
395   if (sig == SIGINT && signal_is_trapped (SIGINT))
396     run_interrupt_trap ();
397
398 #if defined (HISTORY)
399   if (interactive_shell && sig != SIGABRT)
400     maybe_save_shell_history ();
401 #endif /* HISTORY */
402
403 #if defined (JOB_CONTROL)
404   if (interactive && sig == SIGHUP)
405     hangup_all_jobs ();
406   end_job_control ();
407 #endif /* JOB_CONTROL */
408
409 #if defined (PROCESS_SUBSTITUTION)
410   unlink_fifo_list ();
411 #endif /* PROCESS_SUBSTITUTION */
412
413   run_exit_trap ();
414   set_signal_handler (sig, SIG_DFL);
415   kill (getpid (), sig);
416
417   SIGRETURN (0);
418 }
419
420 /* What we really do when SIGINT occurs. */
421 sighandler
422 sigint_sighandler (sig)
423      int sig;
424 {
425 #if defined (MUST_REINSTALL_SIGHANDLERS)
426   signal (sig, sigint_sighandler);
427 #endif
428
429   /* interrupt_state needs to be set for the stack of interrupts to work
430      right.  Should it be set unconditionally? */
431   if (interrupt_state == 0)
432     ADDINTERRUPT;
433
434   if (interrupt_immediately)
435     {
436       interrupt_immediately = 0;
437       throw_to_top_level ();
438     }
439
440   SIGRETURN (0);
441 }
442
443 /* Signal functions used by the rest of the code. */
444 #if !defined (HAVE_POSIX_SIGNALS)
445
446 #if defined (JOB_CONTROL)
447 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
448 sigprocmask (operation, newset, oldset)
449      int operation, *newset, *oldset;
450 {
451   int old, new;
452
453   if (newset)
454     new = *newset;
455   else
456     new = 0;
457
458   switch (operation)
459     {
460     case SIG_BLOCK:
461       old = sigblock (new);
462       break;
463
464     case SIG_SETMASK:
465       sigsetmask (new);
466       break;
467
468     default:
469       internal_error ("Bad code in sig.c: sigprocmask");
470     }
471
472   if (oldset)
473     *oldset = old;
474 }
475 #endif /* JOB_CONTROL */
476
477 #else
478
479 #if !defined (SA_INTERRUPT)
480 #  define SA_INTERRUPT 0
481 #endif
482
483 #if !defined (SA_RESTART)
484 #  define SA_RESTART 0
485 #endif
486
487 SigHandler *
488 set_signal_handler (sig, handler)
489      int sig;
490      SigHandler *handler;
491 {
492   struct sigaction act, oact;
493
494   act.sa_handler = handler;
495   act.sa_flags = 0;
496 #if 0
497   if (sig == SIGALRM)
498     act.sa_flags |= SA_INTERRUPT;       /* XXX */
499   else
500     act.sa_flags |= SA_RESTART;         /* XXX */
501 #endif
502   sigemptyset (&act.sa_mask);
503   sigemptyset (&oact.sa_mask);
504   sigaction (sig, &act, &oact);
505   return (oact.sa_handler);
506 }
507 #endif /* HAVE_POSIX_SIGNALS */