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