Line data Source code
1 : /* Quagga signal handling functions.
2 : * Copyright (C) 2004 Paul Jakma,
3 : *
4 : * This file is part of Quagga.
5 : *
6 : * Quagga is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * Quagga is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with Quagga; see the file COPYING. If not, write to the Free
18 : * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : * 02111-1307, USA.
20 : */
21 :
22 : #include <zebra.h>
23 : #include <sigevent.h>
24 : #include <log.h>
25 : #include <memory.h>
26 :
27 : #ifdef SA_SIGINFO
28 : #ifdef HAVE_UCONTEXT_H
29 : #ifdef GNU_LINUX
30 : /* get REG_EIP from ucontext.h */
31 : #ifndef __USE_GNU
32 : #define __USE_GNU
33 : #endif /* __USE_GNU */
34 : #endif /* GNU_LINUX */
35 : #include <ucontext.h>
36 : #endif /* HAVE_UCONTEXT_H */
37 : #endif /* SA_SIGINFO */
38 :
39 :
40 : /* master signals descriptor struct */
41 : struct quagga_sigevent_master_t
42 : {
43 : struct thread *t;
44 :
45 : struct quagga_signal_t *signals;
46 : int sigc;
47 :
48 : volatile sig_atomic_t caught;
49 : } sigmaster;
50 :
51 : /* Generic signal handler
52 : * Schedules signal event thread
53 : */
54 : static void
55 90 : quagga_signal_handler (int signo)
56 : {
57 : int i;
58 : struct quagga_signal_t *sig;
59 :
60 450 : for (i = 0; i < sigmaster.sigc; i++)
61 : {
62 360 : sig = &(sigmaster.signals[i]);
63 :
64 360 : if (sig->signal == signo)
65 90 : sig->caught = 1;
66 : }
67 :
68 90 : sigmaster.caught = 1;
69 90 : }
70 :
71 : /* check if signals have been caught and run appropriate handlers */
72 : int
73 2274 : quagga_sigevent_process (void)
74 : {
75 : struct quagga_signal_t *sig;
76 : int i;
77 : #ifdef SIGEVENT_BLOCK_SIGNALS
78 : /* shouldnt need to block signals, but potentially may be needed */
79 : sigset_t newmask, oldmask;
80 :
81 : /*
82 : * Block most signals, but be careful not to defer SIGTRAP because
83 : * doing so breaks gdb, at least on NetBSD 2.0. Avoid asking to
84 : * block SIGKILL, just because we shouldn't be able to do so.
85 : */
86 : sigfillset (&newmask);
87 : sigdelset (&newmask, SIGTRAP);
88 : sigdelset (&newmask, SIGKILL);
89 :
90 : if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0)
91 : {
92 : zlog_err ("quagga_signal_timer: couldnt block signals!");
93 : return -1;
94 : }
95 : #endif /* SIGEVENT_BLOCK_SIGNALS */
96 :
97 2274 : if (sigmaster.caught > 0)
98 : {
99 45 : sigmaster.caught = 0;
100 : /* must not read or set sigmaster.caught after here,
101 : * race condition with per-sig caught flags if one does
102 : */
103 :
104 180 : for (i = 0; i < sigmaster.sigc; i++)
105 : {
106 180 : sig = &(sigmaster.signals[i]);
107 :
108 180 : if (sig->caught > 0)
109 : {
110 90 : sig->caught = 0;
111 90 : sig->handler ();
112 : }
113 : }
114 : }
115 :
116 : #ifdef SIGEVENT_BLOCK_SIGNALS
117 : if ( sigprocmask (SIG_UNBLOCK, &oldmask, NULL) < 0 );
118 : return -1;
119 : #endif /* SIGEVENT_BLOCK_SIGNALS */
120 :
121 2229 : return 0;
122 : }
123 :
124 : #ifdef SIGEVENT_SCHEDULE_THREAD
125 : /* timer thread to check signals. Shouldnt be needed */
126 : int
127 : quagga_signal_timer (struct thread *t)
128 : {
129 : struct quagga_sigevent_master_t *sigm;
130 : struct quagga_signal_t *sig;
131 : int i;
132 :
133 : sigm = THREAD_ARG (t);
134 : sigm->t = thread_add_timer (sigm->t->master, quagga_signal_timer, &sigmaster,
135 : QUAGGA_SIGNAL_TIMER_INTERVAL);
136 : return quagga_sigevent_process ();
137 : }
138 : #endif /* SIGEVENT_SCHEDULE_THREAD */
139 :
140 : /* Initialization of signal handles. */
141 : /* Signal wrapper. */
142 : static int
143 180 : signal_set (int signo)
144 : {
145 : int ret;
146 : struct sigaction sig;
147 : struct sigaction osig;
148 :
149 180 : sig.sa_handler = &quagga_signal_handler;
150 180 : sigfillset (&sig.sa_mask);
151 180 : sig.sa_flags = 0;
152 180 : if (signo == SIGALRM) {
153 : #ifdef SA_INTERRUPT
154 0 : sig.sa_flags |= SA_INTERRUPT; /* SunOS */
155 : #endif
156 : } else {
157 : #ifdef SA_RESTART
158 180 : sig.sa_flags |= SA_RESTART;
159 : #endif /* SA_RESTART */
160 : }
161 :
162 180 : ret = sigaction (signo, &sig, &osig);
163 180 : if (ret < 0)
164 0 : return ret;
165 : else
166 180 : return 0;
167 : }
168 :
169 : #ifdef SA_SIGINFO
170 :
171 : /* XXX This function should be enhanced to support more platforms
172 : (it currently works only on Linux/x86). */
173 : static void *
174 0 : program_counter(void *context)
175 : {
176 : #ifdef HAVE_UCONTEXT_H
177 : #ifdef GNU_LINUX
178 : #ifdef REG_EIP
179 : if (context)
180 : return (void *)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]);
181 : #endif /* REG_EIP */
182 : #endif /* GNU_LINUX */
183 : #endif /* HAVE_UCONTEXT_H */
184 0 : return NULL;
185 : }
186 :
187 : #endif /* SA_SIGINFO */
188 :
189 : static void __attribute__ ((noreturn))
190 0 : exit_handler(int signo
191 : #ifdef SA_SIGINFO
192 : , siginfo_t *siginfo, void *context
193 : #endif
194 : )
195 : {
196 0 : zlog_signal(signo, "exiting..."
197 : #ifdef SA_SIGINFO
198 : , siginfo, program_counter(context)
199 : #endif
200 : );
201 0 : _exit(128+signo);
202 : }
203 :
204 : static void __attribute__ ((noreturn))
205 0 : core_handler(int signo
206 : #ifdef SA_SIGINFO
207 : , siginfo_t *siginfo, void *context
208 : #endif
209 : )
210 : {
211 0 : zlog_signal(signo, "aborting..."
212 : #ifdef SA_SIGINFO
213 : , siginfo, program_counter(context)
214 : #endif
215 : );
216 0 : abort();
217 : }
218 :
219 : static void
220 45 : trap_default_signals(void)
221 : {
222 : static const int core_signals[] = {
223 : SIGQUIT,
224 : SIGILL,
225 : #ifdef SIGEMT
226 : SIGEMT,
227 : #endif
228 : SIGFPE,
229 : SIGBUS,
230 : SIGSEGV,
231 : #ifdef SIGSYS
232 : SIGSYS,
233 : #endif
234 : #ifdef SIGXCPU
235 : SIGXCPU,
236 : #endif
237 : #ifdef SIGXFSZ
238 : SIGXFSZ,
239 : #endif
240 : };
241 : static const int exit_signals[] = {
242 : SIGHUP,
243 : SIGINT,
244 : SIGALRM,
245 : SIGTERM,
246 : SIGUSR1,
247 : SIGUSR2,
248 : #ifdef SIGPOLL
249 : SIGPOLL,
250 : #endif
251 : #ifdef SIGVTALRM
252 : SIGVTALRM,
253 : #endif
254 : #ifdef SIGSTKFLT
255 : SIGSTKFLT,
256 : #endif
257 : };
258 : static const int ignore_signals[] = {
259 : SIGPIPE,
260 : };
261 : static const struct {
262 : const int *sigs;
263 : u_int nsigs;
264 : void (*handler)(int signo
265 : #ifdef SA_SIGINFO
266 : , siginfo_t *info, void *context
267 : #endif
268 : );
269 : } sigmap[] = {
270 : { core_signals, array_size(core_signals), core_handler},
271 : { exit_signals, array_size(exit_signals), exit_handler},
272 : { ignore_signals, array_size(ignore_signals), NULL},
273 : };
274 : u_int i;
275 :
276 180 : for (i = 0; i < array_size(sigmap); i++)
277 : {
278 : u_int j;
279 :
280 945 : for (j = 0; j < sigmap[i].nsigs; j++)
281 : {
282 : struct sigaction oact;
283 1620 : if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
284 810 : (oact.sa_handler == SIG_DFL))
285 : {
286 : struct sigaction act;
287 630 : sigfillset (&act.sa_mask);
288 630 : if (sigmap[i].handler == NULL)
289 : {
290 0 : act.sa_handler = SIG_IGN;
291 0 : act.sa_flags = 0;
292 : }
293 : else
294 : {
295 : #ifdef SA_SIGINFO
296 : /* Request extra arguments to signal handler. */
297 630 : act.sa_sigaction = sigmap[i].handler;
298 630 : act.sa_flags = SA_SIGINFO;
299 : #else
300 : act.sa_handler = sigmap[i].handler;
301 : act.sa_flags = 0;
302 : #endif
303 : }
304 630 : if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
305 0 : zlog_warn("Unable to set signal handler for signal %d: %s",
306 0 : sigmap[i].sigs[j],safe_strerror(errno));
307 :
308 : }
309 : }
310 : }
311 45 : }
312 :
313 : void
314 45 : signal_init (struct thread_master *m, int sigc,
315 : struct quagga_signal_t signals[])
316 : {
317 :
318 45 : int i = 0;
319 : struct quagga_signal_t *sig;
320 :
321 : /* First establish some default handlers that can be overridden by
322 : the application. */
323 45 : trap_default_signals();
324 :
325 270 : while (i < sigc)
326 : {
327 180 : sig = &signals[i];
328 180 : if ( signal_set (sig->signal) < 0 )
329 0 : exit (-1);
330 180 : i++;
331 : }
332 :
333 45 : sigmaster.sigc = sigc;
334 45 : sigmaster.signals = signals;
335 :
336 : #ifdef SIGEVENT_SCHEDULE_THREAD
337 : sigmaster.t =
338 : thread_add_timer (m, quagga_signal_timer, &sigmaster,
339 : QUAGGA_SIGNAL_TIMER_INTERVAL);
340 : #endif /* SIGEVENT_SCHEDULE_THREAD */
341 45 : }
|