xref: /freebsd/contrib/less/signal.c (revision e2abec625bf07c054f7ac2df2402d6c454113df8)
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