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*/
u_interrupt(int type)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*/
stop(int type)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*/
winch(int type)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
wbreak_handler(DWORD dwCtrlType)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
terminate(int type)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
sigusr(constant char * var)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
sigusr1(int type)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 */
init_signals(int on)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 */
psignals(void)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