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