+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
+
+ The main author of Bacula is Kern Sibbald, with contributions from
+ many others, a complete list can be found in the file AUTHORS.
+ This program is Free Software; you can redistribute it and/or
+ modify it under the terms of version three of the GNU Affero General Public
+ License as published by the Free Software Foundation and included
+ in the file LICENSE.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Bacula® is a registered trademark of Kern Sibbald.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
/*
* Signal handlers for Bacula daemons
*
* Kern Sibbald, April 2000
*
- * Version $Id$
- *
* Note, we probably should do a core dump for the serious
* signals such as SIGBUS, SIGPFE, ...
* Also, for SIGHUP and SIGUSR1, we should re-read the
*
*/
-/*
- Copyright (C) 2000-2004 Kern Sibbald and John Walker
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
-
- */
-
#ifndef HAVE_WIN32
#include "bacula.h"
extern char my_name[];
extern char *exepath;
extern char *exename;
+extern bool prt_kaboom;
static const char *sig_names[BA_NSIG+1];
const char *get_signal_name(int sig)
{
if (sig < 0 || sig > BA_NSIG || !sig_names[sig]) {
- return "Invalid signal number";
+ return _("Invalid signal number");
} else {
return sig_names[sig];
}
}
+/* defined in jcr.c */
+extern void dbg_print_jcr(FILE *fp);
+/* defined in plugins.c */
+extern void dbg_print_plugin(FILE *fp);
+/* defined in lockmgr.c */
+extern void dbg_print_lock(FILE *fp);
+
+/*
+ * !!! WARNING !!!
+ *
+ * This function should be used ONLY after a violent signal. We walk through the
+ * JCR chain without locking, Bacula should not be running.
+ */
+static void dbg_print_bacula()
+{
+ char buf[512];
+
+ snprintf(buf, sizeof(buf), "%s/%s.%d.bactrace",
+ working_directory, my_name, (int)getpid());
+ FILE *fp = fopen(buf, "a+") ;
+ if (!fp) {
+ fp = stderr;
+ }
+
+ fprintf(stderr, "Dumping: %s\n", buf);
+
+ /* Print also B_DB and RWLOCK structure
+ * Can add more info about JCR with dbg_jcr_add_hook()
+ */
+ dbg_print_lock(fp);
+ dbg_print_jcr(fp);
+ dbg_print_plugin(fp);
+
+ if (fp != stderr) {
+#define direct_print
+#ifdef direct_print
+ if (prt_kaboom) {
+ rewind(fp);
+ printf("\n\n ==== bactrace output ====\n\n");
+ while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
+ printf("%s", buf);
+ }
+ printf(" ==== End baktrace output ====\n\n");
+ }
+#else
+ if (prt_kaboom) {
+ char buf1[512];
+ printf("\n\n ==== bactrace output ====\n\n");
+ snprintf(buf1, sizeof(buf1), "/bin/cat %s", buf);
+ system(buf1);
+ printf(" ==== End baktrace output ====\n\n");
+ }
+#endif
+ fclose(fp);
+ }
+}
+
/*
* Handle signals here
*/
return;
}
already_dead++;
+ /* Don't use Emsg here as it may lock and thus block us */
if (sig == SIGTERM) {
-// Emsg1(M_TERM, -1, "Shutting down Bacula service: %s ...\n", my_name);
+ syslog(LOG_DAEMON|LOG_ERR, "Shutting down Bacula service: %s ...\n", my_name);
} else {
- Emsg2(M_FATAL, -1, "Bacula interrupted by signal %d: %s\n", sig, sig_names[sig]);
+ fprintf(stderr, _("Bacula interrupted by signal %d: %s\n"), sig, get_signal_name(sig));
+ syslog(LOG_DAEMON|LOG_ERR,
+ _("Bacula interrupted by signal %d: %s\n"), sig, get_signal_name(sig));
}
#ifdef TRACEBACK
if (sig != SIGTERM) {
struct sigaction sigdefault;
- static char *argv[4];
+ static char *argv[5];
static char pid_buf[20];
static char btpath[400];
- char buf[100];
+ char buf[400];
pid_t pid;
int exelen = strlen(exepath);
- fprintf(stderr, "Kaboom! %s, %s got signal %d. Attempting traceback.\n",
- exename, my_name, sig);
- fprintf(stderr, "Kaboom! exepath=%s\n", exepath);
+ fprintf(stderr, _("Kaboom! %s, %s got signal %d - %s. Attempting traceback.\n"),
+ exename, my_name, sig, get_signal_name(sig));
+ fprintf(stderr, _("Kaboom! exepath=%s\n"), exepath);
if (exelen + 12 > (int)sizeof(btpath)) {
bstrncpy(btpath, "btraceback", sizeof(btpath));
} else {
bstrncpy(btpath, exepath, sizeof(btpath));
- if (btpath[exelen-1] == '/') {
+ if (IsPathSeparator(btpath[exelen-1])) {
btpath[exelen-1] = 0;
}
bstrncat(btpath, "/btraceback", sizeof(btpath));
}
- if (exepath[exelen-1] != '/') {
+ if (!IsPathSeparator(exepath[exelen - 1])) {
strcat(exepath, "/");
}
strcat(exepath, exename);
}
if (chdir(working_directory) != 0) { /* dump in working directory */
berrno be;
- Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory, be.strerror());
+ Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory, be.bstrerror());
strcpy((char *)working_directory, "/tmp/");
}
unlink("./core"); /* get rid of any old core file */
Dmsg1(300, "exepath=%s\n", exepath);
switch (pid = fork()) {
case -1: /* error */
- fprintf(stderr, "Fork error: ERR=%s\n", strerror(errno));
+ fprintf(stderr, _("Fork error: ERR=%s\n"), strerror(errno));
break;
case 0: /* child */
argv[0] = btpath; /* path to btraceback */
argv[1] = exepath; /* path to exe */
argv[2] = pid_buf;
- argv[3] = (char *)NULL;
- fprintf(stderr, "Calling: %s %s %s\n", btpath, exepath, pid_buf);
+ argv[3] = (char *)working_directory;
+ argv[4] = (char *)NULL;
+ fprintf(stderr, _("Calling: %s %s %s %s\n"), btpath, exepath, pid_buf,
+ working_directory);
if (execv(btpath, argv) != 0) {
- printf("execv: %s failed: ERR=%s\n", btpath, strerror(errno));
+ berrno be;
+ printf(_("execv: %s failed: ERR=%s\n"), btpath, be.bstrerror());
}
exit(-1);
default: /* parent */
break;
}
+
/* Parent continue here, waiting for child */
sigdefault.sa_flags = 0;
sigdefault.sa_handler = SIG_DFL;
if (pid > 0) {
Dmsg0(500, "Doing waitpid\n");
waitpid(pid, NULL, 0); /* wait for child to produce dump */
- fprintf(stderr, "Traceback complete, attempting cleanup ...\n");
Dmsg0(500, "Done waitpid\n");
- exit_handler(sig); /* clean up if possible */
- Dmsg0(500, "Done exit_handler\n");
} else {
Dmsg0(500, "Doing sleep\n");
bmicrosleep(30, 0);
}
- fprintf(stderr, "It looks like the traceback worked ...\n");
+ fprintf(stderr, _("It looks like the traceback worked ...\n"));
+ /* If we want it printed, do so */
+#ifdef direct_print
+ if (prt_kaboom) {
+ FILE *fd;
+ snprintf(buf, sizeof(buf), "%s/bacula.%s.traceback", working_directory, pid_buf);
+ fd = fopen(buf, "r");
+ if (fd != NULL) {
+ printf("\n\n ==== Traceback output ====\n\n");
+ while (fgets(buf, (int)sizeof(buf), fd) != NULL) {
+ printf("%s", buf);
+ }
+ fclose(fd);
+ printf(" ==== End traceback output ====\n\n");
+ }
+ }
+#else
+ if (prt_kaboom) {
+ snprintf(buf, sizeof(buf), "/bin/cat %s/bacula.%s.traceback", working_directory, pid_buf);
+ fprintf(stderr, "\n\n ==== Traceback output ====\n\n");
+ system(buf);
+ fprintf(stderr, " ==== End traceback output ====\n\n");
+ }
+#endif
+ /* print information about the current state into working/<file>.bactrace */
+ dbg_print_bacula();
}
#endif
-
exit_handler(sig);
+ Dmsg0(500, "Done exit_handler\n");
}
/*
exit_handler = terminate;
if (BA_NSIG < _sys_nsig)
- Emsg2(M_ABORT, 0, "BA_NSIG too small (%d) should be (%d)\n", BA_NSIG, _sys_nsig);
+ Emsg2(M_ABORT, 0, _("BA_NSIG too small (%d) should be (%d)\n"), BA_NSIG, _sys_nsig);
for (i=0; i<_sys_nsig; i++)
sig_names[i] = _sys_siglist[i];
#else
exit_handler = terminate;
- sig_names[0] = "UNKNOWN SIGNAL";
- sig_names[SIGHUP] = "Hangup";
- sig_names[SIGINT] = "Interrupt";
- sig_names[SIGQUIT] = "Quit";
- sig_names[SIGILL] = "Illegal instruction";;
- sig_names[SIGTRAP] = "Trace/Breakpoint trap";
- sig_names[SIGABRT] = "Abort";
+ sig_names[0] = _("UNKNOWN SIGNAL");
+ sig_names[SIGHUP] = _("Hangup");
+ sig_names[SIGINT] = _("Interrupt");
+ sig_names[SIGQUIT] = _("Quit");
+ sig_names[SIGILL] = _("Illegal instruction");;
+ sig_names[SIGTRAP] = _("Trace/Breakpoint trap");
+ sig_names[SIGABRT] = _("Abort");
#ifdef SIGEMT
- sig_names[SIGEMT] = "EMT instruction (Emulation Trap)";
+ sig_names[SIGEMT] = _("EMT instruction (Emulation Trap)");
#endif
#ifdef SIGIOT
- sig_names[SIGIOT] = "IOT trap";
+ sig_names[SIGIOT] = _("IOT trap");
#endif
- sig_names[SIGBUS] = "BUS error";
- sig_names[SIGFPE] = "Floating-point exception";
- sig_names[SIGKILL] = "Kill, unblockable";
- sig_names[SIGUSR1] = "User-defined signal 1";
- sig_names[SIGSEGV] = "Segmentation violation";
- sig_names[SIGUSR2] = "User-defined signal 2";
- sig_names[SIGPIPE] = "Broken pipe";
- sig_names[SIGALRM] = "Alarm clock";
- sig_names[SIGTERM] = "Termination";
+ sig_names[SIGBUS] = _("BUS error");
+ sig_names[SIGFPE] = _("Floating-point exception");
+ sig_names[SIGKILL] = _("Kill, unblockable");
+ sig_names[SIGUSR1] = _("User-defined signal 1");
+ sig_names[SIGSEGV] = _("Segmentation violation");
+ sig_names[SIGUSR2] = _("User-defined signal 2");
+ sig_names[SIGPIPE] = _("Broken pipe");
+ sig_names[SIGALRM] = _("Alarm clock");
+ sig_names[SIGTERM] = _("Termination");
#ifdef SIGSTKFLT
- sig_names[SIGSTKFLT] = "Stack fault";
+ sig_names[SIGSTKFLT] = _("Stack fault");
#endif
- sig_names[SIGCHLD] = "Child status has changed";
- sig_names[SIGCONT] = "Continue";
- sig_names[SIGSTOP] = "Stop, unblockable";
- sig_names[SIGTSTP] = "Keyboard stop";
- sig_names[SIGTTIN] = "Background read from tty";
- sig_names[SIGTTOU] = "Background write to tty";
- sig_names[SIGURG] = "Urgent condition on socket";
- sig_names[SIGXCPU] = "CPU limit exceeded";
- sig_names[SIGXFSZ] = "File size limit exceeded";
- sig_names[SIGVTALRM] = "Virtual alarm clock";
- sig_names[SIGPROF] = "Profiling alarm clock";
- sig_names[SIGWINCH] = "Window size change";
- sig_names[SIGIO] = "I/O now possible";
+ sig_names[SIGCHLD] = _("Child status has changed");
+ sig_names[SIGCONT] = _("Continue");
+ sig_names[SIGSTOP] = _("Stop, unblockable");
+ sig_names[SIGTSTP] = _("Keyboard stop");
+ sig_names[SIGTTIN] = _("Background read from tty");
+ sig_names[SIGTTOU] = _("Background write to tty");
+ sig_names[SIGURG] = _("Urgent condition on socket");
+ sig_names[SIGXCPU] = _("CPU limit exceeded");
+ sig_names[SIGXFSZ] = _("File size limit exceeded");
+ sig_names[SIGVTALRM] = _("Virtual alarm clock");
+ sig_names[SIGPROF] = _("Profiling alarm clock");
+ sig_names[SIGWINCH] = _("Window size change");
+ sig_names[SIGIO] = _("I/O now possible");
#ifdef SIGPWR
- sig_names[SIGPWR] = "Power failure restart";
+ sig_names[SIGPWR] = _("Power failure restart");
#endif
#ifdef SIGWAITING
- sig_names[SIGWAITING] = "No runnable lwp";
+ sig_names[SIGWAITING] = _("No runnable lwp");
#endif
#ifdef SIGLWP
- sig_name[SIGLWP] = "SIGLWP special signal used by thread library";
+ sig_names[SIGLWP] = _("SIGLWP special signal used by thread library");
#endif
#ifdef SIGFREEZE
- sig_names[SIGFREEZE] = "Checkpoint Freeze";
+ sig_names[SIGFREEZE] = _("Checkpoint Freeze");
#endif
#ifdef SIGTHAW
- sig_names[SIGTHAW] = "Checkpoint Thaw";
+ sig_names[SIGTHAW] = _("Checkpoint Thaw");
#endif
#ifdef SIGCANCEL
- sig_names[SIGCANCEL] = "Thread Cancellation";
+ sig_names[SIGCANCEL] = _("Thread Cancellation");
#endif
#ifdef SIGLOST
- sig_names[SIGLOST] = "Resource Lost (e.g. record-lock lost)";
+ sig_names[SIGLOST] = _("Resource Lost (e.g. record-lock lost)");
#endif
#endif
sigaction(SIGQUIT, &sighandle, NULL);
sigaction(SIGILL, &sighandle, NULL);
sigaction(SIGTRAP, &sighandle, NULL);
-/* sigaction(SIGABRT, &sighandle, NULL); */
+ sigaction(SIGABRT, &sighandle, NULL);
#ifdef SIGEMT
sigaction(SIGEMT, &sighandle, NULL);
#endif
#ifdef SIGIOT
-/* sigaction(SIGIOT, &sighandle, NULL); used by debugger */
+ sigaction(SIGIOT, &sighandle, NULL);
#endif
sigaction(SIGBUS, &sighandle, NULL);
sigaction(SIGFPE, &sighandle, NULL);
- sigaction(SIGKILL, &sighandle, NULL);
+/* sigaction(SIGKILL, &sighandle, NULL); cannot be trapped */
sigaction(SIGUSR1, &sighandle, NULL);
sigaction(SIGSEGV, &sighandle, NULL);
sigaction(SIGUSR2, &sighandle, NULL);
#ifdef SIGSTKFLT
sigaction(SIGSTKFLT, &sighandle, NULL);
#endif
- sigaction(SIGSTOP, &sighandle, NULL);
+/* sigaction(SIGSTOP, &sighandle, NULL); cannot be trapped */
sigaction(SIGTSTP, &sighandle, NULL);
sigaction(SIGTTIN, &sighandle, NULL);
sigaction(SIGTTOU, &sighandle, NULL);