#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/server/main.c,v 2.8 1995/10/16 20:31:54 empire Exp $";
#endif

/*
 * main.c
 *
 * Thread and signal initialization
 * for empire server
 *
 * Dave Pare, 1994
 */

#if defined(aix) || defined(linux)
#include <unistd.h>
#endif /* aix or linux */

#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>

#include "misc.h"
#include "nat.h"
#include "file.h"
#include "player.h"
#include "lwp.h"

#ifdef POSIXSIGNALS
void 	panic();
void	shutdwn();
#else
int	panic();
int	shutdwn();
#endif /* POSIXSIGNALS */

s_char	program[] = "server";

extern	void player_accept();
extern	void player_kill_idle();
extern	void update_sched();


main(argc, argv)
	int	argc;
	s_char	**argv;
{
	long	now;
	long	hour[2];
	int	flags = 0;
	int	debug = 0;
	int	op;
	char *config_file = NULL;
	extern s_char *datadir;
	extern char *optarg;
	s_char tbuf[256];
#ifdef POSIXSIGNALS
	struct sigaction act;
#endif /* POSIXSIGNALS */

	while ((op = getopt(argc, argv, "D:de:psh")) != EOF) {
		switch (op) {
		case 'D':
			datadir = optarg;
			break;
		case 'd':
			debug++;
			break;
		case 'e':
			config_file = optarg;
			break;
		case 'p':
			flags |= LWP_PRINT;
			break;
		case 's':
			flags |= LWP_PRINT|LWP_STACKCHECK;
			break;
		case 'h':
		default:
			printf("Usage: %s -d -p -s\n",argv[0]);
			return 0;
		}
	}
	if (config_file == NULL) {
		sprintf (tbuf, "%s/econfig", datadir);
		config_file = tbuf;
	}
	emp_config (config_file);
#ifdef POSIXSIGNALS
	act.sa_flags = SA_SIGINFO;
	sigemptyset (&act.sa_mask);
	if (debug == 0 && flags == 0) {
		disassoc();
		act.sa_handler = shutdwn;
		sigaction (SIGUSR1, &act, NULL);
		sigaction (SIGTERM, &act, NULL);
		act.sa_handler = panic;
		sigaction (SIGBUS, &act, NULL);
		sigaction (SIGSEGV, &act, NULL);
		sigaction (SIGILL, &act, NULL);
		sigaction (SIGFPE, &act, NULL);
	}
	act.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &act, NULL);
#else
	if (debug == 0 && flags == 0) {
		disassoc();
		signal(SIGUSR1, shutdwn);
		signal(SIGTERM, shutdwn);
		signal(SIGBUS, panic);
		signal(SIGSEGV, panic);
		signal(SIGILL, panic);
		signal(SIGFPE, panic);
	}
	signal(SIGPIPE, SIG_IGN);
#endif /* POSIXSIGNALS */
	logerror("------------------------------------------------------");
	logerror("Empire server (pid %d) started", getpid());
	time(&now);
	srandom(now);
	setfdtablesize(32, 256);
	global_init();
	shutdown_init();
	player_init();
	ef_init();
	init_files();
	io_init();
	gamehours(now, hour);
	lwpInitSystem(6, (char **)&player, flags);
	lwpCreate(PP_ACCEPT, player_accept, 8192, flags, "accept",
		"Accept network connections", 0, 0, 0);
	lwpCreate(PP_KILLIDLE, player_kill_idle, 8192, flags, "killIdle",
		"Kills idle player connections", 0, 0, 0);
	lwpCreate(PP_SCHED, update_sched, 8192, flags, "updateSched",
		"Schedules updates to occur", 0, 0, 0);
	lwpReschedule();
	close_files();
	return 0;
}

init_files()
{
	ef_open(EF_NATION, O_RDWR, EFF_MEM);
	ef_open(EF_SECTOR, O_RDWR, EFF_MEM);
	ef_open(EF_SHIP, O_RDWR, EFF_MEM);
	ef_open(EF_PLANE, O_RDWR, EFF_MEM);
	ef_open(EF_LAND, O_RDWR, EFF_MEM);
	ef_open(EF_NEWS, O_RDWR, 0);
	ef_open(EF_LOAN, O_RDWR, 0);
	ef_open(EF_TREATY, O_RDWR, 0);
	ef_open(EF_NUKE, O_RDWR, 0);
	ef_open(EF_POWER, O_RDWR, 0);
	ef_open(EF_TRADE, O_RDWR, 0);
	ef_open(EF_MAP, O_RDWR, EFF_MEM);
	ef_open(EF_BMAP, O_RDWR, EFF_MEM);
}

close_files()
{
	ef_close(EF_NATION);
	ef_close(EF_SECTOR);
	ef_close(EF_SHIP);
	ef_close(EF_PLANE);
	ef_close(EF_LAND);
	ef_close(EF_NEWS);
	ef_close(EF_LOAN);
	ef_close(EF_TREATY);
	ef_close(EF_NUKE);
	ef_close(EF_POWER);
	ef_close(EF_TRADE);
	ef_close(EF_MAP);
	ef_close(EF_BMAP);
}

/* we're going down.  try to close the files at least */
#ifdef POSIXSIGNALS
void
#endif /* POSIXSIGNALS */
panic(sig)
	int	sig;
{
#ifdef POSIXSIGNALS
	struct sigaction act;

	act.sa_flags = 0;
	sigemptyset (&act.sa_mask);
	act.sa_handler = SIG_DFL;
	sigaction (SIGBUS, &act, NULL);
	sigaction (SIGSEGV, &act, NULL);
	sigaction (SIGILL, &act, NULL);
	sigaction (SIGFPE, &act, NULL);
#else
	signal(SIGBUS, SIG_DFL);
	signal(SIGSEGV, SIG_DFL);
	signal(SIGILL, SIG_DFL);
	signal(SIGFPE, SIG_DFL);
#endif /* POSIXSIGNALS */
	logerror("server received fatal signal %d", sig);
	log_last_commands();
	close_files();
	_exit(0);
}

/* got a USR1 -- a shutdown */
#ifdef POSIXSIGNALS
void
#endif /* POSIXSIGNALS */
shutdwn(sig)
	int	sig;
{
	struct player *p;
	time_t	now;
	int	running = 0;

	for (p = player_next(0); p != 0; p = player_next(p)) {
		if (p->state != PS_PLAYING)
			continue;
		pr_flash(p, "Server shutting down...\n");
		if (p->command) {
			p->state = PS_SHUTDOWN;
			pr_flash(p, "Shutdown aborting command\n");
			p->aborted++;
			lwpWakeupFd(p->proc);
			running++;
		}
	}
	time(&now);
	if (running) {
		/* sleep a few, wait for aborts to take effect */
		lwpSleepUntil(now + 2);
	}
	for (p = player_next(0); p != 0; p = player_next(p)) {
		p->state = PS_KILL;
		p->aborted++;
		lwpTerminate(p->proc);
		p = player_delete(p);
	}
	if (sig)
		logerror("Server shutting down on signal %d", sig);
	else
		logerror("Server shutting down at Deity's request");
	close_files();
	_exit(0);
}
