1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5
6 This program is Free Software; you can redistribute it and/or
7 modify it under the terms of version three of the GNU Affero General Public
8 License as published by the Free Software Foundation and included
9 in the file LICENSE.
10
11 This program 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 Affero General Public License for more details.
15
16 You should have received a copy of the GNU Affero General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA.
20 */
21 /*
22 * Signal handlers for BAREOS daemons
23 *
24 * Kern Sibbald, April 2000
25 *
26 * Note, we probably should do a core dump for the serious
27 * signals such as SIGBUS, SIGPFE, ...
28 * Also, for SIGHUP and SIGUSR1, we should re-read the
29 * configuration file. However, since this is a "general"
30 * routine, we leave it to the individual daemons to
31 * tweak their signals after calling this routine.
32 */
33
34 #ifndef HAVE_WIN32
35 #include "include/bareos.h"
36 #include "lib/watchdog.h"
37 #include "lib/berrno.h"
38 #include "lib/bsignal.h"
39
40 #ifndef _NSIG
41 #define BA_NSIG 100
42 #else
43 #define BA_NSIG _NSIG
44 #endif
45
46 extern char my_name[];
47 extern char* exepath;
48 extern char* exename;
49 extern bool prt_kaboom;
50
51 static const char* sig_names[BA_NSIG + 1];
52
53 typedef void(SIG_HANDLER)(int sig);
54 static SIG_HANDLER* exit_handler;
55
56 /* main process id */
57 static pid_t main_pid = 0;
58
get_signal_name(int sig)59 const char* get_signal_name(int sig)
60 {
61 if (sig < 0 || sig > BA_NSIG || !sig_names[sig]) {
62 return _("Invalid signal number");
63 } else {
64 return sig_names[sig];
65 }
66 }
67
68 /* defined in jcr.c */
69 extern void DbgPrintJcr(FILE* fp);
70 /* defined in plugins.c */
71 extern void DbgPrintPlugin(FILE* fp);
72
73 /*
74 * !!! WARNING !!!
75 *
76 * This function should be used ONLY after a violent signal. We walk through the
77 * JobControlRecord chain without locking, BAREOS should not be running.
78 */
dbg_print_bareos()79 static void dbg_print_bareos()
80 {
81 char buf[512];
82
83 snprintf(buf, sizeof(buf), "%s/%s.%d.bactrace", working_directory, my_name,
84 (int)getpid());
85 FILE* fp = fopen(buf, "a+");
86 if (!fp) { fp = stderr; }
87
88 fprintf(stderr, "Dumping: %s\n", buf);
89
90 /* Print also BareosDb and RWLOCK structure
91 * Can add more info about JobControlRecord with DbgJcrAddHook()
92 */
93 DbgPrintJcr(fp);
94 DbgPrintPlugin(fp);
95
96 if (fp != stderr) {
97 if (prt_kaboom) {
98 rewind(fp);
99 printf("\n\n ==== bactrace output ====\n\n");
100 while (fgets(buf, (int)sizeof(buf), fp) != NULL) { printf("%s", buf); }
101 printf(" ==== End baktrace output ====\n\n");
102 }
103 fclose(fp);
104 }
105 }
106
107 /*
108 * Handle signals here
109 */
SignalHandler(int sig)110 extern "C" void SignalHandler(int sig)
111 {
112 static int already_dead = 0;
113 int chld_status = -1;
114
115 /*
116 * If we come back more than once, get out fast!
117 */
118 if (already_dead) { exit(1); }
119 Dmsg2(900, "sig=%d %s\n", sig, sig_names[sig]);
120
121 /*
122 * Ignore certain signals -- SIGUSR2 used to interrupt threads
123 */
124 if (sig == SIGCHLD || sig == SIGUSR2) { return; }
125 already_dead++;
126
127 /*
128 * Don't use Emsg here as it may lock and thus block us
129 */
130 if (sig == SIGTERM) {
131 syslog(LOG_DAEMON | LOG_ERR, "Shutting down BAREOS service: %s ...\n",
132 my_name);
133 } else {
134 fprintf(stderr, _("BAREOS interrupted by signal %d: %s\n"), sig,
135 get_signal_name(sig));
136 syslog(LOG_DAEMON | LOG_ERR, _("BAREOS interrupted by signal %d: %s\n"),
137 sig, get_signal_name(sig));
138 }
139
140 if (sig != SIGTERM) {
141 struct sigaction sigdefault;
142 static char* argv[5];
143 static char pid_buf[20];
144 static char btpath[400];
145 char buf[400];
146 pid_t pid;
147 int exelen = strlen(exepath);
148
149 fprintf(stderr, _("%s, %s got signal %d - %s. Attempting traceback.\n"),
150 exename, my_name, sig, get_signal_name(sig));
151 fprintf(stderr, _("exepath=%s\n"), exepath);
152
153 if (exelen + 12 > (int)sizeof(btpath)) {
154 bstrncpy(btpath, "btraceback", sizeof(btpath));
155 } else {
156 bstrncpy(btpath, exepath, sizeof(btpath));
157 if (IsPathSeparator(btpath[exelen - 1])) { btpath[exelen - 1] = 0; }
158 bstrncat(btpath, "/btraceback", sizeof(btpath));
159 }
160 if (!IsPathSeparator(exepath[exelen - 1])) { strcat(exepath, "/"); }
161 strcat(exepath, exename);
162 if (!working_directory) {
163 working_directory = buf;
164 *buf = 0;
165 }
166 if (*working_directory == 0) { strcpy((char*)working_directory, "/tmp/"); }
167 if (chdir(working_directory) != 0) { /* dump in working directory */
168 BErrNo be;
169 Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory,
170 be.bstrerror());
171 strcpy((char*)working_directory, "/tmp/");
172 }
173 SecureErase(NULL, "./core"); /* get rid of any old core file */
174
175 #ifdef DEVELOPER /* When DEVELOPER not set, this is done below */
176 /*
177 * Print information about the current state into working/<file>.bactrace
178 */
179 dbg_print_bareos();
180 #endif
181
182 sprintf(pid_buf, "%d", (int)main_pid);
183 Dmsg1(300, "Working=%s\n", working_directory);
184 Dmsg1(300, "btpath=%s\n", btpath);
185 Dmsg1(300, "exepath=%s\n", exepath);
186 switch (pid = fork()) {
187 case -1: /* error */
188 fprintf(stderr, _("Fork error: ERR=%s\n"), strerror(errno));
189 break;
190 case 0: /* child */
191 argv[0] = btpath; /* path to btraceback */
192 argv[1] = exepath; /* path to exe */
193 argv[2] = pid_buf;
194 argv[3] = (char*)working_directory;
195 argv[4] = (char*)NULL;
196 fprintf(stderr, _("Calling: %s %s %s %s\n"), btpath, exepath, pid_buf,
197 working_directory);
198 if (execv(btpath, argv) != 0) {
199 BErrNo be;
200 printf(_("execv: %s failed: ERR=%s\n"), btpath, be.bstrerror());
201 }
202 exit(-1);
203 default: /* parent */
204 break;
205 }
206
207 /*
208 * Parent continue here, waiting for child
209 */
210 sigdefault.sa_flags = 0;
211 sigdefault.sa_handler = SIG_DFL;
212 sigfillset(&sigdefault.sa_mask);
213
214 sigaction(sig, &sigdefault, NULL);
215 if (pid > 0) {
216 Dmsg0(500, "Doing waitpid\n");
217 waitpid(pid, &chld_status, 0); /* wait for child to produce dump */
218 Dmsg0(500, "Done waitpid\n");
219 } else {
220 Dmsg0(500, "Doing sleep\n");
221 Bmicrosleep(30, 0);
222 }
223 if (WEXITSTATUS(chld_status) == 0) {
224 fprintf(stderr, _("It looks like the traceback worked...\n"));
225 } else {
226 fprintf(stderr, _("The btraceback call returned %d\n"),
227 WEXITSTATUS(chld_status));
228 }
229
230 /*
231 * If we want it printed, do so
232 */
233 if (prt_kaboom) {
234 FILE* fd;
235
236 snprintf(buf, sizeof(buf), "%s/bareos.%s.traceback", working_directory,
237 pid_buf);
238 fd = fopen(buf, "r");
239 if (fd != NULL) {
240 printf("\n\n ==== Traceback output ====\n\n");
241 while (fgets(buf, (int)sizeof(buf), fd) != NULL) { printf("%s", buf); }
242 fclose(fd);
243 printf(" ==== End traceback output ====\n\n");
244 }
245 }
246 #ifndef DEVELOPER /* When DEVELOPER set, this is done above */
247 /*
248 * Print information about the current state into working/<file>.bactrace
249 */
250 dbg_print_bareos();
251 #endif
252 }
253 exit_handler(sig);
254 Dmsg0(500, "Done exit_handler\n");
255 }
256
257 /*
258 * Init stack dump by saving main process id -- needed by debugger to attach to
259 * this program.
260 */
InitStackDump(void)261 void InitStackDump(void) { main_pid = getpid(); /* save main thread's pid */ }
262
263 /*
264 * Initialize signals
265 */
InitSignals(void Terminate (int sig))266 void InitSignals(void Terminate(int sig))
267 {
268 struct sigaction sighandle;
269 struct sigaction sigignore;
270 struct sigaction sigdefault;
271 #ifdef _sys_nsig
272 int i;
273
274 exit_handler = Terminate;
275 if (BA_NSIG < _sys_nsig) {
276 Emsg2(M_ABORT, 0, _("BA_NSIG too small (%d) should be (%d)\n"), BA_NSIG,
277 _sys_nsig);
278 }
279
280 for (i = 0; i < _sys_nsig; i++) { sig_names[i] = _sys_siglist[i]; }
281 #else
282 exit_handler = Terminate;
283 sig_names[0] = _("UNKNOWN SIGNAL");
284 sig_names[SIGHUP] = _("Hangup");
285 sig_names[SIGINT] = _("Interrupt");
286 sig_names[SIGQUIT] = _("Quit");
287 sig_names[SIGILL] = _("Illegal instruction");
288 sig_names[SIGTRAP] = _("Trace/Breakpoint trap");
289 sig_names[SIGABRT] = _("Abort");
290 #ifdef SIGEMT
291 sig_names[SIGEMT] = _("EMT instruction (Emulation Trap)");
292 #endif
293 #ifdef SIGIOT
294 sig_names[SIGIOT] = _("IOT trap");
295 #endif
296 sig_names[SIGBUS] = _("BUS error");
297 sig_names[SIGFPE] = _("Floating-point exception");
298 sig_names[SIGKILL] = _("Kill, unblockable");
299 sig_names[SIGUSR1] = _("User-defined signal 1");
300 sig_names[SIGSEGV] = _("Segmentation violation");
301 sig_names[SIGUSR2] = _("User-defined signal 2");
302 sig_names[SIGPIPE] = _("Broken pipe");
303 sig_names[SIGALRM] = _("Alarm clock");
304 sig_names[SIGTERM] = _("Termination");
305 #ifdef SIGSTKFLT
306 sig_names[SIGSTKFLT] = _("Stack fault");
307 #endif
308 sig_names[SIGCHLD] = _("Child status has changed");
309 sig_names[SIGCONT] = _("Continue");
310 sig_names[SIGSTOP] = _("Stop, unblockable");
311 sig_names[SIGTSTP] = _("Keyboard stop");
312 sig_names[SIGTTIN] = _("Background read from tty");
313 sig_names[SIGTTOU] = _("Background write to tty");
314 sig_names[SIGURG] = _("Urgent condition on socket");
315 sig_names[SIGXCPU] = _("CPU limit exceeded");
316 sig_names[SIGXFSZ] = _("File size limit exceeded");
317 sig_names[SIGVTALRM] = _("Virtual alarm clock");
318 sig_names[SIGPROF] = _("Profiling alarm clock");
319 sig_names[SIGWINCH] = _("Window size change");
320 sig_names[SIGIO] = _("I/O now possible");
321 #ifdef SIGPWR
322 sig_names[SIGPWR] = _("Power failure restart");
323 #endif
324 #ifdef SIGWAITING
325 sig_names[SIGWAITING] = _("No runnable lwp");
326 #endif
327 #ifdef SIGLWP
328 sig_names[SIGLWP] = _("SIGLWP special signal used by thread library");
329 #endif
330 #ifdef SIGFREEZE
331 sig_names[SIGFREEZE] = _("Checkpoint Freeze");
332 #endif
333 #ifdef SIGTHAW
334 sig_names[SIGTHAW] = _("Checkpoint Thaw");
335 #endif
336 #ifdef SIGCANCEL
337 sig_names[SIGCANCEL] = _("Thread Cancellation");
338 #endif
339 #ifdef SIGLOST
340 sig_names[SIGLOST] = _("Resource Lost (e.g. record-lock lost)");
341 #endif
342 #endif
343
344 /*
345 * Now setup signal handlers
346 */
347 sighandle.sa_flags = 0;
348 sighandle.sa_handler = SignalHandler;
349 sigfillset(&sighandle.sa_mask);
350 sigignore.sa_flags = 0;
351 sigignore.sa_handler = SIG_IGN;
352 sigfillset(&sigignore.sa_mask);
353 sigdefault.sa_flags = 0;
354 sigdefault.sa_handler = SIG_DFL;
355 sigfillset(&sigdefault.sa_mask);
356
357 sigaction(SIGPIPE, &sigignore, NULL);
358 sigaction(SIGCHLD, &sighandle, NULL);
359 sigaction(SIGCONT, &sigignore, NULL);
360 sigaction(SIGPROF, &sigignore, NULL);
361 sigaction(SIGWINCH, &sigignore, NULL);
362 sigaction(SIGIO, &sighandle, NULL);
363 sigaction(SIGINT, &sigdefault, NULL);
364 sigaction(SIGXCPU, &sigdefault, NULL);
365 sigaction(SIGXFSZ, &sigdefault, NULL);
366 sigaction(SIGHUP, &sigignore, NULL);
367 sigaction(SIGQUIT, &sighandle, NULL);
368 sigaction(SIGILL, &sighandle, NULL);
369 sigaction(SIGTRAP, &sighandle, NULL);
370 sigaction(SIGABRT, &sighandle, NULL);
371 #ifdef SIGEMT
372 sigaction(SIGEMT, &sighandle, NULL);
373 #endif
374 #ifdef SIGIOT
375 sigaction(SIGIOT, &sighandle, NULL);
376 #endif
377 sigaction(SIGBUS, &sighandle, NULL);
378 sigaction(SIGFPE, &sighandle, NULL);
379 sigaction(SIGUSR1, &sighandle, NULL);
380 sigaction(SIGSEGV, &sighandle, NULL);
381 sigaction(SIGUSR2, &sighandle, NULL);
382 sigaction(SIGALRM, &sighandle, NULL);
383 sigaction(SIGTERM, &sighandle, NULL);
384 #ifdef SIGSTKFLT
385 sigaction(SIGSTKFLT, &sighandle, NULL);
386 #endif
387 sigaction(SIGTSTP, &sigdefault, NULL);
388 sigaction(SIGTTIN, &sighandle, NULL);
389 sigaction(SIGTTOU, &sighandle, NULL);
390 sigaction(SIGURG, &sighandle, NULL);
391 sigaction(SIGVTALRM, &sighandle, NULL);
392 #ifdef SIGPWR
393 sigaction(SIGPWR, &sighandle, NULL);
394 #endif
395 #ifdef SIGWAITING
396 sigaction(SIGWAITING, &sighandle, NULL);
397 #endif
398 #ifdef SIGLWP
399 sigaction(SIGLWP, &sighandle, NULL);
400 #endif
401 #ifdef SIGFREEZE
402 sigaction(SIGFREEZE, &sighandle, NULL);
403 #endif
404 #ifdef SIGTHAW
405 sigaction(SIGTHAW, &sighandle, NULL);
406 #endif
407 #ifdef SIGCANCEL
408 sigaction(SIGCANCEL, &sighandle, NULL);
409 #endif
410 #ifdef SIGLOST
411 sigaction(SIGLOST, &sighandle, NULL);
412 #endif
413 }
414
TimeoutHandler(int sig)415 extern "C" void TimeoutHandler(int sig)
416 {
417 return; /* thus interrupting the function */
418 }
419
SetTimeoutHandler()420 void SetTimeoutHandler()
421 {
422 struct sigaction sigtimer;
423 sigtimer.sa_flags = 0;
424 sigtimer.sa_handler = TimeoutHandler;
425 sigfillset(&sigtimer.sa_mask);
426 sigaction(TIMEOUT_SIGNAL, &sigtimer, nullptr);
427 }
428 #else // HAVE_WIN32
SetTimeoutHandler()429 void SetTimeoutHandler() {}
430 #endif // !HAVE_WIN32
431