]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/signal.c
Merge branch 'master' into basejobv3
[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 }
236
237 /*
238  * Initialize signals
239  */
240 void init_signals(void terminate(int sig))
241 {
242    struct sigaction sighandle;
243    struct sigaction sigignore;
244    struct sigaction sigdefault;
245 #ifdef _sys_nsig
246    int i;
247
248    exit_handler = terminate;
249    if (BA_NSIG < _sys_nsig)
250       Emsg2(M_ABORT, 0, _("BA_NSIG too small (%d) should be (%d)\n"), BA_NSIG, _sys_nsig);
251
252    for (i=0; i<_sys_nsig; i++)
253       sig_names[i] = _sys_siglist[i];
254 #else
255    exit_handler = terminate;
256    sig_names[0]         = _("UNKNOWN SIGNAL");
257    sig_names[SIGHUP]    = _("Hangup");
258    sig_names[SIGINT]    = _("Interrupt");
259    sig_names[SIGQUIT]   = _("Quit");
260    sig_names[SIGILL]    = _("Illegal instruction");;
261    sig_names[SIGTRAP]   = _("Trace/Breakpoint trap");
262    sig_names[SIGABRT]   = _("Abort");
263 #ifdef SIGEMT
264    sig_names[SIGEMT]    = _("EMT instruction (Emulation Trap)");
265 #endif
266 #ifdef SIGIOT
267    sig_names[SIGIOT]    = _("IOT trap");
268 #endif
269    sig_names[SIGBUS]    = _("BUS error");
270    sig_names[SIGFPE]    = _("Floating-point exception");
271    sig_names[SIGKILL]   = _("Kill, unblockable");
272    sig_names[SIGUSR1]   = _("User-defined signal 1");
273    sig_names[SIGSEGV]   = _("Segmentation violation");
274    sig_names[SIGUSR2]   = _("User-defined signal 2");
275    sig_names[SIGPIPE]   = _("Broken pipe");
276    sig_names[SIGALRM]   = _("Alarm clock");
277    sig_names[SIGTERM]   = _("Termination");
278 #ifdef SIGSTKFLT
279    sig_names[SIGSTKFLT] = _("Stack fault");
280 #endif
281    sig_names[SIGCHLD]   = _("Child status has changed");
282    sig_names[SIGCONT]   = _("Continue");
283    sig_names[SIGSTOP]   = _("Stop, unblockable");
284    sig_names[SIGTSTP]   = _("Keyboard stop");
285    sig_names[SIGTTIN]   = _("Background read from tty");
286    sig_names[SIGTTOU]   = _("Background write to tty");
287    sig_names[SIGURG]    = _("Urgent condition on socket");
288    sig_names[SIGXCPU]   = _("CPU limit exceeded");
289    sig_names[SIGXFSZ]   = _("File size limit exceeded");
290    sig_names[SIGVTALRM] = _("Virtual alarm clock");
291    sig_names[SIGPROF]   = _("Profiling alarm clock");
292    sig_names[SIGWINCH]  = _("Window size change");
293    sig_names[SIGIO]     = _("I/O now possible");
294 #ifdef SIGPWR
295    sig_names[SIGPWR]    = _("Power failure restart");
296 #endif
297 #ifdef SIGWAITING
298    sig_names[SIGWAITING] = _("No runnable lwp");
299 #endif
300 #ifdef SIGLWP
301    sig_names[SIGLWP]     = _("SIGLWP special signal used by thread library");
302 #endif
303 #ifdef SIGFREEZE
304    sig_names[SIGFREEZE] = _("Checkpoint Freeze");
305 #endif
306 #ifdef SIGTHAW
307    sig_names[SIGTHAW]   = _("Checkpoint Thaw");
308 #endif
309 #ifdef SIGCANCEL
310    sig_names[SIGCANCEL] = _("Thread Cancellation");
311 #endif
312 #ifdef SIGLOST
313    sig_names[SIGLOST]   = _("Resource Lost (e.g. record-lock lost)");
314 #endif
315 #endif
316
317
318 /* Now setup signal handlers */
319    sighandle.sa_flags = 0;
320    sighandle.sa_handler = signal_handler;
321    sigfillset(&sighandle.sa_mask);
322    sigignore.sa_flags = 0;
323    sigignore.sa_handler = SIG_IGN;
324    sigfillset(&sigignore.sa_mask);
325    sigdefault.sa_flags = 0;
326    sigdefault.sa_handler = SIG_DFL;
327    sigfillset(&sigdefault.sa_mask);
328
329
330    sigaction(SIGPIPE,   &sigignore, NULL);
331    sigaction(SIGCHLD,   &sighandle, NULL);
332    sigaction(SIGCONT,   &sigignore, NULL);
333    sigaction(SIGPROF,   &sigignore, NULL);
334    sigaction(SIGWINCH,  &sigignore, NULL);
335    sigaction(SIGIO,     &sighandle, NULL);
336
337    sigaction(SIGINT,    &sigdefault, NULL);
338    sigaction(SIGXCPU,   &sigdefault, NULL);
339    sigaction(SIGXFSZ,   &sigdefault, NULL);
340
341    sigaction(SIGHUP,    &sigignore, NULL);
342    sigaction(SIGQUIT,   &sighandle, NULL);
343    sigaction(SIGILL,    &sighandle, NULL);
344    sigaction(SIGTRAP,   &sighandle, NULL);
345    sigaction(SIGABRT,   &sighandle, NULL);
346 #ifdef SIGEMT
347    sigaction(SIGEMT,    &sighandle, NULL);
348 #endif
349 #ifdef SIGIOT
350    sigaction(SIGIOT,    &sighandle, NULL);                     
351 #endif
352    sigaction(SIGBUS,    &sighandle, NULL);
353    sigaction(SIGFPE,    &sighandle, NULL);
354 /* sigaction(SIGKILL,   &sighandle, NULL);  cannot be trapped */
355    sigaction(SIGUSR1,   &sighandle, NULL);
356    sigaction(SIGSEGV,   &sighandle, NULL);
357    sigaction(SIGUSR2,   &sighandle, NULL);
358    sigaction(SIGALRM,   &sighandle, NULL);
359    sigaction(SIGTERM,   &sighandle, NULL);
360 #ifdef SIGSTKFLT
361    sigaction(SIGSTKFLT, &sighandle, NULL);
362 #endif
363 /* sigaction(SIGSTOP,   &sighandle, NULL); cannot be trapped */
364    sigaction(SIGTSTP,   &sighandle, NULL);
365    sigaction(SIGTTIN,   &sighandle, NULL);
366    sigaction(SIGTTOU,   &sighandle, NULL);
367    sigaction(SIGURG,    &sighandle, NULL);
368    sigaction(SIGVTALRM, &sighandle, NULL);
369 #ifdef SIGPWR
370    sigaction(SIGPWR,    &sighandle, NULL);
371 #endif
372 #ifdef SIGWAITING
373    sigaction(SIGWAITING,&sighandle, NULL);
374 #endif
375 #ifdef SIGLWP
376    sigaction(SIGLWP,    &sighandle, NULL);
377 #endif
378 #ifdef SIGFREEZE
379    sigaction(SIGFREEZE, &sighandle, NULL);
380 #endif
381 #ifdef SIGTHAW
382    sigaction(SIGTHAW,   &sighandle, NULL);
383 #endif
384 #ifdef SIGCANCEL
385    sigaction(SIGCANCEL, &sighandle, NULL);
386 #endif
387 #ifdef SIGLOST
388    sigaction(SIGLOST,   &sighandle, NULL);
389 #endif
390 }
391 #endif