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: quagga_signal_handler (int signo)
56: {
57: int i;
58: struct quagga_signal_t *sig;
59:
60: for (i = 0; i < sigmaster.sigc; i++)
61: {
62: sig = &(sigmaster.signals[i]);
63:
64: if (sig->signal == signo)
65: sig->caught = 1;
66: }
67:
68: sigmaster.caught = 1;
69: }
70:
71: /* check if signals have been caught and run appropriate handlers */
72: int
73: 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: if (sigmaster.caught > 0)
98: {
99: 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: for (i = 0; i < sigmaster.sigc; i++)
105: {
106: sig = &(sigmaster.signals[i]);
107:
108: if (sig->caught > 0)
109: {
110: sig->caught = 0;
111: 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: 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: signal_set (int signo)
144: {
145: int ret;
146: struct sigaction sig;
147: struct sigaction osig;
148:
149: sig.sa_handler = &quagga_signal_handler;
150: sigfillset (&sig.sa_mask);
151: sig.sa_flags = 0;
152: if (signo == SIGALRM) {
153: #ifdef SA_INTERRUPT
154: sig.sa_flags |= SA_INTERRUPT; /* SunOS */
155: #endif
156: } else {
157: #ifdef SA_RESTART
158: sig.sa_flags |= SA_RESTART;
159: #endif /* SA_RESTART */
160: }
161:
162: ret = sigaction (signo, &sig, &osig);
163: if (ret < 0)
164: return ret;
165: else
166: 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: 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: return NULL;
185: }
186:
187: #endif /* SA_SIGINFO */
188:
189: static void __attribute__ ((noreturn))
190: exit_handler(int signo
191: #ifdef SA_SIGINFO
192: , siginfo_t *siginfo, void *context
193: #endif
194: )
195: {
196: zlog_signal(signo, "exiting..."
197: #ifdef SA_SIGINFO
198: , siginfo, program_counter(context)
199: #endif
200: );
201: _exit(128+signo);
202: }
203:
204: static void __attribute__ ((noreturn))
205: core_handler(int signo
206: #ifdef SA_SIGINFO
207: , siginfo_t *siginfo, void *context
208: #endif
209: )
210: {
211: zlog_signal(signo, "aborting..."
212: #ifdef SA_SIGINFO
213: , siginfo, program_counter(context)
214: #endif
215: );
216: abort();
217: }
218:
219: static void
220: 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: for (i = 0; i < array_size(sigmap); i++)
277: {
278: u_int j;
279:
280: for (j = 0; j < sigmap[i].nsigs; j++)
281: {
282: struct sigaction oact;
283: if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
284: (oact.sa_handler == SIG_DFL))
285: {
286: struct sigaction act;
287: sigfillset (&act.sa_mask);
288: if (sigmap[i].handler == NULL)
289: {
290: act.sa_handler = SIG_IGN;
291: act.sa_flags = 0;
292: }
293: else
294: {
295: #ifdef SA_SIGINFO
296: /* Request extra arguments to signal handler. */
297: act.sa_sigaction = sigmap[i].handler;
298: act.sa_flags = SA_SIGINFO;
299: #else
300: act.sa_handler = sigmap[i].handler;
301: act.sa_flags = 0;
302: #endif
303: }
304: if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
305: zlog_warn("Unable to set signal handler for signal %d: %s",
306: sigmap[i].sigs[j],safe_strerror(errno));
307:
308: }
309: }
310: }
311: }
312:
313: void
314: signal_init (struct thread_master *m, int sigc,
315: struct quagga_signal_t signals[])
316: {
317:
318: 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: trap_default_signals();
324:
325: while (i < sigc)
326: {
327: sig = &signals[i];
328: if ( signal_set (sig->signal) < 0 )
329: exit (-1);
330: i++;
331: }
332:
333: sigmaster.sigc = sigc;
334: 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>