]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/signal.c
Update copyrights
[bacula/bacula] / bacula / src / lib / signal.c
1 /*
2  *  Signal handlers for Bacula daemons
3  *
4  *   Kern Sibbald, April 2000
5  *
6  *   Version $Id$
7  *
8  * Note, we probably should do a core dump for the serious
9  * signals such as SIGBUS, SIGPFE, ...
10  * Also, for SIGHUP and SIGUSR1, we should re-read the
11  * configuration file.  However, since this is a "general"
12  * routine, we leave it to the individual daemons to
13  * tweek their signals after calling this routine.
14  *
15  */
16 /*
17    Bacula® - The Network Backup Solution
18
19    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
20
21    The main author of Bacula is Kern Sibbald, with contributions from
22    many others, a complete list can be found in the file AUTHORS.
23    This program is Free Software; you can redistribute it and/or
24    modify it under the terms of version two of the GNU General Public
25    License as published by the Free Software Foundation plus additions
26    that are listed in the file LICENSE.
27
28    This program is distributed in the hope that it will be useful, but
29    WITHOUT ANY WARRANTY; without even the implied warranty of
30    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31    General Public License for more details.
32
33    You should have received a copy of the GNU General Public License
34    along with this program; if not, write to the Free Software
35    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
36    02110-1301, USA.
37
38    Bacula® is a registered trademark of John Walker.
39    The licensor of Bacula is the Free Software Foundation Europe
40    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
41    Switzerland, email:ftf@fsfeurope.org.
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, sig_names[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. Attempting traceback.\n"),
108               exename, my_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 (btpath[exelen-1] == '/') {
116             btpath[exelen-1] = 0;
117          }
118          bstrncat(btpath, "/btraceback", sizeof(btpath));
119       }
120       if (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.strerror());
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             printf(_("execv: %s failed: ERR=%s\n"), btpath, strerror(errno));
153          }
154          exit(-1);
155       default:                        /* parent */
156          break;
157       }
158       /* Parent continue here, waiting for child */
159       sigdefault.sa_flags = 0;
160       sigdefault.sa_handler = SIG_DFL;
161       sigfillset(&sigdefault.sa_mask);
162
163       sigaction(sig,  &sigdefault, NULL);
164       if (pid > 0) {
165          Dmsg0(500, "Doing waitpid\n");
166          waitpid(pid, NULL, 0);       /* wait for child to produce dump */
167          fprintf(stderr, _("Traceback complete, attempting cleanup ...\n"));
168          Dmsg0(500, "Done waitpid\n");
169          exit_handler(sig);           /* clean up if possible */
170          Dmsg0(500, "Done exit_handler\n");
171       } else {
172          Dmsg0(500, "Doing sleep\n");
173          bmicrosleep(30, 0);
174       }
175       fprintf(stderr, _("It looks like the traceback worked ...\n"));
176    }
177 #endif
178
179    exit_handler(sig);
180 }
181
182 /*
183  * Init stack dump by saving main process id --
184  *   needed by debugger to attach to this program.
185  */
186 void init_stack_dump(void)
187 {
188    main_pid = getpid();               /* save main thread's pid */
189 }
190
191 /*
192  * Initialize signals
193  */
194 void init_signals(void terminate(int sig))
195 {
196    struct sigaction sighandle;
197    struct sigaction sigignore;
198    struct sigaction sigdefault;
199 #ifdef _sys_nsig
200    int i;
201
202    exit_handler = terminate;
203    if (BA_NSIG < _sys_nsig)
204       Emsg2(M_ABORT, 0, _("BA_NSIG too small (%d) should be (%d)\n"), BA_NSIG, _sys_nsig);
205
206    for (i=0; i<_sys_nsig; i++)
207       sig_names[i] = _sys_siglist[i];
208 #else
209    exit_handler = terminate;
210    sig_names[0]         = _("UNKNOWN SIGNAL");
211    sig_names[SIGHUP]    = _("Hangup");
212    sig_names[SIGINT]    = _("Interrupt");
213    sig_names[SIGQUIT]   = _("Quit");
214    sig_names[SIGILL]    = _("Illegal instruction");;
215    sig_names[SIGTRAP]   = _("Trace/Breakpoint trap");
216    sig_names[SIGABRT]   = _("Abort");
217 #ifdef SIGEMT
218    sig_names[SIGEMT]    = _("EMT instruction (Emulation Trap)");
219 #endif
220 #ifdef SIGIOT
221    sig_names[SIGIOT]    = _("IOT trap");
222 #endif
223    sig_names[SIGBUS]    = _("BUS error");
224    sig_names[SIGFPE]    = _("Floating-point exception");
225    sig_names[SIGKILL]   = _("Kill, unblockable");
226    sig_names[SIGUSR1]   = _("User-defined signal 1");
227    sig_names[SIGSEGV]   = _("Segmentation violation");
228    sig_names[SIGUSR2]   = _("User-defined signal 2");
229    sig_names[SIGPIPE]   = _("Broken pipe");
230    sig_names[SIGALRM]   = _("Alarm clock");
231    sig_names[SIGTERM]   = _("Termination");
232 #ifdef SIGSTKFLT
233    sig_names[SIGSTKFLT] = _("Stack fault");
234 #endif
235    sig_names[SIGCHLD]   = _("Child status has changed");
236    sig_names[SIGCONT]   = _("Continue");
237    sig_names[SIGSTOP]   = _("Stop, unblockable");
238    sig_names[SIGTSTP]   = _("Keyboard stop");
239    sig_names[SIGTTIN]   = _("Background read from tty");
240    sig_names[SIGTTOU]   = _("Background write to tty");
241    sig_names[SIGURG]    = _("Urgent condition on socket");
242    sig_names[SIGXCPU]   = _("CPU limit exceeded");
243    sig_names[SIGXFSZ]   = _("File size limit exceeded");
244    sig_names[SIGVTALRM] = _("Virtual alarm clock");
245    sig_names[SIGPROF]   = _("Profiling alarm clock");
246    sig_names[SIGWINCH]  = _("Window size change");
247    sig_names[SIGIO]     = _("I/O now possible");
248 #ifdef SIGPWR
249    sig_names[SIGPWR]    = _("Power failure restart");
250 #endif
251 #ifdef SIGWAITING
252    sig_names[SIGWAITING] = _("No runnable lwp");
253 #endif
254 #ifdef SIGLWP
255    sig_names[SIGLWP]     = _("SIGLWP special signal used by thread library");
256 #endif
257 #ifdef SIGFREEZE
258    sig_names[SIGFREEZE] = _("Checkpoint Freeze");
259 #endif
260 #ifdef SIGTHAW
261    sig_names[SIGTHAW]   = _("Checkpoint Thaw");
262 #endif
263 #ifdef SIGCANCEL
264    sig_names[SIGCANCEL] = _("Thread Cancellation");
265 #endif
266 #ifdef SIGLOST
267    sig_names[SIGLOST]   = _("Resource Lost (e.g. record-lock lost)");
268 #endif
269 #endif
270
271
272 /* Now setup signal handlers */
273    sighandle.sa_flags = 0;
274    sighandle.sa_handler = signal_handler;
275    sigfillset(&sighandle.sa_mask);
276    sigignore.sa_flags = 0;
277    sigignore.sa_handler = SIG_IGN;
278    sigfillset(&sigignore.sa_mask);
279    sigdefault.sa_flags = 0;
280    sigdefault.sa_handler = SIG_DFL;
281    sigfillset(&sigdefault.sa_mask);
282
283
284    sigaction(SIGPIPE,   &sigignore, NULL);
285    sigaction(SIGCHLD,   &sighandle, NULL);
286    sigaction(SIGCONT,   &sigignore, NULL);
287    sigaction(SIGPROF,   &sigignore, NULL);
288    sigaction(SIGWINCH,  &sigignore, NULL);
289    sigaction(SIGIO,     &sighandle, NULL);
290
291    sigaction(SIGINT,    &sigdefault, NULL);
292    sigaction(SIGXCPU,   &sigdefault, NULL);
293    sigaction(SIGXFSZ,   &sigdefault, NULL);
294
295    sigaction(SIGHUP,    &sigignore, NULL);
296    sigaction(SIGQUIT,   &sighandle, NULL);
297    sigaction(SIGILL,    &sighandle, NULL);
298    sigaction(SIGTRAP,   &sighandle, NULL);
299 /* sigaction(SIGABRT,   &sighandle, NULL);   */
300 #ifdef SIGEMT
301    sigaction(SIGEMT,    &sighandle, NULL);
302 #endif
303 #ifdef SIGIOT
304 /* sigaction(SIGIOT,    &sighandle, NULL);  used by debugger */
305 #endif
306    sigaction(SIGBUS,    &sighandle, NULL);
307    sigaction(SIGFPE,    &sighandle, NULL);
308    sigaction(SIGKILL,   &sighandle, NULL);
309    sigaction(SIGUSR1,   &sighandle, NULL);
310    sigaction(SIGSEGV,   &sighandle, NULL);
311    sigaction(SIGUSR2,   &sighandle, NULL);
312    sigaction(SIGALRM,   &sighandle, NULL);
313    sigaction(SIGTERM,   &sighandle, NULL);
314 #ifdef SIGSTKFLT
315    sigaction(SIGSTKFLT, &sighandle, NULL);
316 #endif
317    sigaction(SIGSTOP,   &sighandle, NULL);
318    sigaction(SIGTSTP,   &sighandle, NULL);
319    sigaction(SIGTTIN,   &sighandle, NULL);
320    sigaction(SIGTTOU,   &sighandle, NULL);
321    sigaction(SIGURG,    &sighandle, NULL);
322    sigaction(SIGVTALRM, &sighandle, NULL);
323 #ifdef SIGPWR
324    sigaction(SIGPWR,    &sighandle, NULL);
325 #endif
326 #ifdef SIGWAITING
327    sigaction(SIGWAITING,&sighandle, NULL);
328 #endif
329 #ifdef SIGLWP
330    sigaction(SIGLWP,    &sighandle, NULL);
331 #endif
332 #ifdef SIGFREEZE
333    sigaction(SIGFREEZE, &sighandle, NULL);
334 #endif
335 #ifdef SIGTHAW
336    sigaction(SIGTHAW,   &sighandle, NULL);
337 #endif
338 #ifdef SIGCANCEL
339    sigaction(SIGCANCEL, &sighandle, NULL);
340 #endif
341 #ifdef SIGLOST
342    sigaction(SIGLOST,   &sighandle, NULL);
343 #endif
344 }
345 #endif