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