1 /* signals.c -- install and maintain signal handlers.
2 $Id: signals.c,v 1.1.1.4 2006/07/17 16:03:44 espie Exp $
3
4 Copyright (C) 1993, 1994, 1995, 1998, 2002, 2003, 2004 Free Software
5 Foundation, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21 Originally written by Brian Fox (bfox@ai.mit.edu). */
22
23 #include "info.h"
24 #include "signals.h"
25
26 void initialize_info_signal_handler (void);
27
28 /* **************************************************************** */
29 /* */
30 /* Pretending That We Have POSIX Signals */
31 /* */
32 /* **************************************************************** */
33
34 #if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK)
35 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
36 static void
sigprocmask(int operation,int * newset,int * oldset)37 sigprocmask (int operation, int *newset, int *oldset)
38 {
39 switch (operation)
40 {
41 case SIG_UNBLOCK:
42 sigsetmask (sigblock (0) & ~(*newset));
43 break;
44
45 case SIG_BLOCK:
46 *oldset = sigblock (*newset);
47 break;
48
49 case SIG_SETMASK:
50 sigsetmask (*newset);
51 break;
52
53 default:
54 abort ();
55 }
56 }
57 #endif /* !HAVE_SIGPROCMASK && HAVE_SIGSETMASK */
58
59 /* **************************************************************** */
60 /* */
61 /* Signal Handling for Info */
62 /* */
63 /* **************************************************************** */
64
65 #if defined (HAVE_SIGACTION) || defined (HAVE_SIGPROCMASK) ||\
66 defined (HAVE_SIGSETMASK)
67 static void
mask_termsig(sigset_t * set)68 mask_termsig (sigset_t *set)
69 {
70 # if defined (SIGTSTP)
71 sigaddset (set, SIGTSTP);
72 sigaddset (set, SIGTTOU);
73 sigaddset (set, SIGTTIN);
74 # endif
75 # if defined (SIGWINCH)
76 sigaddset (set, SIGWINCH);
77 # endif
78 #if defined (SIGQUIT)
79 sigaddset (set, SIGQUIT);
80 #endif
81 #if defined (SIGINT)
82 sigaddset (set, SIGINT);
83 #endif
84 # if defined (SIGUSR1)
85 sigaddset (set, SIGUSR1);
86 # endif
87 }
88 #endif /* HAVE_SIGACTION || HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
89
90 static RETSIGTYPE info_signal_proc (int sig);
91 #if defined (HAVE_SIGACTION)
92 typedef struct sigaction signal_info;
93 signal_info info_signal_handler;
94
95 static void
set_termsig(int sig,signal_info * old)96 set_termsig (int sig, signal_info *old)
97 {
98 sigaction (sig, &info_signal_handler, old);
99 }
100
101 static void
restore_termsig(int sig,const signal_info * saved)102 restore_termsig (int sig, const signal_info *saved)
103 {
104 sigaction (sig, saved, NULL);
105 }
106 #else /* !HAVE_SIGACTION */
107 typedef RETSIGTYPE (*signal_info) ();
108 #define set_termsig(sig, old) (void)(*(old) = signal (sig, info_signal_proc))
109 #define restore_termsig(sig, saved) (void)signal (sig, *(saved))
110 #define info_signal_handler info_signal_proc
111 static int term_conf_busy = 0;
112 #endif /* !HAVE_SIGACTION */
113
114 static signal_info old_TSTP, old_TTOU, old_TTIN;
115 static signal_info old_WINCH, old_INT, old_USR1;
116 static signal_info old_QUIT;
117
118 void
initialize_info_signal_handler(void)119 initialize_info_signal_handler (void)
120 {
121 #ifdef SA_NOCLDSTOP
122 /* (Based on info from Paul Eggert found in coreutils.) Don't use
123 HAVE_SIGACTION to decide whether to use the sa_handler, sa_flags,
124 sa_mask members, as some systems (Solaris 7+) don't define them. Use
125 SA_NOCLDSTOP instead; it's been part of POSIX.1 since day 1 (in 1988). */
126 info_signal_handler.sa_handler = info_signal_proc;
127 info_signal_handler.sa_flags = 0;
128 mask_termsig (&info_signal_handler.sa_mask);
129 #endif /* SA_NOCLDSTOP */
130
131 #if defined (SIGTSTP)
132 set_termsig (SIGTSTP, &old_TSTP);
133 set_termsig (SIGTTOU, &old_TTOU);
134 set_termsig (SIGTTIN, &old_TTIN);
135 #endif /* SIGTSTP */
136
137 #if defined (SIGWINCH)
138 set_termsig (SIGWINCH, &old_WINCH);
139 #endif
140
141 #if defined (SIGQUIT)
142 set_termsig (SIGQUIT, &old_QUIT);
143 #endif
144
145 #if defined (SIGINT)
146 set_termsig (SIGINT, &old_INT);
147 #endif
148
149 #if defined (SIGUSR1)
150 /* Used by DJGPP to simulate SIGTSTP on Ctrl-Z. */
151 set_termsig (SIGUSR1, &old_USR1);
152 #endif
153 }
154
155 static void
redisplay_after_signal(void)156 redisplay_after_signal (void)
157 {
158 terminal_clear_screen ();
159 display_clear_display (the_display);
160 window_mark_chain (windows, W_UpdateWindow);
161 display_update_display (windows);
162 display_cursor_at_point (active_window);
163 fflush (stdout);
164 }
165
166 static void
reset_info_window_sizes(void)167 reset_info_window_sizes (void)
168 {
169 terminal_goto_xy (0, 0);
170 fflush (stdout);
171 terminal_unprep_terminal ();
172 terminal_get_screen_size ();
173 terminal_prep_terminal ();
174 display_initialize_display (screenwidth, screenheight);
175 window_new_screen_size (screenwidth, screenheight);
176 redisplay_after_signal ();
177 }
178
179 static RETSIGTYPE
info_signal_proc(int sig)180 info_signal_proc (int sig)
181 {
182 signal_info *old_signal_handler = NULL;
183
184 #if !defined (HAVE_SIGACTION)
185 /* best effort: first increment this counter and later block signals */
186 if (term_conf_busy)
187 return;
188 term_conf_busy++;
189 #if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK)
190 {
191 sigset_t nvar, ovar;
192 sigemptyset (&nvar);
193 mask_termsig (&nvar);
194 sigprocmask (SIG_BLOCK, &nvar, &ovar);
195 }
196 #endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
197 #endif /* !HAVE_SIGACTION */
198 switch (sig)
199 {
200 #if defined (SIGTSTP)
201 case SIGTSTP:
202 case SIGTTOU:
203 case SIGTTIN:
204 #endif
205 #if defined (SIGQUIT)
206 case SIGQUIT:
207 #endif
208 #if defined (SIGINT)
209 case SIGINT:
210 #endif
211 {
212 #if defined (SIGTSTP)
213 if (sig == SIGTSTP)
214 old_signal_handler = &old_TSTP;
215 if (sig == SIGTTOU)
216 old_signal_handler = &old_TTOU;
217 if (sig == SIGTTIN)
218 old_signal_handler = &old_TTIN;
219 #endif /* SIGTSTP */
220 #if defined (SIGQUIT)
221 if (sig == SIGQUIT)
222 old_signal_handler = &old_QUIT;
223 #endif /* SIGQUIT */
224 #if defined (SIGINT)
225 if (sig == SIGINT)
226 old_signal_handler = &old_INT;
227 #endif /* SIGINT */
228
229 /* For stop signals, restore the terminal IO, leave the cursor
230 at the bottom of the window, and stop us. */
231 terminal_goto_xy (0, screenheight - 1);
232 terminal_clear_to_eol ();
233 fflush (stdout);
234 terminal_unprep_terminal ();
235 restore_termsig (sig, old_signal_handler);
236 UNBLOCK_SIGNAL (sig);
237 kill (getpid (), sig);
238
239 /* The program is returning now. Restore our signal handler,
240 turn on terminal handling, redraw the screen, and place the
241 cursor where it belongs. */
242 terminal_prep_terminal ();
243 set_termsig (sig, old_signal_handler);
244 /* window size might be changed while sleeping */
245 reset_info_window_sizes ();
246 }
247 break;
248
249 #if defined (SIGWINCH) || defined (SIGUSR1)
250 #ifdef SIGWINCH
251 case SIGWINCH:
252 #endif
253 #ifdef SIGUSR1
254 case SIGUSR1:
255 #endif
256 {
257 /* Turn off terminal IO, tell our parent that the window has changed,
258 then reinitialize the terminal and rebuild our windows. */
259 #ifdef SIGWINCH
260 if (sig == SIGWINCH)
261 old_signal_handler = &old_WINCH;
262 #endif
263 #ifdef SIGUSR1
264 if (sig == SIGUSR1)
265 old_signal_handler = &old_USR1;
266 #endif
267 terminal_goto_xy (0, 0);
268 fflush (stdout);
269 terminal_unprep_terminal (); /* needless? */
270 restore_termsig (sig, old_signal_handler);
271 UNBLOCK_SIGNAL (sig);
272 kill (getpid (), sig);
273
274 /* After our old signal handler returns... */
275 set_termsig (sig, old_signal_handler); /* needless? */
276 terminal_prep_terminal ();
277 reset_info_window_sizes ();
278 }
279 break;
280 #endif /* SIGWINCH || SIGUSR1 */
281 }
282 #if !defined (HAVE_SIGACTION)
283 /* at this time it is safer to perform unblock after decrement */
284 term_conf_busy--;
285 #if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK)
286 {
287 sigset_t nvar, ovar;
288 sigemptyset (&nvar);
289 mask_termsig (&nvar);
290 sigprocmask (SIG_UNBLOCK, &nvar, &ovar);
291 }
292 #endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
293 #endif /* !HAVE_SIGACTION */
294 }
295 /* vim: set sw=2 cino={1s>2sn-s^-se-s: */
296