#ifndef lint
static char *RCSid = "$Header: main.c,v 1.14 90/04/13 12:27:39 mr-frog Exp $";
#endif /* not lint */

/*
 * main.c
 *
 * main command loop and initialization
 * for empire login server
 *
 * Dave Pare, 1986
 */

#include "misc.h"
#include "bit.h"
#include "proto.h"
#include "login.h"
#include "file.h"
#include "io_mask.h"

#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#ifndef SIGCHLD
#define SIGCHLD SIGCLD
#endif

char	*program = "login";

int	(*leprfunc)();		/* logerror pr function, == NULL */

main()
{
	extern	char loginport[];
	extern	cd_new();
	int	cleanchild();
	extern	int errno;
	struct	sockaddr_in sin;
	struct	servent *sp;
	int	s;
	short	port;
	int	val;

#ifndef DEBUG
	disassoc();
#endif
	lo_init();
	cd_init();
	io_init();
	(void) signal(SIGCHLD, cleanchild);
	(void) signal(SIGINT, SIG_IGN);
#ifdef SIGTSTP
	(void) signal(SIGTSTP, SIG_IGN);
#endif
	(void) signal(SIGHUP, SIG_IGN);
#ifdef notdef
	setfdtablesize(32, 256);
#endif
	sp = getservbyname("empire", "tcp");
	if (sp == 0)
		port = htons(atoi(loginport));
	else
		port = sp->s_port;
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = port;
	sin.sin_family = AF_INET;
	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		logerror("inet socket create");
		exit(1);
	}
	val = 1;
	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
		logerror("inet socket setsockopt SO_REUSEADDR");
		exit(1);
	}
	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
		logerror("inet socket bind");
		exit(1);
	}
	if (listen(s, 5) < 0) {
		logerror("inet socket listen");
		exit(1);
	}
	(void) io_open(s, IO_READ|IO_NEWSOCK, 0, cd_new, 0);
	ef_open(EF_NATION, O_RDONLY, EFF_MEM);
	logerror("server started, pid %d", getpid());
	while (1) {
		if (io_select(0) <= 0) {
			if (errno == EINTR) {
				errno = 0;
				continue;
			}
			logerror("main loop select; terminating");
			break;
		}
		io_flush();
	}
	close(s);
}

int
cleanchild()
{
	extern	char *signame();
#ifdef linux
	int	w;
#else
	union	wait w;
#endif
	struct	login *lp;
	int	pid;

	while ((pid = wait3(&w, WNOHANG, (struct rusage *)0)) > 0) {
		if ((lp = lo_find(pid)) == 0) {
			logerror("got sigchld from a non-user child (%d)", pid);
		} else
			lo_delete(lp);
#ifdef linux
		if (WTERMSIG(w))
#else
		if (w.w_termsig)
#endif
			logerror("child terminated on signal; %s%s",
#ifdef linux
				signame(WTERMSIG(w)),
				WCOREDUMP(w) ? " (core dumped)" : "");
		else if (WEXITSTATUS(w))
			logerror("child exited: return %d", WEXITSTATUS(w));
#else
				signame(w.w_termsig),
				w.w_coredump ? " (core dumped)" : "");
		else if (w.w_retcode)
			logerror("child exited: return %d", w.w_retcode);
#endif
	}
#ifdef sys5
	(void) signal(SIGCHLD, cleanchild);
#endif
	return 0;
}
