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