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