X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Freadline%2Fsignals.c;h=48dd885fbcd052aff1e255799b0b053cabd9316a;hb=3185942a5234e26ab13fa02f9c51d340cec514f8;hp=2fe79532d8d17a63ffec53c39db47d24485e40db;hpb=ccc6cda312fea9f0468ee65b8f368e9653e1380b;p=platform%2Fupstream%2Fbash.git diff --git a/lib/readline/signals.c b/lib/readline/signals.c index 2fe7953..48dd885 100644 --- a/lib/readline/signals.c +++ b/lib/readline/signals.c @@ -1,24 +1,24 @@ /* signals.c -- signal handling support for readline. */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. - The GNU Readline Library 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 1, or + Readline 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. - The GNU Readline Library 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 + Readline 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. - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 675 Mass Ave, Cambridge, MA 02139, USA. */ + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + #define READLINE_LIBRARY #if defined (HAVE_CONFIG_H) @@ -40,26 +40,13 @@ # include #endif /* GWINSZ_IN_SYS_IOCTL */ -#if defined (__GO32__) -# undef HANDLE_SIGNALS -#endif /* __GO32__ */ - -#if defined (HANDLE_SIGNALS) /* Some standard library routines. */ #include "readline.h" #include "history.h" -extern int readline_echoing_p; -extern int rl_pending_input; -extern int _rl_meta_flag; +#include "rlprivate.h" -extern void free_undo_list (); -extern void _rl_get_screen_size (); -extern void _rl_redisplay_after_sigwinch (); -extern void _rl_clean_up_for_exit (); -extern void _rl_kill_kbd_macro (); -extern void _rl_init_argument (); -extern void rl_deprep_terminal (), rl_prep_terminal (); +#if defined (HANDLE_SIGNALS) #if !defined (RETSIGTYPE) # if defined (VOID_SIGHANDLER) @@ -75,32 +62,59 @@ extern void rl_deprep_terminal (), rl_prep_terminal (); # define SIGHANDLER_RETURN return (0) #endif -/* This typedef is equivalant to the one for Function; it allows us +/* This typedef is equivalent to the one for Function; it allows us to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ typedef RETSIGTYPE SigHandler (); -static SigHandler *rl_set_sighandler (); - -/* **************************************************************** */ -/* */ -/* Signal Handling */ -/* */ -/* **************************************************************** */ - #if defined (HAVE_POSIX_SIGNALS) typedef struct sigaction sighandler_cxt; # define rl_sigaction(s, nh, oh) sigaction(s, nh, oh) #else -typedef struct { SigHandler *sa_handler; } sighandler_cxt; +typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt; # define sigemptyset(m) #endif /* !HAVE_POSIX_SIGNALS */ -static sighandler_cxt old_int, old_alrm; +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + +static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); +static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); + +/* Exported variables for use by applications. */ + +/* If non-zero, readline will install its own signal handlers for + SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ +int rl_catch_signals = 1; + +/* If non-zero, readline will install a signal handler for SIGWINCH. */ +#ifdef SIGWINCH +int rl_catch_sigwinch = 1; +#else +int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */ +#endif + +/* Private variables. */ +/* If non-zero, print characters corresponding to received signals. */ +int _rl_echoctl = 0; + +int _rl_intr_char = 0; +int _rl_quit_char = 0; +int _rl_susp_char = 0; + +static int signals_set_flag; +static int sigwinch_set_flag; -#if !defined (SHELL) -static sighandler_cxt old_tstp, old_ttou, old_ttin, old_term; -#endif /* !SHELL */ +/* **************************************************************** */ +/* */ +/* Signal Handling */ +/* */ +/* **************************************************************** */ +static sighandler_cxt old_int, old_term, old_alrm, old_quit; +#if defined (SIGTSTP) +static sighandler_cxt old_tstp, old_ttou, old_ttin; +#endif #if defined (SIGWINCH) static sighandler_cxt old_winch; #endif @@ -116,45 +130,48 @@ rl_signal_handler (sig) #else /* !HAVE_POSIX_SIGNALS */ # if defined (HAVE_BSD_SIGNALS) long omask; -# endif /* HAVE_BSD_SIGNALS */ +# else /* !HAVE_BSD_SIGNALS */ + sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */ +# endif /* !HAVE_BSD_SIGNALS */ #endif /* !HAVE_POSIX_SIGNALS */ + RL_SETSTATE(RL_STATE_SIGHANDLER); + #if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) /* Since the signal will not be blocked while we are in the signal handler, ignore it until rl_clear_signals resets the catcher. */ +# if defined (SIGALRM) if (sig == SIGINT || sig == SIGALRM) - rl_set_sighandler (sig, SIG_IGN, (sighandler_cxt *)NULL); +# else + if (sig == SIGINT) +# endif + rl_set_sighandler (sig, SIG_IGN, &dummy_cxt); #endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ switch (sig) { case SIGINT: - { - register HIST_ENTRY *entry; - - free_undo_list (); - - entry = current_history (); - if (entry) - entry->data = (char *)NULL; - } - _rl_kill_kbd_macro (); - rl_clear_message (); - _rl_init_argument (); + _rl_reset_completion_state (); + rl_free_line_state (); + /* FALLTHROUGH */ + case SIGTERM: #if defined (SIGTSTP) case SIGTSTP: case SIGTTOU: case SIGTTIN: #endif /* SIGTSTP */ +#if defined (SIGALRM) case SIGALRM: - case SIGTERM: - _rl_clean_up_for_exit (); - (*rl_deprep_term_function) (); - rl_clear_signals (); - rl_pending_input = 0; +#endif +#if defined (SIGQUIT) + case SIGQUIT: +#endif + rl_echo_signal_char (sig); + rl_cleanup_after_signal (); #if defined (HAVE_POSIX_SIGNALS) + sigemptyset (&set); sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set); sigdelset (&set, sig); #else /* !HAVE_POSIX_SIGNALS */ @@ -163,7 +180,15 @@ rl_signal_handler (sig) # endif /* HAVE_BSD_SIGNALS */ #endif /* !HAVE_POSIX_SIGNALS */ +#if defined (__EMX__) + signal (sig, SIG_ACK); +#endif + +#if defined (HAVE_KILL) kill (getpid (), sig); +#else + raise (sig); /* assume we have raise */ +#endif /* Let the signal that we just sent through. */ #if defined (HAVE_POSIX_SIGNALS) @@ -174,31 +199,39 @@ rl_signal_handler (sig) # endif /* HAVE_BSD_SIGNALS */ #endif /* !HAVE_POSIX_SIGNALS */ - (*rl_prep_term_function) (_rl_meta_flag); - rl_set_signals (); + rl_reset_after_signal (); } + RL_UNSETSTATE(RL_STATE_SIGHANDLER); SIGHANDLER_RETURN; } #if defined (SIGWINCH) static RETSIGTYPE -rl_handle_sigwinch (sig) +rl_sigwinch_handler (sig) int sig; { SigHandler *oh; - if (readline_echoing_p) - { - _rl_get_screen_size (fileno (rl_instream), 1); - _rl_redisplay_after_sigwinch (); - } +#if defined (MUST_REINSTALL_SIGHANDLERS) + sighandler_cxt dummy_winch; + + /* We don't want to change old_winch -- it holds the state of SIGWINCH + disposition set by the calling application. We need this state + because we call the application's SIGWINCH handler after updating + our own idea of the screen size. */ + rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch); +#endif + + RL_SETSTATE(RL_STATE_SIGHANDLER); + rl_resize_terminal (); /* If another sigwinch handler has been installed, call it. */ oh = (SigHandler *)old_winch.sa_handler; if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL) (*oh) (sig); + RL_UNSETSTATE(RL_STATE_SIGHANDLER); SIGHANDLER_RETURN; } #endif /* SIGWINCH */ @@ -225,73 +258,135 @@ rl_set_sighandler (sig, handler, ohandler) SigHandler *handler; sighandler_cxt *ohandler; { + sighandler_cxt old_handler; #if defined (HAVE_POSIX_SIGNALS) struct sigaction act; act.sa_handler = handler; +# if defined (SIGWINCH) + act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0; +# else act.sa_flags = 0; +# endif /* SIGWINCH */ sigemptyset (&act.sa_mask); sigemptyset (&ohandler->sa_mask); - sigaction (sig, &act, ohandler); + sigaction (sig, &act, &old_handler); #else - ohandler->sa_handler = (SigHandler *)signal (sig, handler); + old_handler.sa_handler = (SigHandler *)signal (sig, handler); #endif /* !HAVE_POSIX_SIGNALS */ + + /* XXX -- assume we have memcpy */ + /* If rl_set_signals is called twice in a row, don't set the old handler to + rl_signal_handler, because that would cause infinite recursion. */ + if (handler != rl_signal_handler || old_handler.sa_handler != rl_signal_handler) + memcpy (ohandler, &old_handler, sizeof (sighandler_cxt)); + return (ohandler->sa_handler); } +static void +rl_maybe_set_sighandler (sig, handler, ohandler) + int sig; + SigHandler *handler; + sighandler_cxt *ohandler; +{ + sighandler_cxt dummy; + SigHandler *oh; + + sigemptyset (&dummy.sa_mask); + oh = rl_set_sighandler (sig, handler, ohandler); + if (oh == (SigHandler *)SIG_IGN) + rl_sigaction (sig, ohandler, &dummy); +} + int rl_set_signals () { sighandler_cxt dummy; SigHandler *oh; +#if defined (HAVE_POSIX_SIGNALS) + static int sigmask_set = 0; + static sigset_t bset, oset; +#endif #if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&dummy.sa_mask); + if (rl_catch_signals && sigmask_set == 0) + { + sigemptyset (&bset); + + sigaddset (&bset, SIGINT); + sigaddset (&bset, SIGTERM); +#if defined (SIGQUIT) + sigaddset (&bset, SIGQUIT); +#endif +#if defined (SIGALRM) + sigaddset (&bset, SIGALRM); +#endif +#if defined (SIGTSTP) + sigaddset (&bset, SIGTSTP); +#endif +#if defined (SIGTTIN) + sigaddset (&bset, SIGTTIN); #endif +#if defined (SIGTTOU) + sigaddset (&bset, SIGTTOU); +#endif + sigmask_set = 1; + } +#endif /* HAVE_POSIX_SIGNALS */ - oh = rl_set_sighandler (SIGINT, rl_signal_handler, &old_int); - if (oh == (SigHandler *)SIG_IGN) - rl_sigaction (SIGINT, &old_int, &dummy); + if (rl_catch_signals && signals_set_flag == 0) + { +#if defined (HAVE_POSIX_SIGNALS) + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &bset, &oset); +#endif - oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm); - if (oh == (SigHandler *)SIG_IGN) - rl_sigaction (SIGALRM, &old_alrm, &dummy); + rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int); + rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term); +#if defined (SIGQUIT) + rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit); +#endif + +#if defined (SIGALRM) + oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm); + if (oh == (SigHandler *)SIG_IGN) + rl_sigaction (SIGALRM, &old_alrm, &dummy); #if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART) - /* If the application using readline has already installed a signal - handler with SA_RESTART, SIGALRM will cause reads to be restarted - automatically, so readline should just get out of the way. Since - we tested for SIG_IGN above, we can just test for SIG_DFL here. */ - if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART)) - rl_sigaction (SIGALRM, &old_alrm, &dummy); + /* If the application using readline has already installed a signal + handler with SA_RESTART, SIGALRM will cause reads to be restarted + automatically, so readline should just get out of the way. Since + we tested for SIG_IGN above, we can just test for SIG_DFL here. */ + if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART)) + rl_sigaction (SIGALRM, &old_alrm, &dummy); #endif /* HAVE_POSIX_SIGNALS */ - -#if !defined (SHELL) +#endif /* SIGALRM */ #if defined (SIGTSTP) - oh = rl_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp); - if (oh == (SigHandler *)SIG_IGN) - rl_sigaction (SIGTSTP, &old_tstp, &dummy); -#else - oh = (SigHandler *)NULL; + rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp); #endif /* SIGTSTP */ #if defined (SIGTTOU) - rl_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou); - rl_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin); - - if (oh == (SigHandler *)SIG_IGN) - { - rl_set_sighandler (SIGTTOU, SIG_IGN, &dummy); - rl_set_sighandler (SIGTTIN, SIG_IGN, &dummy); - } + rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou); #endif /* SIGTTOU */ - /* Handle SIGTERM if we're not being compiled as part of bash. */ - rl_set_sighandler (SIGTERM, rl_signal_handler, &old_term); -#endif /* !SHELL */ +#if defined (SIGTTIN) + rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin); +#endif /* SIGTTIN */ + + signals_set_flag = 1; + +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); +#endif + } #if defined (SIGWINCH) - rl_set_sighandler (SIGWINCH, rl_handle_sigwinch, &old_winch); + if (rl_catch_sigwinch && sigwinch_set_flag == 0) + { + rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch); + sigwinch_set_flag = 1; + } #endif /* SIGWINCH */ return 0; @@ -302,33 +397,187 @@ rl_clear_signals () { sighandler_cxt dummy; -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&dummy.sa_mask); -#endif - - rl_sigaction (SIGINT, &old_int, &dummy); - rl_sigaction (SIGALRM, &old_alrm, &dummy); + if (rl_catch_signals && signals_set_flag == 1) + { + sigemptyset (&dummy.sa_mask); -#if !defined (SHELL) + rl_sigaction (SIGINT, &old_int, &dummy); + rl_sigaction (SIGTERM, &old_term, &dummy); +#if defined (SIGQUIT) + rl_sigaction (SIGQUIT, &old_quit, &dummy); +#endif +#if defined (SIGALRM) + rl_sigaction (SIGALRM, &old_alrm, &dummy); +#endif #if defined (SIGTSTP) - rl_sigaction (SIGTSTP, &old_tstp, &dummy); -#endif + rl_sigaction (SIGTSTP, &old_tstp, &dummy); +#endif /* SIGTSTP */ #if defined (SIGTTOU) - rl_sigaction (SIGTTOU, &old_ttou, &dummy); - rl_sigaction (SIGTTIN, &old_ttin, &dummy); + rl_sigaction (SIGTTOU, &old_ttou, &dummy); #endif /* SIGTTOU */ - rl_sigaction (SIGTERM, &old_term, &dummy); +#if defined (SIGTTIN) + rl_sigaction (SIGTTIN, &old_ttin, &dummy); +#endif /* SIGTTIN */ -#endif /* !SHELL */ + signals_set_flag = 0; + } #if defined (SIGWINCH) - sigemptyset (&dummy.sa_mask); - rl_sigaction (SIGWINCH, &old_winch, &dummy); + if (rl_catch_sigwinch && sigwinch_set_flag == 1) + { + sigemptyset (&dummy.sa_mask); + rl_sigaction (SIGWINCH, &old_winch, &dummy); + sigwinch_set_flag = 0; + } #endif return 0; } + +/* Clean up the terminal and readline state after catching a signal, before + resending it to the calling application. */ +void +rl_cleanup_after_signal () +{ + _rl_clean_up_for_exit (); + if (rl_deprep_term_function) + (*rl_deprep_term_function) (); + rl_clear_pending_input (); + rl_clear_signals (); +} + +/* Reset the terminal and readline state after a signal handler returns. */ +void +rl_reset_after_signal () +{ + if (rl_prep_term_function) + (*rl_prep_term_function) (_rl_meta_flag); + rl_set_signals (); +} + +/* Free up the readline variable line state for the current line (undo list, + any partial history entry, any keyboard macros in progress, and any + numeric arguments in process) after catching a signal, before calling + rl_cleanup_after_signal(). */ +void +rl_free_line_state () +{ + register HIST_ENTRY *entry; + + rl_free_undo_list (); + + entry = current_history (); + if (entry) + entry->data = (char *)NULL; + + _rl_kill_kbd_macro (); + rl_clear_message (); + _rl_reset_argument (); +} + #endif /* HANDLE_SIGNALS */ + +/* **************************************************************** */ +/* */ +/* SIGINT Management */ +/* */ +/* **************************************************************** */ + +#if defined (HAVE_POSIX_SIGNALS) +static sigset_t sigint_set, sigint_oset; +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) +static int sigint_oldmask; +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + +static int sigint_blocked; + +/* Cause SIGINT to not be delivered until the corresponding call to + release_sigint(). */ +void +_rl_block_sigint () +{ + if (sigint_blocked) + return; + +#if defined (HAVE_POSIX_SIGNALS) + sigemptyset (&sigint_set); + sigemptyset (&sigint_oset); + sigaddset (&sigint_set, SIGINT); + sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset); +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + sigint_oldmask = sigblock (sigmask (SIGINT)); +# else /* !HAVE_BSD_SIGNALS */ +# if defined (HAVE_USG_SIGHOLD) + sighold (SIGINT); +# endif /* HAVE_USG_SIGHOLD */ +# endif /* !HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + sigint_blocked = 1; +} + +/* Allow SIGINT to be delivered. */ +void +_rl_release_sigint () +{ + if (sigint_blocked == 0) + return; + +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL); +#else +# if defined (HAVE_BSD_SIGNALS) + sigsetmask (sigint_oldmask); +# else /* !HAVE_BSD_SIGNALS */ +# if defined (HAVE_USG_SIGHOLD) + sigrelse (SIGINT); +# endif /* HAVE_USG_SIGHOLD */ +# endif /* !HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + sigint_blocked = 0; +} + +/* **************************************************************** */ +/* */ +/* Echoing special control characters */ +/* */ +/* **************************************************************** */ +void +rl_echo_signal_char (sig) + int sig; +{ + char cstr[3]; + int cslen, c; + + if (_rl_echoctl == 0) + return; + + switch (sig) + { + case SIGINT: c = _rl_intr_char; break; + case SIGQUIT: c = _rl_quit_char; break; + case SIGTSTP: c = _rl_susp_char; break; + default: return; + } + + if (CTRL_CHAR (c) || c == RUBOUT) + { + cstr[0] = '^'; + cstr[1] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; + cstr[cslen = 2] = '\0'; + } + else + { + cstr[0] = c; + cstr[cslen = 1] = '\0'; + } + + _rl_output_some_chars (cstr, cslen); +}