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