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