/* IRCfs - IRC FileServ for *nix. * Copyright (C) 2002 Nick 'Zaf' Clifford * For licensing details, refer to the LICENSE file in the source * code directory. * */ #define _GNU_SOURCE #include #include #include "runtime.h" #include "crash.h" #include "config.h" #ifdef ENABLE_DEBUG #define DUMP_CORE #if defined(HAVE_GETRLIMIT) && HAVE_SYS_RESOURCE_H #include #endif #endif #ifdef HAVE_BACKTRACE #include #endif volatile sig_atomic_t crash_fatal_error_in_progress = 0; volatile sig_atomic_t crash_debugger_running = 0; void signal_fatal_handler(int signum); #ifndef HAVE_STRSIGNAL char *strsignal(int signum) { return "Unknown - no strsignal"; } #endif void signal_setup() { struct sigaction sa; sigaction (SIGTRAP, NULL, &sa); if (sa.sa_handler != SIG_DFL) { /* Signal Trap is set, so we'll defer to the debugger. */ fprintf(stderr,"Hello debugger!\n"); crash_debugger_running = 1; } else { sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = signal_fatal_handler; #ifdef SIGSEGV sigaction(SIGSEGV,&sa,NULL); #endif #ifdef SIGILL sigaction(SIGILL,&sa,NULL); #endif #ifdef SIGFPE sigaction(SIGFPE,&sa,NULL); #endif #ifdef SIGBUS sigaction(SIGBUS,&sa,NULL); #endif #ifdef SIGTRAP sigaction(SIGTRAP,&sa,NULL); #endif #ifdef SIGEMT sigaction(SIGEMT,&sa,NULL); #endif #ifdef SIGSYS sigaction(SIGSYS,&sa,NULL); #endif } /* Signals we ignore */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = SIG_IGN; #ifdef SIGINFO sigaction(SIGINFO,&sa,NULL); #endif #ifdef SIGWINCH sigaction(SIGWINCH,&sa,NULL); #endif #ifdef SIGUSR1 sigaction(SIGUSR1,&sa,NULL); #endif #ifdef SIGUSR2 sigaction(SIGUSR2,&sa,NULL); #endif #ifdef SIGPIPE sigaction(SIGPIPE,&sa,NULL); #endif #ifdef SIGIO sigaction(SIGIO,&sa,NULL); #endif #ifdef SIGALRM sigaction(SIGALRM,&sa,NULL); #endif /* Signals we ignore, but shouldn't (eg TODO) */ #ifdef SIGXFSZ sigaction(SIGXFSZ,&sa,NULL); /* Exceeded file size limits */ #endif #ifdef SIGXCPU sigaction(SIGXCPU,&sa,NULL); /* Exceeded CPU limits */ #endif #ifdef SIGLOST sigaction(SIGLOST,&sa,NULL); /* Lost an NFS resource */ #endif } int setup_core_dump() { #if defined(DUMP_CORE) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) struct rlimit rl; #ifndef RLIM_INFINITY /* If RLIM_INIFINITY isn't defined try BSDs OFILE */ #ifdef RLIMIT_OFILE #define RLIM_INFINITY RLIM_OFILE #else #define RLIM_INFINITY 0xFFFF #endif #endif if (getrlimit(RLIMIT_CORE,&rl) == -1) { return -1; } if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY) { return 0; } rl.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_CORE,&rl) == -1) { return -1; } return 0; #else return -1; #endif } void signal_fatal_handler(int signum) { static char buffer[255]; const char *cp; #ifdef HAVE_BACKTRACE static void *backtrace_buffer[91]; int n; #endif /* Since this handler is established for more than one kind of signal, * it might still get invoked recursively by delivery of some other * kind of signal. Use a static variable to keep track of that. * Raising the signal again invokes the signals default behaviour */ if (crash_fatal_error_in_progress) raise (signum); crash_fatal_error_in_progress = 1; /* It *should* be safe to write to stderr since it isn't used * anywhere else in the program */ snprintf(buffer,sizeof(buffer)-1,"Received fatal signal %d: ", signum); write(2,buffer,strlen(buffer)); cp = strsignal(signum); write(2,cp,strlen(cp)); write(2,"\n",1); #ifdef HAVE_BACKTRACE n = backtrace(backtrace_buffer,90); if (n == -1) { snprintf(buffer,sizeof(buffer)-1, "backtrace() returned -1 error=%d:", errno); write(2,buffer,strlen(buffer)); cp = strerror(errno); write(2,cp,strlen(cp)); write(2,"\n",1); } else { cp = "Generating backtrace:\n"; write(2,cp,strlen(cp)); backtrace_symbols_fd(backtrace_buffer,n,2); cp = "Done\n"; write(2,cp,strlen(cp)); } #else cp = "No backtrace support on this system\n"; write(2,cp,strlen(cp)); #endif abort(); }