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