--- 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;