
- Added used of Show* stuff in sig.c rather than printf. git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@6048 54d463be-8e91-2dee-dedb-b68131a5f0ec
212 lines
4.9 KiB
C
212 lines
4.9 KiB
C
// $Id: sig.c 1 2005-6-13 3:17:17 PM Celestia $
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#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() {
|
|
ShowError("sig: This plugin is not supported - Enable 'exchndl' instead!");
|
|
return 0;
|
|
}
|
|
int sig_final() { return 0; }
|
|
#elif defined (__NETBSD__) || defined (__FREEBSD__)
|
|
int sig_init() {
|
|
ShowError("sig: This plugin is not supported!");
|
|
return 0;
|
|
}
|
|
int sig_final() { return 0; }
|
|
#else
|
|
|
|
//////////////////////////////////////
|
|
|
|
#if !defined(CYGWIN)
|
|
#include <execinfo.h>
|
|
#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
|
|
|
|
ShowNotice ("Dumping stack to '"CL_WHITE"%s"CL_RESET"'...\n", 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
|
|
|
|
ShowNotice("%s Saved.\n", file);
|
|
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
|
|
|