~ubuntu-branches/ubuntu/utopic/coreutils/utopic-proposed

« back to all changes in this revision

Viewing changes to lib/fatal-signal.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2012-11-28 03:03:42 UTC
  • mfrom: (8.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20121128030342-21zanj8354gas5gr
Tags: 8.20-3ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Make 'uname -i -p' return the real processor/hardware, instead of
    unknown.
  - Build-depend on gettext:any instead of on gettext, so that apt-get can
    properly resolve build-dependencies on the tool when cross-building.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Emergency actions in case of a fatal signal.
 
2
   Copyright (C) 2003-2004, 2006-2012 Free Software Foundation, Inc.
 
3
   Written by Bruno Haible <bruno@clisp.org>, 2003.
 
4
 
 
5
   This program is free software: you can redistribute it and/or modify
 
6
   it under the terms of the GNU General Public License as published by
 
7
   the Free Software Foundation; either version 3 of the License, or
 
8
   (at your option) any later version.
 
9
 
 
10
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
   GNU General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License
 
16
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
17
 
 
18
 
 
19
#include <config.h>
 
20
 
 
21
/* Specification.  */
 
22
#include "fatal-signal.h"
 
23
 
 
24
#include <stdbool.h>
 
25
#include <stdlib.h>
 
26
#include <signal.h>
 
27
#include <unistd.h>
 
28
 
 
29
#include "sig-handler.h"
 
30
#include "xalloc.h"
 
31
 
 
32
#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
 
33
 
 
34
/* ========================================================================= */
 
35
 
 
36
 
 
37
/* The list of fatal signals.
 
38
   These are those signals whose default action is to terminate the process
 
39
   without a core dump, except
 
40
     SIGKILL - because it cannot be caught,
 
41
     SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications
 
42
       often use them for their own purpose,
 
43
     SIGPROF SIGVTALRM - because they are used for profiling,
 
44
     SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS,
 
45
     SIGSYS - because it is more similar to SIGABRT, SIGSEGV,
 
46
     SIGPWR - because it of too special use,
 
47
     SIGRTMIN...SIGRTMAX - because they are reserved for application use.
 
48
   plus
 
49
     SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM.  */
 
50
 
 
51
static int fatal_signals[] =
 
52
  {
 
53
    /* ISO C 99 signals.  */
 
54
#ifdef SIGINT
 
55
    SIGINT,
 
56
#endif
 
57
#ifdef SIGTERM
 
58
    SIGTERM,
 
59
#endif
 
60
    /* POSIX:2001 signals.  */
 
61
#ifdef SIGHUP
 
62
    SIGHUP,
 
63
#endif
 
64
#ifdef SIGPIPE
 
65
    SIGPIPE,
 
66
#endif
 
67
    /* BSD signals.  */
 
68
#ifdef SIGXCPU
 
69
    SIGXCPU,
 
70
#endif
 
71
#ifdef SIGXFSZ
 
72
    SIGXFSZ,
 
73
#endif
 
74
    /* Native Windows signals.  */
 
75
#ifdef SIGBREAK
 
76
    SIGBREAK,
 
77
#endif
 
78
    0
 
79
  };
 
80
 
 
81
#define num_fatal_signals (SIZEOF (fatal_signals) - 1)
 
82
 
 
83
/* Eliminate signals whose signal handler is SIG_IGN.  */
 
84
 
 
85
static void
 
86
init_fatal_signals (void)
 
87
{
 
88
  static bool fatal_signals_initialized = false;
 
89
  if (!fatal_signals_initialized)
 
90
    {
 
91
      size_t i;
 
92
 
 
93
      for (i = 0; i < num_fatal_signals; i++)
 
94
        {
 
95
          struct sigaction action;
 
96
 
 
97
          if (sigaction (fatal_signals[i], NULL, &action) >= 0
 
98
              && get_handler (&action) == SIG_IGN)
 
99
            fatal_signals[i] = -1;
 
100
        }
 
101
 
 
102
      fatal_signals_initialized = true;
 
103
    }
 
104
}
 
105
 
 
106
 
 
107
/* ========================================================================= */
 
108
 
 
109
 
 
110
typedef void (*action_t) (void);
 
111
 
 
112
/* Type of an entry in the actions array.
 
113
   The 'action' field is accessed from within the fatal_signal_handler(),
 
114
   therefore we mark it as 'volatile'.  */
 
115
typedef struct
 
116
{
 
117
  volatile action_t action;
 
118
}
 
119
actions_entry_t;
 
120
 
 
121
/* The registered cleanup actions.  */
 
122
static actions_entry_t static_actions[32];
 
123
static actions_entry_t * volatile actions = static_actions;
 
124
static sig_atomic_t volatile actions_count = 0;
 
125
static size_t actions_allocated = SIZEOF (static_actions);
 
126
 
 
127
 
 
128
/* The saved signal handlers.
 
129
   Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34.  */
 
130
static struct sigaction saved_sigactions[64];
 
131
 
 
132
 
 
133
/* Uninstall the handlers.  */
 
134
static inline void
 
135
uninstall_handlers (void)
 
136
{
 
137
  size_t i;
 
138
 
 
139
  for (i = 0; i < num_fatal_signals; i++)
 
140
    if (fatal_signals[i] >= 0)
 
141
      {
 
142
        int sig = fatal_signals[i];
 
143
        if (saved_sigactions[sig].sa_handler == SIG_IGN)
 
144
          saved_sigactions[sig].sa_handler = SIG_DFL;
 
145
        sigaction (sig, &saved_sigactions[sig], NULL);
 
146
      }
 
147
}
 
148
 
 
149
 
 
150
/* The signal handler.  It gets called asynchronously.  */
 
151
static void
 
152
fatal_signal_handler (int sig)
 
153
{
 
154
  for (;;)
 
155
    {
 
156
      /* Get the last registered cleanup action, in a reentrant way.  */
 
157
      action_t action;
 
158
      size_t n = actions_count;
 
159
      if (n == 0)
 
160
        break;
 
161
      n--;
 
162
      actions_count = n;
 
163
      action = actions[n].action;
 
164
      /* Execute the action.  */
 
165
      action ();
 
166
    }
 
167
 
 
168
  /* Now execute the signal's default action.
 
169
     If the signal being delivered was blocked, the re-raised signal would be
 
170
     delivered when this handler returns.  But the way we install this handler,
 
171
     no signal is blocked, and the re-raised signal is delivered already
 
172
     during raise().  */
 
173
  uninstall_handlers ();
 
174
  raise (sig);
 
175
}
 
176
 
 
177
 
 
178
/* Install the handlers.  */
 
179
static inline void
 
180
install_handlers (void)
 
181
{
 
182
  size_t i;
 
183
  struct sigaction action;
 
184
 
 
185
  action.sa_handler = &fatal_signal_handler;
 
186
  /* If we get a fatal signal while executing fatal_signal_handler, enter
 
187
     fatal_signal_handler recursively, since it is reentrant.  Hence no
 
188
     SA_RESETHAND.  */
 
189
  action.sa_flags = SA_NODEFER;
 
190
  sigemptyset (&action.sa_mask);
 
191
  for (i = 0; i < num_fatal_signals; i++)
 
192
    if (fatal_signals[i] >= 0)
 
193
      {
 
194
        int sig = fatal_signals[i];
 
195
 
 
196
        if (!(sig < sizeof (saved_sigactions) / sizeof (saved_sigactions[0])))
 
197
          abort ();
 
198
        sigaction (sig, &action, &saved_sigactions[sig]);
 
199
      }
 
200
}
 
201
 
 
202
 
 
203
/* Register a cleanup function to be executed when a catchable fatal signal
 
204
   occurs.  */
 
205
void
 
206
at_fatal_signal (action_t action)
 
207
{
 
208
  static bool cleanup_initialized = false;
 
209
  if (!cleanup_initialized)
 
210
    {
 
211
      init_fatal_signals ();
 
212
      install_handlers ();
 
213
      cleanup_initialized = true;
 
214
    }
 
215
 
 
216
  if (actions_count == actions_allocated)
 
217
    {
 
218
      /* Extend the actions array.  Note that we cannot use xrealloc(),
 
219
         because then the cleanup() function could access an already
 
220
         deallocated array.  */
 
221
      actions_entry_t *old_actions = actions;
 
222
      size_t old_actions_allocated = actions_allocated;
 
223
      size_t new_actions_allocated = 2 * actions_allocated;
 
224
      actions_entry_t *new_actions =
 
225
        XNMALLOC (new_actions_allocated, actions_entry_t);
 
226
      size_t k;
 
227
 
 
228
      /* Don't use memcpy() here, because memcpy takes non-volatile arguments
 
229
         and is therefore not guaranteed to complete all memory stores before
 
230
         the next statement.  */
 
231
      for (k = 0; k < old_actions_allocated; k++)
 
232
        new_actions[k] = old_actions[k];
 
233
      actions = new_actions;
 
234
      actions_allocated = new_actions_allocated;
 
235
      /* Now we can free the old actions array.  */
 
236
      if (old_actions != static_actions)
 
237
        free (old_actions);
 
238
    }
 
239
  /* The two uses of 'volatile' in the types above (and ISO C 99 section
 
240
     5.1.2.3.(5)) ensure that we increment the actions_count only after
 
241
     the new action has been written to the memory location
 
242
     actions[actions_count].  */
 
243
  actions[actions_count].action = action;
 
244
  actions_count++;
 
245
}
 
246
 
 
247
 
 
248
/* ========================================================================= */
 
249
 
 
250
 
 
251
static sigset_t fatal_signal_set;
 
252
 
 
253
static void
 
254
init_fatal_signal_set (void)
 
255
{
 
256
  static bool fatal_signal_set_initialized = false;
 
257
  if (!fatal_signal_set_initialized)
 
258
    {
 
259
      size_t i;
 
260
 
 
261
      init_fatal_signals ();
 
262
 
 
263
      sigemptyset (&fatal_signal_set);
 
264
      for (i = 0; i < num_fatal_signals; i++)
 
265
        if (fatal_signals[i] >= 0)
 
266
          sigaddset (&fatal_signal_set, fatal_signals[i]);
 
267
 
 
268
      fatal_signal_set_initialized = true;
 
269
    }
 
270
}
 
271
 
 
272
/* Temporarily delay the catchable fatal signals.  */
 
273
void
 
274
block_fatal_signals (void)
 
275
{
 
276
  init_fatal_signal_set ();
 
277
  sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
 
278
}
 
279
 
 
280
/* Stop delaying the catchable fatal signals.  */
 
281
void
 
282
unblock_fatal_signals (void)
 
283
{
 
284
  init_fatal_signal_set ();
 
285
  sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
 
286
}