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