static char rcsid[] = "@(#)$Id: signals.c,v 1.5 1999/03/24 14:04:06 wfp5p Exp $"; /******************************************************************************* * The Elm Mail System - $Revision: 1.5 $ $State: Exp $ * * Copyright (c) 1988-1995 USENET Community Trust * Copyright (c) 1986,1987 Dave Taylor ******************************************************************************* * Bug reports, patches, comments, suggestions should be sent to: * * Bill Pemberton, Elm Coordinator * flash@virginia.edu * ******************************************************************************* * $Log: signals.c,v $ * Revision 1.5 1999/03/24 14:04:06 wfp5p * elm 2.5PL0 * * Revision 1.4 1996/03/14 17:29:53 wfp5p * Alpha 9 * * Revision 1.3 1995/09/29 17:42:29 wfp5p * Alpha 8 (Chip's big changes) * * Revision 1.2 1995/07/18 19:00:10 wfp5p * Alpha 6 * * Revision 1.1.1.1 1995/04/19 20:38:38 wfp5p * Initial import of elm 2.4 PL0 as base for elm 2.5. * ******************************************************************************/ /** This set of routines traps various signals and informs the user of the error, leaving the program in a nice, graceful manner. **/ #include "elm_defs.h" #include #include "elm_globals.h" #include "s_elm.h" #define INIT_SIG(NUM, NAME, ACTION, DESCR) \ (signame[NUM] = (NAME), sigdescr[NUM] = (DESCR), signal((NUM), (ACTION))) static char *signame[NSIG]; static char *sigdescr[NSIG]; /* * it makes me very very nervous that we are doing stuff * like printfs in signal handlers */ static SIGHAND_TYPE bailout_handler P_((int)); static SIGHAND_TYPE sigalrm_catcher P_((int)); static SIGHAND_TYPE sigpipe_catcher P_((int)); #ifdef SIGTSTP static SIGHAND_TYPE sigtstp_catcher P_((int)); static SIGHAND_TYPE sigcont_catcher P_((int)); #endif #ifdef SIGWINCH static SIGHAND_TYPE sigwinch_catcher P_((int)); #endif #ifdef SIGTSTP static char *mssg_sigtstp, *mssg_sigcont; #endif PUBLIC void initialize_signals() { int i; /* signals to ignore */ INIT_SIG(SIGINT, "SIGINT", SIG_IGN, catgets(elm_msg_cat, ElmSet, ElmSigDescripInt, "Interrupt")); /* signals that invoke error exit */ INIT_SIG(SIGHUP, "SIGHUP", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripHup, "Hangup")); INIT_SIG(SIGQUIT, "SIGQUIT", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripQuit, "Quit")); INIT_SIG(SIGTERM, "SIGTERM", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripTerm, "Terminate")); /* signals that invoke a mailbox cleanup */ INIT_SIG(SIGUSR1, "SIGUSR1", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripUsr1, "First User-Defined")); INIT_SIG(SIGUSR2, "SIGUSR2", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripUsr2, "Second User-Defined")); /* signals that invoke emergency exit */ INIT_SIG(SIGILL, "SIGILL", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripIll, "Illegal Instruction")); INIT_SIG(SIGFPE, "SIGFPE", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripFpe, "Floating Point Exception")); #ifdef SIGBUS INIT_SIG(SIGBUS, "SIGBUS", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripBus, "Bus Error")); #endif INIT_SIG(SIGSEGV, "SIGSEGV", bailout_handler, catgets(elm_msg_cat, ElmSet, ElmSigDescripSegv, "Segment Violation")); #if !defined(POSIX_SIGNALS) && defined(SIGVEC) && defined(SV_INTERRUPT) INIT_SIG(SIGALRM, "SIGALRM", SIG_DFL, catgets(elm_msg_cat, ElmSet, ElmSigDescripAlrm, "Alarm Clock")); { struct sigvec alarm_vec; bzero((char *) &alarm_vec, sizeof(alarm_vec)); alarm_vec.sv_handler = alarm_signal; alarm_vec.sv_flags = SV_INTERRUPT; sigvec(SIGALRM, &alarm_vec, (struct sigvec *)0); } #else INIT_SIG(SIGALRM, "SIGALRM", sigalrm_catcher, catgets(elm_msg_cat, ElmSet, ElmSigDescripAlrm, "Alarm Clock")); #endif INIT_SIG(SIGPIPE, "SIGPIPE", sigpipe_catcher, catgets(elm_msg_cat, ElmSet, ElmSigDescripPipe, "Write to Pipe")); #ifdef SIGTSTP INIT_SIG(SIGTSTP, "SIGTSTP", sigtstp_catcher, catgets(elm_msg_cat, ElmSet, ElmSigDescripTstp, "Stop from Terminal")); INIT_SIG(SIGCONT, "SIGCONT", sigcont_catcher, catgets(elm_msg_cat, ElmSet, ElmSigDescripCont, "Continue Stopped Process")); #endif #ifdef SIGWINCH INIT_SIG(SIGWINCH,"SIGWINCH",sigwinch_catcher, catgets(elm_msg_cat, ElmSet, ElmSigDescripWinch, "Window Size Change")); #endif for (i = 0 ; i < NSIG ; ++i) { char buf[64]; if (signame[i] == NULL) { sprintf(buf, "SIGNAL %d", i); signame[i] = safe_strdup(buf); sprintf(buf, "Signal Number %d", i); sigdescr[i] = safe_strdup(buf); } } #ifdef SIGTSTP mssg_sigtstp = catgets(elm_msg_cat, ElmSet, ElmStoppedUseFGToReturn, "\n\nStopped. Use \"fg\" to return to ELM\n\n"); mssg_sigcont = catgets(elm_msg_cat, ElmSet, ElmBackInElmRedraw, "\nBack in ELM. (You might need to explicitly request a redraw.)\n\n"); #endif } static SIGHAND_TYPE bailout_handler(sig) int sig; { /* * This routine does lots of things that are dangerous to perform * in a signal hander. Since, however, we are about to exit we * probably can get away with it. */ dprint(1, (debugfile, "\n\n** Received %s **\n\n", signame[sig])); ShutdownTerm(); error1("Received %s signal!", sigdescr[sig]); switch (sig) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGTERM: leave(LEAVE_ERROR | LEAVE_KEEP_EDITTMP); case SIGUSR1: /* leave WITHOUT moving read messages to =received */ while (leave_mbox(/*resync*/TRUE, /*quit*/TRUE, /*prompt*/FALSE) == -1) newmbox(curr_folder.filename, TRUE); /* new mail has arrived */ leave(LEAVE_NORMAL); case SIGUSR2: /* leave WITH moving read messages to =received */ while (leave_mbox(/*resync*/FALSE, /*quit*/TRUE, /*prompt*/FALSE) == -1) newmbox(curr_folder.filename, TRUE); /* new mail has arrived */ leave(LEAVE_NORMAL); case SIGILL: case SIGFPE: #ifdef SIGBUS case SIGBUS: #endif case SIGSEGV: default: leave(LEAVE_EMERGENCY); } fprintf(stderr, "\r\n\nSignal handling failed!!! Bailing out!\r\n"); exit(1); } static SIGHAND_TYPE sigalrm_catcher(sig) int sig; { signal(SIGALRM, sigalrm_catcher); if (GetKey_active) { #ifdef HASSIGHOLD sigrelse(SIGALRM); #endif LONGJMP(GetKey_jmpbuf, sig); } } static SIGHAND_TYPE sigpipe_catcher(sig) int sig; { extern int pipe_abort; /*DANGEROUS*/ dprint(2, (debugfile, "\n\n** Received %s **\n\n", signame[sig])); signal(SIGPIPE, sigpipe_catcher); pipe_abort = TRUE; } #ifdef SIGTSTP /*{*/ /* state passed between SIGTSTP and SIGCONT handlers */ static int save_term_status; static SIGHAND_TYPE sigtstp_catcher(sig) int sig; { /*DANGEROUS*/ dprint(1, (debugfile, "\n\n** Received %s **\n\n", signame[sig])); signal(SIGTSTP, SIG_DFL); save_term_status = Term.status; /* We probably shouldn't be doing stdio in a signal handler. */ Raw(OFF); EnableFkeys(OFF); /* * write() is ok in signal handler. This might get jumbled about * with any buffered stdio data, but if the guy did a ^Z in the * middle of display output things are going to be jumbled about anyway. */ write(STDERR_FILENO, mssg_sigtstp, strlen(mssg_sigtstp)); kill(0, SIGSTOP); } static SIGHAND_TYPE sigcont_catcher(sig) int sig; { /*DANGEROUS*/ dprint(1, (debugfile, "\n\n** Received %s **\n\n", signame[sig])); /* * This flag is set when either a SIGWINCH or SIGCONT is * received. When a calling routine detects this flag is * set, it should call ResizeScreen() and then fully redraw * the display. */ caught_screen_change_sig = TRUE; signal(SIGCONT, sigcont_catcher); signal(SIGTSTP, sigtstp_catcher); write(STDERR_FILENO, mssg_sigcont, strlen(mssg_sigcont)); /* restore tty state */ if (save_term_status & TERM_IS_RAW) Raw(ON); if (save_term_status & TERM_IS_FKEY) EnableFkeys(ON); if (GetKey_active) { #ifdef HASSIGHOLD sigrelse(SIGTSTP); sigrelse(SIGCONT); #endif LONGJMP(GetKey_jmpbuf, sig); } } #endif /*}SIGTSTP*/ #ifdef SIGWINCH /*{*/ static SIGHAND_TYPE sigwinch_catcher(sig) int sig; { /* * This flag is set when either a SIGWINCH or SIGCONT is * received. When a calling routine detects this flag is * set, it should call ResizeScreen() and then fully redraw * the display. */ caught_screen_change_sig = TRUE; signal(SIGWINCH, sigwinch_catcher); if (GetKey_active) { #ifdef HASSIGHOLD sigrelse(SIGWINCH); #endif LONGJMP(GetKey_jmpbuf, sig); } } #endif /*}SIGWINCH*/