Line data Source code
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 <http://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 9338 : init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
55 : {
56 : # ifdef HAVE_SIGACTION
57 : struct sigaction oact, nact;
58 :
59 9338 : if (check_ign)
60 : {
61 : /* we don't want to change an IGN handler */
62 6670 : sigaction (sig, NULL, &oact );
63 6670 : if (oact.sa_handler == SIG_IGN )
64 9338 : return;
65 : }
66 :
67 9338 : nact.sa_handler = handler;
68 9338 : sigemptyset (&nact.sa_mask);
69 9338 : nact.sa_flags = 0;
70 9338 : sigaction ( sig, &nact, NULL);
71 : # else
72 : RETSIGTYPE (*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 : }
82 : #endif /*!HAVE_DOSISH_SYSTEM*/
83 :
84 : #ifndef HAVE_DOSISH_SYSTEM
85 : static const char *
86 0 : get_signal_name( int signum )
87 : {
88 : /* Note that we can't use strsignal(), because it is not
89 : reentrant. */
90 : #if HAVE_DECL_SYS_SIGLIST && defined(NSIG)
91 0 : return (signum >= 0 && signum < NSIG) ? sys_siglist[signum] : "?";
92 : #else
93 : return NULL;
94 : #endif
95 : }
96 : #endif /*!HAVE_DOSISH_SYSTEM*/
97 :
98 : #ifndef HAVE_DOSISH_SYSTEM
99 : static RETSIGTYPE
100 0 : got_fatal_signal (int sig)
101 : {
102 : const char *s;
103 :
104 0 : if (caught_fatal_sig)
105 0 : raise (sig);
106 0 : caught_fatal_sig = 1;
107 :
108 0 : if (cleanup_fnc)
109 0 : cleanup_fnc ();
110 : /* Better don't translate these messages. */
111 0 : (void)write (2, "\n", 1 );
112 0 : s = log_get_prefix (NULL);
113 0 : if (s)
114 0 : (void)write(2, s, strlen (s));
115 0 : (void)write (2, ": signal ", 9 );
116 0 : s = get_signal_name(sig);
117 0 : if (s)
118 0 : (void) write (2, s, strlen(s) );
119 : else
120 : {
121 : /* We are in a signal handler so we can't use any kind of printf
122 : even not sprintf. So we use a straightforward algorithm. We
123 : got a report that on one particular system, raising a signal
124 : while in this handler, the parameter SIG get sclobbered and
125 : things are messed up because we modify its value. Although
126 : this is a bug in that system, we will protect against it. */
127 0 : if (sig < 0 || sig >= 100000)
128 0 : (void)write (2, "?", 1);
129 : else
130 : {
131 0 : int i, value, any=0;
132 :
133 0 : for (value=sig,i=10000; i; i /= 10)
134 : {
135 0 : if (value >= i || ((any || i==1) && !(value/i)))
136 : {
137 0 : (void)write (2, "0123456789"+(value/i), 1);
138 0 : if ((value/i))
139 0 : any = 1;
140 0 : value %= i;
141 : }
142 : }
143 : }
144 : }
145 0 : (void)write (2, " caught ... exiting\n", 20);
146 :
147 : /* Reset action to default action and raise signal again */
148 0 : init_one_signal (sig, SIG_DFL, 0);
149 : /* Fixme: remove_lockfiles ();*/
150 : #ifdef __riscos__
151 : close_fds ();
152 : #endif /* __riscos__ */
153 0 : raise( sig );
154 0 : }
155 : #endif /*!HAVE_DOSISH_SYSTEM*/
156 :
157 : #ifndef HAVE_DOSISH_SYSTEM
158 : static RETSIGTYPE
159 0 : got_usr_signal (int sig)
160 : {
161 : (void)sig;
162 0 : caught_sigusr1 = 1;
163 0 : }
164 : #endif /*!HAVE_DOSISH_SYSTEM*/
165 :
166 : void
167 1334 : gnupg_init_signals (int mode, void (*fast_cleanup)(void))
168 : {
169 1334 : assert (!mode);
170 :
171 1334 : cleanup_fnc = fast_cleanup;
172 : #ifndef HAVE_DOSISH_SYSTEM
173 1334 : init_one_signal (SIGINT, got_fatal_signal, 1 );
174 1334 : init_one_signal (SIGHUP, got_fatal_signal, 1 );
175 1334 : init_one_signal (SIGTERM, got_fatal_signal, 1 );
176 1334 : init_one_signal (SIGQUIT, got_fatal_signal, 1 );
177 1334 : init_one_signal (SIGSEGV, got_fatal_signal, 1 );
178 1334 : init_one_signal (SIGUSR1, got_usr_signal, 0 );
179 1334 : init_one_signal (SIGPIPE, SIG_IGN, 0 );
180 : #endif
181 1334 : }
182 :
183 :
184 : static void
185 0 : do_block (int block)
186 : {
187 : #ifdef HAVE_DOSISH_SYSTEM
188 : (void)block;
189 : #else /*!HAVE_DOSISH_SYSTEM*/
190 : static int is_blocked;
191 : #ifdef HAVE_SIGPROCMASK
192 : static sigset_t oldmask;
193 :
194 0 : if (block)
195 : {
196 : sigset_t newmask;
197 :
198 0 : if (is_blocked)
199 0 : log_bug ("signals are already blocked\n");
200 0 : sigfillset( &newmask );
201 0 : sigprocmask( SIG_BLOCK, &newmask, &oldmask );
202 0 : is_blocked = 1;
203 : }
204 : else
205 : {
206 0 : if (!is_blocked)
207 0 : log_bug("signals are not blocked\n");
208 0 : sigprocmask (SIG_SETMASK, &oldmask, NULL);
209 0 : is_blocked = 0;
210 : }
211 : #else /*!HAVE_SIGPROCMASK*/
212 : static void (*disposition[MAXSIG])();
213 : int sig;
214 :
215 : if (block)
216 : {
217 : if (is_blocked)
218 : log_bug("signals are already blocked\n");
219 : for (sig=1; sig < MAXSIG; sig++)
220 : {
221 : disposition[sig] = sigset (sig, SIG_HOLD);
222 : }
223 : is_blocked = 1;
224 : }
225 : else
226 : {
227 : if (!is_blocked)
228 : log_bug ("signals are not blocked\n");
229 : for (sig=1; sig < MAXSIG; sig++) {
230 : sigset (sig, disposition[sig]);
231 : }
232 : is_blocked = 0;
233 : }
234 : #endif /*!HAVE_SIGPROCMASK*/
235 : #endif /*!HAVE_DOSISH_SYSTEM*/
236 0 : }
237 :
238 :
239 : void
240 0 : gnupg_block_all_signals ()
241 : {
242 0 : do_block(1);
243 0 : }
244 :
245 : void
246 0 : gnupg_unblock_all_signals ()
247 : {
248 0 : do_block(0);
249 0 : }
|