Coverage Report

Created: 2026-02-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/signal.c
Line
Count
Source
1
/* signal.c - signal handling
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3
 *               2005 Free Software Foundation, Inc.
4
 *
5
 * This file is part of GnuPG.
6
 *
7
 * This file is free software; you can redistribute it and/or modify
8
 * it under the terms of either
9
 *
10
 *   - the GNU Lesser General Public License as published by the Free
11
 *     Software Foundation; either version 3 of the License, or (at
12
 *     your option) any later version.
13
 *
14
 * or
15
 *
16
 *   - the GNU General Public License as published by the Free
17
 *     Software Foundation; either version 2 of the License, or (at
18
 *     your option) any later version.
19
 *
20
 * or both in parallel, as here.
21
 *
22
 * This file is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU General Public License
28
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
29
 */
30
31
#include <config.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#ifdef HAVE_SIGNAL_H
35
# include <signal.h>
36
#endif
37
#include <unistd.h>
38
#include <string.h>
39
#include <errno.h>
40
#include <assert.h>
41
42
#include "util.h"
43
44
45
#ifndef HAVE_DOSISH_SYSTEM
46
static volatile int caught_fatal_sig;
47
static volatile int caught_sigusr1;
48
#endif
49
static void (*cleanup_fnc)(void);
50
51
52
#ifndef HAVE_DOSISH_SYSTEM
53
static void
54
init_one_signal (int sig, void (*handler)(int), int check_ign )
55
0
{
56
0
# ifdef HAVE_SIGACTION
57
0
  struct sigaction oact, nact;
58
59
0
  if (check_ign)
60
0
    {
61
      /* we don't want to change an IGN handler */
62
0
      sigaction (sig, NULL, &oact );
63
0
      if (oact.sa_handler == SIG_IGN )
64
0
        return;
65
0
    }
66
67
0
  nact.sa_handler = handler;
68
0
  sigemptyset (&nact.sa_mask);
69
0
  nact.sa_flags = 0;
70
0
  sigaction ( sig, &nact, NULL);
71
# else
72
  void (*ohandler)(int);
73
74
  ohandler = signal (sig, handler);
75
  if (check_ign && ohandler == SIG_IGN)
76
    {
77
      /* Change it back if it was already set to IGN */
78
      signal (sig, SIG_IGN);
79
    }
80
# endif
81
0
}
82
#endif /*!HAVE_DOSISH_SYSTEM*/
83
84
#ifndef HAVE_DOSISH_SYSTEM
85
static const char *
86
get_signal_name( int signum )
87
0
{
88
  /* Note that we can't use strsignal(), because it is not
89
     reentrant. */
90
#if HAVE_SIGDESCR_NP
91
  return sigdescr_np (signum);
92
#elif (HAVE_DECL_SYS_SIGLIST || HAVE_DECL__SYS_SIGLIST) && defined(NSIG)
93
#if HAVE_DECL_SYS_SIGLIST
94
0
#undef _sys_siglist
95
0
#define _sys_siglist sys_siglist
96
0
#endif
97
0
  return (signum >= 0 && signum < NSIG) ? _sys_siglist[signum] : "?";
98
#else
99
  return NULL;
100
#endif
101
0
}
102
#endif /*!HAVE_DOSISH_SYSTEM*/
103
104
#ifndef HAVE_DOSISH_SYSTEM
105
static void
106
got_fatal_signal (int sig)
107
0
{
108
0
  const char *s;
109
110
0
  if (caught_fatal_sig)
111
0
    raise (sig);
112
0
  caught_fatal_sig = 1;
113
114
0
  if (cleanup_fnc)
115
0
    cleanup_fnc ();
116
  /* Better don't translate these messages. */
117
0
  (void)write (2, "\n", 1 );
118
0
  s = log_get_prefix (NULL);
119
0
  if (s)
120
0
    (void)write(2, s, strlen (s));
121
0
  (void)write (2, ": signal ", 9 );
122
0
  s = get_signal_name(sig);
123
0
  if (s)
124
0
    (void) write (2, s, strlen(s) );
125
0
  else
126
0
    {
127
      /* We are in a signal handler so we can't use any kind of printf
128
         even not sprintf.  So we use a straightforward algorithm.  We
129
         got a report that on one particular system, raising a signal
130
         while in this handler, the parameter SIG get sclobbered and
131
         things are messed up because we modify its value.  Although
132
         this is a bug in that system, we will protect against it.  */
133
0
      if (sig < 0 || sig >= 100000)
134
0
        (void)write (2, "?", 1);
135
0
      else
136
0
        {
137
0
          int i, value, any=0;
138
139
0
          for (value=sig,i=10000; i; i /= 10)
140
0
            {
141
0
              if (value >= i || ((any || i==1) && !(value/i)))
142
0
                {
143
0
                  (void)write (2, &"0123456789"[value/i], 1);
144
0
                  if ((value/i))
145
0
                    any = 1;
146
0
                  value %= i;
147
0
                }
148
0
            }
149
0
        }
150
0
    }
151
0
  (void)write (2, " caught ... exiting\n", 20);
152
153
  /* Reset action to default action and raise signal again */
154
0
  init_one_signal (sig, SIG_DFL, 0);
155
  /* Fixme: remove_lockfiles ();*/
156
#ifdef __riscos__
157
  close_fds ();
158
#endif /* __riscos__ */
159
0
  raise( sig );
160
0
}
161
#endif /*!HAVE_DOSISH_SYSTEM*/
162
163
#ifndef HAVE_DOSISH_SYSTEM
164
static void
165
got_usr_signal (int sig)
166
0
{
167
0
  (void)sig;
168
0
  caught_sigusr1 = 1;
169
0
}
170
#endif /*!HAVE_DOSISH_SYSTEM*/
171
172
void
173
gnupg_init_signals (int mode, void (*fast_cleanup)(void))
174
0
{
175
0
  assert (!mode);
176
177
0
  cleanup_fnc = fast_cleanup;
178
0
#ifndef HAVE_DOSISH_SYSTEM
179
0
  init_one_signal (SIGINT, got_fatal_signal, 1 );
180
0
  init_one_signal (SIGHUP, got_fatal_signal, 1 );
181
0
  init_one_signal (SIGTERM, got_fatal_signal, 1 );
182
0
  init_one_signal (SIGQUIT, got_fatal_signal, 1 );
183
0
  init_one_signal (SIGSEGV, got_fatal_signal, 1 );
184
0
  init_one_signal (SIGUSR1, got_usr_signal, 0 );
185
0
  init_one_signal (SIGPIPE, SIG_IGN, 0 );
186
0
#endif
187
0
}
188
189
190
static void
191
do_block (int block)
192
4.40k
{
193
#ifdef HAVE_DOSISH_SYSTEM
194
  (void)block;
195
#else /*!HAVE_DOSISH_SYSTEM*/
196
4.40k
  static int is_blocked;
197
4.40k
#ifdef HAVE_SIGPROCMASK
198
4.40k
  static sigset_t oldmask;
199
200
4.40k
  if (block)
201
2.20k
    {
202
2.20k
      sigset_t newmask;
203
204
2.20k
      if (is_blocked)
205
2.20k
        log_bug ("signals are already blocked\n");
206
2.20k
      sigfillset( &newmask );
207
2.20k
      sigprocmask( SIG_BLOCK, &newmask, &oldmask );
208
2.20k
      is_blocked = 1;
209
2.20k
    }
210
2.20k
  else
211
2.20k
    {
212
2.20k
      if (!is_blocked)
213
2.20k
        log_bug("signals are not blocked\n");
214
2.20k
      sigprocmask (SIG_SETMASK, &oldmask, NULL);
215
2.20k
      is_blocked = 0;
216
2.20k
    }
217
#else /*!HAVE_SIGPROCMASK*/
218
  static void (*disposition[MAXSIG])();
219
  int sig;
220
221
  if (block)
222
    {
223
      if (is_blocked)
224
        log_bug("signals are already blocked\n");
225
      for (sig=1; sig < MAXSIG; sig++)
226
        {
227
          disposition[sig] = sigset (sig, SIG_HOLD);
228
        }
229
      is_blocked = 1;
230
    }
231
  else
232
    {
233
      if (!is_blocked)
234
        log_bug ("signals are not blocked\n");
235
      for (sig=1; sig < MAXSIG; sig++) {
236
        sigset (sig, disposition[sig]);
237
      }
238
      is_blocked = 0;
239
    }
240
#endif /*!HAVE_SIGPROCMASK*/
241
4.40k
#endif /*!HAVE_DOSISH_SYSTEM*/
242
4.40k
}
243
244
245
void
246
gnupg_block_all_signals (void)
247
2.20k
{
248
2.20k
  do_block(1);
249
2.20k
}
250
251
void
252
gnupg_unblock_all_signals (void)
253
2.20k
{
254
2.20k
  do_block(0);
255
2.20k
}