1 #include <errno.h>
2 /*
3 * Copyright (C) 1984-2026 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*/
u_interrupt(int type)44 static RETSIGTYPE u_interrupt(int type)
45 {
46 (void) type;
47 lbell();
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 polling_ok();
68 intio();
69 }
70 #endif
71
72 #ifdef SIGTSTP
73 /*
74 * "Stop" (^Z) signal handler.
75 */
76 /* ARGSUSED*/
stop(int type)77 static RETSIGTYPE stop(int type)
78 {
79 (void) type;
80 LSIGNAL(SIGTSTP, stop);
81 sigs |= S_STOP;
82 intio();
83 }
84 #endif
85
86 #undef SIG_LESSWINDOW
87 #ifdef SIGWINCH
88 #define SIG_LESSWINDOW SIGWINCH
89 #else
90 #ifdef SIGWIND
91 #define SIG_LESSWINDOW SIGWIND
92 #endif
93 #endif
94
95 #ifdef SIG_LESSWINDOW
96 /*
97 * "Window" change handler
98 */
99 /* ARGSUSED*/
lwinch(int type)100 public RETSIGTYPE lwinch(int type)
101 {
102 (void) type;
103 LSIGNAL(SIG_LESSWINDOW, lwinch);
104 #if LESSTEST
105 /*
106 * Ignore window changes during lesstest.
107 * Changes in the real window are unrelated to the simulated
108 * screen used by lesstest.
109 */
110 if (is_lesstest())
111 return;
112 #endif
113 sigs |= S_WINCH;
114 intio();
115 }
116 #endif
117
118 #if MSDOS_COMPILER==WIN32C
119 /*
120 * Handle CTRL-C and CTRL-BREAK keys.
121 */
122 #define WIN32_LEAN_AND_MEAN
123 #include <windows.h>
124
wbreak_handler(DWORD dwCtrlType)125 static BOOL WINAPI wbreak_handler(DWORD dwCtrlType)
126 {
127 switch (dwCtrlType)
128 {
129 case CTRL_C_EVENT:
130 case CTRL_BREAK_EVENT:
131 sigs |= S_INTERRUPT;
132 #if HILITE_SEARCH
133 set_filter_pattern(NULL, 0);
134 #endif
135 return (TRUE);
136 default:
137 break;
138 }
139 return (FALSE);
140 }
141 #endif
142
terminate(int type)143 static RETSIGTYPE terminate(int type)
144 {
145 (void) type;
146 quit(15);
147 }
148
149 /*
150 * Handle a SIGUSR signal.
151 */
152 #ifdef SIGUSR1
sigusr(constant char * var)153 static void sigusr(constant char *var)
154 {
155 constant char *cmd = lgetenv(var);
156 if (isnullenv(cmd))
157 return;
158 ungetsc(cmd);
159 intio();
160 }
161
sigusr1(int type)162 static RETSIGTYPE sigusr1(int type)
163 {
164 (void) type;
165 LSIGNAL(SIGUSR1, sigusr1);
166 sigusr("LESS_SIGUSR1");
167 }
168 #endif
169
170 /*
171 * Set up the signal handlers.
172 */
init_signals(int on)173 public void init_signals(int on)
174 {
175 if (on)
176 {
177 /*
178 * Set signal handlers.
179 */
180 #if MSDOS_COMPILER==WIN32C
181 SetConsoleCtrlHandler(wbreak_handler, TRUE);
182 #else
183 (void) LSIGNAL(SIGINT, u_interrupt);
184 #endif
185 #ifdef SIGTSTP
186 (void) LSIGNAL(SIGTSTP, !secure_allow(SF_STOP) ? SIG_IGN : stop);
187 #endif
188 #ifdef SIGWINCH
189 (void) LSIGNAL(SIGWINCH, lwinch);
190 #endif
191 #ifdef SIGWIND
192 (void) LSIGNAL(SIGWIND, lwinch);
193 #endif
194 #ifdef SIGQUIT
195 (void) LSIGNAL(SIGQUIT, SIG_IGN);
196 #endif
197 #ifdef SIGTERM
198 (void) LSIGNAL(SIGTERM, terminate);
199 #endif
200 #ifdef SIGHUP
201 (void) LSIGNAL(SIGHUP, terminate);
202 #endif
203 #ifdef SIGUSR1
204 (void) LSIGNAL(SIGUSR1, sigusr1);
205 #endif
206 } else
207 {
208 /*
209 * Restore signals to defaults.
210 */
211 #if MSDOS_COMPILER==WIN32C
212 SetConsoleCtrlHandler(wbreak_handler, FALSE);
213 #else
214 (void) LSIGNAL(SIGINT, SIG_DFL);
215 #endif
216 #ifdef SIGTSTP
217 (void) LSIGNAL(SIGTSTP, SIG_DFL);
218 #endif
219 #ifdef SIGWINCH
220 (void) LSIGNAL(SIGWINCH, SIG_IGN);
221 #endif
222 #ifdef SIGWIND
223 (void) LSIGNAL(SIGWIND, SIG_IGN);
224 #endif
225 #ifdef SIGQUIT
226 (void) LSIGNAL(SIGQUIT, SIG_DFL);
227 #endif
228 #ifdef SIGTERM
229 (void) LSIGNAL(SIGTERM, SIG_DFL);
230 #endif
231 #ifdef SIGHUP
232 (void) LSIGNAL(SIGHUP, SIG_DFL);
233 #endif
234 #ifdef SIGUSR1
235 (void) LSIGNAL(SIGUSR1, SIG_DFL);
236 #endif
237 }
238 }
239
240 /*
241 * Process any signals we have received.
242 * A received signal cause a bit to be set in "sigs".
243 */
psignals(void)244 public void psignals(void)
245 {
246 int tsignals;
247
248 if ((tsignals = sigs) == 0)
249 return;
250 sigs = 0;
251
252 #ifdef SIGTSTP
253 if (tsignals & S_STOP)
254 {
255 /*
256 * Clean up the terminal.
257 */
258 #ifdef SIGTTOU
259 LSIGNAL(SIGTTOU, SIG_IGN);
260 #endif
261 clear_bot();
262 term_deinit();
263 flush();
264 raw_mode(0);
265 #ifdef SIGTTOU
266 LSIGNAL(SIGTTOU, SIG_DFL);
267 #endif
268 LSIGNAL(SIGTSTP, SIG_DFL);
269 kill(getpid(), SIGTSTP);
270 /*
271 * ... Bye bye. ...
272 * Hopefully we'll be back later and resume here...
273 * Reset the terminal and arrange to repaint the
274 * screen when we get back to the main command loop.
275 */
276 LSIGNAL(SIGTSTP, stop);
277 raw_mode(1);
278 term_init();
279 screen_trashed();
280 tsignals |= S_WINCH;
281 }
282 #endif
283 #ifdef S_WINCH
284 if (tsignals & S_WINCH)
285 {
286 int old_width, old_height;
287 /*
288 * Re-execute scrsize() to read the new window size.
289 */
290 old_width = sc_width;
291 old_height = sc_height;
292 get_term();
293 if (sc_width != old_width || sc_height != old_height)
294 screen_size_changed();
295 screen_trashed();
296 }
297 #endif
298 if (tsignals & S_INTERRUPT)
299 {
300 if (quit_on_intr)
301 quit(QUIT_INTERRUPT);
302 getcc_clear();
303 #if MSDOS_COMPILER==WIN32C
304 win32_getch_clear();
305 #endif
306 }
307 }
308