8609671b937c3d1c36864f2dc7ce21de399e8298
[apps/madmutt.git] / lib-sys / mutt_signal.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #include <lib-lib/lib-lib.h>
11
12 #include <lib-ui/curses.h>
13
14 #include "mutt_signal.h"
15
16 static sigset_t Sigset;
17 static sigset_t SigsetSys;
18 static struct sigaction SysOldInt;
19 static struct sigaction SysOldQuit;
20 static int IsEndwin = 0;
21
22 /* Attempt to catch "ordinary" signals and shut down gracefully. */
23 static void exit_handler (int sig)
24 {
25   curs_set (1);
26   endwin ();                    /* just to be safe */
27   printf(_("Caught %s...  Exiting.\n"), strsignal(sig));
28   exit (0);
29 }
30
31 static void chld_handler(int sig __attribute__((unused)))
32 {
33   /* empty */
34 }
35
36 static void sighandler (int sig)
37 {
38   int save_errno = errno;
39
40   switch (sig) {
41   case SIGTSTP:                /* user requested a suspend */
42     if (!option (OPTSUSPEND))
43       break;
44     IsEndwin = isendwin ();
45     curs_set (1);
46     if (!IsEndwin)
47       endwin ();
48     kill (0, SIGSTOP);
49
50   case SIGCONT:
51     if (!IsEndwin)
52       refresh ();
53     mutt_curs_set (-1);
54 #if defined (HAVE_RESIZETERM)
55     /* We don't receive SIGWINCH when suspended; however, no harm is done by
56      * just assuming we received one, and triggering the 'resize' anyway. */
57     SigWinch = 1;
58 #endif
59     break;
60
61 #if defined (HAVE_RESIZETERM)
62   case SIGWINCH:
63     SigWinch = 1;
64     break;
65 #endif
66
67   case SIGINT:
68     SigInt = 1;
69     break;
70
71   }
72   errno = save_errno;
73 }
74
75 void mutt_signal_initialize (void)
76 {
77   struct sigaction act;
78
79   sigemptyset (&act.sa_mask);
80   act.sa_flags = 0;
81   act.sa_handler = SIG_IGN;
82   sigaction (SIGPIPE, &act, NULL);
83
84   act.sa_handler = exit_handler;
85   sigaction (SIGTERM, &act, NULL);
86   sigaction (SIGHUP, &act, NULL);
87   sigaction (SIGQUIT, &act, NULL);
88
89   /* we want to avoid race conditions */
90   sigaddset (&act.sa_mask, SIGTSTP);
91
92   act.sa_handler = sighandler;
93
94   /* we want SIGALRM to abort the current syscall, so we do this before
95    * setting the SA_RESTART flag below.  currently this is only used to
96    * timeout on a connect() call in a reasonable amout of time.
97    */
98   sigaction (SIGALRM, &act, NULL);
99
100   /* we also don't want to mess with interrupted system calls */
101 #ifdef SA_RESTART
102   act.sa_flags = SA_RESTART;
103 #endif
104
105   sigaction (SIGCONT, &act, NULL);
106   sigaction (SIGTSTP, &act, NULL);
107   sigaction (SIGINT, &act, NULL);
108 #if defined (HAVE_RESIZETERM)
109   sigaction (SIGWINCH, &act, NULL);
110 #endif
111
112   /* POSIX doesn't allow us to ignore SIGCHLD,
113    * so we just install a dummy handler for it
114    */
115   act.sa_handler = chld_handler;
116   /* don't need to block any other signals here */
117   sigemptyset (&act.sa_mask);
118   /* we don't want to mess with stopped children */
119   act.sa_flags |= SA_NOCLDSTOP;
120   sigaction (SIGCHLD, &act, NULL);
121 }
122
123 /* signals which are important to block while doing critical ops */
124 void mutt_block_signals (void)
125 {
126   if (!option (OPTSIGNALSBLOCKED)) {
127     sigemptyset (&Sigset);
128     sigaddset (&Sigset, SIGTERM);
129     sigaddset (&Sigset, SIGHUP);
130     sigaddset (&Sigset, SIGTSTP);
131     sigaddset (&Sigset, SIGINT);
132 #if defined (HAVE_RESIZETERM)
133     sigaddset (&Sigset, SIGWINCH);
134 #endif
135     sigprocmask (SIG_BLOCK, &Sigset, 0);
136     set_option (OPTSIGNALSBLOCKED);
137   }
138 }
139
140 /* restore the previous signal mask */
141 void mutt_unblock_signals (void)
142 {
143   if (option (OPTSIGNALSBLOCKED)) {
144     sigprocmask (SIG_UNBLOCK, &Sigset, 0);
145     unset_option (OPTSIGNALSBLOCKED);
146   }
147 }
148
149 void mutt_block_signals_system (void)
150 {
151   struct sigaction sa;
152
153   if (!option (OPTSYSSIGNALSBLOCKED)) {
154     /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD  before exec */
155     sa.sa_handler = SIG_IGN;
156     sa.sa_flags = 0;
157     sigemptyset (&sa.sa_mask);
158     sigaction (SIGINT, &sa, &SysOldInt);
159     sigaction (SIGQUIT, &sa, &SysOldQuit);
160
161     sigemptyset (&SigsetSys);
162     sigaddset (&SigsetSys, SIGCHLD);
163     sigprocmask (SIG_BLOCK, &SigsetSys, 0);
164     set_option (OPTSYSSIGNALSBLOCKED);
165   }
166 }
167
168 void mutt_unblock_signals_system (int catch)
169 {
170   if (option (OPTSYSSIGNALSBLOCKED)) {
171     sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL);
172     if (catch) {
173       sigaction (SIGQUIT, &SysOldQuit, NULL);
174       sigaction (SIGINT, &SysOldInt, NULL);
175     }
176     else {
177       struct sigaction sa;
178
179       sa.sa_handler = SIG_DFL;
180       sigemptyset (&sa.sa_mask);
181       sa.sa_flags = 0;
182       sigaction (SIGQUIT, &sa, NULL);
183       sigaction (SIGINT, &sa, NULL);
184     }
185
186     unset_option (OPTSYSSIGNALSBLOCKED);
187   }
188 }
189
190 void mutt_allow_interrupt (int disposition)
191 {
192   struct sigaction sa;
193
194   p_clear(&sa, 1);
195   sa.sa_handler = sighandler;
196 #ifdef SA_RESTART
197   if (disposition == 0)
198     sa.sa_flags |= SA_RESTART;
199 #endif
200   sigaction (SIGINT, &sa, NULL);
201 }