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