/*
 * Restart
 * Author: Linh Ngo (Swiftest@Copperdiku)
 * Date : 4/10/92
 * Restarts dmserver in the event of a crash. Only root and group
 * dmserver should have access to run it.
 *
 * Restart also performs a copy-over (copy new files from working
 * directory to /usr/games/diku directory) if given the copyover flag
 *
 * Should be setuid, and owned by user root, and group dmserver like this:
 *
 * -rws--x---  1 root     dmserver    51539 Apr 10 20:15 restart*
 *
 * Restart will also redirect stderr into the SYSLOG file and
 * do a chdir() to the /usr/games/diku directory so we don't have
 * to define the library path like before.
 *
 * Define DEBUG when testing as we don't want to corrupt the real
 * data files, or just do a kill -9 pid so that the autosave is not
 * invoked.
 *
 * Define NO_STRDUP if the library call strdup() is missing.
 *
 * TO DO:
 * 1. zero out the IFS environment flag (or change it to space? colon?)
 * This for security measures (needed for older shells).
 *
 * ----------
 * CHANGE LOG
 * ----------
 * 6/2 Added chdir() so that we don't have to define the library path
 * 9/17 Added copy-over capability with copyover flag
 */

#include <stdio.h>	/* printf(), etc. */
#include <string.h>	/* for strdup(), etc. */
#include <pwd.h>
#include <ctype.h>	/* for isnum() */

#define CRASH_SCRIPT	"scripts/crash.csh"
#define INSTALLFILE	"scripts/diku.install"
#define MIN_PORT	4000	/* port must be equal or higher than this */

#if !defined(DEBUG)

#define CHDIR		"<path to run mud from>"
#define BINFULL		"<path to run mud from>/dmserver"
#define BINSHORT	"dmserver"
#define SYSLOG		"<path to run mud from>/syslog"
#define DEFAULT_PORT	"4000"	/* No port specified defaults to port 4000 */

#else /* DEBUG */

#define LIBPATH		"./lib"
#define BINFULL		"dmserver"
#define BINSHORT	"dmserver"
#define SYSLOG		"syslogtest"
#define DEFAULT_PORT	"4444"

#endif /* DEBUG */

#ifdef NO_STRDUP
char *
strdup( char *str)
{
	char *tmp = (char*)malloc(strlen(str)+1);

	if(tmp == (char*)0 ) {
		perror(str), exit(1);
	}
	strcpy(tmp, str);
	return tmp;
}
#endif /* NO_STRDUP */

main(int argc, char **argv)
{
	int copyover = 0;	/* 0 == restart the mud, 1 == copyover */
	char *port;
	int ruid, euid;
	int pid;
	struct passwd *pswd;

	/* Check args */

#ifdef DEBUG
	printf("DEBUG flag set\n");
#endif

	if(argc == 1){
		port = strdup( DEFAULT_PORT );
	} else if(argc==2 ){
		if( !strcmp( argv[1], "copyover") ){
			copyover = 1;
		} else {
			port = strdup(argv[1]);
			if( atoi(port) < MIN_PORT ){
				fprintf(stderr, "Error: Port argument [%s] must be greater than or equal to 4000\n",port);
				exit(-1);
			}
		}
	} else {
		fprintf(stderr,"usage: restart [ port | copyover ]\n");
		exit(1);
	}

	if( !copyover ) {
		printf("Restart: Selected port number is %s\n", port);
	} else {
		printf("Restart: Attempting copyover\n");
	}

	/* Fork to go into the background */

	if((pid=fork())== -1) {
		perror("fork");
		exit(1);
	} else if(pid!=0){	/* Parent dies */
		exit(0);
	}
	/* Child continues */
		
	ruid = getuid();
	euid = geteuid();
	pswd = getpwuid(ruid);

	/* 
	 * This sets the real user id to be the effective one
	 * so we are really root. This is required to run dmserver.
	 */

	if (setreuid(euid, euid) != 0 ) {
		perror("setreuid");
		exit(1);
	}

	/*
	 * Run CRASH_SCRIPT to clean up the log files first
	 */

	switch( pid=fork() ){
	case -1:
		perror("fork");
		exit(1);
	case 0:
		/* child executes script */
		fprintf(stderr,"Restart: Executing %s\n", CRASH_SCRIPT);
		execl(CRASH_SCRIPT, CRASH_SCRIPT, (char*)0 );
		perror(CRASH_SCRIPT);	/* never get here if works */
		exit(1);
	default: /* parent */
		wait();	/* parent waits for shell script to finish */
		fprintf(stderr,"Restart: Parent done waiting for crash_script\n");
		break;
	}

	/* If we used the copyover switch, then execute the
	 * diku.install Bourne script.
	 */
	if( copyover ) {
		fprintf(stderr,"Copyover: executing %s\n",INSTALLFILE);
		execl(INSTALLFILE, INSTALLFILE, (char*)0);
		perror("execl installfile");
		exit(1);
	}

	/* Change directory to CHDIR */

	fprintf(stderr,"Restart: changing directory to %s\n",CHDIR);
	if( chdir(CHDIR) == -1 ) {
		perror(CHDIR);
		exit(1);
	}

	/* Append stderr to SYSLOG so we can continue logging */

	if(freopen(SYSLOG, "w", stderr) == (FILE*)0){
		perror(SYSLOG);
		exit(1);
	}

	/* Execute our binary file securely (hopefully) */

	execl(BINFULL, BINSHORT, port, (char*)0 );
	perror("execl dmserver");
	exit(1);
}