📄 trap.c
字号:
/* trap.c -- Not the trap command, but useful functions for manipulating those objects. The trap command is in builtins/trap.def. *//* Copyright (C) 1987-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"#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#include "bashtypes.h"#include "bashansi.h"#include <stdio.h>#include <errno.h>#include "bashintl.h"#include "trap.h"#include "shell.h"#include "flags.h"#include "input.h" /* for save_token_state, restore_token_state */#include "jobs.h"#include "signames.h"#include "builtins.h"#include "builtins/common.h"#include "builtins/builtext.h"#ifndef errnoextern int errno;#endif/* Flags which describe the current handling state of a signal. */#define SIG_INHERITED 0x0 /* Value inherited from parent. */#define SIG_TRAPPED 0x1 /* Currently trapped. */#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */#define SIG_SPECIAL 0x4 /* Treat this signal specially. */#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)/* An array of such flags, one for each signal, describing what the shell will do with a signal. DEBUG_TRAP == NSIG; some code below assumes this. */static int sigmodes[BASH_NSIG];static void free_trap_command __P((int));static void change_signal __P((int, char *));static void get_original_signal __P((int));static int _run_trap_internal __P((int, char *));static void free_trap_string __P((int));static void reset_signal __P((int));static void restore_signal __P((int));static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));/* Variables used here but defined in other files. */extern int last_command_exit_value;extern int line_number;extern char *this_command_name;extern sh_builtin_func_t *this_shell_builtin;extern procenv_t wait_intr_buf;extern int return_catch_flag, return_catch_value;extern int subshell_level;extern WORD_LIST *subst_assign_varlist;/* The list of things to do originally, before we started trapping. */SigHandler *original_signals[NSIG];/* For each signal, a slot for a string, which is a command to be executed when that signal is recieved. The slot can also contain DEFAULT_SIG, which means do whatever you were going to do before you were so rudely interrupted, or IGNORE_SIG, which says ignore this signal. */char *trap_list[BASH_NSIG];/* A bitmap of signals received for which we have trap handlers. */int pending_traps[NSIG];/* Set to the number of the signal we're running the trap for + 1. Used in execute_cmd.c and builtins/common.c to clean up when parse_and_execute does not return normally after executing the trap command (e.g., when `return' is executed in the trap command). */int running_trap;/* Set to last_command_exit_value before running a trap. */int trap_saved_exit_value;/* The (trapped) signal received while executing in the `wait' builtin */int wait_signal_received;#define GETORIGSIG(sig) \ do { \ original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \ set_signal_handler (sig, original_signals[sig]); \ if (original_signals[sig] == SIG_IGN) \ sigmodes[sig] |= SIG_HARD_IGNORE; \ } while (0)#define SETORIGSIG(sig,handler) \ do { \ original_signals[sig] = handler; \ if (original_signals[sig] == SIG_IGN) \ sigmodes[sig] |= SIG_HARD_IGNORE; \ } while (0)#define GET_ORIGINAL_SIGNAL(sig) \ if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ GETORIGSIG(sig)voidinitialize_traps (){ register int i; initialize_signames(); trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED; original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER; for (i = 1; i < NSIG; i++) { pending_traps[i] = 0; trap_list[i] = (char *)DEFAULT_SIG; sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */ original_signals[i] = IMPOSSIBLE_TRAP_HANDLER; } /* Show which signals are treated specially by the shell. */#if defined (SIGCHLD) GETORIGSIG (SIGCHLD); sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);#endif /* SIGCHLD */ GETORIGSIG (SIGINT); sigmodes[SIGINT] |= SIG_SPECIAL;#if defined (__BEOS__) /* BeOS sets SIGINT to SIG_IGN! */ original_signals[SIGINT] = SIG_DFL; sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;#endif GETORIGSIG (SIGQUIT); sigmodes[SIGQUIT] |= SIG_SPECIAL; if (interactive) { GETORIGSIG (SIGTERM); sigmodes[SIGTERM] |= SIG_SPECIAL; }}#ifdef INCLUDE_UNUSED/* Return a printable representation of the trap handler for SIG. */static char *trap_handler_string (sig) int sig;{ if (trap_list[sig] == (char *)DEFAULT_SIG) return "DEFAULT_SIG"; else if (trap_list[sig] == (char *)IGNORE_SIG) return "IGNORE_SIG"; else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) return "IMPOSSIBLE_TRAP_HANDLER"; else if (trap_list[sig]) return trap_list[sig]; else return "NULL";}#endif/* Return the print name of this signal. */char *signal_name (sig) int sig;{ char *ret; /* on cygwin32, signal_names[sig] could be null */ ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL) ? _("invalid signal number") : signal_names[sig]; return ret;}/* Turn a string into a signal number, or a number into a signal number. If STRING is "2", "SIGINT", or "INT", then (int)2 is returned. Return NO_SIG if STRING doesn't contain a valid signal descriptor. */intdecode_signal (string, flags) char *string; int flags;{ intmax_t sig; char *name; if (legal_number (string, &sig)) return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG); /* A leading `SIG' may be omitted. */ for (sig = 0; sig < BASH_NSIG; sig++) { name = signal_names[sig]; if (name == 0 || name[0] == '\0') continue; /* Check name without the SIG prefix first case sensitivly or insensitively depending on whether flags includes DSIG_NOCASE */ if (STREQN (name, "SIG", 3)) { name += 3; if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) return ((int)sig); else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) return ((int)sig); /* If we can't use the `SIG' prefix to match, punt on this name now. */ else if ((flags & DSIG_SIGPREFIX) == 0) continue; } /* Check name with SIG prefix case sensitively or insensitively depending on whether flags includes DSIG_NOCASE */ name = signal_names[sig]; if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) return ((int)sig); else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) return ((int)sig); } return (NO_SIG);}/* Non-zero when we catch a trapped signal. */static int catch_flag;voidrun_pending_traps (){ register int sig; int old_exit_value, *token_state; WORD_LIST *save_subst_varlist;#if defined (ARRAY_VARS) ARRAY *ps;#endif if (catch_flag == 0) /* simple optimization */ return; catch_flag = 0; /* Preserve $? when running trap. */ old_exit_value = last_command_exit_value;#if defined (ARRAY_VARS) ps = save_pipestatus_array ();#endif for (sig = 1; sig < NSIG; sig++) { /* XXX this could be made into a counter by using while (pending_traps[sig]--) instead of the if statement. */ if (pending_traps[sig]) {#if defined (HAVE_POSIX_SIGNALS) sigset_t set, oset; sigemptyset (&set); sigemptyset (&oset); sigaddset (&set, sig); sigprocmask (SIG_BLOCK, &set, &oset);#else# if defined (HAVE_BSD_SIGNALS) int oldmask = sigblock (sigmask (sig));# endif#endif /* HAVE_POSIX_SIGNALS */ if (sig == SIGINT) { run_interrupt_trap (); CLRINTERRUPT; }#if defined (JOB_CONTROL) && defined (SIGCHLD) else if (sig == SIGCHLD && trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER && (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0) { run_sigchld_trap (pending_traps[sig]); /* use as counter */ }#endif else if (trap_list[sig] == (char *)DEFAULT_SIG || trap_list[sig] == (char *)IGNORE_SIG || trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) { /* This is possible due to a race condition. Say a bash process has SIGTERM trapped. A subshell is spawned using { list; } & and the parent does something and kills the subshell with SIGTERM. It's possible for the subshell to set pending_traps[SIGTERM] to 1 before the code in execute_cmd.c eventually calls restore_original_signals to reset the SIGTERM signal handler in the subshell. The next time run_pending_traps is called, pending_traps[SIGTERM] will be 1, but the trap handler in trap_list[SIGTERM] will be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG). Unless we catch this, the subshell will dump core when trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is usually 0x0. */ internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"), sig, trap_list[sig]); if (trap_list[sig] == (char *)DEFAULT_SIG) { internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig)); kill (getpid (), sig); } } else { token_state = save_token_state (); save_subst_varlist = subst_assign_varlist; subst_assign_varlist = 0; parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE); restore_token_state (token_state); free (token_state); subst_assign_varlist = save_subst_varlist; } pending_traps[sig] = 0;#if defined (HAVE_POSIX_SIGNALS) sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);#else# if defined (HAVE_BSD_SIGNALS) sigsetmask (oldmask);# endif#endif /* POSIX_VERSION */ } }#if defined (ARRAY_VARS) restore_pipestatus_array (ps);#endif last_command_exit_value = old_exit_value;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -