]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/signal.c
ebl update new "bactrace" option to dump information into
[bacula/bacula] / bacula / src / lib / signal.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Signal handlers for Bacula daemons
30  *
31  *   Kern Sibbald, April 2000
32  *
33  *   Version $Id$
34  *
35  * Note, we probably should do a core dump for the serious
36  * signals such as SIGBUS, SIGPFE, ...
37  * Also, for SIGHUP and SIGUSR1, we should re-read the
38  * configuration file.  However, since this is a "general"
39  * routine, we leave it to the individual daemons to
40  * tweek their signals after calling this routine.
41  *
42  */
43
44 #ifndef HAVE_WIN32
45 #include "bacula.h"
46
47 #ifndef _NSIG
48 #define BA_NSIG 100
49 #else
50 #define BA_NSIG _NSIG
51 #endif
52
53 extern char my_name[];
54 extern char *exepath;
55 extern char *exename;
56 extern void print_jcr_dbg();
57
58 static const char *sig_names[BA_NSIG+1];
59
60 typedef void (SIG_HANDLER)(int sig);
61 static SIG_HANDLER *exit_handler;
62
63 /* main process id */
64 static pid_t main_pid = 0;
65
66 const char *get_signal_name(int sig)
67 {
68    if (sig < 0 || sig > BA_NSIG || !sig_names[sig]) {
69       return _("Invalid signal number");
70    } else {
71       return sig_names[sig];
72    }
73 }
74
75 /*
76  * Global variables to get information about lock/unlock db access
77  */
78 utime_t _db_lock_time = 0;
79 int _db_lock_recurse_count = 0;
80 pthread_t _db_lock_threadid;
81
82 static void print_lock_dbg(FILE *fp)
83 {
84    char buf[128];
85    bstrutime(buf, sizeof(buf), _db_lock_time);
86
87    fprintf(fp, "lock info: recurse_count=%i threadid=0x%x time=%s\n",
88            _db_lock_recurse_count, (int)_db_lock_threadid, buf);
89 }
90
91 /* defined in jcr.c */
92 extern void _print_jcr_dbg(FILE *fp);
93
94 /*
95  * !!! WARNING !!! 
96  *
97  * This function should be used ONLY after a violent signal. We walk through the
98  * JCR chain without doing any lock, bacula should not be running.
99  */
100 static void print_bacula_dbg()
101 {
102    char buf[512];
103
104    snprintf(buf, sizeof(buf), "%s/bacula.%d.bactrace", 
105             working_directory, getpid());
106    FILE *fp = fopen(buf, "ab") ;
107    if (!fp) {
108       fp = stderr;
109    }
110
111    _print_jcr_dbg(fp);
112    print_lock_dbg(fp);
113
114    if (fp != stderr) {
115       fclose(fp);
116    }
117 }
118
119 /*
120  * Handle signals here
121  */
122 extern "C" void signal_handler(int sig)
123 {
124    static int already_dead = 0;
125
126    /* If we come back more than once, get out fast! */
127    if (already_dead) {
128       exit(1);
129    }
130    Dmsg2(900, "sig=%d %s\n", sig, sig_names[sig]);
131    /* Ignore certain signals -- SIGUSR2 used to interrupt threads */
132    if (sig == SIGCHLD || sig == SIGUSR2) {
133       return;
134    }
135    already_dead++;
136    if (sig == SIGTERM) {
137 //    Emsg1(M_TERM, -1, "Shutting down Bacula service: %s ...\n", my_name);
138    } else {
139       Emsg2(M_FATAL, -1, _("Bacula interrupted by signal %d: %s\n"), sig, get_signal_name(sig));
140    }
141
142 #ifdef TRACEBACK
143    if (sig != SIGTERM) {
144       struct sigaction sigdefault;
145       static char *argv[4];
146       static char pid_buf[20];
147       static char btpath[400];
148       char buf[100];
149       pid_t pid;
150       int exelen = strlen(exepath);
151
152       fprintf(stderr, _("Kaboom! %s, %s got signal %d - %s. Attempting traceback.\n"),
153               exename, my_name, sig, get_signal_name(sig));
154       fprintf(stderr, _("Kaboom! exepath=%s\n"), exepath);
155
156       if (exelen + 12 > (int)sizeof(btpath)) {
157          bstrncpy(btpath, "btraceback", sizeof(btpath));
158       } else {
159          bstrncpy(btpath, exepath, sizeof(btpath));
160          if (IsPathSeparator(btpath[exelen-1])) {
161             btpath[exelen-1] = 0;
162          }
163          bstrncat(btpath, "/btraceback", sizeof(btpath));
164       }
165       if (!IsPathSeparator(exepath[exelen - 1])) {
166          strcat(exepath, "/");
167       }
168       strcat(exepath, exename);
169       if (!working_directory) {
170          working_directory = buf;
171          *buf = 0;
172       }
173       if (*working_directory == 0) {
174          strcpy((char *)working_directory, "/tmp/");
175       }
176       if (chdir(working_directory) != 0) {  /* dump in working directory */
177          berrno be;
178          Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory,  be.bstrerror());
179          strcpy((char *)working_directory, "/tmp/");
180       }
181       unlink("./core");               /* get rid of any old core file */
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 *)NULL;
195          fprintf(stderr, _("Calling: %s %s %s\n"), btpath, exepath, pid_buf);
196          if (execv(btpath, argv) != 0) {
197             berrno be;
198             printf(_("execv: %s failed: ERR=%s\n"), btpath, be.bstrerror());
199          }
200          exit(-1);
201       default:                        /* parent */
202          break;
203       }
204
205       /* Parent continue here, waiting for child */
206       sigdefault.sa_flags = 0;
207       sigdefault.sa_handler = SIG_DFL;
208       sigfillset(&sigdefault.sa_mask);
209
210       sigaction(sig,  &sigdefault, NULL);
211       if (pid > 0) {
212          Dmsg0(500, "Doing waitpid\n");
213          waitpid(pid, NULL, 0);       /* wait for child to produce dump */
214          Dmsg0(500, "Done waitpid\n");
215          fprintf(stderr, _("Traceback complete, attempting cleanup ...\n"));
216          /* print information about the current state into working/<file>.bactrace */
217          print_bacula_dbg();
218          exit_handler(sig);           /* clean up if possible */
219          Dmsg0(500, "Done exit_handler\n");
220       } else {
221          Dmsg0(500, "Doing sleep\n");
222          bmicrosleep(30, 0);
223       }
224       fprintf(stderr, _("It looks like the traceback worked ...\n"));
225    }
226 #endif
227
228    exit_handler(sig);
229 }
230
231 /*
232  * Init stack dump by saving main process id --
233  *   needed by debugger to attach to this program.
234  */
235 void init_stack_dump(void)
236 {
237    main_pid = getpid();               /* save main thread's pid */
238 }
239
240 /*
241  * Initialize signals
242  */
243 void init_signals(void terminate(int sig))
244 {
245    struct sigaction sighandle;
246    struct sigaction sigignore;
247    struct sigaction sigdefault;
248 #ifdef _sys_nsig
249    int i;
250
251    exit_handler = terminate;
252    if (BA_NSIG < _sys_nsig)
253       Emsg2(M_ABORT, 0, _("BA_NSIG too small (%d) should be (%d)\n"), BA_NSIG, _sys_nsig);
254
255    for (i=0; i<_sys_nsig; i++)
256       sig_names[i] = _sys_siglist[i];
257 #else
258    exit_handler = terminate;
259    sig_names[0]         = _("UNKNOWN SIGNAL");
260    sig_names[SIGHUP]    = _("Hangup");
261    sig_names[SIGINT]    = _("Interrupt");
262    sig_names[SIGQUIT]   = _("Quit");
263    sig_names[SIGILL]    = _("Illegal instruction");;
264    sig_names[SIGTRAP]   = _("Trace/Breakpoint trap");
265    sig_names[SIGABRT]   = _("Abort");
266 #ifdef SIGEMT
267    sig_names[SIGEMT]    = _("EMT instruction (Emulation Trap)");
268 #endif
269 #ifdef SIGIOT
270    sig_names[SIGIOT]    = _("IOT trap");
271 #endif
272    sig_names[SIGBUS]    = _("BUS error");
273    sig_names[SIGFPE]    = _("Floating-point exception");
274    sig_names[SIGKILL]   = _("Kill, unblockable");
275    sig_names[SIGUSR1]   = _("User-defined signal 1");
276    sig_names[SIGSEGV]   = _("Segmentation violation");
277    sig_names[SIGUSR2]   = _("User-defined signal 2");
278    sig_names[SIGPIPE]   = _("Broken pipe");
279    sig_names[SIGALRM]   = _("Alarm clock");
280    sig_names[SIGTERM]   = _("Termination");
281 #ifdef SIGSTKFLT
282    sig_names[SIGSTKFLT] = _("Stack fault");
283 #endif
284    sig_names[SIGCHLD]   = _("Child status has changed");
285    sig_names[SIGCONT]   = _("Continue");
286    sig_names[SIGSTOP]   = _("Stop, unblockable");
287    sig_names[SIGTSTP]   = _("Keyboard stop");
288    sig_names[SIGTTIN]   = _("Background read from tty");
289    sig_names[SIGTTOU]   = _("Background write to tty");
290    sig_names[SIGURG]    = _("Urgent condition on socket");
291    sig_names[SIGXCPU]   = _("CPU limit exceeded");
292    sig_names[SIGXFSZ]   = _("File size limit exceeded");
293    sig_names[SIGVTALRM] = _("Virtual alarm clock");
294    sig_names[SIGPROF]   = _("Profiling alarm clock");
295    sig_names[SIGWINCH]  = _("Window size change");
296    sig_names[SIGIO]     = _("I/O now possible");
297 #ifdef SIGPWR
298    sig_names[SIGPWR]    = _("Power failure restart");
299 #endif
300 #ifdef SIGWAITING
301    sig_names[SIGWAITING] = _("No runnable lwp");
302 #endif
303 #ifdef SIGLWP
304    sig_names[SIGLWP]     = _("SIGLWP special signal used by thread library");
305 #endif
306 #ifdef SIGFREEZE
307    sig_names[SIGFREEZE] = _("Checkpoint Freeze");
308 #endif
309 #ifdef SIGTHAW
310    sig_names[SIGTHAW]   = _("Checkpoint Thaw");
311 #endif
312 #ifdef SIGCANCEL
313    sig_names[SIGCANCEL] = _("Thread Cancellation");
314 #endif
315 #ifdef SIGLOST
316    sig_names[SIGLOST]   = _("Resource Lost (e.g. record-lock lost)");
317 #endif
318 #endif
319
320
321 /* Now setup signal handlers */
322    sighandle.sa_flags = 0;
323    sighandle.sa_handler = signal_handler;
324    sigfillset(&sighandle.sa_mask);
325    sigignore.sa_flags = 0;
326    sigignore.sa_handler = SIG_IGN;
327    sigfillset(&sigignore.sa_mask);
328    sigdefault.sa_flags = 0;
329    sigdefault.sa_handler = SIG_DFL;
330    sigfillset(&sigdefault.sa_mask);
331
332
333    sigaction(SIGPIPE,   &sigignore, NULL);
334    sigaction(SIGCHLD,   &sighandle, NULL);
335    sigaction(SIGCONT,   &sigignore, NULL);
336    sigaction(SIGPROF,   &sigignore, NULL);
337    sigaction(SIGWINCH,  &sigignore, NULL);
338    sigaction(SIGIO,     &sighandle, NULL);
339
340    sigaction(SIGINT,    &sigdefault, NULL);
341    sigaction(SIGXCPU,   &sigdefault, NULL);
342    sigaction(SIGXFSZ,   &sigdefault, NULL);
343
344    sigaction(SIGHUP,    &sigignore, NULL);
345    sigaction(SIGQUIT,   &sighandle, NULL);
346    sigaction(SIGILL,    &sighandle, NULL);
347    sigaction(SIGTRAP,   &sighandle, NULL);
348    sigaction(SIGABRT,   &sighandle, NULL);
349 #ifdef SIGEMT
350    sigaction(SIGEMT,    &sighandle, NULL);
351 #endif
352 #ifdef SIGIOT
353    sigaction(SIGIOT,    &sighandle, NULL);                     
354 #endif
355    sigaction(SIGBUS,    &sighandle, NULL);
356    sigaction(SIGFPE,    &sighandle, NULL);
357 /* sigaction(SIGKILL,   &sighandle, NULL);  cannot be trapped */
358    sigaction(SIGUSR1,   &sighandle, NULL);
359    sigaction(SIGSEGV,   &sighandle, NULL);
360    sigaction(SIGUSR2,   &sighandle, NULL);
361    sigaction(SIGALRM,   &sighandle, NULL);
362    sigaction(SIGTERM,   &sighandle, NULL);
363 #ifdef SIGSTKFLT
364    sigaction(SIGSTKFLT, &sighandle, NULL);
365 #endif
366 /* sigaction(SIGSTOP,   &sighandle, NULL); cannot be trapped */
367    sigaction(SIGTSTP,   &sighandle, NULL);
368    sigaction(SIGTTIN,   &sighandle, NULL);
369    sigaction(SIGTTOU,   &sighandle, NULL);
370    sigaction(SIGURG,    &sighandle, NULL);
371    sigaction(SIGVTALRM, &sighandle, NULL);
372 #ifdef SIGPWR
373    sigaction(SIGPWR,    &sighandle, NULL);
374 #endif
375 #ifdef SIGWAITING
376    sigaction(SIGWAITING,&sighandle, NULL);
377 #endif
378 #ifdef SIGLWP
379    sigaction(SIGLWP,    &sighandle, NULL);
380 #endif
381 #ifdef SIGFREEZE
382    sigaction(SIGFREEZE, &sighandle, NULL);
383 #endif
384 #ifdef SIGTHAW
385    sigaction(SIGTHAW,   &sighandle, NULL);
386 #endif
387 #ifdef SIGCANCEL
388    sigaction(SIGCANCEL, &sighandle, NULL);
389 #endif
390 #ifdef SIGLOST
391    sigaction(SIGLOST,   &sighandle, NULL);
392 #endif
393 }
394 #endif