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