/*
* 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);
}