X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fsignal.c;h=68ba78586b8915d5461b29e7cc1f2932898c9b19;hb=897707854a8240d026e933215009f931bb9c5762;hp=de9fdfe6913c38e4324c3543e27da1eabeaaf3a4;hpb=9081f20ef8f97245ec769479dac904a6e16d0ef6;p=bacula%2Fbacula diff --git a/bacula/src/lib/signal.c b/bacula/src/lib/signal.c index de9fdfe691..68ba78586b 100644 --- a/bacula/src/lib/signal.c +++ b/bacula/src/lib/signal.c @@ -1,38 +1,45 @@ /* - * Signal handlers for Bacula daemons - * - * Kern Sibbald, April 2000 - * - * 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 - * configuration file. However, since this is a "general" - * routine, we leave it to the individual daemons to - * tweek their signals after calling this routine. - * - */ + Bacula® - The Network Backup Solution -/* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + Copyright (C) 2000-2009 Free Software Foundation Europe e.V. - 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. + 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 + 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. + 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 + * + * 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 + * configuration file. However, since this is a "general" + * routine, we leave it to the individual daemons to + * tweek their signals after calling this routine. + * */ - +#ifndef HAVE_WIN32 #include "bacula.h" #ifndef _NSIG @@ -44,6 +51,7 @@ extern char my_name[]; extern char *exepath; extern char *exename; +extern bool prt_kaboom; static const char *sig_names[BA_NSIG+1]; @@ -53,63 +61,164 @@ static SIG_HANDLER *exit_handler; /* main process id */ static pid_t main_pid = 0; -/* +const char *get_signal_name(int sig) +{ + if (sig < 0 || sig > BA_NSIG || !sig_names[sig]) { + 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 */ -static void signal_handler(int sig) +extern "C" void signal_handler(int sig) { - static int already_dead = FALSE; - struct sigaction sigdefault; + static int already_dead = 0; + /* If we come back more than once, get out fast! */ if (already_dead) { - _exit(1); + exit(1); + } + Dmsg2(900, "sig=%d %s\n", sig, sig_names[sig]); + /* Ignore certain signals -- SIGUSR2 used to interrupt threads */ + if (sig == SIGCHLD || sig == SIGUSR2) { + return; } - already_dead = TRUE; + 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, "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) { - static char *argv[4]; + struct sigaction sigdefault; + static char *argv[5]; static char pid_buf[20]; static char btpath[400]; + char buf[400]; pid_t pid; + int exelen = strlen(exepath); - Dmsg1(000, "Kaboom! Got signal %d. Attempting traceback\n", sig); - if (strlen(exepath) + 12 > (int)sizeof(btpath)) { - strcpy(btpath, "btraceback"); + 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 { - strcpy(btpath, exepath); - strcat(btpath, "/btraceback"); + bstrncpy(btpath, exepath, sizeof(btpath)); + if (IsPathSeparator(btpath[exelen-1])) { + btpath[exelen-1] = 0; + } + bstrncat(btpath, "/btraceback", sizeof(btpath)); + } + if (!IsPathSeparator(exepath[exelen - 1])) { + strcat(exepath, "/"); } - strcat(exepath, "/"); strcat(exepath, exename); - if (chdir(working_directory) !=0) { /* dump in working directory */ - Dmsg1(000, "chdir failed. ERR=%s\n", strerror(errno)); + if (!working_directory) { + working_directory = buf; + *buf = 0; + } + if (*working_directory == 0) { + strcpy((char *)working_directory, "/tmp/"); + } + if (chdir(working_directory) != 0) { /* dump in working directory */ + berrno be; + 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 */ - sprintf(pid_buf, "%d", main_pid); + sprintf(pid_buf, "%d", (int)main_pid); Dmsg1(300, "Working=%s\n", working_directory); Dmsg1(300, "btpath=%s\n", btpath); Dmsg1(300, "exepath=%s\n", exepath); switch (pid = fork()) { - case -1: /* error */ - break; - case 0: /* child */ - argv[0] = btpath; /* path to btraceback */ - argv[1] = exepath; /* path to exe */ - argv[2] = pid_buf; - argv[3] = (char *)NULL; - if (execv(btpath, argv) != 0) { - printf("execv: %s failed: ERR=%s\n", btpath, strerror(errno)); - } - exit(-1); - default: /* parent */ - break; + case -1: /* error */ + 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 *)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) { + 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; sigfillset(&sigdefault.sa_mask); @@ -117,18 +226,42 @@ static void signal_handler(int sig) sigaction(sig, &sigdefault, NULL); if (pid > 0) { Dmsg0(500, "Doing waitpid\n"); - waitpid(pid, NULL, 0); /* wait for child to produce dump */ + waitpid(pid, NULL, 0); /* wait for child to produce dump */ Dmsg0(500, "Done waitpid\n"); - exit_handler(1); /* clean up if possible */ - Dmsg0(500, "Done exit_handler\n"); } else { Dmsg0(500, "Doing sleep\n"); - sleep(30); + bmicrosleep(30, 0); } + 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/.bactrace */ + dbg_print_bacula(); } #endif - - exit_handler(1); + exit_handler(sig); + Dmsg0(500, "Done exit_handler\n"); } /* @@ -153,70 +286,70 @@ void init_signals(void terminate(int sig)) 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 @@ -226,71 +359,72 @@ void init_signals(void terminate(int sig)) sighandle.sa_handler = signal_handler; sigfillset(&sighandle.sa_mask); sigignore.sa_flags = 0; - sigignore.sa_handler = SIG_IGN; + sigignore.sa_handler = SIG_IGN; sigfillset(&sigignore.sa_mask); sigdefault.sa_flags = 0; sigdefault.sa_handler = SIG_DFL; sigfillset(&sigdefault.sa_mask); - sigaction(SIGPIPE, &sigignore, NULL); - sigaction(SIGCHLD, &sigignore, NULL); - sigaction(SIGCONT, &sigignore, NULL); - sigaction(SIGPROF, &sigignore, NULL); - sigaction(SIGWINCH, &sigignore, NULL); - sigaction(SIGIO, &sighandle, NULL); + sigaction(SIGPIPE, &sigignore, NULL); + sigaction(SIGCHLD, &sighandle, NULL); + sigaction(SIGCONT, &sigignore, NULL); + sigaction(SIGPROF, &sigignore, NULL); + sigaction(SIGWINCH, &sigignore, NULL); + sigaction(SIGIO, &sighandle, NULL); - sigaction(SIGINT, &sigdefault, NULL); - sigaction(SIGXCPU, &sigdefault, NULL); - sigaction(SIGXFSZ, &sigdefault, NULL); + sigaction(SIGINT, &sigdefault, NULL); + sigaction(SIGXCPU, &sigdefault, NULL); + sigaction(SIGXFSZ, &sigdefault, NULL); - sigaction(SIGHUP, &sighandle, NULL); - sigaction(SIGQUIT, &sighandle, NULL); - sigaction(SIGILL, &sighandle, NULL); - sigaction(SIGTRAP, &sighandle, NULL); -/* sigaction(SIGABRT, &sighandle, NULL); */ + sigaction(SIGHUP, &sigignore, NULL); + sigaction(SIGQUIT, &sighandle, NULL); + sigaction(SIGILL, &sighandle, NULL); + sigaction(SIGTRAP, &sighandle, NULL); + sigaction(SIGABRT, &sighandle, NULL); #ifdef SIGEMT - sigaction(SIGEMT, &sighandle, NULL); + 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(SIGUSR1, &sighandle, NULL); - sigaction(SIGSEGV, &sighandle, NULL); - sigaction(SIGUSR2, &sighandle, NULL); - sigaction(SIGALRM, &sighandle, NULL); - sigaction(SIGTERM, &sighandle, NULL); + sigaction(SIGBUS, &sighandle, NULL); + sigaction(SIGFPE, &sighandle, NULL); +/* sigaction(SIGKILL, &sighandle, NULL); cannot be trapped */ + sigaction(SIGUSR1, &sighandle, NULL); + sigaction(SIGSEGV, &sighandle, NULL); + sigaction(SIGUSR2, &sighandle, NULL); + sigaction(SIGALRM, &sighandle, NULL); + sigaction(SIGTERM, &sighandle, NULL); #ifdef SIGSTKFLT - sigaction(SIGSTKFLT, &sighandle, NULL); + sigaction(SIGSTKFLT, &sighandle, NULL); #endif - sigaction(SIGSTOP, &sighandle, NULL); - sigaction(SIGTSTP, &sighandle, NULL); - sigaction(SIGTTIN, &sighandle, NULL); - sigaction(SIGTTOU, &sighandle, NULL); - sigaction(SIGURG, &sighandle, NULL); - sigaction(SIGVTALRM, &sighandle, NULL); +/* sigaction(SIGSTOP, &sighandle, NULL); cannot be trapped */ + sigaction(SIGTSTP, &sighandle, NULL); + sigaction(SIGTTIN, &sighandle, NULL); + sigaction(SIGTTOU, &sighandle, NULL); + sigaction(SIGURG, &sighandle, NULL); + sigaction(SIGVTALRM, &sighandle, NULL); #ifdef SIGPWR - sigaction(SIGPWR, &sighandle, NULL); + sigaction(SIGPWR, &sighandle, NULL); #endif #ifdef SIGWAITING sigaction(SIGWAITING,&sighandle, NULL); #endif #ifdef SIGLWP - sigaction(SIGLWP, &sighandle, NULL); + sigaction(SIGLWP, &sighandle, NULL); #endif #ifdef SIGFREEZE sigaction(SIGFREEZE, &sighandle, NULL); #endif #ifdef SIGTHAW - sigaction(SIGTHAW, &sighandle, NULL); + sigaction(SIGTHAW, &sighandle, NULL); #endif #ifdef SIGCANCEL sigaction(SIGCANCEL, &sighandle, NULL); #endif #ifdef SIGLOST - sigaction(SIGLOST, &sighandle, NULL); + sigaction(SIGLOST, &sighandle, NULL); #endif } +#endif