signal.c 6.27 KB
Newer Older
Thomas Roessler's avatar
Thomas Roessler committed
1
/*
2
 * Copyright (C) 1996-2000,2012 Michael R. Elkins <me@mutt.org>
Thomas Roessler's avatar
Thomas Roessler committed
3 4 5 6 7 8 9 10 11 12 13 14 15
 * 
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program; if not, write to the Free Software
16
 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Thomas Roessler's avatar
Thomas Roessler committed
17 18
 */ 

19 20 21 22
#if HAVE_CONFIG_H
# include "config.h"
#endif

Thomas Roessler's avatar
Thomas Roessler committed
23 24 25 26 27 28
#include "mutt.h"
#include "mutt_curses.h"

#include <signal.h>
#include <string.h>
#include <sys/wait.h>
29
#include <errno.h>
Thomas Roessler's avatar
Thomas Roessler committed
30 31

static sigset_t Sigset;
32
static sigset_t SigsetSys;
33 34
static struct sigaction SysOldInt;
static struct sigaction SysOldQuit;
Thomas Roessler's avatar
Thomas Roessler committed
35 36 37
static int IsEndwin = 0;

/* Attempt to catch "ordinary" signals and shut down gracefully. */
38
static void exit_handler (int sig)
Thomas Roessler's avatar
Thomas Roessler committed
39 40 41 42
{
  curs_set (1);
  endwin (); /* just to be safe */
#if SYS_SIGLIST_DECLARED
43
  printf(_("%s...  Exiting.\n"), sys_siglist[sig]);
Thomas Roessler's avatar
Thomas Roessler committed
44 45
#else
#if (__sun__ && __svr4__)
46
  printf(_("Caught %s...  Exiting.\n"), _sys_siglist[sig]);
47 48 49
#else
#if (__alpha && __osf__)
  printf(_("Caught %s...  Exiting.\n"), __sys_siglist[sig]);
Thomas Roessler's avatar
Thomas Roessler committed
50
#else
51
  printf(_("Caught signal %d...  Exiting.\n"), sig);
Thomas Roessler's avatar
Thomas Roessler committed
52
#endif
53
#endif
Thomas Roessler's avatar
Thomas Roessler committed
54 55 56 57
#endif
  exit (0);
}

58
static void chld_handler (int sig)
Thomas Roessler's avatar
Thomas Roessler committed
59
{
60
  /* empty */
Thomas Roessler's avatar
Thomas Roessler committed
61 62
}

63
static void sighandler (int sig)
Thomas Roessler's avatar
Thomas Roessler committed
64
{
65 66
  int save_errno = errno;

Thomas Roessler's avatar
Thomas Roessler committed
67 68 69
  switch (sig)
  {
    case SIGTSTP: /* user requested a suspend */
70
      if (!option (OPTSUSPEND))
Thomas Roessler's avatar
Thomas Roessler committed
71 72 73 74 75 76 77 78 79 80 81
        break;
      IsEndwin = isendwin ();
      curs_set (1);
      if (!IsEndwin)
	endwin ();
      kill (0, SIGSTOP);

    case SIGCONT:
      if (!IsEndwin)
	refresh ();
      mutt_curs_set (-1);
82 83 84 85 86
#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
      /* We don't receive SIGWINCH when suspended; however, no harm is done by
       * just assuming we received one, and triggering the 'resize' anyway. */
      SigWinch = 1;
#endif
Thomas Roessler's avatar
Thomas Roessler committed
87 88 89 90
      break;

#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
    case SIGWINCH:
91
      SigWinch = 1;
Thomas Roessler's avatar
Thomas Roessler committed
92 93
      break;
#endif
94

Thomas Roessler's avatar
Thomas Roessler committed
95
    case SIGINT:
96
      SigInt = 1;
Thomas Roessler's avatar
Thomas Roessler committed
97 98 99
      break;

  }
100
  errno = save_errno;
Thomas Roessler's avatar
Thomas Roessler committed
101 102 103 104 105 106 107 108 109 110 111 112 113
}

#ifdef USE_SLANG_CURSES
int mutt_intr_hook (void)
{
  return (-1);
}
#endif /* USE_SLANG_CURSES */

void mutt_signal_init (void)
{
  struct sigaction act;

114 115
  sigemptyset (&act.sa_mask);
  act.sa_flags = 0;
Thomas Roessler's avatar
Thomas Roessler committed
116 117 118
  act.sa_handler = SIG_IGN;
  sigaction (SIGPIPE, &act, NULL);

119
  act.sa_handler = exit_handler;
Thomas Roessler's avatar
Thomas Roessler committed
120 121
  sigaction (SIGTERM, &act, NULL);
  sigaction (SIGHUP, &act, NULL);
122
  sigaction (SIGQUIT, &act, NULL);
Thomas Roessler's avatar
Thomas Roessler committed
123

124 125
  /* we want to avoid race conditions */
  sigaddset (&act.sa_mask, SIGTSTP);
Thomas Roessler's avatar
Thomas Roessler committed
126

127 128 129 130
  act.sa_handler = sighandler;

  /* we want SIGALRM to abort the current syscall, so we do this before
   * setting the SA_RESTART flag below.  currently this is only used to
Ondřej Bílka's avatar
Ondřej Bílka committed
131
   * timeout on a connect() call in a reasonable amount of time.
132 133 134
   */
  sigaction (SIGALRM, &act, NULL);

135
  /* we also don't want to mess with interrupted system calls */
Thomas Roessler's avatar
Thomas Roessler committed
136 137 138 139
#ifdef SA_RESTART
  act.sa_flags = SA_RESTART;
#endif

140 141 142
  sigaction (SIGCONT, &act, NULL);
  sigaction (SIGTSTP, &act, NULL);
  sigaction (SIGINT, &act, NULL);
Thomas Roessler's avatar
Thomas Roessler committed
143 144 145 146
#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
  sigaction (SIGWINCH, &act, NULL);
#endif

147 148 149 150 151 152
  /* POSIX doesn't allow us to ignore SIGCHLD,
   * so we just install a dummy handler for it
   */
  act.sa_handler = chld_handler;
  /* don't need to block any other signals here */
  sigemptyset (&act.sa_mask);
Thomas Roessler's avatar
Thomas Roessler committed
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
  /* we don't want to mess with stopped children */
  act.sa_flags |= SA_NOCLDSTOP;
  sigaction (SIGCHLD, &act, NULL);

#ifdef USE_SLANG_CURSES
  /* This bit of code is required because of the implementation of
   * SLcurses_wgetch().  If a signal is received (like SIGWINCH) when we
   * are in blocking mode, SLsys_getkey() will not return an error unless
   * a handler function is defined and it returns -1.  This is needed so
   * that if the user resizes the screen while at a prompt, it will just
   * abort and go back to the main-menu.
   */
  SLang_getkey_intr_hook = mutt_intr_hook;
#endif
}

/* signals which are important to block while doing critical ops */
void mutt_block_signals (void)
{
  if (!option (OPTSIGNALSBLOCKED))
  {
    sigemptyset (&Sigset);
    sigaddset (&Sigset, SIGTERM);
176
    sigaddset (&Sigset, SIGHUP);
Thomas Roessler's avatar
Thomas Roessler committed
177
    sigaddset (&Sigset, SIGTSTP);
178 179 180 181
    sigaddset (&Sigset, SIGINT);
#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
    sigaddset (&Sigset, SIGWINCH);
#endif
Thomas Roessler's avatar
Thomas Roessler committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    sigprocmask (SIG_BLOCK, &Sigset, 0);
    set_option (OPTSIGNALSBLOCKED);
  }
}

/* restore the previous signal mask */
void mutt_unblock_signals (void)
{
  if (option (OPTSIGNALSBLOCKED))
  {
    sigprocmask (SIG_UNBLOCK, &Sigset, 0);
    unset_option (OPTSIGNALSBLOCKED);
  }
}

void mutt_block_signals_system (void)
{
  struct sigaction sa;

201
  if (! option (OPTSYSSIGNALSBLOCKED))
Thomas Roessler's avatar
Thomas Roessler committed
202
  {
203
    /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD  before exec */
Thomas Roessler's avatar
Thomas Roessler committed
204 205
    sa.sa_handler = SIG_IGN;
    sa.sa_flags = 0;
206 207 208
    sigemptyset (&sa.sa_mask);
    sigaction (SIGINT, &sa, &SysOldInt);
    sigaction (SIGQUIT, &sa, &SysOldQuit);
209 210 211 212

    sigemptyset (&SigsetSys);
    sigaddset (&SigsetSys, SIGCHLD);
    sigprocmask (SIG_BLOCK, &SigsetSys, 0);
213
    set_option (OPTSYSSIGNALSBLOCKED);
Thomas Roessler's avatar
Thomas Roessler committed
214 215 216 217 218
  }
}

void mutt_unblock_signals_system (int catch)
{
219
  if (option (OPTSYSSIGNALSBLOCKED))
Thomas Roessler's avatar
Thomas Roessler committed
220
  {
221
    sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL);
Thomas Roessler's avatar
Thomas Roessler committed
222
    if (catch)
223
    {
224 225
      sigaction (SIGQUIT, &SysOldQuit, NULL);
      sigaction (SIGINT, &SysOldInt, NULL);
226 227 228
    }
    else
    {
229 230
      struct sigaction sa;

231
      sa.sa_handler = SIG_DFL;
232 233
      sigemptyset (&sa.sa_mask);
      sa.sa_flags = 0;
234 235 236 237
      sigaction (SIGQUIT, &sa, NULL);
      sigaction (SIGINT, &sa, NULL);
    }

238
    unset_option (OPTSYSSIGNALSBLOCKED);
Thomas Roessler's avatar
Thomas Roessler committed
239 240
  }
}
241 242 243 244 245 246 247 248 249 250 251 252 253

void mutt_allow_interrupt (int disposition)
{
  struct sigaction sa;
  
  memset (&sa, 0, sizeof sa);
  sa.sa_handler = sighandler;
#ifdef SA_RESTART
  if (disposition == 0)
    sa.sa_flags |= SA_RESTART;
#endif
  sigaction (SIGINT, &sa, NULL);
}