1 /* signals.c -- install and maintain signal handlers. 2 $Id: signals.c,v 1.1.1.4 2006/07/17 16:03:44 espie 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 26 void 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. */ 36 static void 37 sigprocmask (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) 67 static void 68 mask_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 90 static RETSIGTYPE info_signal_proc (int sig); 91 #if defined (HAVE_SIGACTION) 92 typedef struct sigaction signal_info; 93 signal_info info_signal_handler; 94 95 static void 96 set_termsig (int sig, signal_info *old) 97 { 98 sigaction (sig, &info_signal_handler, old); 99 } 100 101 static void 102 restore_termsig (int sig, const signal_info *saved) 103 { 104 sigaction (sig, saved, NULL); 105 } 106 #else /* !HAVE_SIGACTION */ 107 typedef 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 111 static int term_conf_busy = 0; 112 #endif /* !HAVE_SIGACTION */ 113 114 static signal_info old_TSTP, old_TTOU, old_TTIN; 115 static signal_info old_WINCH, old_INT, old_USR1; 116 static signal_info old_QUIT; 117 118 void 119 initialize_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 155 static void 156 redisplay_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 166 static void 167 reset_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 179 static RETSIGTYPE 180 info_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