/**************************************************************************** * ^ +----- | / ^ ^ | | +-\ * * / \ | | / |\ /| | | | \ * * / \ +--- |< | \ / | | | | | * * /-----\ | | \ | v | | | | / * * / \ | | \ | | +-----+ +-/ * **************************************************************************** * AFKMud Copyright 1997-2003 by Roger Libiez (Samson), * * Levi Beckerson (Whir), Michael Ward (Tarl), Erik Wolfe (Dwip), * * Cameron Carroll (Cam), Cyberfox, Karangi, Rathian, Raine, and Adjani. * * All Rights Reserved. * * * * Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag, * * Blodkai, Haus, Narn, Scryn, Swordbearer, Tricops, Gorog, Rennard, * * Grishnakh, Fireblade, and Nivek. * * * * Original MERC 2.1 code by Hatchet, Furey, and Kahn. * * * * Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen, * * Michael Seifert, and Sebastian Hammer. * **************************************************************************** * Hotboot module * ****************************************************************************/ #include <stdio.h> #include <string.h> #include <dirent.h> #if !defined(WIN32) #include <dlfcn.h> #else #include <windows.h> #define dlopen( libname, flags ) LoadLibrary( (libname) ) #define dlclose( libname ) FreeLibrary( (HINSTANCE) (libname) ) #endif #include <unistd.h> #include "h/mud.h" #include "h/mccp.h" bool write_to_descriptor( DESCRIPTOR_DATA *d, char *txt, int length ); bool write_to_descriptor_old( int desc, char *txt, int length ); void open_mud_log(void); extern ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH]; /* Warm reboot stuff, gotta make sure to thank Erwin for this :) */ void do_hotboot( CHAR_DATA *ch, char *argument ) { FILE *fp; CHAR_DATA *victim = NULL; DESCRIPTOR_DATA *d, *de_next; char buf[100], buf2[100], buf3[100]; extern int control; int count = 0; bool found = false; for( d = first_descriptor; d; d = d->next ) { if( ( d->connected == CON_PLAYING || d->connected == CON_EDITING ) && ( victim = d->character ) && !is_npc( victim ) && victim->in_room && victim->fighting && victim->level >= 1 && victim->level <= MAX_LEVEL ) { found = true; count++; } } if( found ) { ch_printf( ch, "Can't hotboot at this time. There are %d combats in progress.\r\n", count ); return; } found = false; for( d = first_descriptor; d; d = d->next ) { if( d->connected == CON_EDITING && d->character ) { found = true; break; } } if( found ) { send_to_char( "Can't hotboot at this time. Someone is using the line editor.\r\n", ch ); return; } log_printf( "Hotboot initiated by %s.", ch->name ); open_mud_log(); log_string("Hotboot: Spawning new log file"); log_printf( "Hotboot initiated by %s.", ch->name ); if( !( fp = fopen( HOTBOOT_FILE, "w" ) ) ) { send_to_char( "Hotboot file not writeable, aborted.\r\n", ch ); bug( "Could not write to hotboot file: %s. Hotboot aborted.", HOTBOOT_FILE ); perror( "do_copyover:fopen" ); return; } log_string( "Saving player files and connection states...." ); if( ch && ch->desc ) write_to_descriptor( ch->desc, "\033[0m", 0 ); snprintf( buf, sizeof( buf ), "\r\nThe flow of time is halted momentarily as the world is reshaped!\r\n" ); /* For each playing descriptor, save its state */ for( d = first_descriptor; d; d = de_next ) { CHAR_DATA *och = CH( d ); de_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, "\r\nSorry, we are rebooting. Come back in a few minutes.\r\n", 0 ); close_socket( d, false ); /* throw'em out */ } else { int room = sysdata.room_limbo; if( och->pcdata && xIS_SET( och->pcdata->flags, PCFLAG_IDLE ) && och->was_in_room ) room = och->was_in_room->vnum; else if( och->in_room ) room = och->in_room->vnum; else bug( "%s: NULL room for %s, leaving room as %d.", __FUNCTION__, och->name, room ); fprintf( fp, "%d %d %d %d %s %s\n", d->descriptor, room, d->port, d->idle, och->name, d->host ); /* One of two places this gets changed */ och->pcdata->hotboot = true; save_char_obj( och ); write_to_descriptor( d, buf, 0 ); compressEnd( d ); d->can_compress = false; } } fprintf( fp, "0 0 0 %d maxp maxp\n", sysdata.maxplayers ); fprintf( fp, "%s", "-1\n" ); fclose( fp ); fp = NULL; #ifdef IMC imc_hotboot( ); #endif /* added this in case there's a need to debug the contents of the various files */ if( argument && !str_cmp( argument, "debug" ) ) { log_string( "Hotboot debug - Aborting before execl" ); return; } log_string( "Executing hotboot...." ); /* exec - descriptors are inherited */ snprintf( buf, sizeof( buf ), "%d", port ); snprintf( buf2, sizeof( buf2 ), "%d", control ); #ifdef IMC if( this_imcmud ) snprintf( buf3, sizeof( buf3 ), "%d", this_imcmud->desc ); else strncpy( buf3, "-1", sizeof( buf3 ) ); #else strncpy( buf3, "-1", sizeof( buf3 ) ); #endif set_alarm( 0 ); dlclose( sysdata.dlHandle ); execl( EXE_FILE, "smaug", buf, "hotboot", buf2, buf3, ( char * )NULL ); /* Failed - sucessful exec won't return */ perror( "do_hotboot: execl" ); if( !( sysdata.dlHandle = dlopen( NULL, RTLD_LAZY ) ) ) { bug( "%s", "FATAL ERROR: Unable to reopen system executable handle!" ); exit( 1 ); } bug( "%s", "Hotboot execution failed!!" ); send_to_char( "Hotboot FAILED!\r\n", ch ); } /* Recover from a hotboot - load players */ void hotboot_recover( void ) { DESCRIPTOR_DATA *d = NULL; FILE *fp; char name[100], host[MSL]; int desc, room, dport, idle, maxp = 0; bool fOld; if( !( fp = fopen( HOTBOOT_FILE, "r" ) ) ) /* there are some descriptors open which will hang forever then ? */ { perror( "hotboot_recover: fopen" ); bug( "%s", "Hotboot file not found. Exitting." ); exit( 1 ); } remove_file( HOTBOOT_FILE ); /* In case something crashes - doesn't prevent reading */ for( ;; ) { d = NULL; fscanf( fp, "%d %d %d %d %s %s\n", &desc, &room, &dport, &idle, name, host ); if( desc == -1 || feof( fp ) ) break; if( !str_cmp( name, "maxp" ) || !str_cmp( host, "maxp" ) ) { maxp = idle; continue; } /* Write something, and check if it goes error-free */ if( !write_to_descriptor_old( desc, "The ether swirls in chaos.\r\n", 0 ) ) { bug( "%s closeing descriptor.", __FUNCTION__ ); close( desc ); /* nope */ continue; } CREATE( d, DESCRIPTOR_DATA, 1 ); d->next = NULL; d->descriptor = desc; d->connected = CON_GET_NAME; d->outsize = 2000; d->tempidle = 0; d->idle = 0; d->lines = 0; d->scrlen = 24; d->newstate = 0; d->prevcolor = 0x08; CREATE( d->outbuf, char, d->outsize ); d->host = STRALLOC( host ); d->port = dport; d->idle = idle; CREATE( d->mccp, MCCP, 1 ); d->can_compress = false; 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, true ); if( !fOld ) /* Player file not found?! */ { write_to_descriptor( d, "Somehow, your character was lost during hotboot. Contact the immortals ASAP.\r\n", 0 ); close_socket( d, false ); } else /* ok! */ { write_to_descriptor( d, "Time resumes its normal flow.\r\n", 0 ); /* Insert in the char_list */ LINK( d->character, first_char, last_char, next, prev ); if( d->character && d->character->pcdata && xIS_SET( d->character->pcdata->flags, PCFLAG_IDLE ) ) { d->character->was_in_room = get_room_index( room ); d->character->in_room = get_room_index( sysdata.room_limbo ); } else { d->character->in_room = get_room_index( room ); d->character->was_in_room = get_room_index( room ); } if( !d->character->in_room ) d->character->in_room = get_room_index( sysdata.room_temple ); char_to_room( d->character, d->character->in_room ); act( AT_MAGIC, "A puff of ethereal smoke dissipates around you!", d->character, NULL, NULL, TO_CHAR ); act( AT_MAGIC, "$n appears in a puff of ethereal smoke!", d->character, NULL, NULL, TO_ROOM ); d->connected = CON_PLAYING; if( ++num_descriptors > sysdata.maxplayers ) sysdata.maxplayers = num_descriptors; write_to_descriptor( d, will_compress2_str, 0 ); } } fclose( fp ); fp = NULL; if( maxp > sysdata.maxplayers ) sysdata.maxplayers = maxp; log_string( "Hotboot recovery complete." ); }