1 /* $NetBSD: signals.c,v 1.1.1.1 2016/01/14 00:11:29 christos Exp $ */ 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 28 void 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. */ 38 static void 39 sigprocmask (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) 69 static void 70 mask_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 92 static RETSIGTYPE info_signal_proc (int sig); 93 #if defined (HAVE_SIGACTION) 94 typedef struct sigaction signal_info; 95 signal_info info_signal_handler; 96 97 static void 98 set_termsig (int sig, signal_info *old) 99 { 100 sigaction (sig, &info_signal_handler, old); 101 } 102 103 static void 104 restore_termsig (int sig, const signal_info *saved) 105 { 106 sigaction (sig, saved, NULL); 107 } 108 #else /* !HAVE_SIGACTION */ 109 typedef 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 113 static int term_conf_busy = 0; 114 #endif /* !HAVE_SIGACTION */ 115 116 static signal_info old_TSTP, old_TTOU, old_TTIN; 117 static signal_info old_WINCH, old_INT, old_USR1; 118 static signal_info old_QUIT; 119 120 void 121 initialize_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 157 static void 158 redisplay_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 168 static void 169 reset_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 181 static RETSIGTYPE 182 info_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