/* * Copyright (C) 1995-1997 Christopher D. Granz * * This header may not be removed. * * Refer to the file "License" included in this package for further * information and before using any of the following. */ /* * This file contains all the signal handling routines. */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <setjmp.h> #include <unistd.h> #include <errno.h> #include <sys/signal.h> #include <sys/types.h> #include <sys/wait.h> #include "sapphire.h" #include "emerald.h" /* * Structures */ struct signal_handler { int iSignal; void ( *pHandler ) ( int, int, struct sigcontext * ); }; /* * Prototypes */ int sigaltstack ( const struct sigaltstack *, struct sigaltstack * ); static void basic_handler ( int, char *, char * ); /* * Globals */ bool bIsPrompt; static jmp_buf jbCheckAddress; static bool bCheckingAddress; /* * Tables */ static struct signal_handler shSignalHandlers[] = { { SIGHUP, SIG_IGN }, { SIGINT, &sigint_handler }, { SIGPIPE, SIG_IGN }, { SIGILL, &sigill_handler }, { SIGBUS, &sigbus_handler }, { SIGSEGV, &sigsegv_handler }, { SIGSYS, &sigsys_handler }, { SIGTERM, &sigterm_handler }, { SIGPROF, &sigprof_handler }, { 0, NULL } }; /* * Functions */ void init_signal_handlers( void ) { struct sigaltstack sSignalStack; struct sigaction sSignalAction; int i; sSignalStack.ss_base = alloc_mem( SIGSTKSZ ); sSignalStack.ss_size = SIGSTKSZ; sSignalStack.ss_flags = 0; #ifndef _sysLinux if ( sigaltstack( &sSignalStack, NULL ) < 0 ) sap_fatal( "Signal stack: %s.", strerror( errno ) ); #endif for ( i = 0; shSignalHandlers[i].iSignal != 0; i++ ) { sSignalAction.sa_handler = shSignalHandlers[i].pHandler; sSignalAction.sa_mask = 0; #ifndef _sysLinux sSignalAction.sa_flags = SA_ONSTACK; #endif sigaction( shSignalHandlers[i].iSignal, &sSignalAction, NULL ); } } static void basic_handler( int iSignal, char *pMsg1, char *pMsg2 ) { pid_t pPid; if ( pLogFile != stdout ) fprintf( stderr, pMsg1 ); lprintf( pMsg1 ); /* * Fork and then force the default handler for the signal * to be called by the child. Thus, we can core dump * (or anything else) and still reboot. */ retry: if ( ( pPid = fork( ) ) < 0 ) { if ( errno == EINTR ) goto retry; sap_fatal( "Fork process: %s.", strerror( errno ) ); } else if ( pPid == 0 ) { struct sigaction sSignalAction; sSignalAction.sa_handler = SIG_DFL; sigemptyset( &sSignalAction.sa_mask ); sSignalAction.sa_flags = 0; if ( sTelnetControl > -1 ) close( sTelnetControl ); if ( sBinaryControl > -1 ) close( sBinaryControl ); if ( sMUDCommControl > -1 ) close( sMUDCommControl ); sigaction( iSignal, &sSignalAction, NULL ); kill( getpid( ), iSignal ); /* Force the default handler. */ } else { MUD_COMM_DATA *pMUDComm, *pMUDCommNext; TERM_DATA *pTerm, *pTermNext; char *pArg[] = { pProgramName, pBootFilename, NULL, NULL }; int i; do { errno = 0; wait( &i ); } while ( errno == EINTR ); for ( pMUDComm = pMUDCommList; pMUDComm; pMUDComm = pMUDCommNext ) { pMUDCommNext = pMUDComm->pNext; close_mudcomm_connection( &pMUDComm ); } for ( pTerm = pTermList; pTerm != NULL; pTerm = pTermNext ) { pTermNext = pTerm->pNext; write_string_buffer( pTerm, pMsg2 ); close_connection( &pTerm ); } if ( sTelnetControl > -1 ) close( sTelnetControl ); if ( sBinaryControl > -1 ) close( sBinaryControl ); if ( sMUDCommControl > -1 ) close( sMUDCommControl ); if ( pLogFile != stdout ) fclose( pLogFile ); else pArg[2] = "-l"; sleep( 15 ); do { errno = 0; execv( pProgramName, pArg ); } while ( errno == EINTR ); if ( errno != 0 ) exit( 1 ); } } /* * Handles when the user types the interupt character (^C). */ void sigint_handler( int iSignal, int iCode, struct sigcontext *pSC ) { struct sigaction sSignalAction; sSignalAction.sa_handler = &sigint_handler_2; sSignalAction.sa_mask = 0; sSignalAction.sa_flags = 0; sigaction( SIGINT, &sSignalAction, NULL ); fprintf( stderr, "\n[Main Control Menu]\n" "\n" " 1) Exit menu\n" " 2) Shutdown\n" "\n" " 3) Show connected sockets\n" " 4) Show character creation code\n" "\n" " 5) Enter shell (`%s')\n" #ifdef DEBUG " 6) Core dump\n" #endif , pShellProgramName ); fprintf( stderr, "\n%s> ", pMUDName ); bIsPrompt = TRUE; } void sigint_handler_2( int iSignal, int iCode, struct sigcontext *pSC ) { TERM_DATA *pTerm; for ( pTerm = pTermList; pTerm != NULL; pTerm = pTerm->pNext ) { write_string_buffer( pTerm, "\n\rServer shutdown.\n\r" ); tflush( pTerm ); } putc( '\n', stderr ); if ( pLogFile != stdout ) fprintf( stderr, "Server shutdown.\n" ); lprintf( "Server shutdown." ); #ifdef DEBUG abort( ); #else exit( 0 ); #endif } /* * Handles illegal instructions. */ void sigill_handler( int iSignal, int iCode, struct sigcontext *pSC ) { basic_handler( iSignal, "\nIllegal instruction; will core dump.\n" "Forcing reboot.\n", "\n\rThere has been an internal error.\n\r" "I must attemp to reboot.\n\r" ); } /* * Handles segmentation faults. */ void sigsegv_handler( int iSignal, int iCode, struct sigcontext *pSC ) { if ( bCheckingAddress == TRUE ) longjmp( jbCheckAddress, 1 ); else basic_handler( iSignal, "\nSegmentation fault; will core dump.\n" "Forcing reboot.\n", "\n\rThere has been a memory failure.\n\r" "I must attemp to reboot.\n\r" ); } /* * Handles bus errors. */ void sigbus_handler( int iSignal, int iCode, struct sigcontext *pSC ) { basic_handler( iSignal, "\nBus error; will core dump.\n" "Forcing reboot.\n", "\n\rThere has been an internal error.\n\r" "I must attemp to reboot.\n\r" ); } /* * Handles invalid system calls. */ void sigsys_handler( int iSignal, int iCode, struct sigcontext *pSC ) { basic_handler( iSignal, "\nInvalid system call; will core dump.\n" "Forcing reboot.\n", "\n\rThere has been an internal error.\n\r" "I must attemp to reboot.\n\r" ); } /* * Handles software termination signals (usaully caused by `kill'.) */ void sigterm_handler( int iSignal, int iCode, struct sigcontext *pSC ) { TERM_DATA *pTerm; for ( pTerm = pTermList; pTerm != NULL; pTerm = pTerm->pNext ) { write_string_buffer( pTerm, "\n\rServer shutdown.\n\r" ); tflush( pTerm ); } if ( pLogFile != stdout ) fprintf( stderr, "Server shutdown.\n" ); lprintf( "Server shutdown." ); exit( 0 ); } void sigprof_handler( int iSignal, int iCode, struct sigcontext *pSC ) { em_abort( ); } bool valid_address( void *p ) { char cBuf[2]; char *p2 = (char *) p; if ( setjmp( jbCheckAddress ) == 1 ) { bCheckingAddress = FALSE; return ( FALSE ); } bCheckingAddress = TRUE; sprintf( cBuf, "%c", *p2 ); /* Try dereferencing it. */ return ( TRUE ); } /* * End of signal.c */