From 15e5e9fa5d67fd415fac5962a62fabf5d8a9e3dc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wilfried=20G=C3=B6esgens?= Date: Sun, 26 Aug 2007 21:31:51 +0000 Subject: [PATCH] * modules registering serverports now need to specify a plaintext name. * added David Frascones ecrash lib * hooked ecrash into citserver and citadel (not yet all done) --- citadel/Makefile.in | 10 +- citadel/citadel.c | 36 + citadel/citadel_dirs.c | 12 +- citadel/citadel_dirs.h | 1 + citadel/citserver.c | 26 + citadel/citserver.h | 2 + citadel/commands.c | 11 + citadel/debian/rules | 16 +- citadel/ecrash.c | 646 ++++++++++++++++++ citadel/ecrash.h | 185 +++++ citadel/include/ctdl_module.h | 9 +- citadel/modules/imap/serv_imap.c | 7 +- .../modules/managesieve/serv_managesieve.c | 5 +- citadel/modules/pop3/serv_pop3.c | 8 +- citadel/modules/smtp/serv_smtp.c | 21 +- citadel/modules/vandelay/serv_vandelay.c | 2 +- citadel/modules/vcard/serv_vcard.c | 5 +- citadel/serv_extensions.c | 17 +- citadel/server.h | 2 + citadel/server_main.c | 38 +- citadel/sysdep.c | 32 +- 21 files changed, 1027 insertions(+), 64 deletions(-) create mode 100644 citadel/ecrash.c create mode 100644 citadel/ecrash.h diff --git a/citadel/Makefile.in b/citadel/Makefile.in index 2aaa0de71..9cbace959 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -87,14 +87,14 @@ CFLAGS=@CFLAGS@ -I ./include/ CPPFLAGS=@CPPFLAGS@ -I. -I ./include/ DATABASE=@DATABASE@ DEFS=@DEFS@ -LDFLAGS=@LDFLAGS@ +LDFLAGS=@LDFLAGS@ -rdynamic LIBS=@LIBS@ LIBOBJS=@LIBOBJS@ INSTALL=@INSTALL@ INSTALL_DATA=@INSTALL_DATA@ RESOLV=@RESOLV@ SHELL=/bin/sh -SERVER_LDFLAGS=@SERVER_LDFLAGS@ +SERVER_LDFLAGS=@SERVER_LDFLAGS@ -rdynamic SERVER_LIBS=@SERVER_LIBS@ SETUP_LIBS=@SETUP_LIBS@ YACC=@YACC@ @@ -108,7 +108,7 @@ SOURCES=aidepost.c auth.c base64.c chkpwd.c chkpw.c citadel.c citadel_ipc.c \ clientsocket.c commands.c config.c control.c $(DATABASE) \ domain.c serv_extensions.c file_ops.c genstamp.c getutline.c \ housekeeping.c html.c ical_dezonify.c \ - internet_addressing.c \ + internet_addressing.c ecrash.c \ ipc_c_tcp.c locate_host.c md5.c messages.c \ modules/autocompletion/serv_autocompletion.c \ mime_parser.c msgbase.c msgform.c parsedate.c policy.c \ @@ -169,7 +169,7 @@ citadel$(EXEEXT): citadel.o citadel_ipc.o client_chat.o client_passwords.o \ routines2.o screen.o tools.o citadel_dirs.o $(LIBOBJS) $(CC) citadel.o citadel_ipc.o client_chat.o client_passwords.o \ commands.o html.o ipc_c_tcp.o md5.o messages.o rooms.o routines.o \ - routines2.o screen.o tools.o citadel_dirs.o $(LIBOBJS) \ + routines2.o screen.o tools.o citadel_dirs.o ecrash.o $(LIBOBJS) \ $(LDFLAGS) -o citadel $(LIBS) .y.c: @@ -191,7 +191,7 @@ SERV_OBJS = server_main.o \ file_ops.o msgbase.o euidindex.o \ locate_host.o housekeeping.o mime_parser.o html.o \ internet_addressing.o journaling.o \ - parsedate.o genstamp.o \ + parsedate.o genstamp.o ecrash.o \ clientsocket.o modules_init.o $(AUTH) $(SERV_MODULES) citserver: $(SERV_OBJS) diff --git a/citadel/citadel.c b/citadel/citadel.c index e9c979adb..4330cf784 100644 --- a/citadel/citadel.c +++ b/citadel/citadel.c @@ -52,6 +52,7 @@ #include "screen.h" #include "citadel_dirs.h" +#include "ecrash.h" #include "md5.h" #define IFEXPERT if (userflags&US_EXPERT) @@ -110,6 +111,23 @@ extern int next_lazy_cmd; CtdlIPC *ipc_for_signal_handlers; /* KLUDGE cover your eyes */ + +/* + * lprintf() ... Write logging information; + * simple here to have the same + * symbols in the client. + */ +enum LogLevel {CTDL_EMERG}; + +void lprintf(enum LogLevel loglevel, const char *format, ...) { + va_list arg_ptr; + + va_start(arg_ptr, format); + vfprintf(stderr, format, arg_ptr); + va_end(arg_ptr); + fflush(stderr); +} + /* * here is our 'clean up gracefully and exit' routine */ @@ -1387,9 +1405,27 @@ int main(int argc, char **argv) char relhome[PATH_MAX]=""; char ctdldir[PATH_MAX]=CTDLDIR; int lp; + eCrashParameters params; +// eCrashSymbolTable symbol_table; calc_dirs_n_files(relh, home, relhome, ctdldir); + + bzero(¶ms, sizeof(params)); + params.filename = file_pid_paniclog; +// panic_fd=open(file_pid_paniclog, O_APPEND|O_CREAT|O_DIRECT); + params.filep = fopen(file_pid_paniclog, "a+"); + params.debugLevel = ECRASH_DEBUG_VERBOSE; + params.dumpAllThreads = TRUE; + params.useBacktraceSymbols = 1; +/// BuildSymbolTable(&symbol_table); +// params.symbolTable = &symbol_table; + params.signals[0]=SIGSEGV; + params.signals[1]=SIGILL; + params.signals[2]=SIGBUS; + params.signals[3]=SIGABRT; + + eCrash_Init(¶ms); setIPCDeathHook(screen_delete); setIPCErrorPrintf(err_printf); diff --git a/citadel/citadel_dirs.c b/citadel/citadel_dirs.c index 045b1d190..29552761e 100644 --- a/citadel/citadel_dirs.c +++ b/citadel/citadel_dirs.c @@ -59,6 +59,7 @@ char file_arcq[PATH_MAX]=""; char file_citadel_socket[PATH_MAX]=""; char file_mail_aliases[PATH_MAX]=""; char file_pid_file[PATH_MAX]=""; +char file_pid_paniclog[PATH_MAX]=""; char file_crpt_file_key[PATH_MAX]=""; char file_crpt_file_csr[PATH_MAX]=""; char file_crpt_file_cer[PATH_MAX]=""; @@ -195,10 +196,13 @@ void calc_dirs_n_files(int relh, int home, const char *relhome,const char *ctdl "%scitadel.socket", ctdl_run_dir); snprintf(file_pid_file, - sizeof file_pid_file, - "%scitadel.pid", - ctdl_run_dir); - + sizeof file_pid_file, + "%scitadel.pid", + ctdl_run_dir); + snprintf(file_pid_paniclog, + sizeof file_pid_paniclog, + "%spanic.log", + ctdl_home_directory); snprintf(file_crpt_file_key, sizeof file_crpt_file_key, "%s/citadel.key", diff --git a/citadel/citadel_dirs.h b/citadel/citadel_dirs.h index 3395db018..1eb0a1138 100644 --- a/citadel/citadel_dirs.h +++ b/citadel/citadel_dirs.h @@ -42,6 +42,7 @@ extern char file_arcq[PATH_MAX]; extern char file_citadel_socket[PATH_MAX]; extern char file_mail_aliases[PATH_MAX]; extern char file_pid_file[PATH_MAX]; +extern char file_pid_paniclog[PATH_MAX]; extern char file_crpt_file_key[PATH_MAX]; extern char file_crpt_file_csr[PATH_MAX]; extern char file_crpt_file_cer[PATH_MAX]; diff --git a/citadel/citserver.c b/citadel/citserver.c index 92d031d41..a25a2ea20 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -68,6 +68,7 @@ char *unique_session_numbers; int ScheduledShutdown = 0; int do_defrag = 0; time_t server_startup_time; +int panic_fd; /** * \brief print the actual stack frame. @@ -91,6 +92,31 @@ void cit_backtrace(void) free(strings); #endif } + +/** + * \brief print the actual stack frame. + */ +void cit_panic_backtrace(int SigNum) +{ +#ifdef HAVE_BACKTRACE + void *stack_frames[10]; + size_t size, i; + char **strings; + + printf("caught signal 11\n"); + size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*)); + strings = backtrace_symbols(stack_frames, size); + for (i = 0; i < size; i++) { + if (strings != NULL) + lprintf(1, "%s\n", strings[i]); + else + lprintf(1, "%p\n", stack_frames[i]); + } + free(strings); +#endif + exit(-1); +} + /* * Various things that need to be initialized at startup */ diff --git a/citadel/citserver.h b/citadel/citserver.h index a9be0025b..b3d3346fd 100644 --- a/citadel/citserver.h +++ b/citadel/citserver.h @@ -13,6 +13,7 @@ struct UserProcList { }; void cit_backtrace(void); +void cit_panic_backtrace(int SigNum); void master_startup (void); void master_cleanup (int exitcode); void RemoveContext (struct CitContext *); @@ -39,6 +40,7 @@ void GenerateRoomDisplay(char *real_room, struct CitContext *viewed, struct CitContext *viewer); extern int do_defrag; +extern int panic_fd; char CtdlCheckExpress(void); int CtdlAccessCheck(int); diff --git a/citadel/commands.c b/citadel/commands.c index 6b9a45164..fb1b99b9b 100644 --- a/citadel/commands.c +++ b/citadel/commands.c @@ -58,6 +58,7 @@ #include "snprintf.h" #endif #include "screen.h" +#include "ecrash.h" struct citcmd { struct citcmd *next; @@ -393,9 +394,19 @@ static int async_ka_enabled = 0; static void *ka_thread(void *arg) { + char threadName[256]; + + // Set up our name + sprintf(threadName, "ka_Thread n"); + + // Register for tracing + eCrash_RegisterThread(threadName, 0); + really_do_keepalive(); pthread_detach(ka_thr_handle); ka_thr_active = 0; + + eCrash_UnregisterThread(); return NULL; } diff --git a/citadel/debian/rules b/citadel/debian/rules index fef1a8bf6..0b4a8020b 100755 --- a/citadel/debian/rules +++ b/citadel/debian/rules @@ -10,11 +10,14 @@ DEB_DESTDIR = $(CURDIR)/debian/tmp CFLAGS = -Wall -g -#ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CFLAGS += -O0 -ggdb -pg -#else -# CFLAGS += -O2 -#endif +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 -ggdb -rdynamic -D_GNU_SOURCE -MD -MP + LDFLAGS += -pg + SERVER_LDFLAGS += -lm +# SERVER_LDFLAGS += -pg +else + CFLAGS += -O2 +endif configure: configure-stamp configure-stamp: @@ -35,7 +38,8 @@ configure-stamp: --with-zlib \ --with-ldap \ --with-libical \ - --with-libsieve + --with-libsieve \ + --enable-debug touch configure-stamp diff --git a/citadel/ecrash.c b/citadel/ecrash.c new file mode 100644 index 000000000..2c04fe97e --- /dev/null +++ b/citadel/ecrash.c @@ -0,0 +1,646 @@ +/* + * File: eCrash.c + * @author David Frascone + * + * eCrash Implementation + * + * eCrash will allow you to capture stack traces in the + * event of a crash, and write those traces to disk, stdout, + * or any other file handle. + * + * modified to integrate closer into citadel by Wilfried Goesgens + * + * vim: ts=4 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sysdep_decls.h" +#include "ecrash.h" + +#define NIY() printf("%s: Not Implemented Yet!\n", __FUNCTION__) + +static eCrashParameters gbl_params; +static int gbl_fd=-1; + +static int gbl_backtraceEntries; +static void **gbl_backtraceBuffer; +static char **gbl_backtraceSymbols; +static int gbl_backtraceDoneFlag = 0; + +/* + * Private structures for our thread list + */ +typedef struct thread_list_node{ + char *threadName; + pthread_t thread; + int backtraceSignal; + sighandler_t oldHandler; + struct thread_list_node *Next; +} ThreadListNode; + +static pthread_mutex_t ThreadListMutex = PTHREAD_MUTEX_INITIALIZER; +static ThreadListNode *ThreadList = NULL; + +/********************************************************************* + ********************************************************************* + ** P R I V A T E F U N C T I O N S + ********************************************************************* + ********************************************************************/ + + +/*! + * Insert a node into our threadList + * + * @param name Text string indicating our thread + * @param thread Our Thread Id + * @param signo Signal to create backtrace with + * @param old_handler Our old handler for signo + * + * @returns zero on success + */ +static int addThreadToList(char *name, pthread_t thread,int signo, + sighandler_t old_handler) +{ + ThreadListNode *node; + + node = malloc(sizeof(ThreadListNode)); + if (!node) return -1; + + DPRINTF(ECRASH_DEBUG_VERBOSE, + "Adding thread 0x%08x (%s)\n", (unsigned int)thread, name); + node->threadName = strdup(name); + node->thread = thread; + node->backtraceSignal = signo; + node->oldHandler = old_handler; + + /* And, add it to the list */ + pthread_mutex_lock(&ThreadListMutex); + node->Next = ThreadList; + ThreadList = node; + pthread_mutex_unlock(&ThreadListMutex); + + return 0; + +} // addThreadToList + +/*! + * Remove a node from our threadList + * + * @param thread Our Thread Id + * + * @returns zero on success + */ +static int removeThreadFromList(pthread_t thread) +{ + ThreadListNode *Probe, *Prev=NULL; + ThreadListNode *Removed = NULL; + + DPRINTF(ECRASH_DEBUG_VERBOSE, + "Removing thread 0x%08x from list . . .\n", (unsigned int)thread); + pthread_mutex_lock(&ThreadListMutex); + for (Probe=ThreadList;Probe != NULL; Probe = Probe->Next) { + if (Probe->thread == thread) { + // We found it! Unlink it and move on! + Removed = Probe; + if (Prev == NULL) { // head of list + ThreadList = Probe->Next; + } else { + // Prev != null, so we need to link around ourselves. + Prev->Next = Probe->Next; + } + Removed->Next = NULL; + break; + } + + Prev = Probe; + } + pthread_mutex_unlock(&ThreadListMutex); + + // Now, if something is in Removed, free it, and return success + if (Removed) { + DPRINTF(ECRASH_DEBUG_VERBOSE, + " Found %s -- removing\n", Removed->threadName); + // Reset the signal handler + signal(Removed->backtraceSignal, Removed->oldHandler); + + // And free the allocated memory + free (Removed->threadName); + free (Removed); + + return 0; + } else { + DPRINTF(ECRASH_DEBUG_VERBOSE, + " Not Found\n"); + return -1; // Not Found + } +} // removeThreadFromList + +/*! + * Output text to a fd, looping to avoid being interrupted. + * + * @param str String to output + * @param bytes String length + * @param fd File descriptor to write to + * + * @returns bytes written, or error on failure. + */ +static int blockingWrite(char *str, int bytes, int fd) +{ + int offset=0; + int bytesWritten; + int totalWritten = 0; + + while (bytes > 0) { + bytesWritten = write(fd, &str[offset], bytes); + if (bytesWritten < 1) break; + totalWritten += bytesWritten; + bytes -= bytesWritten; + } + + return totalWritten; + +} // blockingWrite +/*! + * Print out a line of output to all our destinations + * + * One by one, output a line of text to all of our output destinations. + * + * Return failure if we fail to output to any of them. + * + * @param format Normal printf style vararg format + * + * @returns nothing// bytes written, or error on failure. + */ +static void outputPrintf(char *format, ...) +{ + // Our output line of text + static char outputLine[MAX_LINE_LEN]; + //int bytesInLine; + va_list ap; + //int return_value=0; + + va_start(ap, format); + + return lprintf(CTDL_EMERG, format, ap); + +/* + bytesInLine = vsnprintf(outputLine, MAX_LINE_LEN-1, format, ap); + if (bytesInLine > -1 && bytesInLine < (MAX_LINE_LEN-1)) { + // We're a happy camper -- start printing + if (gbl_params.filename) { + // append to our file -- hopefully it's been opened + if (gbl_fd != -1) { + if (blockingWrite(outputLine, bytesInLine, gbl_fd)) { + return_value=-2; + } + } + } + + // Write to our file pointer + if (gbl_params.filep != NULL) { + if (fwrite(outputLine, bytesInLine, 1, gbl_params.filep) != 1) { + return_value=-3; + } + fflush(gbl_params.filep); + } + + // Write to our fd + if (gbl_params.fd != -1) { + if (blockingWrite(outputLine, bytesInLine, gbl_params.fd)) { + return_value=-4; + } + } + } else { + // We overran our string. + return_value=-1; + } +*/ +} // outputPrintf + +/*! + * Initialize our output (open files, etc) + * + * This file initializes all output streams, since we're about + * to have output. + * + */ +static void outputInit( void ) +{ + if (gbl_params.filename) { + /* First try append */ + gbl_fd = open(gbl_params.filename, O_WRONLY|O_APPEND); + if (gbl_fd < 0) { + gbl_fd = open(gbl_params.filename, O_RDWR|O_CREAT, + S_IREAD|S_IWRITE|S_IRGRP|S_IROTH); // 0644 + if (gbl_fd < 0) { + gbl_fd = -1; + } + } + } +} // outputInit + + +/*! + * Finalize our output (close files, etc) + * + * This file closes all output streams. + * + */ +static void outputFini( void ) +{ +/* -> these seem to run into mutexes in the libc... + if (gbl_fd > -1) + close(gbl_fd); + + if (gbl_params.filep != NULL) + fclose(gbl_params.filep); + + if (gbl_params.fd > -1) + close(gbl_params.fd); +*/ + // Just in case someone tries to call outputPrintf after outputFini + gbl_fd = gbl_params.fd = -1; + gbl_params.filep = NULL; + + sync(); + +} // outputFini + +static void *lookupClosestSymbol(eCrashSymbolTable *table, + void *address) +{ + int addr; + eCrashSymbol *last=NULL; + + // For now, use a linear lookup. + DPRINTF(ECRASH_DEBUG_VERBOSE, + "Looking for %p in %d symbols\n", address, table->numSymbols); + for (addr=0; addr < table->numSymbols; addr++) { + DPRINTF(ECRASH_DEBUG_VERBOSE, + " Examining [%d] %p\n", addr, + table->symbols[addr].address); + if (table->symbols[addr].address > address) { + break; + } + last = &table->symbols[addr]; + } + + // last will either be NULL, or the last address less than the + // one we're looking for. + DPRINTF(ECRASH_DEBUG_VERBOSE, + "Returning %s (%p)\n", last?last->function:"(nil)", + last?last->address:0); + return last; + +} // lookupClosestSymbol + +/*! + * Dump our backtrace into a global location + * + * This function will dump out our backtrace into our + * global holding area. + * + */ +static void createGlobalBacktrace( void ) +{ + + gbl_backtraceEntries = backtrace(gbl_backtraceBuffer, + gbl_params.maxStackDepth); + + /* This is NOT signal safe -- it calls malloc. We need to + let the caller pass in a pointer to a symbol table inside of + our params. TODO */ + + if (!gbl_params.symbolTable) { + if (gbl_params.useBacktraceSymbols != FALSE) { + gbl_backtraceSymbols = backtrace_symbols(gbl_backtraceBuffer, + gbl_backtraceEntries); + } + } + +} /* createGlobalBacktrace */ + +/*! + * Print out (to all the fds, etc), or global backtrace + */ +static void outputGlobalBacktrace ( void ) +{ + int i; + + for (i=0; i < gbl_backtraceEntries; i++) { + if (gbl_params.symbolTable) { + eCrashSymbol *symbol; + + symbol = lookupClosestSymbol(gbl_params.symbolTable, + gbl_backtraceBuffer[i]); + + if (symbol) { + outputPrintf("* Frame %02d: %s+%u\n", + i, symbol->function, + gbl_backtraceBuffer[i] - symbol->address); + } else { + outputPrintf("* Frame %02d: %p\n", i, + gbl_backtraceBuffer[i]); + } + } else { + if (gbl_backtraceSymbols != FALSE) { + outputPrintf("* Frame %02d: %s\n", + i, gbl_backtraceSymbols[i]); + } else { + outputPrintf("* Frame %02d: %p\n", i, + gbl_backtraceBuffer[i]); + } + } // symbolTable + } +} // outputGlobalBacktrace + +/*! + * Output our current stack's backtrace + */ +static void outputBacktrace( void ) +{ + createGlobalBacktrace(); + outputGlobalBacktrace(); +} /* outputBacktrace */ + +static void outputBacktraceThreads( void ) +{ + ThreadListNode *probe; + int i; + + // When we're backtracing, don't worry about the mutex . . hopefully + // we're in a safe place. + + for (probe=ThreadList; probe; probe=probe->Next) { + gbl_backtraceDoneFlag = 0; + pthread_kill(probe->thread, probe->backtraceSignal); + for (i=0; i < gbl_params.threadWaitTime; i++) { + if (gbl_backtraceDoneFlag) + break; + sleep(1); + } + if (gbl_backtraceDoneFlag) { + outputPrintf("* Backtrace of \"%s\" (0x%08x)\n", + probe->threadName, (unsigned int)probe->thread); + outputGlobalBacktrace(); + } else { + outputPrintf("* Error: unable to get backtrace of \"%s\" (0x%08x)\n", + probe->threadName, (unsigned int)probe->thread); + } + outputPrintf("*\n"); + } +} // outputBacktraceThreads + + +/*! + * Handle signals (crash signals) + * + * This function will catch all crash signals, and will output the + * crash dump. + * + * It will physically write (and sync) the current thread's information + * before it attempts to send signals to other threads. + * + * @param signum Signal received. + */ +static void crash_handler(int signo) +{ + outputInit(); + outputPrintf("*********************************************************\n"); + outputPrintf("* eCrash Crash Handler\n"); + outputPrintf("*********************************************************\n"); + outputPrintf("*\n"); + outputPrintf("* Got a crash! signo=%d\n", signo); + outputPrintf("*\n"); + outputPrintf("* Offending Thread's Backtrace:\n"); + outputPrintf("*\n"); + outputBacktrace(); + outputPrintf("*\n"); + + if (gbl_params.dumpAllThreads != FALSE) { + outputBacktraceThreads(); + } + + outputPrintf("*\n"); + outputPrintf("*********************************************************\n"); + outputPrintf("* eCrash Crash Handler\n"); + outputPrintf("*********************************************************\n"); + + outputFini(); + + exit(signo); +} // crash_handler + +/*! + * Handle signals (bt signals) + * + * This function shoudl be called to generate a crashdump into our + * global area. Once the dump has been completed, this function will + * return after tickling a global. Since mutexes are not async + * signal safe, the main thread, after signaling us to generate our + * own backtrace, will sleep for a few seconds waiting for us to complete. + * + * @param signum Signal received. + */ +static void bt_handler(int signo) +{ + createGlobalBacktrace(); + gbl_backtraceDoneFlag=1; +} // bt_handler + +/*! + * Validate a passed-in symbol table + * + * For now, just print it out (if verbose), and make sure it's + * sorted and none of the pointers are zero. + */ +static int ValidateSymbolTable( void ) +{ + int i; + int rc=0; + unsigned long lastAddress =0; + + // Get out of here if the table is empty + if (!gbl_params.symbolTable) return 0; + + // Dump it in verbose mode + DPRINTF(ECRASH_DEBUG_VERBOSE, + "Symbol Table Provided with %d symbols\n", + gbl_params.symbolTable->numSymbols); + for (i=0; i < gbl_params.symbolTable->numSymbols; i++){ + // Dump it in verbose mode + DPRINTF(ECRASH_DEBUG_VERBOSE, + "%-30s %p\n", + gbl_params.symbolTable->symbols[i].function, + gbl_params.symbolTable->symbols[i].address); + if (lastAddress > + (unsigned long)gbl_params.symbolTable->symbols[i].address) { + DPRINTF(ECRASH_DEBUG_ERROR, + "Error: symbol table is not sorted (last=%p, current=%p)\n", + (void *)lastAddress, + gbl_params.symbolTable->symbols[i].address); + rc = -1; + } + + } // for + + return rc; + +} // ValidateSymbolTable + +/********************************************************************* + ********************************************************************* + ** P U B L I C F U N C T I O N S + ********************************************************************* + ********************************************************************/ + +/*! + * Initialize eCrash. + * + * This function must be called before calling any other eCrash + * functions. It sets up the global behavior of the system, and + * registers the calling thread for crash dumps. + * + * @param params Our input parameters. The passed in structure will be copied. + * + * @return Zero on success. + */ +int eCrash_Init(eCrashParameters *params) +{ + int sigIndex; + int ret = 0; +#ifdef DO_SIGNALS_RIGHT + sigset_t blocked; + struct sigaction act; +#endif + + DPRINTF(ECRASH_DEBUG_VERY_VERBOSE,"Init Starting params = %p\n", params); + + // Allocate our backtrace area + gbl_backtraceBuffer = malloc(sizeof(void *) * (params->maxStackDepth+5)); + +#ifdef DO_SIGNALS_RIGHT + sigemptyset(&blocked); + act.sa_sigaction = crash_handler; + act.sa_mask = blocked; + act.sa_flags = SA_SIGINFO; +#endif + + if (params != NULL) { + // Make ourselves a global copy of params. + gbl_params = *params; + gbl_params.filename = strdup(params->filename); + + // Set our defaults, if they weren't specified + if (gbl_params.maxStackDepth == 0 ) + gbl_params.maxStackDepth = ECRASH_DEFAULT_STACK_DEPTH; + + if (gbl_params.defaultBacktraceSignal == 0 ) + gbl_params.defaultBacktraceSignal = ECRASH_DEFAULT_BACKTRACE_SIGNAL; + + if (gbl_params.threadWaitTime == 0 ) + gbl_params.threadWaitTime = ECRASH_DEFAULT_THREAD_WAIT_TIME; + + if (gbl_params.debugLevel == 0 ) + gbl_params.debugLevel = ECRASH_DEBUG_DEFAULT; + + // Copy our symbol table + if (gbl_params.symbolTable) { + DPRINTF(ECRASH_DEBUG_VERBOSE, + "symbolTable @ %p -- %d symbols\n", gbl_params.symbolTable, + gbl_params.symbolTable->numSymbols); + // Make a copy of our symbol table + gbl_params.symbolTable = malloc(sizeof(eCrashSymbolTable)); + memcpy(gbl_params.symbolTable, params->symbolTable, + sizeof(eCrashSymbolTable)); + + // Now allocate / copy the actual table. + gbl_params.symbolTable->symbols = malloc(sizeof(eCrashSymbol) * + gbl_params.symbolTable->numSymbols); + memcpy(gbl_params.symbolTable->symbols, + params->symbolTable->symbols, + sizeof(eCrashSymbol) * gbl_params.symbolTable->numSymbols); + + ValidateSymbolTable(); + } + + // And, finally, register for our signals + for (sigIndex=0; gbl_params.signals[sigIndex] != 0; sigIndex++) { + DPRINTF(ECRASH_DEBUG_VERY_VERBOSE, + " Catching signal[%d] %d\n", sigIndex, + gbl_params.signals[sigIndex]); + + // I know there's a better way to catch signals with pthreads. + // I'll do it later TODO + signal(gbl_params.signals[sigIndex], crash_handler); + } + } else { + DPRINTF(ECRASH_DEBUG_ERROR, " Error: Null Params!\n"); + ret = -1; + } + DPRINTF(ECRASH_DEBUG_VERY_VERBOSE, "Init Complete ret=%d\n", ret); + return ret; +} /* eCrash_Init */ + +/*! + * UnInitialize eCrash. + * + * This function may be called to de-activate eCrash, release the + * signal handlers, and free any memory allocated by eCrash. + * + * @return Zero on success. + */ +int eCrash_Uninit( void ) +{ + NIY(); + + return 0; +} /* eCrash_Uninit */ + +/*! + * Register a thread for backtracing on crash. + * + * This function must be called by any thread wanting it's stack + * dumped in the event of a crash. The thread my specify what + * signal should be used, or the default, SIGUSR1 will be used. + * + * @param signo Signal to use to generate dump (default: SIGUSR1) + * + * @return Zero on success. + */ +int eCrash_RegisterThread(char *name, int signo) +{ + sighandler_t old_handler; + + // Register for our signal + if (signo == 0) { + signo = gbl_params.defaultBacktraceSignal; + } + + old_handler = signal(signo, bt_handler); + return addThreadToList(name, pthread_self(), signo, old_handler); + +} /* eCrash_RegisterThread */ + +/*! + * Un-register a thread for stack dumps. + * + * This function may be called to un-register any previously + * registered thread. + * + * @return Zero on success. + */ +int eCrash_UnregisterThread( void ) +{ + return removeThreadFromList(pthread_self()); +} /* eCrash_UnregisterThread */ + diff --git a/citadel/ecrash.h b/citadel/ecrash.h new file mode 100644 index 000000000..271e99144 --- /dev/null +++ b/citadel/ecrash.h @@ -0,0 +1,185 @@ +/** + * \file eCrash.h + * @author David Frascone + * + * eCrash types and prototypes. + * + * vim: ts=4 + */ + +#ifndef _ECRASH_H_ +#define _ECRASH_H_ + +#include +#include + +typedef void (*sighandler_t)(int); + +typedef long BOOL; + +#define MAX_LINE_LEN 256 + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#define BOOL int +#endif + +#define ECRASH_DEFAULT_STACK_DEPTH 10 +#define ECRASH_DEFAULT_BACKTRACE_SIGNAL SIGUSR2 +#define ECRASH_DEFAULT_THREAD_WAIT_TIME 10 +#define ECRASH_MAX_NUM_SIGNALS 30 + +/** \struct eCrashSymbol + * \brief Function Name / Address pair + * + * This is used in conjunction with eCrashSymbolTable to + * provide an alternative to backtrace_symbols. + */ +typedef struct { + char *function; + void *address; +} eCrashSymbol; +/** \struct eCrashSymbolTable + * \brief Symbol table used to avoid backtrace_symbols() + * + * This structure is used to provide a alternative to + * backtrace_symbols which is not async signal safe. + * + * The symbol table should be sorted by address (it will + * be either binary or linearly searched) + */ +typedef struct { + int numSymbols; + eCrashSymbol *symbols; +} eCrashSymbolTable; + + + +#define ECRASH_DEBUG_ENABLE /* undef to turn off debug */ + +#ifdef ECRASH_DEBUG_ENABLE +# define ECRASH_DEBUG_VERY_VERBOSE 1 +# define ECRASH_DEBUG_VERBOSE 2 +# define ECRASH_DEBUG_INFO 3 +# define ECRASH_DEBUG_WARN 4 +# define ECRASH_DEBUG_ERROR 5 +# define ECRASH_DEBUG_OFF 6 +# define ECRASH_DEBUG_DEFAULT (ECRASH_DEBUG_ERROR) +# define DPRINTF(level, fmt...) \ + if (level >= gbl_params.debugLevel) { printf(fmt); fflush(stdout); } +#else /* ECRASH_DEBUG_ENABLE */ +# define DPRINTF(level, fmt...) +#endif /* ECRASH_DEBUG_ENABLE */ + + +/** \struct eCrashParameters + * \brief eCrash Initialization Parameters + * + * This structure contains all the global initialization functions + * for eCrash. + * + * @see eCrash_Init + */ +typedef struct { + + + /* OUTPUT OPTIONS */ + /** Filename to output to, or NULL */ + char *filename; + /** FILE * to output to or NULL */ + FILE *filep; + /** fd to output to or -1 */ + int fd; + + int debugLevel; + + /** If true, all registered threads will + * be dumped + */ + BOOL dumpAllThreads; + + /** How far to backtrace each stack */ + unsigned int maxStackDepth; + + /** Default signal to use to tell a thread to drop it's + * stack. + */ + int defaultBacktraceSignal; + + /** How long to wait for a threads + * dump + */ + unsigned int threadWaitTime; + + /** If this is non-zero, the dangerous function, backtrace_symbols + * will be used. That function does a malloc(), so is not async + * signal safe, and could cause deadlocks. + */ + BOOL useBacktraceSymbols; + + /** To avoid the issues with backtrace_symbols (see comments above) + * the caller can supply it's own symbol table, containing function + * names and start addresses. This table can be created using + * a script, or a static table. + * + * If this variable is not null, it will be used, instead of + * backtrace_symbols, reguardless of the setting + * of useBacktraceSymbols. + */ + eCrashSymbolTable *symbolTable; + + /** Array of crash signals to catch, + * ending in 0 I would have left it a [] array, but I + * do a static copy, so I needed a set size. + */ + int signals[ECRASH_MAX_NUM_SIGNALS]; + +} eCrashParameters; + +/*! + * Initialize eCrash. + * + * This function must be called before calling any other eCrash + * functions. It sets up the global behavior of the system. + * + * @param params Our input parameters. The passed in structure will be copied. + * + * @return Zero on success. + */ +int eCrash_Init(eCrashParameters *params); +/*! + * UnInitialize eCrash. + * + * This function may be called to de-activate eCrash, release the + * signal handlers, and free any memory allocated by eCrash. + * + * @return Zero on success. + */ +int eCrash_Uninit( void ); + +/*! + * Register a thread for backtracing on crash. + * + * This function must be called by any thread wanting it's stack + * dumped in the event of a crash. The thread my specify what + * signal should be used, or the default, SIGUSR1 will be used. + * + * @param name String used to refer to us in crash dumps + * @param signo Signal to use to generate dump (default: SIGUSR1) + * + * @return Zero on success. + */ +int eCrash_RegisterThread(char *name, int signo); + +/*! + * Un-register a thread for stack dumps. + * + * This function may be called to un-register any previously + * registered thread. + * + * @return Zero on success. + */ +int eCrash_UnregisterThread( void ); + +#endif /* _E_CRASH_H_ */ diff --git a/citadel/include/ctdl_module.h b/citadel/include/ctdl_module.h index 905446ee5..8c0efb0e1 100644 --- a/citadel/include/ctdl_module.h +++ b/citadel/include/ctdl_module.h @@ -45,10 +45,11 @@ void CtdlRegisterProtoHook(void (*handler)(char *), char *cmd, char *desc); void CtdlUnregisterProtoHook(void (*handler)(char *), char *cmd); void CtdlRegisterServiceHook(int tcp_port, - char *sockpath, - void (*h_greeting_function) (void), - void (*h_command_function) (void), - void (*h_async_function) (void) + char *sockpath, + void (*h_greeting_function) (void), + void (*h_command_function) (void), + void (*h_async_function) (void), + const char *ServiceName ); void CtdlUnregisterServiceHook(int tcp_port, char *sockpath, diff --git a/citadel/modules/imap/serv_imap.c b/citadel/modules/imap/serv_imap.c index 4d5feb063..ca4acfb6c 100644 --- a/citadel/modules/imap/serv_imap.c +++ b/citadel/modules/imap/serv_imap.c @@ -1582,16 +1582,19 @@ void imap_command_loop(void) } +const char *CitadelServiceIMAP="IMAP"; +const char *CitadelServiceIMAPS="IMAPS"; + /* * This function is called to register the IMAP extension with Citadel. */ CTDL_MODULE_INIT(imap) { CtdlRegisterServiceHook(config.c_imap_port, - NULL, imap_greeting, imap_command_loop, NULL); + NULL, imap_greeting, imap_command_loop, NULL, CitadelServiceIMAP); #ifdef HAVE_OPENSSL CtdlRegisterServiceHook(config.c_imaps_port, - NULL, imaps_greeting, imap_command_loop, NULL); + NULL, imaps_greeting, imap_command_loop, NULL, CitadelServiceIMAPS); #endif CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP); diff --git a/citadel/modules/managesieve/serv_managesieve.c b/citadel/modules/managesieve/serv_managesieve.c index 121cad908..dacc789f9 100644 --- a/citadel/modules/managesieve/serv_managesieve.c +++ b/citadel/modules/managesieve/serv_managesieve.c @@ -567,7 +567,7 @@ void managesieve_command_loop(void) { #endif /* HAVE_LIBSIEVE */ - +const char* CitadelServiceManageSieve = "ManageSieve"; CTDL_MODULE_INIT(managesieve) { @@ -577,7 +577,8 @@ CTDL_MODULE_INIT(managesieve) NULL, managesieve_greeting, managesieve_command_loop, - NULL); + NULL, + CitadelServiceManageSieve); #else /* HAVE_LIBSIEVE */ diff --git a/citadel/modules/pop3/serv_pop3.c b/citadel/modules/pop3/serv_pop3.c index ba2faa1e1..761a4da96 100644 --- a/citadel/modules/pop3/serv_pop3.c +++ b/citadel/modules/pop3/serv_pop3.c @@ -702,6 +702,8 @@ void pop3_command_loop(void) { } +const char *CitadelServicePop3="POP3"; +const char *CitadelServicePop3S="POP3S"; CTDL_MODULE_INIT(pop3) @@ -710,13 +712,15 @@ CTDL_MODULE_INIT(pop3) NULL, pop3_greeting, pop3_command_loop, - NULL); + NULL, + CitadelServicePop3); #ifdef HAVE_OPENSSL CtdlRegisterServiceHook(config.c_pop3s_port, NULL, pop3s_greeting, pop3_command_loop, - NULL); + NULL, + CitadelServicePop3S); #endif CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP); diff --git a/citadel/modules/smtp/serv_smtp.c b/citadel/modules/smtp/serv_smtp.c index ccbe1a78e..e6f3c6957 100644 --- a/citadel/modules/smtp/serv_smtp.c +++ b/citadel/modules/smtp/serv_smtp.c @@ -1803,7 +1803,11 @@ void smtp_cleanup_function(void) { - +const char *CitadelServiceSMTP_MTA="SMTP-MTA"; +const char *CitadelServiceSMTPS_MTA="SMTPs-MTA"; +const char *CitadelServiceSMTP_MSA="SMTP-MSA"; +const char *CitadelServiceSMTP_LMTP="LMTP"; +const char *CitadelServiceSMTP_LMTP_UNF="LMTP-UnF"; CTDL_MODULE_INIT(smtp) { @@ -1811,33 +1815,38 @@ CTDL_MODULE_INIT(smtp) NULL, smtp_mta_greeting, smtp_command_loop, - NULL); + NULL, + CitadelServiceSMTP_MTA); #ifdef HAVE_OPENSSL CtdlRegisterServiceHook(config.c_smtps_port, NULL, smtps_greeting, smtp_command_loop, - NULL); + NULL, + CitadelServiceSMTPS_MTA); #endif CtdlRegisterServiceHook(config.c_msa_port, /* SMTP MSA */ NULL, smtp_msa_greeting, smtp_command_loop, - NULL); + NULL, + CitadelServiceSMTP_MSA); CtdlRegisterServiceHook(0, /* local LMTP */ file_lmtp_socket, lmtp_greeting, smtp_command_loop, - NULL); + NULL, + CitadelServiceSMTP_LMTP); CtdlRegisterServiceHook(0, /* local LMTP */ file_lmtp_unfiltered_socket, lmtp_unfiltered_greeting, smtp_command_loop, - NULL); + NULL, + CitadelServiceSMTP_LMTP_UNF); smtp_init_spoolout(); CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER); diff --git a/citadel/modules/vandelay/serv_vandelay.c b/citadel/modules/vandelay/serv_vandelay.c index 7554ae1a5..07dd5358c 100644 --- a/citadel/modules/vandelay/serv_vandelay.c +++ b/citadel/modules/vandelay/serv_vandelay.c @@ -670,7 +670,7 @@ void artv_do_import(void) { iterations = 0; } else { - cprintf("."); + cprintf("."); if (iterations % 64 == 0) cprintf("\n"); diff --git a/citadel/modules/vcard/serv_vcard.c b/citadel/modules/vcard/serv_vcard.c index f750c101f..54d3c39cb 100644 --- a/citadel/modules/vcard/serv_vcard.c +++ b/citadel/modules/vcard/serv_vcard.c @@ -1330,7 +1330,7 @@ void vcard_fixed_output(char *ptr, int len) { } - +const char *CitadelServiceDICT_TCP="DICT_TCP"; CTDL_MODULE_INIT(vcard) { @@ -1383,7 +1383,8 @@ CTDL_MODULE_INIT(vcard) NULL, check_get_greeting, check_get, - NULL); + NULL, + CitadelServiceDICT_TCP); /* return our Subversion id for the Log */ return "$Id$"; diff --git a/citadel/serv_extensions.c b/citadel/serv_extensions.c index 3cbc5b906..e9461489e 100644 --- a/citadel/serv_extensions.c +++ b/citadel/serv_extensions.c @@ -776,11 +776,11 @@ void CtdlDestroyXmsgHooks(void) void CtdlRegisterServiceHook(int tcp_port, - char *sockpath, - void (*h_greeting_function) (void), - void (*h_command_function) (void), - void (*h_async_function) (void) - ) + char *sockpath, + void (*h_greeting_function) (void), + void (*h_command_function) (void), + void (*h_async_function) (void), + const char *ServiceName) { struct ServiceFunctionHook *newfcn; char *message; @@ -797,13 +797,14 @@ void CtdlRegisterServiceHook(int tcp_port, newfcn->h_greeting_function = h_greeting_function; newfcn->h_command_function = h_command_function; newfcn->h_async_function = h_async_function; + newfcn->ServiceName = ServiceName; if (sockpath != NULL) { newfcn->msock = ig_uds_server(sockpath, config.c_maxsessions, &error); snprintf(message, SIZ, "Unix domain socket '%s': ", sockpath); } else if (tcp_port <= 0) { /* port -1 to disable */ - lprintf(CTDL_INFO, "Service has been manually disabled, skipping\n"); + lprintf(CTDL_INFO, "Service %s has been manually disabled, skipping\n", ServiceName); free (message); free(newfcn); return; @@ -813,8 +814,8 @@ void CtdlRegisterServiceHook(int tcp_port, tcp_port, config.c_maxsessions, &error); - snprintf(message, SIZ, "TCP port %s:%d: ", - config.c_ip_addr, tcp_port); + snprintf(message, SIZ, "TCP port %s:%d: (%s) ", + config.c_ip_addr, tcp_port, ServiceName); } if (newfcn->msock > 0) { diff --git a/citadel/server.h b/citadel/server.h index 3d1c9c487..3913cee58 100644 --- a/citadel/server.h +++ b/citadel/server.h @@ -143,6 +143,7 @@ struct CitContext { struct citmgsve *MGSVE; /**< Managesieve Session struct */ struct cit_ical *CIT_ICAL; /* calendaring data */ struct ma_info *ma; /* multipart/alternative data */ + const char* ServiceName; /**< whats our actual purpose? */ }; typedef struct CitContext t_context; @@ -437,6 +438,7 @@ struct ServiceFunctionHook { void (*h_command_function) (void) ; void (*h_async_function) (void) ; int msock; + const char* ServiceName; /* this is just for debugging and logging purposes. */ }; extern struct ServiceFunctionHook *ServiceHookTable; diff --git a/citadel/server_main.c b/citadel/server_main.c index 4c69e6083..bd3c00321 100644 --- a/citadel/server_main.c +++ b/citadel/server_main.c @@ -59,7 +59,7 @@ #include "citadel_dirs.c" #include "modules_init.h" - +#include "ecrash.h" #ifdef HAVE_SYS_SELECT_H #include @@ -68,6 +68,8 @@ #ifndef HAVE_SNPRINTF #include "snprintf.h" #endif +const char *CitadelServiceUDS="citadel-UDS"; +const char *CitadelServiceTCP="citadel-TCP"; /* * Here's where it all begins. @@ -87,6 +89,8 @@ int main(int argc, char **argv) #ifdef HAVE_RUN_DIR struct stat filestats; #endif + eCrashParameters params; +// eCrashSymbolTable symbol_table; /* initialise semaphores here. Patch by Matt and davew * its called here as they are needed by lprintf for thread safety @@ -154,13 +158,31 @@ int main(int argc, char **argv) } calc_dirs_n_files(relh, home, relhome, ctdldir); - /* daemonize, if we were asked to */ if (running_as_daemon) { start_daemon(0); drop_root_perms = 1; } + bzero(¶ms, sizeof(params)); + params.filename = file_pid_paniclog; + panic_fd=open(file_pid_paniclog, O_APPEND|O_CREAT|O_DIRECT); + params.filep = fopen(file_pid_paniclog, "a+"); + params.debugLevel = ECRASH_DEBUG_VERBOSE; + params.dumpAllThreads = TRUE; + params.useBacktraceSymbols = 1; +/// BuildSymbolTable(&symbol_table); +// params.symbolTable = &symbol_table; + params.signals[0]=SIGSEGV; + params.signals[1]=SIGILL; + params.signals[2]=SIGBUS; + params.signals[3]=SIGABRT; + + eCrash_Init(¶ms); + + eCrash_RegisterThread("MasterThread", 0); + +/// signal(SIGSEGV, cit_panic_backtrace); /* Initialize the syslogger. Yes, we are really using 0 as the * facility, because we are going to bitwise-OR the facility to * the severity of each message, allowing us to write to other @@ -222,10 +244,11 @@ int main(int argc, char **argv) * Bind the server to a Unix-domain socket. */ CtdlRegisterServiceHook(0, - file_citadel_socket, - citproto_begin_session, - do_command_loop, - do_async_loop); + file_citadel_socket, + citproto_begin_session, + do_command_loop, + do_async_loop, + CitadelServiceUDS); /* * Bind the server to our favorite TCP port (usually 504). @@ -234,7 +257,8 @@ int main(int argc, char **argv) NULL, citproto_begin_session, do_command_loop, - do_async_loop); + do_async_loop, + CitadelServiceTCP); /* * Load any server-side extensions available here. diff --git a/citadel/sysdep.c b/citadel/sysdep.c index a6d1b844f..0de30ff22 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -62,6 +62,7 @@ #include "housekeeping.h" #include "tools.h" #include "modules/crypto/serv_crypto.h" /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */ +#include "ecrash.h" #ifdef HAVE_SYS_SELECT_H #include @@ -103,8 +104,8 @@ void DestroyWorkerList(void); * lprintf() ... Write logging information */ void lprintf(enum LogLevel loglevel, const char *format, ...) { - char *buf; va_list arg_ptr; + char buf[SIZ], buf2[SIZ]; if (enable_syslog) { va_start(arg_ptr, format); @@ -113,9 +114,7 @@ void lprintf(enum LogLevel loglevel, const char *format, ...) { } /* stderr output code */ - if (enable_syslog || running_as_daemon) { - return; - } + if (enable_syslog || running_as_daemon) return; /* if we run in forground and syslog is disabled, log to terminal */ if (loglevel <= verbosity) { @@ -127,10 +126,6 @@ void lprintf(enum LogLevel loglevel, const char *format, ...) { /* Promote to time_t; types differ on some OSes (like darwin) */ unixtime = tv.tv_sec; localtime_r(&unixtime, &tim); -// begin_critical_section(S_LOG); - - buf = malloc(SIZ+strlen(format)); - if (CC->cs_pid != 0) { sprintf(buf, "%04d/%02d/%02d %2d:%02d:%02d.%06ld [%3d] ", @@ -145,13 +140,12 @@ void lprintf(enum LogLevel loglevel, const char *format, ...) { tim.tm_mday, tim.tm_hour, tim.tm_min, tim.tm_sec, (long)tv.tv_usec); } - strcat(buf, format); - va_start(arg_ptr, buf); - vfprintf(stderr, buf, arg_ptr); + va_start(arg_ptr, format); + vsprintf(buf2, format, arg_ptr); va_end(arg_ptr); + + fprintf(stderr, "%s%s", buf, buf2); fflush(stderr); - free (buf); -// end_critical_section(S_LOG); } } @@ -370,7 +364,7 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage) int s; int i; int actual_queue_len; - long ret, ret2; + actual_queue_len = queue_len; if (actual_queue_len < 5) actual_queue_len = 5; @@ -619,6 +613,7 @@ void client_write(char *buf, int nbytes) nbytes - bytes_written, strerror(errno), errno); cit_backtrace(); + lprintf(CTDL_DEBUG, "Tried to send: %s", &buf[bytes_written]); CC->kill_me = 1; return; } @@ -777,6 +772,7 @@ void sysdep_master_cleanup(void) { CtdlDestroyFixedOutputHooks(); CtdlDestroySessionHooks(); CtdlDestroyServiceHook(); + eCrash_Uninit(); } @@ -1161,6 +1157,9 @@ void *worker_thread(void *arg) { cdb_allocate_tsd(); + // Register for tracing + eCrash_RegisterThread("WorkerThread", 0); + while (!time_to_die) { /* make doubly sure we're not holding any stale db handles @@ -1265,7 +1264,9 @@ do_select: force_purge = 0; serviceptr->h_command_function; con->h_async_function = serviceptr->h_async_function; - + con->ServiceName = + serviceptr->ServiceName; + /* Determine whether it's a local socket */ if (serviceptr->sockpath != NULL) con->is_local_socket = 1; @@ -1338,6 +1339,7 @@ SKIP_SELECT: } if (con != NULL) free (con);//// TODO: could this harm other threads? /* If control reaches this point, the server is shutting down */ + eCrash_UnregisterThread(); return(NULL); } -- 2.30.2