#!/usr/bin/perl ########################################################### #::: Automatic (Database) Upgrade Script #::: Author: Akkadius #::: Purpose: To upgrade databases with ease and maintain versioning ########################################################### $menu_displayed = 0; use Config; use File::Copy qw(copy); use POSIX qw(strftime); use File::Path; use File::Find; use URI::Escape; use Time::HiRes qw(usleep); $time_stamp = strftime('%m-%d-%Y', gmtime()); $console_output .= " Operating System is: $Config{osname}\n"; if($Config{osname}=~/linux/i){ $OS = "Linux"; } if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } #::: If current version is less than what world is reporting, then download a new one... $current_version = 12; if($ARGV[0] eq "V"){ if($ARGV[1] > $current_version){ print "eqemu_update.pl Automatic Database Upgrade Needs updating...\n"; print " Current version: " . $current_version . "\n"; print " New version: " . $ARGV[1] . "\n"; get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl", "eqemu_update.pl"); exit; } else{ print "[Upgrade Script] No script update necessary \n"; } exit; } #::: Sets database run stage check $db_run_stage = 0; $perl_version = $^V; $perl_version =~s/v//g; print "Perl Version is " . $perl_version . "\n"; if($perl_version > 5.12){ no warnings 'uninitialized'; } no warnings; ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(); my $confile = "eqemu_config.xml"; #default open(F, "<$confile"); my $indb = 0; while() { s/\r//g; if(//i) { $indb = 1; } next unless($indb == 1); if(/<\/database>/i) { $indb = 0; last; } if(/(.*)<\/host>/i) { $host = $1; } elsif(/(.*)<\/username>/i) { $user = $1; } elsif(/(.*)<\/password>/i) { $pass = $1; } elsif(/(.*)<\/db>/i) { $db = $1; } } $console_output = "============================================================ EQEmu: Automatic Upgrade Check ============================================================ "; if($OS eq "Windows"){ $has_mysql_path = `echo %PATH%`; if($has_mysql_path=~/MySQL|MariaDB/i){ @mysql = split(';', $has_mysql_path); foreach my $v (@mysql){ if($v=~/MySQL|MariaDB/i){ $v =~s/\n//g; $path = trim($v) . "/mysql"; last; } } $console_output .= " (Windows) MySQL is in system path \n"; $console_output .= " Path = " . $path . "\n"; $console_output .= "============================================================\n"; } } #::: Linux Check if($OS eq "Linux"){ $path = `which mysql`; if ($path eq "") { $path = `which mariadb`; } $path =~s/\n//g; $console_output .= " (Linux) MySQL is in system path \n"; $console_output .= " Path = " . $path . "\n"; $console_output .= "============================================================\n"; } #::: Path not found, error and exit if($path eq ""){ print "MySQL path not found, please add the path for automatic database upgrading to continue... \n\n"; print "script_exiting...\n"; exit; } if($ARGV[0] eq "installer"){ print "Running EQEmu Server installer routines...\n"; mkdir('logs'); mkdir('updates_staged'); mkdir('shared'); fetch_latest_windows_binaries(); map_files_fetch_bulk(); opcodes_fetch(); plugins_fetch(); quest_files_fetch(); lua_modules_fetch(); get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/lua51.dll", "lua51.dll", 1); get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/zlib1.dll", "zlib1.dll", 1); get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/libmysql.dll", "libmysql.dll", 1); #::: Database Routines print "MariaDB :: Creating Database 'peq'\n"; print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE IF EXISTS peq;"`; print `"$path" --host $host --user $user --password="$pass" -N -B -e "CREATE DATABASE peq"`; if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); } if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); } $bin_db_ver = trim($db_version[1]); check_db_version_table(); $local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1")); fetch_peq_db_full(); print "\nFetching Latest Database Updates...\n"; main_db_management(); print "\nApplying Latest Database Updates...\n"; main_db_management(); if($OS eq "Windows"){ check_windows_firewall_rules(); } exit; } #::: Create db_update working directory if not created mkdir('db_update'); #::: Check if db_version table exists... if(trim(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne "" && $db){ print get_mysql_result("DROP TABLE db_version"); print "Old db_version table present, dropping...\n\n"; } sub check_db_version_table{ if(get_mysql_result("SHOW TABLES LIKE 'db_version'") eq "" && $db){ print get_mysql_result(" CREATE TABLE db_version ( version int(11) DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=latin1; INSERT INTO db_version (version) VALUES ('1000');"); print "Table 'db_version' does not exists.... Creating...\n\n"; } } check_db_version_table(); if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); } if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); } $bin_db_ver = trim($db_version[1]); $local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1")); #::: If ran from Linux startup script, supress output if($bin_db_ver == $local_db_ver && $ARGV[0] eq "ran_from_start"){ print "Database up to date...\n"; exit; } else{ print $console_output if $db; } if($db){ print " Binary Revision / Local: (" . $bin_db_ver . " / " . $local_db_ver . ")\n"; #::: Bots #::: Make sure we're running a bots binary to begin with if(trim($db_version[2]) > 0){ $bots_local_db_version = get_bots_db_version(); if($bots_local_db_version > 0){ print " (Bots) Binary Revision / Local: (" . trim($db_version[2]) . " / " . $bots_local_db_version . ")\n"; } } #::: If World ran this script, and our version is up to date, continue... if($bin_db_ver <= $local_db_ver && $ARGV[0] eq "ran_from_world"){ print " Database up to Date: Continuing World Bootup...\n"; print "============================================================\n"; exit; } } if($local_db_ver < $bin_db_ver && $ARGV[0] eq "ran_from_world"){ print "You have missing database updates, type 1 or 2 to backup your database before running them as recommended...\n\n"; #::: Display Menu show_menu_prompt(); } else{ #::: Most likely ran standalone print "\n"; show_menu_prompt(); } sub do_update_self{ get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl", "eqemu_update.pl"); die "Rerun eqemu_update.pl"; } sub show_menu_prompt { my %dispatch = ( 1 => \&database_dump, 2 => \&database_dump_compress, 3 => \&main_db_management, 4 => \&bots_db_management, 5 => \&opcodes_fetch, 6 => \&map_files_fetch, 7 => \&plugins_fetch, 8 => \&quest_files_fetch, 9 => \&lua_modules_fetch, 10 => \&aa_fetch, 11 => \&fetch_latest_windows_binaries, 12 => \&fetch_server_dlls, 20 => \&do_update_self, 0 => \&script_exit, ); while (1) { { local $| = 1; if(!$menu_show && ($ARGV[0] eq "ran_from_world" || $ARGV[0] eq "ran_from_start")){ $menu_show++; next; } print menu_options(), '> '; $menu_displayed++; if($menu_displayed > 50){ print "Safety: Menu looping too many times, exiting...\n"; exit; } } my $choice = <>; $choice =~ s/\A\s+//; $choice =~ s/\s+\z//; if (defined(my $handler = $dispatch{$choice})) { my $result = $handler->(); unless (defined $result) { exit 0; } } else { if($ARGV[0] ne "ran_from_world"){ # warn "\n\nInvalid selection\n\n"; } } } } sub menu_options { if(@total_updates){ if($bots_db_management == 1){ $option[3] = "Check and stage pending REQUIRED Database updates"; $bots_management = "Run pending REQUIRED updates... (" . scalar (@total_updates) . ")"; } else{ $option[3] = "Run pending REQUIRED updates... (" . scalar (@total_updates) . ")"; if(get_mysql_result("SHOW TABLES LIKE 'bots'") eq ""){ $bots_management = "Install bots database pre-requisites (Requires bots server binaries)"; } else{ $bots_management = "Check for Bot pending REQUIRED database updates... (Must have bots enabled)"; } } } else{ $option[3] = "Check and stage pending REQUIRED Database updates"; $bots_management = "Check for Bot REQUIRED database updates... (Must have bots enabled)"; } return <new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get($URL); if ($response->is_success){ open (FILE, '> ' . $Dest_File . ''); print FILE $response->decoded_content; close (FILE); } else { # print "Error, no connection or failed request...\n\n"; } if(-e $Dest_File) { $break = 1; print " [URL] :: " . $URL . "\n"; print " [Saved] :: " . $Dest_File . "\n"; } else { $break = 0; } usleep(500); } } } if($OS eq "Linux"){ #::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt $wget = `wget --no-check-certificate --quiet -O $Dest_File $URL`; print " o URL: (" . $URL . ")\n"; print " o Saved: (" . $Dest_File . ") \n"; if($wget=~/unable to resolve/i){ print "Error, no connection or failed request...\n\n"; #die; } } } #::: Trim Whitespaces sub trim { my $string = $_[0]; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } #::: Fetch Latest PEQ AA's sub aa_fetch{ if(!$db){ print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n"; return; } print "Pulling down PEQ AA Tables...\n"; get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/peq_aa_tables_post_rework.sql", "db_update/peq_aa_tables_post_rework.sql"); print "\n\nInstalling AA Tables...\n"; print get_mysql_result_from_file("db_update/peq_aa_tables_post_rework.sql"); print "\nDone...\n\n"; } #::: Fetch Latest Opcodes sub opcodes_fetch{ print "Pulling down latest opcodes...\n"; %opcodes = ( 1 => ["opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/opcodes.conf"], 2 => ["mail_opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/mail_opcodes.conf"], 3 => ["Titanium", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Titanium.conf"], 4 => ["Secrets of Faydwer", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoF.conf"], 5 => ["Seeds of Destruction", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoD.conf"], 6 => ["Underfoot", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_UF.conf"], 7 => ["Rain of Fear", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF.conf"], 8 => ["Rain of Fear 2", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF2.conf"], ); $loop = 1; while($opcodes{$loop}[0]){ #::: Split the URL by the patches folder to get the file name from URL @real_file = split("patches/", $opcodes{$loop}[1]); $find = 0; while($real_file[$find]){ $file_name = $real_file[$find]; $find++; } print "\nDownloading (" . $opcodes{$loop}[0] . ") File: '" . $file_name . "'...\n\n"; get_remote_file($opcodes{$loop}[1], $file_name); $loop++; } print "\nDone...\n\n"; } sub copy_file{ $l_source_file = $_[0]; $l_dest_file = $_[1]; if($l_dest_file=~/\//i){ my @dir_path = split('/', $l_dest_file); $build_path = ""; $di = 0; while($dir_path[$di]){ $build_path .= $dir_path[$di] . "/"; #::: If path does not exist, create the directory... if (!-d $build_path) { mkdir($build_path); } if(!$dir_path[$di + 2] && $dir_path[$di + 1]){ # print $actual_path . "\n"; $actual_path = $build_path; last; } $di++; } } copy $l_source_file, $l_dest_file; } sub fetch_latest_windows_binaries{ print "\n --- Fetching Latest Windows Binaries... --- \n"; get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/master_windows_build.zip", "updates_staged/master_windows_build.zip", 1); print "\n --- Fetched Latest Windows Binaries... --- \n"; print "\n --- Extracting... --- \n"; unzip('updates_staged/master_windows_build.zip', 'updates_staged/binaries/'); my @files; my $start_dir = "updates_staged/binaries"; find( sub { push @files, $File::Find::name unless -d; }, $start_dir ); for my $file (@files) { $dest_file = $file; $dest_file =~s/updates_staged\/binaries\///g; print "Installing :: " . $dest_file . "\n"; copy_file($file, $dest_file); } print "\n --- Done... --- \n"; rmtree('updates_staged'); } sub check_windows_firewall_rules{ $output = `netsh advfirewall firewall show rule name=all`; @output_buffer = split("\n", $output); $has_world_rules = 0; $has_zone_rules = 0; foreach my $val (@output_buffer){ if($val=~/Rule Name/i){ $val=~s/Rule Name://g; if($val=~/EQEmu World/i){ $has_world_rules = 1; print "Found existing rule :: " . trim($val) . "\n"; } if($val=~/EQEmu Zone/i){ $has_zone_rules = 1; print "Found existing rule :: " . trim($val) . "\n"; } } } if($has_world_rules == 0){ print "Attempting to add EQEmu World Firewall Rules (TCP) port 9000 \n"; print `netsh advfirewall firewall add rule name="EQEmu World (9000) TCP" dir=in action=allow protocol=TCP localport=9000`; print "Attempting to add EQEmu World Firewall Rules (UDP) port 9000 \n"; print `netsh advfirewall firewall add rule name="EQEmu World (9000) UDP" dir=in action=allow protocol=UDP localport=9000 `; } if($has_zone_rules == 0){ print "Attempting to add EQEmu Zones (7000-7500) TCP \n"; print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) TCP" dir=in action=allow protocol=TCP localport=7000-7500`; print "Attempting to add EQEmu Zones (7000-7500) UDP \n"; print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) UDP" dir=in action=allow protocol=UDP localport=7000-7500`; } } sub fetch_server_dlls{ print "Fetching lua51.dll, zlib1.dll, libmysql.dll...\n"; get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/lua51.dll", "lua51.dll", 1); get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/zlib1.dll", "zlib1.dll", 1); get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/libmysql.dll", "libmysql.dll", 1); } sub fetch_peq_db_full{ print "Downloading latest PEQ Database... Please wait...\n"; get_remote_file("http://edit.peqtgc.com/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1); print "Downloaded latest PEQ Database... Extracting...\n"; unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/'); my $start_dir = "updates_staged\\peq_db"; find( sub { push @files, $File::Find::name unless -d; }, $start_dir ); for my $file (@files) { $dest_file = $file; $dest_file =~s/updates_staged\\peq_db\///g; if($file=~/peqbeta|player_tables/i){ print "MariaDB :: Installing :: " . $dest_file . "\n"; get_mysql_result_from_file($file); } if($file=~/eqtime/i){ print "Installing eqtime.cfg\n"; copy_file($file, "eqtime.cfg"); } } } sub map_files_fetch_bulk{ print "\n --- Fetching Latest Maps... (This could take a few minutes...) --- \n"; get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1); unzip('maps/maps.zip', 'maps/'); my @files; my $start_dir = "maps\\EQEmuMaps-master\\maps"; find( sub { push @files, $File::Find::name unless -d; }, $start_dir ); for my $file (@files) { $dest_file = $file; $dest_file =~s/maps\\EQEmuMaps-master\\maps\///g; print "Installing :: " . $dest_file . "\n"; copy_file($file, "maps/" . $new_file); } print "\n --- Fetched Latest Maps... --- \n"; rmtree('maps/EQEmuMaps-master'); unlink('maps/maps.zip'); } sub map_files_fetch{ print "\n --- Fetching Latest Maps --- \n"; get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/!eqemu_maps_manifest.txt", "updates_staged/eqemu_maps_manifest.txt"); #::: Get Data from manifest open (FILE, "updates_staged/eqemu_maps_manifest.txt"); $i = 0; while (){ chomp; $o = $_; @manifest_map_data = split(',', $o); if($manifest_map_data[0] ne ""){ $maps_manifest[$i] = [$manifest_map_data[0], $manifest_map_data[1]]; $i++; } } #::: Download $fc = 0; for($m = 0; $m <= $i; $m++){ my $file_existing = $maps_manifest[$m][0]; my $file_existing_size = (stat $file_existing)[7]; if($file_existing_size != $maps_manifest[$m][1]){ print "Updating: '" . $maps_manifest[$m][0] . "'\n"; get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/" . $maps_manifest[$m][0], $maps_manifest[$m][0], 1); $fc++; } } if($fc == 0){ print "\nNo Map Updates found... \n\n"; } } sub quest_files_fetch{ if (!-e "updates_staged/Quests-Plugins-master/quests/") { print "\n --- Fetching Latest Quests --- \n"; get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1); print "\nFetched latest quests...\n"; mkdir('updates_staged'); unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/'); } $fc = 0; use File::Find; use File::Compare; my @files; my $start_dir = "updates_staged/Quests-Plugins-master/quests/"; find( sub { push @files, $File::Find::name unless -d; }, $start_dir ); for my $file (@files) { if($file=~/\.pl|\.lua|\.ext/i){ $staged_file = $file; $dest_file = $file; $dest_file =~s/updates_staged\/Quests-Plugins-master\///g; if (!-e $dest_file) { copy_file($staged_file, $dest_file); print "Installing :: '" . $dest_file . "'\n"; $fc++; } else{ $diff = do_file_diff($dest_file, $staged_file); if($diff ne ""){ $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file; print $diff . "\n"; print "\nFile Different :: '" . $dest_file . "'\n"; print "\nDo you wish to update this Quest? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n"; my $input = ; if($input=~/N/i){} else{ #::: Make a backup copy_file($dest_file, $backup_dest); #::: Copy staged to running copy($staged_file, $dest_file); print "Installing :: '" . $dest_file . "'\n\n"; } $fc++; } } } } rmtree('updates_staged'); if($fc == 0){ print "\nNo Quest Updates found... \n\n"; } } sub lua_modules_fetch{ if (!-e "updates_staged/Quests-Plugins-master/quests/lua_modules/") { print "\n --- Fetching Latest LUA Modules --- \n"; get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1); print "\nFetched latest LUA Modules...\n"; unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/'); } $fc = 0; use File::Find; use File::Compare; my @files; my $start_dir = "updates_staged/Quests-Plugins-master/quests/lua_modules/"; find( sub { push @files, $File::Find::name unless -d; }, $start_dir ); for my $file (@files) { if($file=~/\.pl|\.lua|\.ext/i){ $staged_file = $file; $dest_file = $file; $dest_file =~s/updates_staged\/Quests-Plugins-master\/quests\///g; if (!-e $dest_file) { copy_file($staged_file, $dest_file); print "Installing :: '" . $dest_file . "'\n"; $fc++; } else{ $diff = do_file_diff($dest_file, $staged_file); if($diff ne ""){ $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file; print $diff . "\n"; print "\nFile Different :: '" . $dest_file . "'\n"; print "\nDo you wish to update this LUA Module? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n"; my $input = ; if($input=~/N/i){} else{ #::: Make a backup copy_file($dest_file, $backup_dest); #::: Copy staged to running copy($staged_file, $dest_file); print "Installing :: '" . $dest_file . "'\n\n"; } $fc++; } } } } if($fc == 0){ print "\nNo LUA Modules Updates found... \n\n"; } } sub plugins_fetch{ if (!-e "updates_staged/Quests-Plugins-master/plugins/") { print "\n --- Fetching Latest Plugins --- \n"; get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1); print "\nFetched latest plugins...\n"; unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/'); } $fc = 0; use File::Find; use File::Compare; my @files; my $start_dir = "updates_staged/Quests-Plugins-master/plugins/"; find( sub { push @files, $File::Find::name unless -d; }, $start_dir ); for my $file (@files) { if($file=~/\.pl|\.lua|\.ext/i){ $staged_file = $file; $dest_file = $file; $dest_file =~s/updates_staged\/Quests-Plugins-master\///g; if (!-e $dest_file) { copy_file($staged_file, $dest_file); print "Installing :: '" . $dest_file . "'\n"; $fc++; } else{ $diff = do_file_diff($dest_file, $staged_file); if($diff ne ""){ $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file; print $diff . "\n"; print "\nFile Different :: '" . $dest_file . "'\n"; print "\nDo you wish to update this Plugin? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n"; my $input = ; if($input=~/N/i){} else{ #::: Make a backup copy_file($dest_file, $backup_dest); #::: Copy staged to running copy($staged_file, $dest_file); print "Installing :: '" . $dest_file . "'\n\n"; } $fc++; } } } } if($fc == 0){ print "\nNo Plugin Updates found... \n\n"; } } sub do_file_diff{ $file_1 = $_[0]; $file_2 = $_[1]; if($OS eq "Windows"){ eval "use Text::Diff"; $diff = diff($file_1, $file_2, { STYLE => "Unified" }); return $diff; } if($OS eq "Linux"){ # print 'diff -u "$file_1" "$file_2"' . "\n"; return `diff -u "$file_1" "$file_2"`; } } sub unzip{ $archive_to_unzip = $_[0]; $dest_folder = $_[1]; if($OS eq "Windows"){ eval "use Archive::Zip qw( :ERROR_CODES :CONSTANTS )"; my $zip = Archive::Zip->new(); unless ( $zip->read($archive_to_unzip) == AZ_OK ) { die 'read error'; } print "Extracting...\n"; $zip->extractTree('', $dest_folder); } if($OS eq "Linux"){ print `unzip -o "$archive_to_unzip" -d "$dest_folder"`; } } sub are_file_sizes_different{ $file_1 = $_[0]; $file_2 = $_[1]; my $file_1 = (stat $file_1)[7]; my $file_2 = (stat $file_2)[7]; # print $file_1 . " :: " . $file_2 . "\n"; if($file_1 != $file_2){ return 1; } return; } sub get_bots_db_version{ #::: Check if bots_version column exists... if(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'bots_version'") eq "" && $db){ print get_mysql_result("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version;"); print "\nColumn 'bots_version' does not exists.... Adding to 'db_version' table...\n\n"; } $bots_local_db_version = trim(get_mysql_result("SELECT bots_version FROM db_version LIMIT 1")); return $bots_local_db_version; } sub bots_db_management{ #::: Main Binary Database version $bin_db_ver = trim($db_version[2]); #::: If we have stale data from main db run if($db_run_stage > 0 && $bots_db_management == 0){ clear_database_runs(); } if($bin_db_ver == 0){ print "Your server binaries (world/zone) are not compiled for bots...\n"; return; } #::: Set on flag for running bot updates... $bots_db_management = 1; $bots_local_db_version = get_bots_db_version(); run_database_check(); } sub main_db_management{ #::: If we have stale data from bots db run if($db_run_stage > 0 && $bots_db_management == 1){ clear_database_runs(); } #::: Main Binary Database version $bin_db_ver = trim($db_version[1]); $bots_db_management = 0; run_database_check(); } sub clear_database_runs{ # print "DEBUG :: clear_database_runs\n\n"; #::: Clear manifest data... %m_d = (); #::: Clear updates... @total_updates = (); #::: Clear stage $db_run_stage = 0; } #::: Responsible for Database Upgrade Routines sub run_database_check{ if(!$db){ print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n"; return; } if(!@total_updates){ #::: Pull down bots database manifest if($bots_db_management == 1){ print "Retrieving latest bots database manifest...\n"; get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/bots_db_update_manifest.txt", "db_update/db_update_manifest.txt"); } #::: Pull down mainstream database manifest else{ print "Retrieving latest database manifest...\n"; get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt"); } } #::: Run 2 - Running pending updates... if(@total_updates){ @total_updates = sort @total_updates; foreach my $val (@total_updates){ $file_name = trim($m_d{$val}[1]); print "Running Update: " . $val . " - " . $file_name . "\n"; print get_mysql_result_from_file("db_update/$file_name"); print get_mysql_result("UPDATE db_version SET version = $val WHERE version < $val"); } $db_run_stage = 2; } #::: Run 1 - Initial checking of needed updates... else{ print "Reading manifest...\n\n"; use Data::Dumper; open (FILE, "db_update/db_update_manifest.txt"); while () { chomp; $o = $_; if($o=~/#/i){ next; } @manifest = split('\|', $o); $m_d{$manifest[0]} = [@manifest]; } #::: Setting Manifest stage... $db_run_stage = 1; } @total_updates = (); #::: Iterate through Manifest backwards from binary version down to local version... for($i = $bin_db_ver; $i > 1000; $i--){ if(!defined($m_d{$i}[0])){ next; } $file_name = trim($m_d{$i}[1]); $query_check = trim($m_d{$i}[2]); $match_type = trim($m_d{$i}[3]); $match_text = trim($m_d{$i}[4]); #::: Match type update if($match_type eq "contains"){ if(trim(get_mysql_result($query_check))=~/$match_text/i){ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } else{ print "DB up to date with: " . $i . " - '" . $file_name . "' \n"; } print_match_debug(); print_break(); } if($match_type eq "missing"){ if(get_mysql_result($query_check)=~/$match_text/i){ print "DB up to date with: " . $i . " - '" . $file_name . "' \n"; next; } else{ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } print_match_debug(); print_break(); } if($match_type eq "empty"){ if(get_mysql_result($query_check) eq ""){ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } else{ print "DB up to date with: " . $i . " - '" . $file_name . "' \n"; } print_match_debug(); print_break(); } if($match_type eq "not_empty"){ if(get_mysql_result($query_check) ne ""){ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } else{ print "DB up to date with: " . $i . " - '" . $file_name . "' \n"; } print_match_debug(); print_break(); } } print "\n"; if(scalar (@total_updates) == 0 && $db_run_stage == 2){ print "No updates need to be run...\n"; if($bots_db_management == 1){ print "Setting Database to Bots Binary Version (" . $bin_db_ver . ") if not already...\n\n"; get_mysql_result("UPDATE db_version SET bots_version = $bin_db_ver"); } else{ print "Setting Database to Binary Version (" . $bin_db_ver . ") if not already...\n\n"; get_mysql_result("UPDATE db_version SET version = $bin_db_ver"); } clear_database_runs(); } } sub fetch_missing_db_update{ $db_update = $_[0]; $update_file = $_[1]; if($db_update >= 9000){ if($bots_db_management == 1){ get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/required/" . $update_file, "db_update/" . $update_file . ""); } else{ get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/required/" . $update_file, "db_update/" . $update_file . ""); } } elsif($db_update >= 5000 && $db_update <= 9000){ get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/svn/" . $update_file, "db_update/" . $update_file . ""); } } sub print_match_debug{ if(!$debug){ return; } print " Match Type: '" . $match_type . "'\n"; print " Match Text: '" . $match_text . "'\n"; print " Query Check: '" . $query_check . "'\n"; print " Result: '" . trim(get_mysql_result($query_check)) . "'\n"; } sub print_break{ if(!$debug){ return; } print "\n==============================================\n"; }