]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/signal.c
Backport from BEE
[bacula/bacula] / bacula / src / lib / signal.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *  Signal handlers for Bacula daemons
18  *
19  *   Kern Sibbald, April 2000
20  *
21  * Note, we probably should do a core dump for the serious
22  * signals such as SIGBUS, SIGPFE, ...
23  * Also, for SIGHUP and SIGUSR1, we should re-read the
24  * configuration file.  However, since this is a "general"
25  * routine, we leave it to the individual daemons to
26  * tweek their signals after calling this routine.
27  *
28  */
29
30 #ifndef HAVE_WIN32
31 #include "bacula.h"
32
33 #ifndef _NSIG
34 #define BA_NSIG 100
35 #else
36 #define BA_NSIG _NSIG
37 #endif
38
39 extern char my_name[];
40 extern char fail_time[];
41 extern char *exepath;
42 extern char *exename;
43 extern bool prt_kaboom;
44
45 static const char *sig_names[BA_NSIG+1];
46
47 typedef void (SIG_HANDLER)(int sig);
48 static SIG_HANDLER *exit_handler;
49
50 /* main process id */
51 static pid_t main_pid = 0;
52
53 const char *get_signal_name(int sig)
54 {
55    if (sig < 0 || sig > BA_NSIG || !sig_names[sig]) {
56       return _("Invalid signal number");
57    } else {
58       return sig_names[sig];
59    }
60 }
61
62 /* defined in jcr.c */
63 extern void dbg_print_jcr(FILE *fp);
64 /* defined in plugins.c */
65 extern void dbg_print_plugin(FILE *fp);
66 /* defined in lockmgr.c */
67 extern void dbg_print_lock(FILE *fp);
68
69 /*
70  * !!! WARNING !!!
71  *
72  * This function should be used ONLY after a violent signal. We walk through the
73  * JCR chain without locking, Bacula should not be running.
74  */
75 static void dbg_print_bacula()
76 {
77    char buf[512];
78
79    snprintf(buf, sizeof(buf), "%s/%s.%d.lockdump",
80             working_directory, my_name, (int)getpid());
81    FILE *fp = fopen(buf, "a+") ;
82    if (!fp) {
83       fp = stderr;
84    }
85
86    fprintf(stderr, "Dumping: %s\n", buf);
87
88    /* Print also B_DB and RWLOCK structure
89     * Can add more info about JCR with dbg_jcr_add_hook()
90     */
91    dbg_print_lock(fp);
92    dbg_print_jcr(fp);
93    dbg_print_plugin(fp);
94
95    if (fp != stderr) {
96 #define direct_print
97 #ifdef direct_print
98       if (prt_kaboom) {
99          rewind(fp);
100          printf("\n\n ==== lockdump output ====\n\n");
101          while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
102             printf("%s", buf);
103          }
104          printf(" ==== End baktrace output ====\n\n");
105       }
106 #else
107       if (prt_kaboom) {
108          char buf1[512];
109          printf("\n\n ==== lockdump output ====\n\n");
110          snprintf(buf1, sizeof(buf1), "/bin/cat %s", buf);
111          system(buf1);
112          printf(" ==== End baktrace output ====\n\n");
113       }
114 #endif
115       fclose(fp);
116    }
117 }
118
119 /*
120  * Handle signals here
121  */
122 extern "C" void signal_handler(int sig)
123 {
124    static int already_dead = 0;
125    int chld_status=-1;
126    utime_t now;
127
128    /* If we come back more than once, get out fast! */
129    if (already_dead) {
130       exit(1);
131    }
132    Dmsg2(900, "sig=%d %s\n", sig, sig_names[sig]);
133    /* Ignore certain signals -- SIGUSR2 used to interrupt threads */
134    if (sig == SIGCHLD || sig == SIGUSR2) {
135       return;
136    }
137    /* FreeBSD seems to generate a signal of 0, which is of course undefined */
138    if (sig == 0) {
139       return;
140    }
141    already_dead++;
142    /* Don't use Emsg here as it may lock and thus block us */
143    if (sig == SIGTERM) {
144        syslog(LOG_DAEMON|LOG_ERR, "Shutting down Bacula service: %s ...\n", my_name);
145    } else {
146       fprintf(stderr, _("Bacula interrupted by signal %d: %s\n"), sig, get_signal_name(sig));
147       syslog(LOG_DAEMON|LOG_ERR,
148          _("Bacula interrupted by signal %d: %s\n"), sig, get_signal_name(sig));
149       /* Edit current time for showing in the dump */
150       now = time(NULL);
151       bstrftimes(fail_time, 30, now);
152    }
153
154 #ifdef TRACEBACK
155    if (sig != SIGTERM) {
156       struct sigaction sigdefault;
157       static char *argv[5];
158       static char pid_buf[20];
159       static char btpath[400];
160       char buf[400];
161       pid_t pid;
162       int exelen = strlen(exepath);
163
164       fprintf(stderr, _("Kaboom! %s, %s got signal %d - %s at %s. Attempting traceback.\n"),
165               exename, my_name, sig, get_signal_name(sig), fail_time);
166       fprintf(stderr, _("Kaboom! exepath=%s\n"), exepath);
167
168       if (exelen + 12 > (int)sizeof(btpath)) {
169          bstrncpy(btpath, "btraceback", sizeof(btpath));
170       } else {
171          bstrncpy(btpath, exepath, sizeof(btpath));
172          if (IsPathSeparator(btpath[exelen-1])) {
173             btpath[exelen-1] = 0;
174          }
175          bstrncat(btpath, "/btraceback", sizeof(btpath));
176       }
177       if (!IsPathSeparator(exepath[exelen - 1])) {
178          strcat(exepath, "/");
179       }
180       strcat(exepath, exename);
181       if (!working_directory) {
182          working_directory = buf;
183          *buf = 0;
184       }
185       if (*working_directory == 0) {
186          strcpy((char *)working_directory, "/tmp/");
187       }
188       if (chdir(working_directory) != 0) {  /* dump in working directory */
189          berrno be;
190          Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory,  be.bstrerror());
191          strcpy((char *)working_directory, "/tmp/");
192       }
193       unlink("./core");               /* get rid of any old core file */
194
195 #ifdef DEVELOPER /* When DEVELOPER not set, this is done below */
196       /* print information about the current state into working/<file>.lockdump */
197       dbg_print_bacula();
198 #endif
199
200
201       sprintf(pid_buf, "%d", (int)main_pid);
202       Dmsg1(300, "Working=%s\n", working_directory);
203       Dmsg1(300, "btpath=%s\n", btpath);
204       Dmsg1(300, "exepath=%s\n", exepath);
205       switch (pid = fork()) {
206       case -1:                        /* error */
207          fprintf(stderr, _("Fork error: ERR=%s\n"), strerror(errno));
208          break;
209       case 0:                         /* child */
210          argv[0] = btpath;            /* path to btraceback */
211          argv[1] = exepath;           /* path to exe */
212          argv[2] = pid_buf;
213          argv[3] = (char *)working_directory;
214          argv[4] = (char *)NULL;
215          fprintf(stderr, _("Calling: %s %s %s %s\n"), btpath, exepath, pid_buf,
216             working_directory);
217          if (execv(btpath, argv) != 0) {
218             berrno be;
219             printf(_("execv: %s failed: ERR=%s\n"), btpath, be.bstrerror());
220          }
221          exit(-1);
222       default:                        /* parent */
223          break;
224       }
225
226       /* Parent continue here, waiting for child */
227       sigdefault.sa_flags = 0;
228       sigdefault.sa_handler = SIG_DFL;
229       sigfillset(&sigdefault.sa_mask);
230
231       sigaction(sig,  &sigdefault, NULL);
232       if (pid > 0) {
233          Dmsg0(500, "Doing waitpid\n");
234          waitpid(pid, &chld_status, 0);   /* wait for child to produce dump */
235          Dmsg0(500, "Done waitpid\n");
236       } else {
237          Dmsg0(500, "Doing sleep\n");
238          bmicrosleep(30, 0);
239       }
240       if (WEXITSTATUS(chld_status) == 0) {
241          fprintf(stderr, _("It looks like the traceback worked...\n"));
242       } else {
243          fprintf(stderr, _("The btraceback call returned %d\n"),
244                            WEXITSTATUS(chld_status));
245       }
246       /* If we want it printed, do so */
247 #ifdef direct_print
248       if (prt_kaboom) {
249          FILE *fd;
250          snprintf(buf, sizeof(buf), "%s/bacula.%s.traceback", working_directory, pid_buf);
251          fd = fopen(buf, "r");
252          if (fd != NULL) {
253             printf("\n\n ==== Traceback output ====\n\n");
254             while (fgets(buf, (int)sizeof(buf), fd) != NULL) {
255                printf("%s", buf);
256             }
257             fclose(fd);
258             printf(" ==== End traceback output ====\n\n");
259          }
260       }
261 #else
262       if (prt_kaboom) {
263          snprintf(buf, sizeof(buf), "/bin/cat %s/bacula.%s.traceback", working_directory, pid_buf);
264          fprintf(stderr, "\n\n ==== Traceback output ====\n\n");
265          system(buf);
266          fprintf(stderr, " ==== End traceback output ====\n\n");
267       }
268 #endif
269
270 #ifndef DEVELOPER /* When DEVELOPER set, this is done above */
271       /* print information about the current state into working/<file>.lockdump */
272       dbg_print_bacula();
273 #endif
274
275    }
276 #endif
277    exit_handler(sig);
278    Dmsg0(500, "Done exit_handler\n");
279 }
280
281 /*
282  * Init stack dump by saving main process id --
283  *   needed by debugger to attach to this program.
284  */
285 void init_stack_dump(void)
286 {
287    main_pid = getpid();               /* save main thread's pid */
288 }
289
290 /*
291  * Initialize signals
292  */
293 void init_signals(void terminate(int sig))
294 {
295    struct sigaction sighandle;
296    struct sigaction sigignore;
297    struct sigaction sigdefault;
298 #ifdef _sys_nsig
299    int i;
300
301    exit_handler = terminate;
302    if (BA_NSIG < _sys_nsig)
303       Emsg2(M_ABORT, 0, _("BA_NSIG too small (%d) should be (%d)\n"), BA_NSIG, _sys_nsig);
304
305    for (i=0; i<_sys_nsig; i++)
306       sig_names[i] = _sys_siglist[i];
307 #else
308    exit_handler = terminate;
309    sig_names[0]         = _("UNKNOWN SIGNAL");
310    sig_names[SIGHUP]    = _("Hangup");
311    sig_names[SIGINT]    = _("Interrupt");
312    sig_names[SIGQUIT]   = _("Quit");
313    sig_names[SIGILL]    = _("Illegal instruction");;
314    sig_names[SIGTRAP]   = _("Trace/Breakpoint trap");
315    sig_names[SIGABRT]   = _("Abort");
316 #ifdef SIGEMT
317    sig_names[SIGEMT]    = _("EMT instruction (Emulation Trap)");
318 #endif
319 #ifdef SIGIOT
320    sig_names[SIGIOT]    = _("IOT trap");
321 #endif
322    sig_names[SIGBUS]    = _("BUS error");
323    sig_names[SIGFPE]    = _("Floating-point exception");
324    sig_names[SIGKILL]   = _("Kill, unblockable");
325    sig_names[SIGUSR1]   = _("User-defined signal 1");
326    sig_names[SIGSEGV]   = _("Segmentation violation");
327    sig_names[SIGUSR2]   = _("User-defined signal 2");
328    sig_names[SIGPIPE]   = _("Broken pipe");
329    sig_names[SIGALRM]   = _("Alarm clock");
330    sig_names[SIGTERM]   = _("Termination");
331 #ifdef SIGSTKFLT
332    sig_names[SIGSTKFLT] = _("Stack fault");
333 #endif
334    sig_names[SIGCHLD]   = _("Child status has changed");
335    sig_names[SIGCONT]   = _("Continue");
336    sig_names[SIGSTOP]   = _("Stop, unblockable");
337    sig_names[SIGTSTP]   = _("Keyboard stop");
338    sig_names[SIGTTIN]   = _("Background read from tty");
339    sig_names[SIGTTOU]   = _("Background write to tty");
340    sig_names[SIGURG]    = _("Urgent condition on socket");
341    sig_names[SIGXCPU]   = _("CPU limit exceeded");
342    sig_names[SIGXFSZ]   = _("File size limit exceeded");
343    sig_names[SIGVTALRM] = _("Virtual alarm clock");
344    sig_names[SIGPROF]   = _("Profiling alarm clock");
345    sig_names[SIGWINCH]  = _("Window size change");
346    sig_names[SIGIO]     = _("I/O now possible");
347 #ifdef SIGPWR
348    sig_names[SIGPWR]    = _("Power failure restart");
349 #endif
350 #ifdef SIGWAITING
351    sig_names[SIGWAITING] = _("No runnable lwp");
352 #endif
353 #ifdef SIGLWP
354    sig_names[SIGLWP]     = _("SIGLWP special signal used by thread library");
355 #endif
356 #ifdef SIGFREEZE
357    sig_names[SIGFREEZE] = _("Checkpoint Freeze");
358 #endif
359 #ifdef SIGTHAW
360    sig_names[SIGTHAW]   = _("Checkpoint Thaw");
361 #endif
362 #ifdef SIGCANCEL
363    sig_names[SIGCANCEL] = _("Thread Cancellation");
364 #endif
365 #ifdef SIGLOST
366    sig_names[SIGLOST]   = _("Resource Lost (e.g. record-lock lost)");
367 #endif
368 #endif
369
370
371 /* Now setup signal handlers */
372    sighandle.sa_flags = 0;
373    sighandle.sa_handler = signal_handler;
374    sigfillset(&sighandle.sa_mask);
375    sigignore.sa_flags = 0;
376    sigignore.sa_handler = SIG_IGN;
377    sigfillset(&sigignore.sa_mask);
378    sigdefault.sa_flags = 0;
379    sigdefault.sa_handler = SIG_DFL;
380    sigfillset(&sigdefault.sa_mask);
381
382
383    sigaction(SIGPIPE,   &sigignore, NULL);
384    sigaction(SIGCHLD,   &sighandle, NULL);
385    sigaction(SIGCONT,   &sigignore, NULL);
386    sigaction(SIGPROF,   &sigignore, NULL);
387    sigaction(SIGWINCH,  &sigignore, NULL);
388    sigaction(SIGIO,     &sighandle, NULL);
389
390    sigaction(SIGINT,    &sigdefault, NULL);
391    sigaction(SIGXCPU,   &sigdefault, NULL);
392    sigaction(SIGXFSZ,   &sigdefault, NULL);
393
394    sigaction(SIGHUP,    &sigignore, NULL);
395    sigaction(SIGQUIT,   &sighandle, NULL);
396    sigaction(SIGILL,    &sighandle, NULL);
397    sigaction(SIGTRAP,   &sighandle, NULL);
398    sigaction(SIGABRT,   &sighandle, NULL);
399 #ifdef SIGEMT
400    sigaction(SIGEMT,    &sighandle, NULL);
401 #endif
402 #ifdef SIGIOT
403    sigaction(SIGIOT,    &sighandle, NULL);
404 #endif
405    sigaction(SIGBUS,    &sighandle, NULL);
406    sigaction(SIGFPE,    &sighandle, NULL);
407 /* sigaction(SIGKILL,   &sighandle, NULL);  cannot be trapped */
408    sigaction(SIGUSR1,   &sighandle, NULL);
409    sigaction(SIGSEGV,   &sighandle, NULL);
410    sigaction(SIGUSR2,   &sighandle, NULL);
411    sigaction(SIGALRM,   &sighandle, NULL);
412    sigaction(SIGTERM,   &sighandle, NULL);
413 #ifdef SIGSTKFLT
414    sigaction(SIGSTKFLT, &sighandle, NULL);
415 #endif
416 /* sigaction(SIGSTOP,   &sighandle, NULL); cannot be trapped */
417    sigaction(SIGTSTP,   &sighandle, NULL);
418    sigaction(SIGTTIN,   &sighandle, NULL);
419    sigaction(SIGTTOU,   &sighandle, NULL);
420    sigaction(SIGURG,    &sighandle, NULL);
421    sigaction(SIGVTALRM, &sighandle, NULL);
422 #ifdef SIGPWR
423    sigaction(SIGPWR,    &sighandle, NULL);
424 #endif
425 #ifdef SIGWAITING
426    sigaction(SIGWAITING,&sighandle, NULL);
427 #endif
428 #ifdef SIGLWP
429    sigaction(SIGLWP,    &sighandle, NULL);
430 #endif
431 #ifdef SIGFREEZE
432    sigaction(SIGFREEZE, &sighandle, NULL);
433 #endif
434 #ifdef SIGTHAW
435    sigaction(SIGTHAW,   &sighandle, NULL);
436 #endif
437 #ifdef SIGCANCEL
438    sigaction(SIGCANCEL, &sighandle, NULL);
439 #endif
440 #ifdef SIGLOST
441    sigaction(SIGLOST,   &sighandle, NULL);
442 #endif
443 }
444 #endif