From 620e60eebce2c1f35c5c9a82f6ca365b316587f5 Mon Sep 17 00:00:00 2001 From: Valaris Date: Sun, 29 Jan 2006 16:10:48 +0000 Subject: AS OF SVN REV. 5901, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. EVERYTHING ELSE GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5094 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/plugins/sig.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/plugins/sig.c (limited to 'src/plugins/sig.c') diff --git a/src/plugins/sig.c b/src/plugins/sig.c new file mode 100644 index 000000000..1e9c36891 --- /dev/null +++ b/src/plugins/sig.c @@ -0,0 +1,211 @@ +// $Id: sig.c 1 2005-6-13 3:17:17 PM Celestia $ + +#include +#include +#include +#include +#include +#include "../common/plugin.h" +#include "../common/version.h" +#include "../common/showmsg.h" + +PLUGIN_INFO = { + "Signals", + PLUGIN_CORE, + "1.1", + PLUGIN_VERSION, + "Handles program signals" +}; + +PLUGIN_EVENTS_TABLE = { + { "sig_init", "Plugin_Init" }, + { "sig_final", "Plugin_Final" }, + { NULL, NULL } +}; + +////////////////////////////////////// + +#if defined(_WIN32) || defined(MINGW) + int sig_init() { + printf("This plugin is not supported - Enable 'exchndl' instead!"); + return 0; + } + int sig_final() { return 0; } +#elif defined (__NETBSD__) || defined (__FREEBSD__) + int sig_init() { + printf("This plugin is not supported!"); + return 0; + } + int sig_final() { return 0; } +#else + +////////////////////////////////////// + +#if !defined(CYGWIN) + #include +#endif + +const char* (*getrevision)(); +unsigned long (*getuptime)(); +char *server_name; +int crash_flag = 0; + +extern const char *strsignal(int); +int sig_final (); + +// by Gabuzomeu +// This is an implementation of signal() using sigaction() for portability. +// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced +// Programming in the UNIX Environment_. +// +#ifdef WIN32 // windows don't have SIGPIPE +#define SIGPIPE SIGINT +#endif + +#ifndef POSIX +#define compat_signal(signo, func) signal(signo, func) +#else +sigfunc *compat_signal(int signo, sigfunc *func) +{ + struct sigaction sact, oact; + + sact.sa_handler = func; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; +#ifdef SA_INTERRUPT + sact.sa_flags |= SA_INTERRUPT; /* SunOS */ +#endif + + if (sigaction(signo, &sact, &oact) < 0) + return (SIG_ERR); + + return (oact.sa_handler); +} +#endif + +/*========================================= + * Dumps the stack using glibc's backtrace + *----------------------------------------- + */ +#ifdef CYGWIN + #define FOPEN_ freopen + extern void cygwin_stackdump(); +#else + #define FOPEN_(fn,m,s) fopen(fn,m) +#endif +void sig_dump(int sn) +{ + FILE *fp; + char file[256]; + int no = 0; + + crash_flag = 1; + // search for a usable filename + do { + sprintf (file, "log/%s%04d.stackdump", server_name, ++no); + } while((fp = fopen(file,"r")) && (fclose(fp), no < 9999)); + // dump the trace into the file + + if ((fp = FOPEN_(file, "w", stderr)) != NULL) { + const char *revision; + #ifndef CYGWIN + void* array[20]; + char **stack; + size_t size; + #endif + + printf ("Dumping stack to '"CL_WHITE"%s"CL_RESET"'... ", file); + if ((revision = getrevision()) != NULL) + fprintf(fp, "Version: svn%s \n", revision); + else + fprintf(fp, "Version: %2d.%02d.%02d mod%02d \n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION, ATHENA_MOD_VERSION); + fprintf(fp, "Exception: %s \n", strsignal(sn)); + fflush (fp); + + #ifdef CYGWIN + cygwin_stackdump (); + #else + fprintf(fp, "Stack trace:\n"); + size = backtrace (array, 20); + stack = backtrace_symbols (array, size); + for (no = 0; no < size; no++) { + fprintf(fp, "%s\n", stack[no]); + } + fprintf(fp,"End of stack trace\n"); + free(stack); + #endif + + printf ("Done.\n"); + fflush(stdout); + fclose(fp); + } + + sig_final(); // Log our uptime + // Pass the signal to the system's default handler + compat_signal(sn, SIG_DFL); + raise(sn); +} + +/*========================================= + * Shutting down (Program did not crash ^^) + * - Log our current up time + *----------------------------------------- + */ +int sig_final () +{ + time_t curtime; + char curtime2[24]; + FILE *fp; + long seconds = 0, day = 24*60*60, hour = 60*60, + minute = 60, days = 0, hours = 0, minutes = 0; + + fp = fopen("log/uptime.log","a"); + if (fp) { + time(&curtime); + strftime(curtime2, 24, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); + + seconds = getuptime(); + days = seconds/day; + seconds -= (seconds/day>0)?(seconds/day)*day:0; + hours = seconds/hour; + seconds -= (seconds/hour>0)?(seconds/hour)*hour:0; + minutes = seconds/minute; + seconds -= (seconds/minute>0)?(seconds/minute)*minute:0; + + fprintf(fp, "%s: %s %s - %ld days, %ld hours, %ld minutes, %ld seconds.\n", + curtime2, server_name, (crash_flag ? "crashed" : "uptime"), + days, hours, minutes, seconds); + fclose(fp); + } + + return 1; +} + +/*========================================= + * Register the signal handlers + *----------------------------------------- + */ +int sig_init () +{ + void (*func) = sig_dump; +#ifdef CYGWIN // test if dumper is enabled + char *buf = getenv ("CYGWIN"); + if (buf && strstr(buf, "error_start") != NULL) + func = SIG_DFL; +#endif + + IMPORT_SYMBOL(server_name, 1); + IMPORT_SYMBOL(getrevision, 6); + IMPORT_SYMBOL(getuptime, 11); + + compat_signal(SIGSEGV, func); + compat_signal(SIGFPE, func); + compat_signal(SIGILL, func); + #ifndef __WIN32 + compat_signal(SIGBUS, func); + #endif + + return 1; +} +#endif + -- cgit v1.2.3-60-g2f50