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