/*
// ColdMUD was created and is copyright 1993, 1994 by Greg Hudson
//
// ColdX is a derivitive work, and is copyright 1995 by the ColdX Project.
// Full copyright information can be found in the file doc/CREDITS
//
// File:        sig.c
// Version:     0.1-5
// Last Edited: 18 May 1995
//
// ---
//
// Coldmud signal handling.
*/

#define _POSIX_SOURCE

#include "config.h"

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "defs.h"
#include "sig.h"
#include "log.h"          /* write_err() */
#include "execute.h"      /* task() */
#include "cmstring.h"     /* string_from_chars() */
#include "data.h"
#include "x.tab.h"
#include "main.h"

void catch_SIGCHLD(int sig);

void uninit_sig(void) {
    signal(SIGFPE,  SIG_DFL);
    signal(SIGILL,  SIG_DFL);
    signal(SIGQUIT, SIG_DFL);
    signal(SIGSEGV, SIG_DFL);
    signal(SIGINT,  SIG_DFL);
    signal(SIGHUP,  SIG_DFL);
    signal(SIGTERM, SIG_DFL);
    signal(SIGALRM, SIG_DFL);
    signal(SIGUSR1, SIG_DFL);
    signal(SIGUSR2, SIG_DFL);
    signal(SIGCHLD, SIG_DFL);
}

void init_sig(void) {
    signal(SIGFPE,  catch_signal);
    signal(SIGILL,  catch_signal);
    signal(SIGQUIT, catch_signal);
#if 0
    signal(SIGSEGV, catch_signal);
#endif
    signal(SIGINT,  catch_signal);
    signal(SIGHUP,  catch_signal);
    signal(SIGTERM, catch_signal);
    signal(SIGALRM, catch_signal);
    signal(SIGUSR1, catch_signal);
    signal(SIGUSR2, catch_signal);
    signal(SIGCHLD, catch_SIGCHLD);
}

void catch_SIGCHLD(int sig) {
    waitpid(-1, NULL, WNOHANG);
#ifdef SYSV /* BSD signals shouldn't need this, could be wrong though */
    signal(SIGCHLD, catch_SIGCHLD);
#endif
}

char *sig_name(int sig) {
    char buf[10];

    switch(sig) {
        case SIGFPE:  return "SIGFPE";
        case SIGILL:  return "SIGILL";
        case SIGQUIT: return "SIGQUIT";
        case SIGSEGV: return "SIGSEGV";
        case SIGINT:  return "SIGINT";
        case SIGHUP:  return "SIGHUP";
        case SIGTERM: return "SIGTERM";
        case SIGALRM: return "SIGALRM";
        case SIGUSR1: return "SIGUSR1";
        case SIGUSR2: return "SIGUSR2";
        default:      return "Unknown";
    }
    return NULL;
}

/* void catch_signal(int sig, int code, struct sigcontext *scp) { */
void catch_signal(int sig) {
    char *sptr;
    String *sigstr;
    Data arg1, arg2;

    sptr = sig_name(sig);
    sigstr = string_from_chars(sptr, strlen(sptr));

    write_err("Caught signal %d: %S", sig, sigstr);

    /* send a message to the system object */
    arg1.type = SYMBOL;
    arg1.u.symbol = ident_get(sig_name(sig));
    arg2.type = STRING;
    arg2.u.str = sigstr;
    task(NULL, SYSTEM_DBREF, signal_id, 2, &arg1, &arg2);

    /* figure out what to do */
    switch(sig) {
        case SIGUSR1:
        case SIGUSR2:
        case SIGHUP:
        case SIGALRM:
            /* let the server do what it wants, don't shutdown */
            break;
        case SIGILL:
        case SIGFPE:
        case SIGSEGV:
            /* lets panic and hopefully dump */
            panic(sig_name(sig));
            break;
        case SIGINT:
        case SIGQUIT:
        case SIGTERM:
        default: /* shutdown nicely */
            if (running) {
                write_err("*** Attempting normal shutdown ***");
                running = 0;
            } else {
                panic(sig_name(sig));
            }
            break;
    }
#ifdef SYSV /* BSD signals shouldn't need this, could be wrong though */
    signal(sig, catch_signal);
#endif
}