mutt stable branch with some hacks
at master 253 lines 6.4 kB view raw
1/* 2 * Copyright (C) 1996-2000,2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 31static sigset_t Sigset; 32static sigset_t SigsetSys; 33static struct sigaction SysOldInt; 34static struct sigaction SysOldQuit; 35static int IsEndwin = 0; 36 37/* Attempt to catch "ordinary" signals and shut down gracefully. */ 38static void 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 58static void chld_handler (int sig) 59{ 60 /* empty */ 61} 62 63static void sighandler (int sig) 64{ 65 int save_errno = errno; 66 67 switch (sig) 68 { 69 case SIGTSTP: /* user requested a suspend */ 70 if (!option (OPTSUSPEND)) 71 break; 72 IsEndwin = isendwin (); 73 curs_set (1); 74 if (!IsEndwin) 75 endwin (); 76 kill (0, SIGSTOP); 77 78 case SIGCONT: 79 if (!IsEndwin) 80 refresh (); 81 mutt_curs_set (-1); 82#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM) 83 /* We don't receive SIGWINCH when suspended; however, no harm is done by 84 * just assuming we received one, and triggering the 'resize' anyway. */ 85 SigWinch = 1; 86#endif 87 break; 88 89#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM) 90 case SIGWINCH: 91 SigWinch = 1; 92 break; 93#endif 94 95 case SIGINT: 96 SigInt = 1; 97 break; 98 99 } 100 errno = save_errno; 101} 102 103#ifdef USE_SLANG_CURSES 104int mutt_intr_hook (void) 105{ 106 return (-1); 107} 108#endif /* USE_SLANG_CURSES */ 109 110void mutt_signal_init (void) 111{ 112 struct sigaction act; 113 114 sigemptyset (&act.sa_mask); 115 act.sa_flags = 0; 116 act.sa_handler = SIG_IGN; 117 sigaction (SIGPIPE, &act, NULL); 118 119 act.sa_handler = exit_handler; 120 sigaction (SIGTERM, &act, NULL); 121 sigaction (SIGHUP, &act, NULL); 122 sigaction (SIGQUIT, &act, NULL); 123 124 /* we want to avoid race conditions */ 125 sigaddset (&act.sa_mask, SIGTSTP); 126 127 act.sa_handler = sighandler; 128 129 /* we want SIGALRM to abort the current syscall, so we do this before 130 * setting the SA_RESTART flag below. currently this is only used to 131 * timeout on a connect() call in a reasonable amount of time. 132 */ 133 sigaction (SIGALRM, &act, NULL); 134 135 /* we also don't want to mess with interrupted system calls */ 136#ifdef SA_RESTART 137 act.sa_flags = SA_RESTART; 138#endif 139 140 sigaction (SIGCONT, &act, NULL); 141 sigaction (SIGTSTP, &act, NULL); 142 sigaction (SIGINT, &act, NULL); 143#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM) 144 sigaction (SIGWINCH, &act, NULL); 145#endif 146 147 /* POSIX doesn't allow us to ignore SIGCHLD, 148 * so we just install a dummy handler for it 149 */ 150 act.sa_handler = chld_handler; 151 /* don't need to block any other signals here */ 152 sigemptyset (&act.sa_mask); 153 /* we don't want to mess with stopped children */ 154 act.sa_flags |= SA_NOCLDSTOP; 155 sigaction (SIGCHLD, &act, NULL); 156 157#ifdef USE_SLANG_CURSES 158 /* This bit of code is required because of the implementation of 159 * SLcurses_wgetch(). If a signal is received (like SIGWINCH) when we 160 * are in blocking mode, SLsys_getkey() will not return an error unless 161 * a handler function is defined and it returns -1. This is needed so 162 * that if the user resizes the screen while at a prompt, it will just 163 * abort and go back to the main-menu. 164 */ 165 SLang_getkey_intr_hook = mutt_intr_hook; 166#endif 167} 168 169/* signals which are important to block while doing critical ops */ 170void mutt_block_signals (void) 171{ 172 if (!option (OPTSIGNALSBLOCKED)) 173 { 174 sigemptyset (&Sigset); 175 sigaddset (&Sigset, SIGTERM); 176 sigaddset (&Sigset, SIGHUP); 177 sigaddset (&Sigset, SIGTSTP); 178 sigaddset (&Sigset, SIGINT); 179#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM) 180 sigaddset (&Sigset, SIGWINCH); 181#endif 182 sigprocmask (SIG_BLOCK, &Sigset, 0); 183 set_option (OPTSIGNALSBLOCKED); 184 } 185} 186 187/* restore the previous signal mask */ 188void mutt_unblock_signals (void) 189{ 190 if (option (OPTSIGNALSBLOCKED)) 191 { 192 sigprocmask (SIG_UNBLOCK, &Sigset, 0); 193 unset_option (OPTSIGNALSBLOCKED); 194 } 195} 196 197void mutt_block_signals_system (void) 198{ 199 struct sigaction sa; 200 201 if (! option (OPTSYSSIGNALSBLOCKED)) 202 { 203 /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD before exec */ 204 sa.sa_handler = SIG_IGN; 205 sa.sa_flags = 0; 206 sigemptyset (&sa.sa_mask); 207 sigaction (SIGINT, &sa, &SysOldInt); 208 sigaction (SIGQUIT, &sa, &SysOldQuit); 209 210 sigemptyset (&SigsetSys); 211 sigaddset (&SigsetSys, SIGCHLD); 212 sigprocmask (SIG_BLOCK, &SigsetSys, 0); 213 set_option (OPTSYSSIGNALSBLOCKED); 214 } 215} 216 217void mutt_unblock_signals_system (int catch) 218{ 219 if (option (OPTSYSSIGNALSBLOCKED)) 220 { 221 sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL); 222 if (catch) 223 { 224 sigaction (SIGQUIT, &SysOldQuit, NULL); 225 sigaction (SIGINT, &SysOldInt, NULL); 226 } 227 else 228 { 229 struct sigaction sa; 230 231 sa.sa_handler = SIG_DFL; 232 sigemptyset (&sa.sa_mask); 233 sa.sa_flags = 0; 234 sigaction (SIGQUIT, &sa, NULL); 235 sigaction (SIGINT, &sa, NULL); 236 } 237 238 unset_option (OPTSYSSIGNALSBLOCKED); 239 } 240} 241 242void mutt_allow_interrupt (int disposition) 243{ 244 struct sigaction sa; 245 246 memset (&sa, 0, sizeof sa); 247 sa.sa_handler = sighandler; 248#ifdef SA_RESTART 249 if (disposition == 0) 250 sa.sa_flags |= SA_RESTART; 251#endif 252 sigaction (SIGINT, &sa, NULL); 253}