/
From jgoodwin@expert.cc.purdue.edu Tue Apr  8 22:16:20 1997
Date: Sun, 2 Mar 1997 22:34:14 -0500 (EST)
From: Walter Goodwin <jgoodwin@expert.cc.purdue.edu>
To: erwin@andreasen.org
Subject: Re: Copyover Patch completed for stock 1.02


diff -u dist/src/comm.c tmp/src/comm.c
--- dist/src/comm.c	Sun Mar  2 20:54:50 1997
+++ tmp/src/comm.c	Sun Mar  2 20:41:34 1997
@@ -67,6 +67,7 @@
 char		    str_boot_time[MAX_INPUT_LENGTH];
 char		    lastplayercmd[MAX_INPUT_LENGTH*2];
 time_t		    current_time;	/* Time of this pulse		*/
+int                 port;               /* Port number to be used       */
 int		    control;		/* Controlling descriptor	*/
 int		    control2;		/* Controlling descriptor #2	*/
 int		    conclient;		/* MUDClient controlling desc	*/
@@ -111,12 +112,10 @@
 
 void	mail_count		args( ( CHAR_DATA *ch ) );
 
-
-
 int main( int argc, char **argv )
 {
     struct timeval now_time;
-    int port;
+    bool fCopyOver = !TRUE;
 
     /*
      * Memory debugging if needed.
@@ -199,18 +198,32 @@
 	    fprintf( stderr, "Port number must be above 1024.\n" );
 	    exit( 1 );
 	}
-    }
+
+    if (argv[2] && argv[2][0])
+      {
+          fCopyOver = TRUE;
+          control = atoi(argv[3]);
+          control2 = atoi(argv[4]);
+          conclient = atoi(argv[5]);
+          conjava = atoi(argv[6]);
+      }
+    else
+          fCopyOver = FALSE;
+   } 
 
     /*
      * Run the game.
      */
     log_string("Booting Database");
-    boot_db( );
+    boot_db(fCopyOver);
     log_string("Initializing socket");
-    control  = init_socket( port   );
-    control2 = init_socket( port+1 );
-    conclient= init_socket( port+10);
-    conjava  = init_socket( port+20);
+    if (!fCopyOver) /* We have already the port if copyover'ed */
+     {
+        control = init_socket (port);
+        control2 = init_socket( port+1 );
+        conclient= init_socket( port+10);
+        conjava  = init_socket( port+20);
+     }
     sprintf( log_buf, "Realms of Despair ready on port %d.", port );
     log_string( log_buf );
     game_loop( );
@@ -481,7 +494,6 @@
 			    continue;
 			}
 		}
-
 		/* IDENT authentication */
 	        if ( ( d->auth_fd == -1 ) && ( d->atimes < 20 ) 
 		&& !str_cmp( d->user, "unknown" ) )
@@ -644,6 +656,25 @@
     return;
 }
 
+void init_descriptor( DESCRIPTOR_DATA *dnew, int desc)
+{
+    dnew->next		= NULL;
+    dnew->descriptor	= desc;
+    dnew->connected	= CON_GET_NAME;
+    dnew->outsize	= 2000;
+    dnew->idle		= 0;
+    dnew->lines		= 0;
+    dnew->scrlen	= 24;
+    dnew->user		= STRALLOC("unknown");
+    dnew->auth_fd	= -1;
+    dnew->auth_inc	= 0;
+    dnew->auth_state	= 0;
+    dnew->newstate	= 0;
+    dnew->prevcolor	= 0x07;
+
+    CREATE( dnew->outbuf, char, dnew->outsize );
+}
+
 
 void new_descriptor( int new_desc )
 {
@@ -690,24 +721,11 @@
     }
     if ( check_bad_desc( new_desc ) )
       return;
-
     CREATE( dnew, DESCRIPTOR_DATA, 1 );
-    dnew->next		= NULL;
-    dnew->descriptor	= desc;
-    dnew->connected	= CON_GET_NAME;
-    dnew->outsize	= 2000;
-    dnew->idle		= 0;
-    dnew->lines		= 0;
-    dnew->scrlen	= 24;
-    dnew->port		= ntohs( sock.sin_port );
-    dnew->user 		= STRALLOC("unknown");
-    dnew->auth_fd	= -1;
-    dnew->auth_inc	= 0;
-    dnew->auth_state	= 0;
-    dnew->newstate	= 0;
-    dnew->prevcolor	= 0x07;
 
-    CREATE( dnew->outbuf, char, dnew->outsize );
+    init_descriptor(dnew, desc );
+    dnew->port = ntohs(sock.sin_port);
+
 
     strcpy( buf, inet_ntoa( sock.sin_addr ) );
     sprintf( log_buf, "Sock.sinaddr:  %s, port %hd.",
@@ -2446,7 +2464,19 @@
     send_to_pager(buf, ch);
 }
 
+/*  From Erwin  */
+
+void log_printf(char *fmt, ...)
+{
+  char buf[MAX_STRING_LENGTH*2];
+  va_list args;
+
+  va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  va_end(args);
 
+  log_string(buf);
+}
 
 char *obj_short( OBJ_DATA *obj )
 {
@@ -3128,3 +3158,169 @@
   }
   return ret;
 }
+
+/*  Warm reboot stuff, gotta make sure to thank Erwin for this :) */
+
+void do_copyover (CHAR_DATA *ch, char * argument)
+{
+  FILE *fp;
+  DESCRIPTOR_DATA *d, *d_next;
+  char buf [100], buf2[100], buf3[100], buf4[100], buf5[100];
+
+  fp = fopen (COPYOVER_FILE, "w");
+
+  if (!fp)
+   {
+      send_to_char ("Copyover file not writeable, aborted.\n\r",ch);
+      log_printf ("Could not write to copyover file: %s", COPYOVER_FILE);
+      perror ("do_copyover:fopen");
+      return;
+   }
+
+    /* Consider changing all saved areas here, if you use OLC */
+
+    /* do_asave (NULL, ""); - autosave changed areas */
+
+
+    sprintf (buf, "\n\r *** COPYOVER by %s - please remain seated!\n\r", ch->name);
+     /* For each playing descriptor, save its state */
+    for (d = first_descriptor; d ; d = d_next)
+     {
+       CHAR_DATA * och = CH(d);
+       d_next = d->next; /* We delete from the list , so need to save this */
+       if (!d->character || d->connected != CON_PLAYING) /* drop those logging on */
+         {
+            write_to_descriptor (d->descriptor, "\n\rSorry, we are rebooting."
+               " Come back in a few minutes.\n\r", 0);
+            close_socket (d, FALSE); /* throw'em out */
+          }
+        else
+          {
+             fprintf (fp, "%d %s %s\n", d->descriptor, och->name, d->host);
+             if (och->level == 1)
+               {
+                  write_to_descriptor (d->descriptor, "Since you are level one,"
+                     "and level one characters do not save, you gain a free level!\n\r",
+                      0);
+                  advance_level (och);
+                  och->level++; /* Advance_level doesn't do that */
+               }
+                  save_char_obj (och);
+                  write_to_descriptor (d->descriptor, buf, 0);
+           }
+      }
+        fprintf (fp, "-1\n");
+        fclose (fp);
+
+        /* Close reserve and other always-open files and release other resources */
+        fclose (fpReserve);
+        fclose (fpLOG);
+
+        /* exec - descriptors are inherited */
+
+        sprintf (buf, "%d", port);
+        sprintf (buf2, "%d", control);
+        sprintf (buf3, "%d", control2);
+        sprintf (buf4, "%d", conclient);
+        sprintf (buf5, "%d", conjava);
+
+        execl (EXE_FILE, "smaug", buf, "copyover", buf2, buf3,
+          buf4, buf5, (char *) NULL);
+
+        /* Failed - sucessful exec will not return */
+
+        perror ("do_copyover: execl");
+        send_to_char ("Copyover FAILED!\n\r",ch);
+
+        /* Here you might want to reopen fpReserve */
+        /* Since I'm a neophyte type guy, I'll assume this is
+           a good idea and cut and past from main()  */
+
+        if ( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
+         {
+           perror( NULL_FILE );
+           exit( 1 );
+         }
+        if ( ( fpLOG = fopen( NULL_FILE, "r" ) ) == NULL )
+         {
+           perror( NULL_FILE );
+           exit( 1 );
+         }
+
+}
+
+/* Recover from a copyover - load players */
+void copyover_recover ()
+{
+  DESCRIPTOR_DATA *d;
+  FILE *fp;
+  char name [100];
+  char host[MAX_STRING_LENGTH];
+  int desc;
+  bool fOld;
+
+  log_string ("Copyover recovery initiated");
+
+  fp = fopen (COPYOVER_FILE, "r");
+
+  if (!fp) /* there are some descriptors open which will hang forever then ? */
+        {
+          perror ("copyover_recover:fopen");
+          log_string("Copyover file not found. Exitting.\n\r");
+           exit (1);
+        }
+
+  unlink (COPYOVER_FILE); /* In case something crashes
+                              - doesn't prevent reading */
+  for (;;)
+   {
+     fscanf (fp, "%d %s %s\n", &desc, name, host);
+     if (desc == -1)
+       break;
+
+        /* Write something, and check if it goes error-free */
+     if (!write_to_descriptor (desc, "\n\rRestoring from copyover...\n\r", 0))
+       {
+         close (desc); /* nope */
+         continue;
+        }
+
+      CREATE(d, DESCRIPTOR_DATA, 1);
+      init_descriptor (d, desc); /* set up various stuff */
+
+      d->host = STRALLOC( host );
+
+      LINK( d, first_descriptor, last_descriptor, next, prev );
+      d->connected = CON_COPYOVER_RECOVER; /* negative so close_socket
+                                              will cut them off */
+
+        /* Now, find the pfile */
+
+      fOld = load_char_obj (d, name, FALSE);
+
+      if (!fOld) /* Player file not found?! */
+       {
+          write_to_descriptor (desc, "\n\rSomehow, your character was lost in the copyover sorry.\n\r", 0);
+          close_socket (d, FALSE);
+       }
+      else /* ok! */
+       {
+          write_to_descriptor (desc, "\n\rCopyover recovery complete.\n\r",0);
+
+           /* Just In Case,  Someone said this isn't necassary, but _why_
+              do we want to dump someone in limbo? */
+           if (!d->character->in_room)
+                d->character->in_room = get_room_index (ROOM_VNUM_TEMPLE);
+
+           /* Insert in the char_list */
+           LINK( d->character, first_char, last_char, next, prev );
+
+           char_to_room (d->character, d->character->in_room);
+           do_look (d->character, "auto noprog");
+           act (AT_ACTION, "$n materializes!", d->character, NULL, NULL, TO_ROOM);
+           d->connected = CON_PLAYING;
+       }
+
+   }
+   fclose (fp);
+}
+
diff -u dist/src/db.c tmp/src/db.c
--- dist/src/db.c	Thu Feb  6 09:22:48 1997
+++ tmp/src/db.c	Thu Feb 27 15:06:32 1997
@@ -294,7 +294,7 @@
 /*
  * Big mama top level function.
  */
-void boot_db( void )
+void boot_db( bool fCopyOver )
 {
     sh_int wear, x;
 
@@ -601,6 +601,11 @@
         log_string( "Loading corpses" );
         load_corpses( );
         MOBtrigger = TRUE;
+        if (fCopyOver)
+         {
+          log_string("Running copyover_recover.");
+          copyover_recover();
+         }
     }
 
     /* init_maps ( ); */
diff -u dist/src/mud.h tmp/src/mud.h
--- dist/src/mud.h	Thu Feb  6 09:22:50 1997
+++ tmp/src/mud.h	Sun Mar  2 20:40:49 1997
@@ -336,15 +336,30 @@
 /*
  * Connected state for a channel.
  */
-typedef enum
-{
-  CON_PLAYING,		CON_GET_NAME,		CON_GET_OLD_PASSWORD,
-  CON_CONFIRM_NEW_NAME,	CON_GET_NEW_PASSWORD,	CON_CONFIRM_NEW_PASSWORD,
-  CON_GET_NEW_SEX,	CON_GET_NEW_CLASS,	CON_READ_MOTD,
-  CON_GET_NEW_RACE,	CON_GET_EMULATION,	CON_EDITING,
-  CON_GET_WANT_RIPANSI,	CON_TITLE,		CON_PRESS_ENTER,
-  CON_WAIT_1,		CON_WAIT_2,		CON_WAIT_3,
-  CON_ACCEPTED,         CON_GET_PKILL,		CON_READ_IMOTD
+typedef enum {
+  CON_GET_NAME = -100,
+  CON_GET_OLD_PASSWORD,
+  CON_CONFIRM_NEW_NAME,
+  CON_GET_NEW_PASSWORD,
+  CON_CONFIRM_NEW_PASSWORD,
+  CON_GET_NEW_SEX,
+  CON_GET_NEW_CLASS,
+  CON_READ_MOTD,
+  CON_GET_NEW_RACE,
+  CON_GET_EMULATION,
+  CON_GET_WANT_RIPANSI,
+  CON_TITLE,
+  CON_PRESS_ENTER,
+  CON_WAIT_1,
+  CON_WAIT_2,
+  CON_WAIT_3,
+  CON_ACCEPTED,
+  CON_GET_PKILL,
+  CON_READ_IMOTD,
+  CON_COPYOVER_RECOVER,
+
+  CON_PLAYING = 0,
+  CON_EDITING
 } connection_types;
 
 /*
@@ -2451,6 +2466,7 @@
 #define SET_BIT(var, bit)	((var) |= (bit))
 #define REMOVE_BIT(var, bit)	((var) &= ~(bit))
 #define TOGGLE_BIT(var, bit)	((var) ^= (bit))
+#define CH(d)			((d)->original ? (d)->original : (d)->character)
 
 /*
  * Memory allocation macros.
@@ -3014,6 +3030,7 @@
 DECLARE_DO_FUN(	do_compare	);
 DECLARE_DO_FUN(	do_config	);
 DECLARE_DO_FUN(	do_consider	);
+DECLARE_DO_FUN( do_copyover	);
 DECLARE_DO_FUN( do_council_induct);
 DECLARE_DO_FUN( do_council_outcast);
 DECLARE_DO_FUN( do_councils	);
@@ -3570,8 +3587,11 @@
 #define USAGE_FILE	SYSTEM_DIR "usage.txt"    /* How many people are on 
  						     every half hour - trying to
 						     determine best reboot time */
+#define COPYOVER_FILE	SYSTEM_DIR "copyover.dat" /* for warm reboots	 */
+#define EXE_FILE	"../src/smaug"		  /* executable path	 */
 #define CLASSDIR	"../classes/"
 
+
 /*
  * Our function prototypes.
  * One big lump ... this is every function in Merc.
@@ -3689,8 +3709,10 @@
 void	set_pager_color	args( ( sh_int AType, CHAR_DATA *ch ) );
 void	ch_printf	args( ( CHAR_DATA *ch, char *fmt, ... ) );
 void	pager_printf	args( (CHAR_DATA *ch, char *fmt, ...) );
+void	log_printf	args( (char *fmt, ...) );
 void	act		args( ( sh_int AType, const char *format, CHAR_DATA *ch,
 			    const void *arg1, const void *arg2, int type ) );
+void	copyover_recover	args( (void) );
 
 /* reset.c */
 RD  *	make_reset	args( ( char letter, int extra, int arg1, int arg2, int arg3 ) );
@@ -3701,7 +3723,7 @@
 /* db.c */
 void	show_file	args( ( CHAR_DATA *ch, char *filename ) );
 char *	str_dup		args( ( char const *str ) );
-void	boot_db		args( ( void ) );
+void	boot_db		args( ( bool fCopyOver ) );
 void	area_update	args( ( void ) );
 void	add_char	args( ( CHAR_DATA *ch ) );
 CD *	create_mobile	args( ( MOB_INDEX_DATA *pMobIndex ) );
@@ -4398,3 +4420,4 @@
 
 
 #define GET_ADEPT(ch,sn)    (  skill_table[(sn)]->skill_adept[(ch)->class])
+
Only in dist/src: smaug
diff -u dist/src/tables.c tmp/src/tables.c
--- dist/src/tables.c	Thu Feb  6 09:22:50 1997
+++ tmp/src/tables.c	Thu Feb 27 15:30:48 1997
@@ -211,6 +211,7 @@
 	if ( !str_cmp( name, "do_council_outcast" ))	return do_council_outcast;
 	if ( !str_cmp( name, "do_councils" ))		return do_councils;
 	if ( !str_cmp( name, "do_counciltalk" ))	return do_counciltalk;
+	if ( !str_cmp( name, "do_copyover" ))		return do_copyover;
 	if ( !str_cmp( name, "do_credits" ))		return do_credits;
 	if ( !str_cmp( name, "do_cset" ))		return do_cset;
 	break;
@@ -730,6 +731,7 @@
     if ( skill == do_compare )		return "do_compare";
     if ( skill == do_config )		return "do_config";
     if ( skill == do_consider )		return "do_consider";
+    if ( skill == do_copyover )		return "do_copyover";
     if ( skill == do_council_induct )	return "do_council_induct";
     if ( skill == do_council_outcast )	return "do_council_outcast";
     if ( skill == do_councils )		return "do_councils";