xref: /netbsd-src/external/gpl2/texinfo/dist/info/signals.c (revision 29619d2afe564e54d657b83e5a3ae89584f83720)
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
sigprocmask(int operation,int * newset,int * oldset)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
mask_termsig(sigset_t * set)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
set_termsig(int sig,signal_info * old)98 set_termsig (int sig, signal_info *old)
99 {
100   sigaction (sig, &info_signal_handler, old);
101 }
102 
103 static void
restore_termsig(int sig,const signal_info * saved)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
initialize_info_signal_handler(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
redisplay_after_signal(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
reset_info_window_sizes(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
info_signal_proc(int sig)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