00001
00002
00003
00004
00005
00006
00007 #include "config.h"
00008 #include <sys/types.h>
00009 #include <sys/stat.h>
00010 #include <unistd.h>
00011 #include <sys/file.h>
00012 #include <sys/ioctl.h>
00013 #include <sys/wait.h>
00014 #include <signal.h>
00015 #include <errno.h>
00016
00017 #include "debug.h"
00018 #include "mudconf.h"
00019 #include "externs.h"
00020 #include "flags.h"
00021
00022 void signal_TERM(int, siginfo_t *, void *);
00023 void signal_PIPE(int, siginfo_t *, void *);
00024 void signal_USR1(int, siginfo_t *, void *);
00025 void signal_SEGV(int, siginfo_t *, void *);
00026 void signal_BUS(int, siginfo_t *, void *);
00027
00028 struct sigaction saTERM = {.sa_handler = NULL,.sa_sigaction = signal_TERM,
00029 .sa_flags = SA_SIGINFO | SA_RESETHAND | SA_RESTART
00030 };
00031
00032 struct sigaction saPIPE = {.sa_handler = NULL,.sa_sigaction = signal_PIPE,
00033 .sa_flags = SA_SIGINFO
00034 };
00035
00036 struct sigaction saUSR1 = {.sa_handler = NULL,.sa_sigaction = signal_USR1,
00037 .sa_flags = SA_SIGINFO | SA_RESETHAND | SA_RESTART
00038 };
00039
00040 struct sigaction saSEGV = {.sa_handler = NULL,.sa_sigaction = signal_SEGV,
00041 .sa_flags = SA_SIGINFO | SA_RESETHAND | SA_RESTART
00042 };
00043
00044 struct sigaction saBUS = {.sa_handler = NULL,.sa_sigaction = signal_BUS,
00045 .sa_flags = SA_SIGINFO | SA_RESETHAND | SA_RESTART
00046 };
00047
00048 stack_t sighandler_stack;
00049 stack_t regular_stack;
00050
00051 #define ALT_STACK_SIZE (0x40000)
00052 #define ALT_STACK_ALIGN (0x1000)
00053
00054 void bind_signals()
00055 {
00056 int error_code;
00057 dprintk("creating alternate signal stack.");
00058 #ifdef HAVE_POSIX_MEMALIGN
00059 error_code = posix_memalign(&sighandler_stack.ss_sp, ALT_STACK_ALIGN,
00060 ALT_STACK_SIZE);
00061 #else
00062 sighandler_stack.ss_sp = malloc(ALT_STACK_SIZE);
00063 if(sighandler_stack.ss_sp != 0) error_code = 0;
00064 #endif
00065 if(error_code == 0) {
00066 sighandler_stack.ss_size = ALT_STACK_SIZE;
00067 sighandler_stack.ss_flags = 0;
00068 memset(sighandler_stack.ss_sp, 0, ALT_STACK_SIZE);
00069 dperror(sigaltstack(&sighandler_stack, ®ular_stack) <0);
00070 dprintk("Current stack at 0x%x with length 0x%x and flags 0x%x",
00071 (unsigned int)regular_stack.ss_sp, regular_stack.ss_size, regular_stack.ss_flags);
00072 dprintk("Signal stack at 0x%x with length 0x%x and flags 0x%x",
00073 (unsigned int)sighandler_stack.ss_sp, sighandler_stack.ss_size, sighandler_stack.ss_flags);
00074 saSEGV.sa_flags |= SA_ONSTACK;
00075 saBUS.sa_flags |= SA_ONSTACK;
00076 } else {
00077 dprintk("posix_memalign failed with %s", strerror(error_code));
00078 log_error(LOG_PROBLEMS, "SIG", "ERR",
00079 "posix_memalign() failed with error %s, alternate stack not used.",
00080 strerror(error_code));
00081 log_error(LOG_PROBLEMS, "SIG", "ERR",
00082 "running signal_handlers without sigaltstack() will corrupt your coredumps!");
00083 sighandler_stack.ss_sp = NULL;
00084 }
00085 dprintk("binding signals.");
00086 dperror(sigaction(SIGTERM, &saTERM, NULL) <0);
00087
00088 sigaction(SIGUSR1, &saUSR1, NULL);
00089 sigaction(SIGSEGV, &saSEGV, NULL);
00090 sigaction(SIGBUS, &saBUS, NULL);
00091 signal(SIGCHLD, SIG_IGN);
00092 signal(SIGPIPE, SIG_IGN);
00093 dprintk("done.");
00094 }
00095
00096 void unbind_signals()
00097 {
00098 signal(SIGTERM, SIG_DFL);
00099 signal(SIGPIPE, SIG_DFL);
00100 signal(SIGUSR1, SIG_DFL);
00101 signal(SIGSEGV, SIG_DFL);
00102 signal(SIGBUS, SIG_DFL);
00103 signal(SIGCHLD, SIG_DFL);
00104 if(sighandler_stack.ss_sp != NULL) {
00105 void *temp_ptr;
00106 sighandler_stack.ss_flags = SS_DISABLE;
00107 temp_ptr = sighandler_stack.ss_sp;
00108 sigaltstack(&sighandler_stack, NULL);
00109 free(temp_ptr);
00110 sighandler_stack.ss_sp = NULL;
00111 }
00112 }
00113
00114 void signal_TERM(int signo, siginfo_t * siginfo, void *ucontext)
00115 {
00116 dprintk("caught SIGTERM");
00117 do_shutdown(NOTHING, 0, SHUTDN_EXIT, "received SIGTERM from kernel.");
00118 }
00119
00120 void signal_PIPE(int signo, siginfo_t * siginfo, void *ucontext)
00121 {
00122 dprintk("caught SIGPIPE");
00123 #ifdef HAVE_SIGINFO_T_SI_FD
00124 eradicate_broken_fd(siginfo->si_fd);
00125 #else
00126 eradicate_broken_fd(-1);
00127 #endif
00128 }
00129
00130 void signal_USR1(int signo, siginfo_t * siginfo, void *ucontext)
00131 {
00132 mux_release_socket();
00133 dprintk("caught SIGUSR1");
00134 do_restart(1, 1, 0);
00135 }
00136
00137 void signal_SEGV(int signo, siginfo_t * siginfo, void *ucontext)
00138 {
00139 dprintk("caught SIGSEGV");
00140 int child;
00141 mux_release_socket();
00142 if(!(child = fork())) {
00143 sleep(1);
00144
00145
00146 dprintk("(forked child) dumping restart database");
00147 dump_restart_db();
00148 dprintk("(forked child) execing new copy of game.");
00149 execl(mudstate.executable_path, mudstate.executable_path,
00150 mudconf.config_file, NULL);
00151 } else {
00152 switch (siginfo->si_code) {
00153 case SEGV_MAPERR:
00154 raw_broadcast(0,
00155 "Game: Invalid access of unamapped memory at %p. Restarting from Checkpoint.",
00156 siginfo->si_addr);
00157 break;
00158 case SEGV_ACCERR:
00159 raw_broadcast(0,
00160 "Game: Invalid access of protected memory at %p. Restarting from Checkpoint.",
00161 siginfo->si_addr);
00162 break;
00163 default:
00164 raw_broadcast(0,
00165 "Game: Unhandled SEGV at %p. Restarting from checkpoint.",
00166 siginfo->si_addr);
00167 break;
00168 }
00169 dump_database_internal(DUMP_CRASHED);
00170 report();
00171 }
00172 }
00173
00174 void signal_BUS(int signo, siginfo_t * siginfo, void *ucontext)
00175 {
00176 dprintk("caught SIGBUS");
00177 int child;
00178 mux_release_socket();
00179 if(mudconf.sig_action != SA_EXIT && !(child = fork())) {
00180 dump_restart_db();
00181 execl(mudstate.executable_path, mudstate.executable_path,
00182 mudconf.config_file, NULL);
00183 } else {
00184 switch (siginfo->si_code) {
00185 case BUS_ADRALN:
00186 raw_broadcast(0,
00187 "Game: Invalid address alignment accessing %p. Restarting from Checkpoint.",
00188 siginfo->si_addr);
00189 break;
00190 case BUS_ADRERR:
00191 raw_broadcast(0,
00192 "Game: Invalid access of non-existent physical memory at %p. Restarting from Checkpoint.",
00193 siginfo->si_addr);
00194 break;
00195 case BUS_OBJERR:
00196 raw_broadcast(0,
00197 "Game: Invalid object specific hardware error access at %p. Restarting from Checkpoint.",
00198 siginfo->si_addr);
00199 break;
00200 default:
00201 raw_broadcast(0,
00202 "Game: Unhandled SEGV at %p. Restarting from checkpoint.",
00203 siginfo->si_addr);
00204 break;
00205 }
00206 dump_database_internal(DUMP_CRASHED);
00207 report();
00208 }
00209 }