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