8be8fcee3648d177b077e027aae733c5a2502822
[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       wrefresh (stdscr);
53     mutt_curs_set (-1);
54     /* We don't receive SIGWINCH when suspended; however, no harm is done by
55      * just assuming we received one, and triggering the 'resize' anyway. */
56   case SIGWINCH:
57     SigWinch = 1;
58     break;
59
60   case SIGINT:
61     SigInt = 1;
62     break;
63
64   }
65   errno = save_errno;
66 }
67
68 void mutt_signal_initialize (void)
69 {
70   struct sigaction act;
71
72   sigemptyset (&act.sa_mask);
73   act.sa_flags = 0;
74   act.sa_handler = SIG_IGN;
75   sigaction (SIGPIPE, &act, NULL);
76
77   act.sa_handler = exit_handler;
78   sigaction (SIGTERM, &act, NULL);
79   sigaction (SIGHUP, &act, NULL);
80   sigaction (SIGQUIT, &act, NULL);
81
82   /* we want to avoid race conditions */
83   sigaddset (&act.sa_mask, SIGTSTP);
84
85   act.sa_handler = sighandler;
86
87   /* we want SIGALRM to abort the current syscall, so we do this before
88    * setting the SA_RESTART flag below.  currently this is only used to
89    * timeout on a connect() call in a reasonable amout of time.
90    */
91   sigaction (SIGALRM, &act, NULL);
92
93   /* we also don't want to mess with interrupted system calls */
94 #ifdef SA_RESTART
95   act.sa_flags = SA_RESTART;
96 #endif
97
98   sigaction (SIGCONT, &act, NULL);
99   sigaction (SIGTSTP, &act, NULL);
100   sigaction (SIGINT, &act, NULL);
101   sigaction (SIGWINCH, &act, NULL);
102
103   /* POSIX doesn't allow us to ignore SIGCHLD,
104    * so we just install a dummy handler for it
105    */
106   act.sa_handler = chld_handler;
107   /* don't need to block any other signals here */
108   sigemptyset (&act.sa_mask);
109   /* we don't want to mess with stopped children */
110   act.sa_flags |= SA_NOCLDSTOP;
111   sigaction (SIGCHLD, &act, NULL);
112 }
113
114 /* signals which are important to block while doing critical ops */
115 void mutt_block_signals (void)
116 {
117   if (!option (OPTSIGNALSBLOCKED)) {
118     sigemptyset (&Sigset);
119     sigaddset (&Sigset, SIGTERM);
120     sigaddset (&Sigset, SIGHUP);
121     sigaddset (&Sigset, SIGTSTP);
122     sigaddset (&Sigset, SIGINT);
123     sigaddset (&Sigset, SIGWINCH);
124     sigprocmask (SIG_BLOCK, &Sigset, 0);
125     set_option (OPTSIGNALSBLOCKED);
126   }
127 }
128
129 /* restore the previous signal mask */
130 void mutt_unblock_signals (void)
131 {
132   if (option (OPTSIGNALSBLOCKED)) {
133     sigprocmask (SIG_UNBLOCK, &Sigset, 0);
134     unset_option (OPTSIGNALSBLOCKED);
135   }
136 }
137
138 void mutt_block_signals_system (void)
139 {
140   struct sigaction sa;
141
142   if (!option (OPTSYSSIGNALSBLOCKED)) {
143     /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD  before exec */
144     sa.sa_handler = SIG_IGN;
145     sa.sa_flags = 0;
146     sigemptyset (&sa.sa_mask);
147     sigaction (SIGINT, &sa, &SysOldInt);
148     sigaction (SIGQUIT, &sa, &SysOldQuit);
149
150     sigemptyset (&SigsetSys);
151     sigaddset (&SigsetSys, SIGCHLD);
152     sigprocmask (SIG_BLOCK, &SigsetSys, 0);
153     set_option (OPTSYSSIGNALSBLOCKED);
154   }
155 }
156
157 void mutt_unblock_signals_system (int catch)
158 {
159   if (option (OPTSYSSIGNALSBLOCKED)) {
160     sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL);
161     if (catch) {
162       sigaction (SIGQUIT, &SysOldQuit, NULL);
163       sigaction (SIGINT, &SysOldInt, NULL);
164     }
165     else {
166       struct sigaction sa;
167
168       sa.sa_handler = SIG_DFL;
169       sigemptyset (&sa.sa_mask);
170       sa.sa_flags = 0;
171       sigaction (SIGQUIT, &sa, NULL);
172       sigaction (SIGINT, &sa, NULL);
173     }
174
175     unset_option (OPTSYSSIGNALSBLOCKED);
176   }
177 }
178
179 void mutt_allow_interrupt (int disposition)
180 {
181   struct sigaction sa;
182
183   p_clear(&sa, 1);
184   sa.sa_handler = sighandler;
185 #ifdef SA_RESTART
186   if (disposition == 0)
187     sa.sa_flags |= SA_RESTART;
188 #endif
189   sigaction (SIGINT, &sa, NULL);
190 }