/
--- act.wizard.c	1997/07/16 19:39:56	1.1
+++ act.wizard.c	1997/07/17 18:53:30
@@ -2956,3 +2956,74 @@ ACMD (do_syslog)
 	sprintf (buf, "Your syslog is now %s.\r\n", logtypes[tp]);
 	send_to_char (buf, ch);
 }
+
+extern int mother_desc, port;
+extern FILE *player_fl;
+void Crash_rentsave(struct char_data * ch, int cost);
+
+#define EXE_FILE "bin/circle" /* maybe use argv[0] but it's not reliable */
+
+/* (c) 1996-97 Erwin S. Andreasen <erwin@andreasen.org> */
+ACMD(do_copyover)
+{
+	FILE *fp;
+	struct descriptor_data *d, *d_next;
+	char buf [100], buf2[100];
+	
+	fp = fopen (COPYOVER_FILE, "w");
+	
+	if (!fp)
+	{
+		send_to_char ("Copyover file not writeable, aborted.\n\r",ch);
+		return;
+	}
+	
+	/* Consider changing all saved areas here, if you use OLC */
+	sprintf (buf, "\n\r *** COPYOVER by %s - please remain seated!\n\r", GET_NAME(ch));
+	
+	/* For each playing descriptor, save its state */
+	for (d = descriptor_list; d ; d = d_next)
+	{
+		struct char_data * och = d->character;
+		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");
+			close_socket (d); /* throw'em out */
+		}
+		else
+		{
+			fprintf (fp, "%d %s %s\n", d->descriptor, GET_NAME(och), d->host);
+
+            /* save och */
+            Crash_rentsave(och,0);
+            save_char(och, och->in_room);
+			write_to_descriptor (d->descriptor, buf);
+		}
+	}
+	
+	fprintf (fp, "-1\n");
+	fclose (fp);
+	
+	/* Close reserve and other always-open files and release other resources */
+
+    fclose(player_fl);
+    
+	/* exec - descriptors are inherited */
+	
+	sprintf (buf, "%d", port);
+    sprintf (buf2, "-C%d", mother_desc);
+
+    /* Ugh, seems it is expected we are 1 step above lib - this may be dangerous! */
+    chdir ("..");
+
+	execl (EXE_FILE, "circle", buf2, buf, (char *) NULL);
+
+	/* Failed - sucessful exec will not return */
+	
+	perror ("do_copyover: execl");
+	send_to_char ("Copyover FAILED!\n\r",ch);
+	
+    exit (1); /* too much trouble to try to recover! */
+}
--- comm.c	1997/07/16 19:39:56	1.1
+++ comm.c	1997/07/16 22:18:38
@@ -76,6 +76,10 @@ extern int auto_save;			/* see config.c 
 extern int autosave_time;		/* see config.c */
 struct timeval null_time;		/* zero-valued time structure */
 
+static bool fCopyOver;          /* Are we booting in copyover mode? */
+int  mother_desc;        /* Now a global */
+int     port;
+
 /* functions in this file */
 int     get_from_q (struct txt_q *queue, char *dest, int *aliased);
 void    init_game (int port);
@@ -97,7 +101,7 @@ void    record_usage (void);
 void    make_prompt (struct descriptor_data *point);
 void    check_idle_passwords (void);
 void    heartbeat (int pulse);
-
+void    init_descriptor (struct descriptor_data *newd, int desc);
 
 /* extern fcnts */
 void    boot_db (void);
@@ -134,7 +138,6 @@ void    gettimeofday (struct timeval *t,
 
 int     main (int argc, char **argv)
 {
-	int     port;
 	char    buf[512];
 	int     pos = 1;
 	char   *dir;
@@ -146,6 +149,11 @@ int     main (int argc, char **argv)
 	{
 		switch (*(argv[pos] + 1))
 		{
+			case 'C': /* -C<socket number> - recover from copyover, this is the control socket */
+				fCopyOver = TRUE;
+				mother_desc = atoi(argv[pos]+2);
+				break;
+				
 			case 'd':
 				if (*(argv[pos] + 2))
 					dir = argv[pos] + 2;
@@ -228,20 +236,110 @@ int     main (int argc, char **argv)
 	return 0;
 }
 
+int enter_player_game(struct descriptor_data *d);
+
+/* Reload players after a copyover */
+void copyover_recover()
+{
+	struct descriptor_data *d;
+	FILE *fp;
+	char host[1024];
+    struct char_file_u tmp_store;
+	int desc, player_i;
+    bool fOld;
+    char name[MAX_INPUT_LENGTH];
+	
+	log ("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 ("Copyover file not found. Exitting.\n\r");
+		exit (1);
+	}
+
+	unlink (COPYOVER_FILE); /* In case something crashes - doesn't prevent reading	*/
+	
+	for (;;)
+    {
+        fOld = TRUE;
+		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 a new descriptor */
+        CREATE (d, struct descriptor_data, 1);
+        memset ((char *) d, 0, sizeof (struct descriptor_data));
+		init_descriptor (d,desc); /* set up various stuff */
+		
+		strcpy(d->host, host);
+		d->next = descriptor_list;
+		descriptor_list = d;
+
+        d->connected = CON_CLOSE;
+	
+		/* Now, find the pfile */
+		
+        CREATE(d->character, struct char_data, 1);
+        clear_char(d->character);
+        CREATE(d->character->player_specials, struct player_special_data, 1);
+        d->character->desc = d;
+
+        if ((player_i = load_char(name, &tmp_store)) >= 0)
+        {
+            store_to_char(&tmp_store, d->character);
+            GET_PFILEPOS(d->character) = player_i;
+            if (!PLR_FLAGGED(d->character, PLR_DELETED))
+                REMOVE_BIT(PLR_FLAGS(d->character),PLR_WRITING | PLR_MAILING | PLR_CRYO);
+            else
+                fOld = FALSE;
+        }
+        else
+            fOld = FALSE;
+		
+		if (!fOld) /* Player file not found?! */
+		{
+			write_to_descriptor (desc, "\n\rSomehow, your character was lost in the copyover. Sorry.\n\r");
+			close_socket (d);			
+		}
+		else /* ok! */
+		{
+            write_to_descriptor (desc, "\n\rCopyover recovery complete.\n\r");
+            enter_player_game(d);
+            d->connected = CON_PLAYING;
+            look_at_room(d->character, 0);
+		}
+		
+	}
+	
+	fclose (fp);
+}
+
 
 
 /* Init sockets, run game, and cleanup sockets */
 void    init_game (int port)
 {
-	int     mother_desc;
 
 	srandom (time (0));
 
 	log ("Finding player limit.");
 	max_players = get_max_players ();
 
-	log ("Opening mother connection.");
-	mother_desc = init_socket (port);
+	if (!fCopyOver) /* If copyover mother_desc is already set up */
+	{
+		log ("Opening mother connection.");
+		mother_desc = init_socket (port);
+	}
 
 	boot_db ();
 
@@ -250,6 +348,9 @@ void    init_game (int port)
 	signal_setup ();
 #endif
 
+	if (fCopyOver) /* reload players */
+		copyover_recover();
+
 	log ("Entering game loop.");
 
 	game_loop (mother_desc);
@@ -1045,6 +1146,24 @@ void    write_to_output (const char *txt
    *  socket handling                                                  *
    ****************************************************************** */
 
+/* Initialize a descriptor */
+void init_descriptor (struct descriptor_data *newd, int desc)
+{
+    static int last_desc = 0;	/* last descriptor number */
+    
+	newd->descriptor = desc;
+	newd->connected = CON_GET_NAME;
+	newd->idle_tics = 0;
+	newd->wait = 1;
+	newd->output = newd->small_outbuf;
+	newd->bufspace = SMALL_BUFSIZE - 1;
+	newd->next = descriptor_list;
+	newd->login_time = time (0);
+
+	if (++last_desc == 1000)
+		last_desc = 1;
+	newd->desc_num = last_desc;
+}
 
 int     new_descriptor (int s)
 {
@@ -1052,7 +1171,6 @@ int     new_descriptor (int s)
 	int     sockets_connected = 0;
 	unsigned long addr;
 	int     i;
-	static int last_desc = 0;	/* last descriptor number */
 	struct descriptor_data *newd;
 	struct sockaddr_in peer;
 	struct hostent *from;
@@ -1118,19 +1236,7 @@ int     new_descriptor (int s)
 	mudlog (buf2, CMP, LVL_GOD, FALSE);
 #endif
 
-	/* initialize descriptor data */
-	newd->descriptor = desc;
-	newd->connected = CON_GET_NAME;
-	newd->idle_tics = 0;
-	newd->wait = 1;
-	newd->output = newd->small_outbuf;
-	newd->bufspace = SMALL_BUFSIZE - 1;
-	newd->next = descriptor_list;
-	newd->login_time = time (0);
-
-	if (++last_desc == 1000)
-		last_desc = 1;
-	newd->desc_num = last_desc;
+	init_descriptor(newd, desc);
 
 	/* prepend to list */
 	descriptor_list = newd;
--- comm.h	1997/07/16 19:39:56	1.1
+++ comm.h	1997/07/16 21:21:18
@@ -10,6 +10,8 @@
 
 #define NUM_RESERVED_DESCS	8
 
+#define COPYOVER_FILE "copyover.dat"
+
 /* comm.c */
 void    send_to_all (char *messg);
 void    send_to_char (char *messg, struct char_data *ch);
--- db.c	1997/07/16 19:39:56	1.1
+++ db.c	1997/07/16 22:34:45
@@ -609,7 +609,9 @@ void    index_boot (int mode)
 		qsort (help_table, top_of_helpt, sizeof (struct help_index_element), hsort);
 
 		top_of_helpt--;
-	}
+    }
+
+    fclose (index); /* The index file was not closed - deliberate? */
 
 }
 
--- interpreter.c	1997/07/16 19:39:56	1.1
+++ interpreter.c	1997/07/16 22:03:45
@@ -63,6 +63,7 @@ ACMD(do_ban);
 ACMD(do_bash);
 ACMD(do_cast);
 ACMD(do_color);
+ACMD(do_copyover);
 ACMD(do_commands);
 ACMD(do_consider);
 ACMD(do_credits);
@@ -244,6 +245,7 @@ const struct command_info cmd_info[] = {
   { "comb"     , POS_RESTING , do_action   , 0, 0 },
   { "commands" , POS_DEAD    , do_commands , 0, SCMD_COMMANDS },
   { "compact"  , POS_DEAD    , do_gen_tog  , 0, SCMD_COMPACT },
+  { "copyover" , POS_DEAD    , do_copyover , LVL_GRGOD, 0 },
   { "cough"    , POS_RESTING , do_action   , 0, 0 },
   { "credits"  , POS_DEAD    , do_gen_ps   , 0, SCMD_CREDITS },
   { "cringe"   , POS_RESTING , do_action   , 0, 0 },
@@ -1234,6 +1236,46 @@ int perform_dupe_check(struct descriptor
 }
 
 
+/* load the player, put them in the right room - used by copyover_recover too */
+int enter_player_game (struct descriptor_data *d)
+{
+    extern sh_int r_mortal_start_room;
+    extern sh_int r_immort_start_room;
+    extern sh_int r_frozen_start_room;
+    
+    sh_int load_room;
+    int load_result;
+    
+    reset_char(d->character);
+    if (PLR_FLAGGED(d->character, PLR_INVSTART))
+        GET_INVIS_LEV(d->character) = GET_LEVEL(d->character);
+    if ((load_result = Crash_load(d->character)))
+        d->character->in_room = NOWHERE;
+    save_char(d->character, NOWHERE);
+
+    d->character->next = character_list;
+    character_list = d->character;
+    
+    if ((load_room = GET_LOADROOM(d->character)) != NOWHERE)
+        load_room = real_room(load_room);
+    
+    /* If char was saved with NOWHERE, or real_room above failed... */
+    if (load_room == NOWHERE) {
+        if (GET_LEVEL(d->character) >= LVL_IMMORT) {
+            load_room = r_immort_start_room;
+        } else {
+            load_room = r_mortal_start_room;
+        }
+    }
+    
+    if (PLR_FLAGGED(d->character, PLR_FROZEN))
+        load_room = r_frozen_start_room;
+    
+    char_to_room(d->character, load_room);
+
+    return load_result;
+}
+
 
 /* deal with newcomers and other non-playing sockets */
 void nanny(struct descriptor_data *d, char *arg)
@@ -1242,12 +1284,8 @@ void nanny(struct descriptor_data *d, ch
   int player_i, load_result;
   char tmp_name[MAX_INPUT_LENGTH];
   struct char_file_u tmp_store;
-  extern sh_int r_mortal_start_room;
-  extern sh_int r_immort_start_room;
-  extern sh_int r_frozen_start_room;
   extern const char *class_menu;
   extern int max_bad_pws;
-  sh_int load_room;
 
   int load_char(char *name, struct char_file_u *char_element);
   int parse_class(char arg);
@@ -1522,32 +1560,9 @@ void nanny(struct descriptor_data *d, ch
       break;
 
     case '1':
-      reset_char(d->character);
-      if (PLR_FLAGGED(d->character, PLR_INVSTART))
-	GET_INVIS_LEV(d->character) = GET_LEVEL(d->character);
-      if ((load_result = Crash_load(d->character)))
-	d->character->in_room = NOWHERE;
-      save_char(d->character, NOWHERE);
-      send_to_char(WELC_MESSG, d->character);
-      d->character->next = character_list;
-      character_list = d->character;
-
-      if ((load_room = GET_LOADROOM(d->character)) != NOWHERE)
-	load_room = real_room(load_room);
-
-      /* If char was saved with NOWHERE, or real_room above failed... */
-      if (load_room == NOWHERE) {
-	if (GET_LEVEL(d->character) >= LVL_IMMORT) {
-	  load_room = r_immort_start_room;
-	} else {
-	  load_room = r_mortal_start_room;
-	}
-      }
 
-      if (PLR_FLAGGED(d->character, PLR_FROZEN))
-	load_room = r_frozen_start_room;
-
-      char_to_room(d->character, load_room);
+      load_result = enter_player_game(d);
+      send_to_char(WELC_MESSG, d->character);
       act("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM);
 
       STATE(d) = CON_PLAYING;