📄 sig.c
字号:
/* sig.c - interface for shell signal handlers and signal initialization. *//* Copyright (C) 1994-2010 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash. If not, see <http://www.gnu.org/licenses/>.*/#include "config.h"#include "bashtypes.h"#if defined (HAVE_UNISTD_H)# ifdef _MINIX# include <sys/types.h># endif# include <unistd.h>#endif#include <stdio.h>#include <signal.h>#include "bashintl.h"#include "shell.h"#if defined (JOB_CONTROL)#include "jobs.h"#endif /* JOB_CONTROL */#include "siglist.h"#include "sig.h"#include "trap.h"#include "builtins/common.h"#if defined (READLINE)# include "bashline.h"#endif#if defined (HISTORY)# include "bashhist.h"#endifextern int last_command_exit_value;extern int last_command_exit_signal;extern int return_catch_flag;extern int loop_level, continuing, breaking, funcnest;extern int executing_list;extern int comsub_ignore_return;extern int parse_and_execute_level, shell_initialized;#if defined (HISTORY)extern int history_lines_this_session;#endifextern void initialize_siglist ();/* Non-zero after SIGINT. */volatile int interrupt_state = 0;/* Non-zero after SIGWINCH */volatile int sigwinch_received = 0;/* Set to the value of any terminating signal received. */volatile int terminating_signal = 0;/* The environment at the top-level R-E loop. We use this in the case of error return. */procenv_t top_level;#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)/* The signal masks that this shell runs with. */sigset_t top_level_mask;#endif /* JOB_CONTROL *//* When non-zero, we throw_to_top_level (). */int interrupt_immediately = 0;/* When non-zero, we call the terminating signal handler immediately. */int terminate_immediately = 0;#if defined (SIGWINCH)static SigHandler *old_winch = (SigHandler *)SIG_DFL;#endifstatic void initialize_shell_signals __P((void));voidinitialize_signals (reinit) int reinit;{ initialize_shell_signals (); initialize_job_signals ();#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) if (reinit == 0) initialize_siglist ();#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */}/* A structure describing a signal that terminates the shell if not caught. The orig_handler member is present so children can reset these signals back to their original handlers. */struct termsig { int signum; SigHandler *orig_handler; int orig_flags;};#define NULL_HANDLER (SigHandler *)SIG_DFL/* The list of signals that would terminate the shell if not caught. We catch them, but just so that we can write the history file, and so forth. */static struct termsig terminating_signals[] = {#ifdef SIGHUP{ SIGHUP, NULL_HANDLER, 0 },#endif#ifdef SIGINT{ SIGINT, NULL_HANDLER, 0 },#endif#ifdef SIGILL{ SIGILL, NULL_HANDLER, 0 },#endif#ifdef SIGTRAP{ SIGTRAP, NULL_HANDLER, 0 },#endif#ifdef SIGIOT{ SIGIOT, NULL_HANDLER, 0 },#endif#ifdef SIGDANGER{ SIGDANGER, NULL_HANDLER, 0 },#endif#ifdef SIGEMT{ SIGEMT, NULL_HANDLER, 0 },#endif#ifdef SIGFPE{ SIGFPE, NULL_HANDLER, 0 },#endif#ifdef SIGBUS{ SIGBUS, NULL_HANDLER, 0 },#endif#ifdef SIGSEGV{ SIGSEGV, NULL_HANDLER, 0 },#endif#ifdef SIGSYS{ SIGSYS, NULL_HANDLER, 0 },#endif#ifdef SIGPIPE{ SIGPIPE, NULL_HANDLER, 0 },#endif#ifdef SIGALRM{ SIGALRM, NULL_HANDLER, 0 },#endif#ifdef SIGTERM{ SIGTERM, NULL_HANDLER, 0 },#endif#ifdef SIGXCPU{ SIGXCPU, NULL_HANDLER, 0 },#endif#ifdef SIGXFSZ{ SIGXFSZ, NULL_HANDLER, 0 },#endif#ifdef SIGVTALRM{ SIGVTALRM, NULL_HANDLER, 0 },#endif#if 0#ifdef SIGPROF{ SIGPROF, NULL_HANDLER, 0 },#endif#endif#ifdef SIGLOST{ SIGLOST, NULL_HANDLER, 0 },#endif#ifdef SIGUSR1{ SIGUSR1, NULL_HANDLER, 0 },#endif#ifdef SIGUSR2{ SIGUSR2, NULL_HANDLER, 0 },#endif};#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))#define XSIG(x) (terminating_signals[x].signum)#define XHANDLER(x) (terminating_signals[x].orig_handler)#define XSAFLAGS(x) (terminating_signals[x].orig_flags)static int termsigs_initialized = 0;/* Initialize signals that will terminate the shell to do some unwind protection. For non-interactive shells, we only call this when a trap is defined for EXIT (0) or when trap is run to display signal dispositions. */voidinitialize_terminating_signals (){ register int i;#if defined (HAVE_POSIX_SIGNALS) struct sigaction act, oact;#endif if (termsigs_initialized) return; /* The following code is to avoid an expensive call to set_signal_handler () for each terminating_signals. Fortunately, this is possible in Posix. Unfortunately, we have to call signal () on non-Posix systems for each signal in terminating_signals. */#if defined (HAVE_POSIX_SIGNALS) act.sa_handler = termsig_sighandler; act.sa_flags = 0; sigemptyset (&act.sa_mask); sigemptyset (&oact.sa_mask); for (i = 0; i < TERMSIGS_LENGTH; i++) sigaddset (&act.sa_mask, XSIG (i)); for (i = 0; i < TERMSIGS_LENGTH; i++) { /* If we've already trapped it, don't do anything. */ if (signal_is_trapped (XSIG (i))) continue; sigaction (XSIG (i), &act, &oact); XHANDLER(i) = oact.sa_handler; XSAFLAGS(i) = oact.sa_flags; /* Don't do anything with signals that are ignored at shell entry if the shell is not interactive. */ /* XXX - should we do this for interactive shells, too? */ if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) { sigaction (XSIG (i), &oact, &act); set_signal_ignored (XSIG (i)); }#if defined (SIGPROF) && !defined (_MINIX) if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) sigaction (XSIG (i), &oact, (struct sigaction *)NULL);#endif /* SIGPROF && !_MINIX */ }#else /* !HAVE_POSIX_SIGNALS */ for (i = 0; i < TERMSIGS_LENGTH; i++) { /* If we've already trapped it, don't do anything. */ if (signal_is_trapped (XSIG (i))) continue; XHANDLER(i) = signal (XSIG (i), termsig_sighandler); XSAFLAGS(i) = 0; /* Don't do anything with signals that are ignored at shell entry if the shell is not interactive. */ /* XXX - should we do this for interactive shells, too? */ if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) { signal (XSIG (i), SIG_IGN); set_signal_ignored (XSIG (i)); }#ifdef SIGPROF if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) signal (XSIG (i), XHANDLER (i));#endif }#endif /* !HAVE_POSIX_SIGNALS */ termsigs_initialized = 1;}static voidinitialize_shell_signals (){ if (interactive) initialize_terminating_signals ();#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) /* All shells use the signal mask they inherit, and pass it along to child processes. Children will never block SIGCHLD, though. */ sigemptyset (&top_level_mask); sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);# if defined (SIGCHLD) sigdelset (&top_level_mask, SIGCHLD);# endif#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */ /* And, some signals that are specifically ignored by the shell. */ set_signal_handler (SIGQUIT, SIG_IGN); if (interactive) { set_signal_handler (SIGINT, sigint_sighandler); set_signal_handler (SIGTERM, SIG_IGN); set_sigwinch_handler (); }}voidreset_terminating_signals (){ register int i;#if defined (HAVE_POSIX_SIGNALS) struct sigaction act;#endif if (termsigs_initialized == 0) return;#if defined (HAVE_POSIX_SIGNALS) act.sa_flags = 0; sigemptyset (&act.sa_mask); for (i = 0; i < TERMSIGS_LENGTH; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -