1 #include <errno.h> 2 /* 3 * Copyright (C) 1984-2025 Mark Nudelman 4 * 5 * You may distribute under the terms of either the GNU General Public 6 * License or the Less License, as specified in the README file. 7 * 8 * For more information, see the README file. 9 */ 10 11 /* $FreeBSD$ */ 12 13 /* 14 * Routines dealing with signals. 15 * 16 * A signal usually merely causes a bit to be set in the "signals" word. 17 * At some convenient time, the mainline code checks to see if any 18 * signals need processing by calling psignal(). 19 * If we happen to be reading from a file [in iread()] at the time 20 * the signal is received, we call intio to interrupt the iread. 21 */ 22 23 #include "less.h" 24 #include <signal.h> 25 26 /* 27 * "sigs" contains bits indicating signals which need to be processed. 28 */ 29 public int sigs; 30 31 extern int sc_width, sc_height; 32 extern int linenums; 33 extern int wscroll; 34 extern int quit_on_intr; 35 extern long jump_sline_fraction; 36 37 extern int less_is_more; 38 39 /* 40 * Interrupt signal handler. 41 */ 42 #if MSDOS_COMPILER!=WIN32C 43 /* ARGSUSED*/ 44 static RETSIGTYPE u_interrupt(int type) 45 { 46 (void) type; 47 bell(); 48 #if OS2 49 LSIGNAL(SIGINT, SIG_ACK); 50 #endif 51 LSIGNAL(SIGINT, u_interrupt); 52 sigs |= S_INTERRUPT; 53 #if MSDOS_COMPILER==DJGPPC 54 /* 55 * If a keyboard has been hit, it must be Ctrl-C 56 * (as opposed to Ctrl-Break), so consume it. 57 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.) 58 */ 59 if (kbhit()) 60 getkey(); 61 #endif 62 if (less_is_more) 63 quit(0); 64 #if HILITE_SEARCH 65 set_filter_pattern(NULL, 0); 66 #endif 67 intio(); 68 } 69 #endif 70 71 #ifdef SIGTSTP 72 /* 73 * "Stop" (^Z) signal handler. 74 */ 75 /* ARGSUSED*/ 76 static RETSIGTYPE stop(int type) 77 { 78 (void) type; 79 LSIGNAL(SIGTSTP, stop); 80 sigs |= S_STOP; 81 intio(); 82 } 83 #endif 84 85 #undef SIG_LESSWINDOW 86 #ifdef SIGWINCH 87 #define SIG_LESSWINDOW SIGWINCH 88 #else 89 #ifdef SIGWIND 90 #define SIG_LESSWINDOW SIGWIND 91 #endif 92 #endif 93 94 #ifdef SIG_LESSWINDOW 95 /* 96 * "Window" change handler 97 */ 98 /* ARGSUSED*/ 99 public RETSIGTYPE winch(int type) 100 { 101 (void) type; 102 LSIGNAL(SIG_LESSWINDOW, winch); 103 #if LESSTEST 104 /* 105 * Ignore window changes during lesstest. 106 * Changes in the real window are unrelated to the simulated 107 * screen used by lesstest. 108 */ 109 if (is_lesstest()) 110 return; 111 #endif 112 sigs |= S_WINCH; 113 intio(); 114 } 115 #endif 116 117 #if MSDOS_COMPILER==WIN32C 118 /* 119 * Handle CTRL-C and CTRL-BREAK keys. 120 */ 121 #define WIN32_LEAN_AND_MEAN 122 #include <windows.h> 123 124 static BOOL WINAPI wbreak_handler(DWORD dwCtrlType) 125 { 126 switch (dwCtrlType) 127 { 128 case CTRL_C_EVENT: 129 case CTRL_BREAK_EVENT: 130 sigs |= S_INTERRUPT; 131 #if HILITE_SEARCH 132 set_filter_pattern(NULL, 0); 133 #endif 134 return (TRUE); 135 default: 136 break; 137 } 138 return (FALSE); 139 } 140 #endif 141 142 static RETSIGTYPE terminate(int type) 143 { 144 (void) type; 145 quit(15); 146 } 147 148 /* 149 * Handle a SIGUSR signal. 150 */ 151 #ifdef SIGUSR1 152 static void sigusr(constant char *var) 153 { 154 constant char *cmd = lgetenv(var); 155 if (isnullenv(cmd)) 156 return; 157 ungetsc(cmd); 158 intio(); 159 } 160 161 static RETSIGTYPE sigusr1(int type) 162 { 163 (void) type; 164 LSIGNAL(SIGUSR1, sigusr1); 165 sigusr("LESS_SIGUSR1"); 166 } 167 #endif 168 169 /* 170 * Set up the signal handlers. 171 */ 172 public void init_signals(int on) 173 { 174 if (on) 175 { 176 /* 177 * Set signal handlers. 178 */ 179 #if MSDOS_COMPILER==WIN32C 180 SetConsoleCtrlHandler(wbreak_handler, TRUE); 181 #else 182 (void) LSIGNAL(SIGINT, u_interrupt); 183 #endif 184 #ifdef SIGTSTP 185 (void) LSIGNAL(SIGTSTP, !secure_allow(SF_STOP) ? SIG_IGN : stop); 186 #endif 187 #ifdef SIGWINCH 188 (void) LSIGNAL(SIGWINCH, winch); 189 #endif 190 #ifdef SIGWIND 191 (void) LSIGNAL(SIGWIND, winch); 192 #endif 193 #ifdef SIGQUIT 194 (void) LSIGNAL(SIGQUIT, SIG_IGN); 195 #endif 196 #ifdef SIGTERM 197 (void) LSIGNAL(SIGTERM, terminate); 198 #endif 199 #ifdef SIGUSR1 200 (void) LSIGNAL(SIGUSR1, sigusr1); 201 #endif 202 } else 203 { 204 /* 205 * Restore signals to defaults. 206 */ 207 #if MSDOS_COMPILER==WIN32C 208 SetConsoleCtrlHandler(wbreak_handler, FALSE); 209 #else 210 (void) LSIGNAL(SIGINT, SIG_DFL); 211 #endif 212 #ifdef SIGTSTP 213 (void) LSIGNAL(SIGTSTP, SIG_DFL); 214 #endif 215 #ifdef SIGWINCH 216 (void) LSIGNAL(SIGWINCH, SIG_IGN); 217 #endif 218 #ifdef SIGWIND 219 (void) LSIGNAL(SIGWIND, SIG_IGN); 220 #endif 221 #ifdef SIGQUIT 222 (void) LSIGNAL(SIGQUIT, SIG_DFL); 223 #endif 224 #ifdef SIGTERM 225 (void) LSIGNAL(SIGTERM, SIG_DFL); 226 #endif 227 #ifdef SIGUSR1 228 (void) LSIGNAL(SIGUSR1, SIG_DFL); 229 #endif 230 } 231 } 232 233 /* 234 * Process any signals we have received. 235 * A received signal cause a bit to be set in "sigs". 236 */ 237 public void psignals(void) 238 { 239 int tsignals; 240 241 if ((tsignals = sigs) == 0) 242 return; 243 sigs = 0; 244 245 #ifdef SIGTSTP 246 if (tsignals & S_STOP) 247 { 248 /* 249 * Clean up the terminal. 250 */ 251 #ifdef SIGTTOU 252 LSIGNAL(SIGTTOU, SIG_IGN); 253 #endif 254 clear_bot(); 255 deinit(); 256 flush(); 257 raw_mode(0); 258 #ifdef SIGTTOU 259 LSIGNAL(SIGTTOU, SIG_DFL); 260 #endif 261 LSIGNAL(SIGTSTP, SIG_DFL); 262 kill(getpid(), SIGTSTP); 263 /* 264 * ... Bye bye. ... 265 * Hopefully we'll be back later and resume here... 266 * Reset the terminal and arrange to repaint the 267 * screen when we get back to the main command loop. 268 */ 269 LSIGNAL(SIGTSTP, stop); 270 raw_mode(1); 271 init(); 272 screen_trashed(); 273 tsignals |= S_WINCH; 274 } 275 #endif 276 #ifdef S_WINCH 277 if (tsignals & S_WINCH) 278 { 279 int old_width, old_height; 280 /* 281 * Re-execute scrsize() to read the new window size. 282 */ 283 old_width = sc_width; 284 old_height = sc_height; 285 get_term(); 286 if (sc_width != old_width || sc_height != old_height) 287 { 288 wscroll = (sc_height + 1) / 2; 289 screen_size_changed(); 290 } 291 screen_trashed(); 292 } 293 #endif 294 if (tsignals & S_INTERRUPT) 295 { 296 if (quit_on_intr) 297 quit(QUIT_INTERRUPT); 298 } 299 } 300