/* main.c     main entrypoint
 *
 * $Id: main.c,v 1.5 1995/03/19 17:21:06 bdale Exp $
 *
 * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
 * This software may be freely used, distributed, or modified, providing
 * this header is not removed.
 *
 */

#ifdef LINUX
#define __USE_BSD_SIGNAL
#endif
#include "ipip.h"
#include "version.h"
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <setjmp.h>
#include <syslog.h>
#include <unistd.h>
#include <stdlib.h>

#ifdef LINUX
sigjmp_buf restart_env;
#else
jmp_buf restart_env;
#endif
static void hupper(int sig);
jmp_buf term_env;
static void terminator();
int stat_interval;
int no_timestamp;
int debugd;
int debugt;

char progname[32];
char *configfile, *routefile;
int version_only;

int
main(argc, argv)
	int argc;
	char *argv[];
{
	int n, i, oops, help;
	FILE *pid_file;

	debugd = 0;
	debugt = 0;
	help = 0;
	no_timestamp = 0;
	version_only = 0;
	routefile = DEFAULTROUTE;
	configfile = DEFAULTCONFIG;
	stat_interval = -1; 		/* print at exit only */

	/* let's use syslogd for all this junk... */
	openlog("ipip", LOG_PID | LOG_NOWAIT, IPIP_SYSLOG);

	(void)sprintf(progname,"ipip[%d]: ",getpid());

	/* log our pid so that we can get kicked during log rotation */
	if(!(pid_file = fopen(PIDLOG,"w"))) {
		syslog(LOG_CRIT, "could not log pid to file %s",PIDLOG);
        	exit(1);
	}
	fprintf(pid_file,"%d\n",getpid());
	fclose(pid_file);

	/* Process arguments */
	oops = 0;
	for(i=1;((i<argc)&&(oops==0));i++){
		if(strcmp(argv[i],"-c")==0){		
			i++;
			if(i<argc)configfile = argv[i];
			else oops++;
		} else if(strcmp(argv[i],"-r")==0){
			i++;
			if(i<argc)routefile = argv[i];
			else oops++;
		} else if(strcmp(argv[i],"-s")==0){
			i++;
			if(i<argc)stat_interval = atoi(argv[i]) * 60;
			else oops++;
		} else if(strcmp(argv[i],"-d")==0){
			debugd++;
		} else if(strcmp(argv[i],"-t")==0){
			debugt++;
		} else if(strcmp(argv[i],"-v")==0){
			version_only++;
		} else if(strcmp(argv[i],"-np")==0){
			progname[0] = '\0';
		} else if(strcmp(argv[i],"-nts")==0){
			no_timestamp++;
		} else if(strcmp(argv[i],"-help")==0){
			help++;
		} else oops++;
	}

	if(oops){
		(void)fprintf(stderr,"%sUsage: %s [-help] [-c <configfile>] [-r <routefile>] [-s <minutes>] [-np] [-nts] [-t] [-d] [-v]\n",
			progname,argv[0]);
		(void)printf("%sexit (syntax error)\n",progname);
		exit(1);
	}

	if(help){
		(void)printf("%s Options are:\n",progname);
		(void)printf("%s  -help      Print this summary of options\n",
			progname);
		(void)printf("%s  -v         Print just the version number and exit\n",
			progname);
		(void)printf("%s  -c file    Use the supplied filename as the config file\n",
			progname);
		(void)printf("%s  -r file    Use the supplied filename as the route file\n",
			progname);
		(void)printf("%s  -s n       Report statistics every n minutes\n",
			progname);
		(void)printf("%s  -np        Don't print the ipip[1234]: prefix\n",
			progname);
		(void)printf("%s  -nts       Don't include a timestamp in the statistics\n",
			progname);
		(void)printf("%s  -t         Turn on tracing of incoming packets\n",
			progname);
		(void)printf("%s  -d         Print out some debugging information\n",
			progname);
		exit(0);
	}

#ifdef NO_STRTOUL
	if(strtol("0xffffffff",NULL,0)!=0xffffffff){
		(void)fprintf(stderr,"%sAssertion failed: this program cannot properly read\n",progname);
		(void)fprintf(stderr,"%sunsigned numbers from the config files.  See the\n",progname);
		(void)fprintf(stderr,"%ssource code for details.  ABORTED.\n",progname);
		(void)printf("%sexit (program error)\n",progname);
		exit(2);
	}
#endif

	if(setjmp(term_env)!=0){
		send_stats(1);		/* force print of statistics */
		syslog(LOG_CRIT, "exit (killed)");
		exit(0);
	}

	(void)signal(SIGTERM, terminator);
	(void)signal(SIGINT, terminator);

	/* Say hello to the world */
	syslog(LOG_DEBUG,"version %s Copyright 1991, Michael Westerhof.",VERS);

	if(version_only!=0)exit(0);

	/* Read the configuration file */

	if(read_config(configfile)<0){
		syslog(LOG_CRIT, "exit (config file error)");
		exit(1);
	}

	/* Here's where we restart when we get a SIGHUP signal */
#ifdef LINUX
	if(sigsetjmp(restart_env,1)==0){
#else
	if(setjmp(restart_env,1)==0){
#endif
		(void)signal(SIGHUP, hupper);
	}

	/* make sure to close and reopen the log channel if we get a SIGHUP,
	   since it might mean the log file was just rotated!  */
	closelog();
	openlog("ipip", LOG_PID | LOG_NOWAIT, IPIP_SYSLOG);

	/* Read the route tables */

	if(read_routes(routefile)<0){
		syslog(LOG_CRIT, "exit (routes file error)");
		exit(1);
	}

	/* flush the stdout buffer before we start to run */
/*	(void)fflush(stdout);	*/

	/* And run it! */

	n = run_it();
	if(n<0){
		syslog(LOG_CRIT, "exit (I/O error)");
		exit(1);
	}

	/* Should never return this way... but stuff happens... */
	send_stats(1);
	syslog(LOG_CRIT, "exit (no error code?)");
	exit(0);
}

static void
hupper(int sig)
{
	syslog(LOG_DEBUG, "SIGHUP received");
#ifdef LINUX
	siglongjmp(restart_env, 1);
#else
	longjmp(restart_env, 1);
#endif
}

static void
terminator()
{
	longjmp(term_env, 1);
}
