81f1d70e7712e4406bf6128166d0ffce253d525c
[apps/madmutt.git] / signal.c
1 /*
2  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3  * 
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  * 
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  * 
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19 #if HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include "mutt.h"
24 #include "mutt_curses.h"
25
26 #include <signal.h>
27 #include <string.h>
28 #include <sys/wait.h>
29 #include <errno.h>
30
31 static sigset_t Sigset;
32 static sigset_t SigsetSys;
33 static struct sigaction SysOldInt;
34 static struct sigaction SysOldQuit;
35 static int IsEndwin = 0;
36
37 /* Attempt to catch "ordinary" signals and shut down gracefully. */
38 RETSIGTYPE exit_handler (int sig)
39 {
40   curs_set (1);
41   endwin ();                    /* just to be safe */
42 #if SYS_SIGLIST_DECLARED
43   printf (_("%s...  Exiting.\n"), sys_siglist[sig]);
44 #else
45 #if (__sun__ && __svr4__)
46   printf (_("Caught %s...  Exiting.\n"), _sys_siglist[sig]);
47 #else
48 #if (__alpha && __osf__)
49   printf (_("Caught %s...  Exiting.\n"), __sys_siglist[sig]);
50 #else
51   printf (_("Caught signal %d...  Exiting.\n"), sig);
52 #endif
53 #endif
54 #endif
55   exit (0);
56 }
57
58 RETSIGTYPE chld_handler (int sig)
59 {
60   /* empty */
61 }
62
63 RETSIGTYPE sighandler (int sig)
64 {
65   int save_errno = errno;
66
67   switch (sig) {
68   case SIGTSTP:                /* user requested a suspend */
69     if (!option (OPTSUSPEND))
70       break;
71     IsEndwin = isendwin ();
72     curs_set (1);
73     if (!IsEndwin)
74       endwin ();
75     kill (0, SIGSTOP);
76
77   case SIGCONT:
78     if (!IsEndwin)
79       refresh ();
80     mutt_curs_set (-1);
81 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
82     /* We don't receive SIGWINCH when suspended; however, no harm is done by
83      * just assuming we received one, and triggering the 'resize' anyway. */
84     SigWinch = 1;
85 #endif
86     break;
87
88 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
89   case SIGWINCH:
90     SigWinch = 1;
91     break;
92 #endif
93
94   case SIGINT:
95     SigInt = 1;
96     break;
97
98   }
99   errno = save_errno;
100 }
101
102 #ifdef USE_SLANG_CURSES
103 int mutt_intr_hook (void)
104 {
105   return (-1);
106 }
107 #endif /* USE_SLANG_CURSES */
108
109 void mutt_signal_init (void)
110 {
111   struct sigaction act;
112
113   sigemptyset (&act.sa_mask);
114   act.sa_flags = 0;
115   act.sa_handler = SIG_IGN;
116   sigaction (SIGPIPE, &act, NULL);
117
118   act.sa_handler = exit_handler;
119   sigaction (SIGTERM, &act, NULL);
120   sigaction (SIGHUP, &act, NULL);
121   sigaction (SIGQUIT, &act, NULL);
122
123   /* we want to avoid race conditions */
124   sigaddset (&act.sa_mask, SIGTSTP);
125
126   act.sa_handler = sighandler;
127
128   /* we want SIGALRM to abort the current syscall, so we do this before
129    * setting the SA_RESTART flag below.  currently this is only used to
130    * timeout on a connect() call in a reasonable amout of time.
131    */
132   sigaction (SIGALRM, &act, NULL);
133
134   /* we also don't want to mess with interrupted system calls */
135 #ifdef SA_RESTART
136   act.sa_flags = SA_RESTART;
137 #endif
138
139   sigaction (SIGCONT, &act, NULL);
140   sigaction (SIGTSTP, &act, NULL);
141   sigaction (SIGINT, &act, NULL);
142 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
143   sigaction (SIGWINCH, &act, NULL);
144 #endif
145
146   /* POSIX doesn't allow us to ignore SIGCHLD,
147    * so we just install a dummy handler for it
148    */
149   act.sa_handler = chld_handler;
150   /* don't need to block any other signals here */
151   sigemptyset (&act.sa_mask);
152   /* we don't want to mess with stopped children */
153   act.sa_flags |= SA_NOCLDSTOP;
154   sigaction (SIGCHLD, &act, NULL);
155
156 #ifdef USE_SLANG_CURSES
157   /* This bit of code is required because of the implementation of
158    * SLcurses_wgetch().  If a signal is received (like SIGWINCH) when we
159    * are in blocking mode, SLsys_getkey() will not return an error unless
160    * a handler function is defined and it returns -1.  This is needed so
161    * that if the user resizes the screen while at a prompt, it will just
162    * abort and go back to the main-menu.
163    */
164   SLang_getkey_intr_hook = mutt_intr_hook;
165 #endif
166 }
167
168 /* signals which are important to block while doing critical ops */
169 void mutt_block_signals (void)
170 {
171   if (!option (OPTSIGNALSBLOCKED)) {
172     sigemptyset (&Sigset);
173     sigaddset (&Sigset, SIGTERM);
174     sigaddset (&Sigset, SIGHUP);
175     sigaddset (&Sigset, SIGTSTP);
176     sigaddset (&Sigset, SIGINT);
177 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
178     sigaddset (&Sigset, SIGWINCH);
179 #endif
180     sigprocmask (SIG_BLOCK, &Sigset, 0);
181     set_option (OPTSIGNALSBLOCKED);
182   }
183 }
184
185 /* restore the previous signal mask */
186 void mutt_unblock_signals (void)
187 {
188   if (option (OPTSIGNALSBLOCKED)) {
189     sigprocmask (SIG_UNBLOCK, &Sigset, 0);
190     unset_option (OPTSIGNALSBLOCKED);
191   }
192 }
193
194 void mutt_block_signals_system (void)
195 {
196   struct sigaction sa;
197
198   if (!option (OPTSYSSIGNALSBLOCKED)) {
199     /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD  before exec */
200     sa.sa_handler = SIG_IGN;
201     sa.sa_flags = 0;
202     sigemptyset (&sa.sa_mask);
203     sigaction (SIGINT, &sa, &SysOldInt);
204     sigaction (SIGQUIT, &sa, &SysOldQuit);
205
206     sigemptyset (&SigsetSys);
207     sigaddset (&SigsetSys, SIGCHLD);
208     sigprocmask (SIG_BLOCK, &SigsetSys, 0);
209     set_option (OPTSYSSIGNALSBLOCKED);
210   }
211 }
212
213 void mutt_unblock_signals_system (int catch)
214 {
215   if (option (OPTSYSSIGNALSBLOCKED)) {
216     sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL);
217     if (catch) {
218       sigaction (SIGQUIT, &SysOldQuit, NULL);
219       sigaction (SIGINT, &SysOldInt, NULL);
220     }
221     else {
222       struct sigaction sa;
223
224       sa.sa_handler = SIG_DFL;
225       sigemptyset (&sa.sa_mask);
226       sa.sa_flags = 0;
227       sigaction (SIGQUIT, &sa, NULL);
228       sigaction (SIGINT, &sa, NULL);
229     }
230
231     unset_option (OPTSYSSIGNALSBLOCKED);
232   }
233 }
234
235 void mutt_allow_interrupt (int disposition)
236 {
237   struct sigaction sa;
238
239   memset (&sa, 0, sizeof sa);
240   sa.sa_handler = sighandler;
241 #ifdef SA_RESTART
242   if (disposition == 0)
243     sa.sa_flags |= SA_RESTART;
244 #endif
245   sigaction (SIGINT, &sa, NULL);
246 }