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