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