1 |
/* Signal handling routines. |
2 |
* |
3 |
* IRC Services is copyright (c) 1996-2009 Andrew Church. |
4 |
* E-mail: <achurch@achurch.org> |
5 |
* Parts written by Andrew Kempe and others. |
6 |
* This program is free but copyrighted software; see the file GPL.txt for |
7 |
* details. |
8 |
*/ |
9 |
|
10 |
#include "services.h" |
11 |
#include <setjmp.h> |
12 |
|
13 |
/*************************************************************************/ |
14 |
|
15 |
/* If we get a signal, use this to jump out of the main loop. */ |
16 |
static sigjmp_buf *panic_ptr = NULL; |
17 |
|
18 |
/*************************************************************************/ |
19 |
/*************************************************************************/ |
20 |
|
21 |
/* Various signal handlers. */ |
22 |
|
23 |
/*************************************************************************/ |
24 |
|
25 |
/* SIGHUP = save databases and rehash configuration files */ |
26 |
static void sighup_handler(int sig_unused) |
27 |
{ |
28 |
signal(SIGHUP, SIG_IGN); /* in case we get double signalled */ |
29 |
log("Received SIGHUP, saving data and rehashing."); |
30 |
wallops(NULL, |
31 |
"Received SIGHUP, saving data and rehashing configuration files"); |
32 |
save_data_now(); |
33 |
reconfigure(); |
34 |
signal(SIGHUP, sighup_handler); |
35 |
} |
36 |
|
37 |
/*************************************************************************/ |
38 |
|
39 |
/* SIGTERM = save databases and shut down */ |
40 |
static void sigterm_handler(int sig_unused) |
41 |
{ |
42 |
save_data = 1; |
43 |
delayed_quit = 1; |
44 |
signal(SIGTERM, SIG_IGN); |
45 |
signal(SIGHUP, SIG_IGN); |
46 |
log("Received SIGTERM, exiting."); |
47 |
strbcpy(quitmsg, "Shutting down on SIGTERM"); |
48 |
siglongjmp(*panic_ptr, 1); |
49 |
} |
50 |
|
51 |
/*************************************************************************/ |
52 |
|
53 |
/* SIGUSR2 = close and reopen log file */ |
54 |
static void sigusr2_handler(int sig_unused) |
55 |
{ |
56 |
log("Received SIGUSR2, cycling log file."); |
57 |
if (log_is_open()) { |
58 |
close_log(); |
59 |
open_log(); |
60 |
} |
61 |
signal(SIGUSR2, sigusr2_handler); |
62 |
} |
63 |
|
64 |
/*************************************************************************/ |
65 |
|
66 |
/* If we get a weird signal, come here. */ |
67 |
static void weirdsig_handler(int signum) |
68 |
{ |
69 |
static int dying = 0; /* Flag to avoid infinite recursion */ |
70 |
|
71 |
if (dying++) { |
72 |
/* Double signal, give up. Set `servsock' to NULL to avoid a |
73 |
* message going out that way, just in case the socket code is |
74 |
* confused/broken */ |
75 |
servsock = NULL; |
76 |
if (signum == SIGUSR2) { |
77 |
fatal("Out of memory while shutting down"); |
78 |
} else { |
79 |
#if HAVE_STRSIGNAL |
80 |
fatal("Caught signal %d (%s) while shutting down", signum, |
81 |
strsignal(signum)); |
82 |
#else |
83 |
fatal("Caught signal %d while shutting down", signum); |
84 |
#endif |
85 |
} |
86 |
} |
87 |
|
88 |
/* Avoid spurious keyboard signals killing us while shutting down */ |
89 |
signal(SIGINT, SIG_IGN); |
90 |
signal(SIGQUIT, SIG_IGN); |
91 |
signal(SIGTSTP, SIG_IGN); |
92 |
|
93 |
/* If we died processing a message, let people know about it */ |
94 |
if (signum != SIGINT && signum != SIGQUIT) { |
95 |
if (*inbuf) { |
96 |
log("PANIC! signal %d, buffer = %s", signum, inbuf); |
97 |
/* Cut off if this would make IRC command >510 characters. */ |
98 |
if (strlen(inbuf) > 448) { |
99 |
inbuf[446] = '>'; |
100 |
inbuf[447] = '>'; |
101 |
inbuf[448] = 0; |
102 |
} |
103 |
wallops(NULL, "PANIC! buffer = %s\r\n", inbuf); |
104 |
} else { |
105 |
log("PANIC! signal %d (no buffer)", signum); |
106 |
wallops(NULL, "PANIC! signal %d (no buffer)", signum); |
107 |
} |
108 |
} |
109 |
|
110 |
/* Pick an appropriate quit message */ |
111 |
if (signum == SIGUSR1) { |
112 |
strbcpy(quitmsg, "Out of memory!"); |
113 |
quitting = 1; |
114 |
} else { |
115 |
#if HAVE_STRSIGNAL |
116 |
snprintf(quitmsg, sizeof(quitmsg), |
117 |
"Services terminating: %s", strsignal(signum)); |
118 |
#else |
119 |
snprintf(quitmsg, sizeof(quitmsg), |
120 |
"Services terminating on signal %d", signum); |
121 |
#endif |
122 |
quitting = 1; |
123 |
} |
124 |
|
125 |
/* Actually quit */ |
126 |
if (panic_ptr) { |
127 |
siglongjmp(*panic_ptr, 1); |
128 |
} else { |
129 |
log("%s", quitmsg); |
130 |
if (isatty(2)) |
131 |
fprintf(stderr, "%s\n", quitmsg); |
132 |
exit(1); |
133 |
} |
134 |
} |
135 |
|
136 |
/*************************************************************************/ |
137 |
/*************************************************************************/ |
138 |
|
139 |
/* Set up signal handlers. Catch certain signals to let us do things or |
140 |
* panic as necessary, and ignore all others. |
141 |
*/ |
142 |
|
143 |
void init_signals(void) |
144 |
{ |
145 |
int i; |
146 |
|
147 |
/* Start out with special signals disabled */ |
148 |
disable_signals(); |
149 |
|
150 |
/* Set all signals to "ignore" */ |
151 |
for (i = 1; i <= NSIG; i++) { |
152 |
#if DUMPCORE |
153 |
if (i != SIGSEGV) |
154 |
#endif |
155 |
if (i != SIGPROF && i != SIGCHLD) |
156 |
signal(i, SIG_IGN); |
157 |
} |
158 |
|
159 |
/* Specify particular signals we want to catch */ |
160 |
|
161 |
/* Signals that probably mean bad things have happened */ |
162 |
#if !DUMPCORE |
163 |
signal(SIGSEGV, weirdsig_handler); |
164 |
#endif |
165 |
signal(SIGBUS, weirdsig_handler); |
166 |
signal(SIGILL, weirdsig_handler); |
167 |
signal(SIGTRAP, weirdsig_handler); |
168 |
signal(SIGFPE, weirdsig_handler); |
169 |
#ifdef SIGIOT |
170 |
signal(SIGIOT, weirdsig_handler); |
171 |
#endif |
172 |
|
173 |
/* This is our "out-of-memory" panic switch */ |
174 |
signal(SIGUSR1, weirdsig_handler); |
175 |
|
176 |
/* Other special handlers */ |
177 |
signal(SIGTERM, sigterm_handler); |
178 |
signal(SIGINT, weirdsig_handler); |
179 |
signal(SIGQUIT, weirdsig_handler); |
180 |
signal(SIGHUP, sighup_handler); |
181 |
signal(SIGUSR2, sigusr2_handler); |
182 |
|
183 |
} |
184 |
|
185 |
/*************************************************************************/ |
186 |
|
187 |
/* Helper routine for main.c's DO_SIGSETJMP() macro; saves a pointer to the |
188 |
* environment buffer locally. |
189 |
*/ |
190 |
|
191 |
void do_sigsetjmp(void *bufptr) |
192 |
{ |
193 |
panic_ptr = bufptr; |
194 |
} |
195 |
|
196 |
/*************************************************************************/ |
197 |
|
198 |
/* Enable or disable receipt of certain signals (in particular, those which |
199 |
* cause us to take actions other than simply terminating the program, to |
200 |
* avoid such signals happening at inopportune times and causing things to |
201 |
* break). |
202 |
*/ |
203 |
|
204 |
void enable_signals(void) |
205 |
{ |
206 |
sigset_t sigs; |
207 |
sigemptyset(&sigs); |
208 |
sigaddset(&sigs, SIGHUP); |
209 |
sigaddset(&sigs, SIGTERM); |
210 |
sigaddset(&sigs, SIGUSR2); |
211 |
sigprocmask(SIG_UNBLOCK, &sigs, NULL); |
212 |
} |
213 |
|
214 |
|
215 |
void disable_signals(void) |
216 |
{ |
217 |
sigset_t sigs; |
218 |
sigemptyset(&sigs); |
219 |
sigaddset(&sigs, SIGHUP); |
220 |
sigaddset(&sigs, SIGTERM); |
221 |
sigaddset(&sigs, SIGUSR2); |
222 |
sigprocmask(SIG_BLOCK, &sigs, NULL); |
223 |
} |
224 |
|
225 |
/*************************************************************************/ |
226 |
|
227 |
/* |
228 |
* Local variables: |
229 |
* c-file-style: "stroustrup" |
230 |
* c-file-offsets: ((case-label . *) (statement-case-intro . *)) |
231 |
* indent-tabs-mode: nil |
232 |
* End: |
233 |
* |
234 |
* vim: expandtab shiftwidth=4: |
235 |
*/ |