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