* modules registering serverports now need to specify a plaintext name.
authorWilfried Göesgens <willi@citadel.org>
Sun, 26 Aug 2007 21:31:51 +0000 (21:31 +0000)
committerWilfried Göesgens <willi@citadel.org>
Sun, 26 Aug 2007 21:31:51 +0000 (21:31 +0000)
* added David Frascones ecrash lib
* hooked ecrash into citserver and citadel (not yet all done)

21 files changed:
citadel/Makefile.in
citadel/citadel.c
citadel/citadel_dirs.c
citadel/citadel_dirs.h
citadel/citserver.c
citadel/citserver.h
citadel/commands.c
citadel/debian/rules
citadel/ecrash.c [new file with mode: 0644]
citadel/ecrash.h [new file with mode: 0644]
citadel/include/ctdl_module.h
citadel/modules/imap/serv_imap.c
citadel/modules/managesieve/serv_managesieve.c
citadel/modules/pop3/serv_pop3.c
citadel/modules/smtp/serv_smtp.c
citadel/modules/vandelay/serv_vandelay.c
citadel/modules/vcard/serv_vcard.c
citadel/serv_extensions.c
citadel/server.h
citadel/server_main.c
citadel/sysdep.c

index 2aaa0de71ae99cd3fb8c9a2c6363c4b0386bb873..9cbace9595190b5c645e530969464bc35954cd7c 100644 (file)
@@ -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)
index e9c979adbc91489e818998f93994dd4db53acbfc..4330cf7842caaba3cf31716255454b37e540e8f1 100644 (file)
@@ -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(&params, 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(&params);
        
        setIPCDeathHook(screen_delete);
        setIPCErrorPrintf(err_printf);
index 045b1d190a27f1a747c77c611164a7f8b2fc6bda..29552761e33e854535f0d5e63dd78d7da4af4ad0 100644 (file)
@@ -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",
index 3395db018b32969c869e38fd780e060863bf730c..1eb0a1138cd7d84006aa34561386092a936d9158 100644 (file)
@@ -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];
index 92d031d41d8919387304aed4c30d37c38975e5bb..a25a2ea2077e69332092e67c537395c807eb7d91 100644 (file)
@@ -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
  */
index a9be0025b308b4ae8e0dc6c0c22bfd23124c8f56..b3d3346fd6452a1352d148616864e26b8dd65d6b 100644 (file)
@@ -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);
index 6b9a45164a1ef6c2e26e44a139a590a33fb6c57b..fb1b99b9b9ee5c9430a17c51021697e408732bc8 100644 (file)
@@ -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;
 }
 
index fef1a8bf64bad9fa1b826c56e1602220305e944a..0b4a8020b86259eca4f684a57b18700dec53572b 100755 (executable)
@@ -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 (file)
index 0000000..2c04fe9
--- /dev/null
@@ -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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <execinfo.h>
+#include <pthread.h>
+#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 (file)
index 0000000..271e991
--- /dev/null
@@ -0,0 +1,185 @@
+/**
+ * \file eCrash.h
+ * @author David Frascone
+ * 
+ *  eCrash types and prototypes.
+ *
+ * vim: ts=4
+ */
+
+#ifndef _ECRASH_H_
+#define _ECRASH_H_
+
+#include <stdio.h>
+#include <signal.h>
+
+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_ */
index 905446ee55aa8d0a7e387cdce09c9e9c128f6a17..8c0efb0e173647739db7f877ef7ff1b884565fbb 100644 (file)
@@ -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,
index 4d5feb063ec62c139ccd07b76141c166b94e2296..ca4acfb6c38dca00a0ad52381d67f5dd244d11e7 100644 (file)
@@ -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);
 
index 121cad908c19f4a434feba284fe8952a6d0dde14..dacc789f9c298d1158c91a9aa3b6cd847771f318 100644 (file)
@@ -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 */
 
index ba2faa1e1009ba4ac6190e221d094303818e9bb7..761a4da967e510c06b697ef7722ea9fcb5964073 100644 (file)
@@ -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);
 
index ccbe1a78ef3a9c7795d8fa0417958626d3168f34..e6f3c6957d9c53a4c4e84bbc60be25b9ad671be7 100644 (file)
@@ -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);
index 7554ae1a5418ae5f72363e6b5e2817c9b1e9f130..07dd5358c2d0b5ce350aedbc3bfad44323828120 100644 (file)
@@ -670,7 +670,7 @@ void artv_do_import(void) {
                        iterations = 0;
                }
                else {
-                       cprintf(".");
+                       cprintf(".");
                        if (iterations % 64 == 0)
                                cprintf("\n");
                        
index f750c101f647758c5358dfde6ec95c80be8065ca..54d3c39cb5f39c87de3a3045675ea5dd16fd3a39 100644 (file)
@@ -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$";
index 3cbc5b9069d01469a50ace56f7f30ae87b90f35e..e9461489e68a8fb60cda010f4b0a4f5af9affe64 100644 (file)
@@ -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) {
index 3d1c9c487a721d151a8dd3769c528f2eb4dc36c4..3913cee5885ec64b20f6ef841c1679b10fef7fed 100644 (file)
@@ -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;
 
index 4c69e608342f9c9c3af4aa9cdc653f77f279b3fa..bd3c0032116a1e9727991b6bb50ab2c630c0727b 100644 (file)
@@ -59,7 +59,7 @@
 #include "citadel_dirs.c"
 
 #include "modules_init.h"
-
+#include "ecrash.h"
 
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
@@ -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(&params, 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(&params);
+               
+       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.
index a6d1b844f93953c11065adc481cf72514d0e169e..0de30ff225d27f45dbf16b776811ac6fe3ebf916 100644 (file)
@@ -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 <sys/select.h>
@@ -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);
 }