1/* signals.c -- install and maintain signal handlers. 2 $Id: signals.c,v 1.7 2004/04/11 17:56:46 karl Exp $ 3 4 Copyright (C) 1993, 1994, 1995, 1998, 2002, 2003, 2004 Free Software 5 Foundation, Inc. 6 7 This program 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 2, or (at your option) 10 any later version. 11 12 This program 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 this program; if not, write to the Free Software 19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 21 Originally written by Brian Fox (bfox@ai.mit.edu). */ 22 23#include "info.h" 24#include "signals.h" 25 26void initialize_info_signal_handler (void); 27 28/* **************************************************************** */ 29/* */ 30/* Pretending That We Have POSIX Signals */ 31/* */ 32/* **************************************************************** */ 33 34#if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK) 35/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ 36static void 37sigprocmask (int operation, int *newset, int *oldset) 38{ 39 switch (operation) 40 { 41 case SIG_UNBLOCK: 42 sigsetmask (sigblock (0) & ~(*newset)); 43 break; 44 45 case SIG_BLOCK: 46 *oldset = sigblock (*newset); 47 break; 48 49 case SIG_SETMASK: 50 sigsetmask (*newset); 51 break; 52 53 default: 54 abort (); 55 } 56} 57#endif /* !HAVE_SIGPROCMASK && HAVE_SIGSETMASK */ 58 59/* **************************************************************** */ 60/* */ 61/* Signal Handling for Info */ 62/* */ 63/* **************************************************************** */ 64 65#if defined (HAVE_SIGACTION) || defined (HAVE_SIGPROCMASK) ||\ 66 defined (HAVE_SIGSETMASK) 67static void 68mask_termsig (sigset_t *set) 69{ 70# if defined (SIGTSTP) 71 sigaddset (set, SIGTSTP); 72 sigaddset (set, SIGTTOU); 73 sigaddset (set, SIGTTIN); 74# endif 75# if defined (SIGWINCH) 76 sigaddset (set, SIGWINCH); 77# endif 78#if defined (SIGQUIT) 79 sigaddset (set, SIGQUIT); 80#endif 81#if defined (SIGINT) 82 sigaddset (set, SIGINT); 83#endif 84# if defined (SIGUSR1) 85 sigaddset (set, SIGUSR1); 86# endif 87} 88#endif /* HAVE_SIGACTION || HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ 89 90static RETSIGTYPE info_signal_proc (int sig); 91#if defined (HAVE_SIGACTION) 92typedef struct sigaction signal_info; 93signal_info info_signal_handler; 94 95static void 96set_termsig (int sig, signal_info *old) 97{ 98 sigaction (sig, &info_signal_handler, old); 99} 100 101static void 102restore_termsig (int sig, const signal_info *saved) 103{ 104 sigaction (sig, saved, NULL); 105} 106#else /* !HAVE_SIGACTION */ 107typedef RETSIGTYPE (*signal_info) (); 108#define set_termsig(sig, old) (void)(*(old) = signal (sig, info_signal_proc)) 109#define restore_termsig(sig, saved) (void)signal (sig, *(saved)) 110#define info_signal_handler info_signal_proc 111static int term_conf_busy = 0; 112#endif /* !HAVE_SIGACTION */ 113 114static signal_info old_TSTP, old_TTOU, old_TTIN; 115static signal_info old_WINCH, old_INT, old_USR1; 116static signal_info old_QUIT; 117 118void 119initialize_info_signal_handler (void) 120{ 121#ifdef SA_NOCLDSTOP 122 /* (Based on info from Paul Eggert found in coreutils.) Don't use 123 HAVE_SIGACTION to decide whether to use the sa_handler, sa_flags, 124 sa_mask members, as some systems (Solaris 7+) don't define them. Use 125 SA_NOCLDSTOP instead; it's been part of POSIX.1 since day 1 (in 1988). */ 126 info_signal_handler.sa_handler = info_signal_proc; 127 info_signal_handler.sa_flags = 0; 128 mask_termsig (&info_signal_handler.sa_mask); 129#endif /* SA_NOCLDSTOP */ 130 131#if defined (SIGTSTP) 132 set_termsig (SIGTSTP, &old_TSTP); 133 set_termsig (SIGTTOU, &old_TTOU); 134 set_termsig (SIGTTIN, &old_TTIN); 135#endif /* SIGTSTP */ 136 137#if defined (SIGWINCH) 138 set_termsig (SIGWINCH, &old_WINCH); 139#endif 140 141#if defined (SIGQUIT) 142 set_termsig (SIGQUIT, &old_QUIT); 143#endif 144 145#if defined (SIGINT) 146 set_termsig (SIGINT, &old_INT); 147#endif 148 149#if defined (SIGUSR1) 150 /* Used by DJGPP to simulate SIGTSTP on Ctrl-Z. */ 151 set_termsig (SIGUSR1, &old_USR1); 152#endif 153} 154 155static void 156redisplay_after_signal (void) 157{ 158 terminal_clear_screen (); 159 display_clear_display (the_display); 160 window_mark_chain (windows, W_UpdateWindow); 161 display_update_display (windows); 162 display_cursor_at_point (active_window); 163 fflush (stdout); 164} 165 166static void 167reset_info_window_sizes (void) 168{ 169 terminal_goto_xy (0, 0); 170 fflush (stdout); 171 terminal_unprep_terminal (); 172 terminal_get_screen_size (); 173 terminal_prep_terminal (); 174 display_initialize_display (screenwidth, screenheight); 175 window_new_screen_size (screenwidth, screenheight); 176 redisplay_after_signal (); 177} 178 179static RETSIGTYPE 180info_signal_proc (int sig) 181{ 182 signal_info *old_signal_handler = NULL; 183 184#if !defined (HAVE_SIGACTION) 185 /* best effort: first increment this counter and later block signals */ 186 if (term_conf_busy) 187 return; 188 term_conf_busy++; 189#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK) 190 { 191 sigset_t nvar, ovar; 192 sigemptyset (&nvar); 193 mask_termsig (&nvar); 194 sigprocmask (SIG_BLOCK, &nvar, &ovar); 195 } 196#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ 197#endif /* !HAVE_SIGACTION */ 198 switch (sig) 199 { 200#if defined (SIGTSTP) 201 case SIGTSTP: 202 case SIGTTOU: 203 case SIGTTIN: 204#endif 205#if defined (SIGQUIT) 206 case SIGQUIT: 207#endif 208#if defined (SIGINT) 209 case SIGINT: 210#endif 211 { 212#if defined (SIGTSTP) 213 if (sig == SIGTSTP) 214 old_signal_handler = &old_TSTP; 215 if (sig == SIGTTOU) 216 old_signal_handler = &old_TTOU; 217 if (sig == SIGTTIN) 218 old_signal_handler = &old_TTIN; 219#endif /* SIGTSTP */ 220#if defined (SIGQUIT) 221 if (sig == SIGQUIT) 222 old_signal_handler = &old_QUIT; 223#endif /* SIGQUIT */ 224#if defined (SIGINT) 225 if (sig == SIGINT) 226 old_signal_handler = &old_INT; 227#endif /* SIGINT */ 228 229 /* For stop signals, restore the terminal IO, leave the cursor 230 at the bottom of the window, and stop us. */ 231 terminal_goto_xy (0, screenheight - 1); 232 terminal_clear_to_eol (); 233 fflush (stdout); 234 terminal_unprep_terminal (); 235 restore_termsig (sig, old_signal_handler); 236 UNBLOCK_SIGNAL (sig); 237 kill (getpid (), sig); 238 239 /* The program is returning now. Restore our signal handler, 240 turn on terminal handling, redraw the screen, and place the 241 cursor where it belongs. */ 242 terminal_prep_terminal (); 243 set_termsig (sig, old_signal_handler); 244 /* window size might be changed while sleeping */ 245 reset_info_window_sizes (); 246 } 247 break; 248 249#if defined (SIGWINCH) || defined (SIGUSR1) 250#ifdef SIGWINCH 251 case SIGWINCH: 252#endif 253#ifdef SIGUSR1 254 case SIGUSR1: 255#endif 256 { 257 /* Turn off terminal IO, tell our parent that the window has changed, 258 then reinitialize the terminal and rebuild our windows. */ 259#ifdef SIGWINCH 260 if (sig == SIGWINCH) 261 old_signal_handler = &old_WINCH; 262#endif 263#ifdef SIGUSR1 264 if (sig == SIGUSR1) 265 old_signal_handler = &old_USR1; 266#endif 267 terminal_goto_xy (0, 0); 268 fflush (stdout); 269 terminal_unprep_terminal (); /* needless? */ 270 restore_termsig (sig, old_signal_handler); 271 UNBLOCK_SIGNAL (sig); 272 kill (getpid (), sig); 273 274 /* After our old signal handler returns... */ 275 set_termsig (sig, old_signal_handler); /* needless? */ 276 terminal_prep_terminal (); 277 reset_info_window_sizes (); 278 } 279 break; 280#endif /* SIGWINCH || SIGUSR1 */ 281 } 282#if !defined (HAVE_SIGACTION) 283 /* at this time it is safer to perform unblock after decrement */ 284 term_conf_busy--; 285#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK) 286 { 287 sigset_t nvar, ovar; 288 sigemptyset (&nvar); 289 mask_termsig (&nvar); 290 sigprocmask (SIG_UNBLOCK, &nvar, &ovar); 291 } 292#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ 293#endif /* !HAVE_SIGACTION */ 294} 295/* vim: set sw=2 cino={1s>2sn-s^-se-s: */ 296