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