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