root/src/plugins/sig.c @ 18

Revision 1, 4.9 kB (checked in by jinshiro, 17 years ago)
Line 
1// $Id: sig.c 1 2005-6-13 3:17:17 PM Celestia $
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <signal.h>
6#include <string.h>
7#include <time.h>
8#include "../common/plugin.h"
9#include "../common/version.h"
10#include "../common/showmsg.h"
11
12PLUGIN_INFO = {
13        "Signals",
14        PLUGIN_CORE,
15        "1.1",
16        PLUGIN_VERSION,
17        "Handles program signals"
18};
19
20PLUGIN_EVENTS_TABLE = {
21        { "sig_init", "Plugin_Init" },
22        { "sig_final", "Plugin_Final" },
23        { NULL, NULL }
24};
25
26//////////////////////////////////////
27
28#if defined(_WIN32) || defined(MINGW)
29        int sig_init()
30        {
31                ShowError("sig: This plugin is not supported - Enable 'exchndl' instead!\n");
32                return 0;
33        }
34        int sig_final() { return 0; }
35#elif defined (__NETBSD__) || defined (__FREEBSD__)
36        int sig_init()
37        {
38                ShowError("sig: This plugin is not supported!\n");
39                return 0;
40        }
41        int sig_final() { return 0; }
42#else
43
44//////////////////////////////////////
45
46#if !defined(CYGWIN)
47        #include <execinfo.h>
48#endif
49
50const char* (*getrevision)();
51unsigned long (*getuptime)();
52char *server_name;
53int crash_flag = 0;
54
55extern const char *strsignal(int);
56int sig_final ();
57
58// by Gabuzomeu
59// This is an implementation of signal() using sigaction() for portability.
60// (sigaction() is POSIX; signal() is not.)  Taken from Stevens' _Advanced
61// Programming in the UNIX Environment_.
62//
63#ifdef WIN32    // windows don't have SIGPIPE
64#define SIGPIPE SIGINT
65#endif
66
67#ifndef POSIX
68#define compat_signal(signo, func) signal(signo, func)
69#else
70sigfunc *compat_signal(int signo, sigfunc *func)
71{
72        struct sigaction sact, oact;
73
74        sact.sa_handler = func;
75        sigemptyset(&sact.sa_mask);
76        sact.sa_flags = 0;
77#ifdef SA_INTERRUPT
78        sact.sa_flags |= SA_INTERRUPT;  /* SunOS */
79#endif
80
81        if (sigaction(signo, &sact, &oact) < 0)
82                return (SIG_ERR);
83
84        return (oact.sa_handler);
85}
86#endif
87
88/*=========================================
89 *      Dumps the stack using glibc's backtrace
90 *-----------------------------------------
91 */
92#ifdef CYGWIN
93        #define FOPEN_ freopen
94        extern void cygwin_stackdump();
95#else
96        #define FOPEN_(fn,m,s) fopen(fn,m)
97#endif
98void sig_dump(int sn)
99{
100        FILE *fp;
101        char file[256];
102        int no = 0;
103
104        crash_flag = 1; 
105        // search for a usable filename
106        do {
107                sprintf (file, "log/%s%04d.stackdump", server_name, ++no);
108        } while((fp = fopen(file,"r")) && (fclose(fp), no < 9999));
109        // dump the trace into the file
110
111        if ((fp = FOPEN_(file, "w", stderr)) != NULL) {
112                const char *revision;
113        #ifndef CYGWIN
114                void* array[20];
115                char **stack;
116                size_t size;
117        #endif
118
119                ShowNotice ("Dumping stack to '"CL_WHITE"%s"CL_RESET"'...\n", file);
120                if ((revision = getrevision()) != NULL)
121                        fprintf(fp, "Version: svn%s \n", revision);
122                else
123                        fprintf(fp, "Version: %2d.%02d.%02d mod%02d \n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION, ATHENA_MOD_VERSION);
124                fprintf(fp, "Exception: %s \n", strsignal(sn));
125                fflush (fp);
126
127        #ifdef CYGWIN
128                cygwin_stackdump ();
129        #else
130                fprintf(fp, "Stack trace:\n");
131                size = backtrace (array, 20);
132                stack = backtrace_symbols (array, size);
133                for (no = 0; no < size; no++) {
134                        fprintf(fp, "%s\n", stack[no]);
135                }
136                fprintf(fp,"End of stack trace\n");
137                free(stack);
138        #endif
139
140                ShowNotice("%s Saved.\n", file);
141                fflush(stdout);
142                fclose(fp);
143        }
144
145        sig_final();    // Log our uptime
146        // Pass the signal to the system's default handler
147        compat_signal(sn, SIG_DFL);
148        raise(sn);
149}
150
151/*=========================================
152 *      Shutting down (Program did not crash ^^)
153 *      - Log our current up time
154 *-----------------------------------------
155 */
156int sig_final ()
157{
158        time_t curtime;
159        char curtime2[24];     
160        FILE *fp;
161        long seconds = 0, day = 24*60*60, hour = 60*60,
162                minute = 60, days = 0, hours = 0, minutes = 0;
163
164        fp = fopen("log/uptime.log","a");
165        if (fp) {
166                time(&curtime);
167                strftime(curtime2, 24, "%m/%d/%Y %H:%M:%S", localtime(&curtime));
168
169                seconds = getuptime();
170                days = seconds/day;
171                seconds -= (seconds/day>0)?(seconds/day)*day:0;
172                hours = seconds/hour;
173                seconds -= (seconds/hour>0)?(seconds/hour)*hour:0;
174                minutes = seconds/minute;
175                seconds -= (seconds/minute>0)?(seconds/minute)*minute:0;
176
177                fprintf(fp, "%s: %s %s - %ld days, %ld hours, %ld minutes, %ld seconds.\n",
178                        curtime2, server_name, (crash_flag ? "crashed" : "uptime"),
179                        days, hours, minutes, seconds);
180                fclose(fp);
181        }
182
183        return 1;
184}
185
186/*=========================================
187 *      Register the signal handlers
188 *-----------------------------------------
189 */
190int sig_init ()
191{
192        void (*func) = sig_dump;
193#ifdef CYGWIN   // test if dumper is enabled
194        char *buf = getenv ("CYGWIN");
195        if (buf && strstr(buf, "error_start") != NULL)
196                func = SIG_DFL;
197#endif
198
199        IMPORT_SYMBOL(server_name, 1);
200        IMPORT_SYMBOL(getrevision, 6);
201        IMPORT_SYMBOL(getuptime, 11);
202
203        compat_signal(SIGSEGV, func);
204        compat_signal(SIGFPE, func);
205        compat_signal(SIGILL, func);
206        #ifndef __WIN32
207                compat_signal(SIGBUS, func);
208        #endif
209
210        return 1;
211}
212#endif
Note: See TracBrowser for help on using the browser.