2024-05-12 03:19:01 -04:00
# define _FILE_OFFSET_BITS 64
# include <string>
# include <vector>
# include <libreborn/libreborn.h>
# include "util.h"
# include "bootstrap.h"
# include "patchelf.h"
# define MCPI_BINARY "minecraft-pi"
# define REQUIRED_PAGE_SIZE 4096
// Debug Information
static void run_debug_command ( const char * const command [ ] , const char * prefix ) {
int status = 0 ;
char * output = run_command ( command , & status , nullptr ) ;
if ( output ! = nullptr ) {
// Remove Newline
size_t length = strlen ( output ) ;
if ( length > 0 & & output [ length - 1 ] = = ' \n ' ) {
output [ length - 1 ] = ' \0 ' ;
}
// Print
DEBUG ( " %s: %s " , prefix , output ) ;
free ( output ) ;
}
if ( ! is_exit_status_success ( status ) ) {
ERR ( " Unable To Gather Debug Information " ) ;
}
}
static void print_debug_information ( ) {
// System Information
const char * const command [ ] = { " uname " , " -a " , nullptr } ;
run_debug_command ( command , " System Information " ) ;
// Version
DEBUG ( " Reborn Version: v%s " , MCPI_VERSION ) ;
// Architecture
2024-06-17 18:09:30 -04:00
const char * arch =
2024-05-12 03:19:01 -04:00
# ifdef __x86_64__
2024-06-17 18:09:30 -04:00
" AMD64 "
2024-05-12 03:19:01 -04:00
# elif defined(__aarch64__)
2024-06-17 18:09:30 -04:00
" ARM64 "
2024-05-12 03:19:01 -04:00
# elif defined(__arm__)
2024-06-17 18:09:30 -04:00
" ARM32 "
# else
" Unknown "
2024-05-12 03:19:01 -04:00
# endif
2024-06-17 18:09:30 -04:00
;
2024-05-12 03:19:01 -04:00
DEBUG ( " Reborn Target Architecture: %s " , arch ) ;
}
// Bootstrap
2024-07-05 03:24:27 -04:00
void bootstrap ( const options_t & options ) {
2024-05-12 03:19:01 -04:00
// Debug Information
print_debug_information ( ) ;
// Check Page Size (Not Needed When Using QEMU)
long page_size = sysconf ( _SC_PAGESIZE ) ;
if ( page_size ! = REQUIRED_PAGE_SIZE ) {
2024-07-05 03:24:27 -04:00
CONDITIONAL_ERR ( ! options . skip_pagesize_check , " Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes. " , ( long ) REQUIRED_PAGE_SIZE , page_size ) ;
2024-05-12 03:19:01 -04:00
}
// Get Binary Directory
2024-06-17 18:09:30 -04:00
const std : : string binary_directory = get_binary_directory ( ) ;
2024-05-12 03:19:01 -04:00
DEBUG ( " Binary Directory: %s " , binary_directory . c_str ( ) ) ;
// Copy SDK
2024-06-16 00:04:42 -04:00
if ( ! reborn_is_server ( ) ) {
copy_sdk ( binary_directory , true ) ;
}
2024-05-12 03:19:01 -04:00
// Set MCPI_REBORN_ASSETS_PATH
{
2024-06-17 18:09:30 -04:00
std : : string assets_path = safe_realpath ( " /proc/self/exe " ) ;
chop_last_component ( assets_path ) ;
assets_path + = " /data " ;
set_and_print_env ( _MCPI_REBORN_ASSETS_PATH_ENV , assets_path . c_str ( ) ) ;
2024-05-12 03:19:01 -04:00
}
// Resolve Binary Path & Set MCPI_DIRECTORY
2024-06-17 18:09:30 -04:00
std : : string game_binary ;
2024-05-12 03:19:01 -04:00
{
// Log
DEBUG ( " Resolving File Paths... " ) ;
// Resolve Full Binary Path
const std : : string full_path = binary_directory + ( " / " MCPI_BINARY ) ;
2024-06-17 18:09:30 -04:00
game_binary = safe_realpath ( full_path ) ;
2024-05-12 03:19:01 -04:00
}
// Fix MCPI Dependencies
char new_mcpi_exe_path [ ] = MCPI_PATCHED_DIR " /XXXXXX " ;
2024-05-20 16:37:55 -04:00
std : : string linker ;
2024-05-12 03:19:01 -04:00
{
// Log
DEBUG ( " Patching ELF Dependencies... " ) ;
// Find Linker
2024-05-20 16:37:55 -04:00
linker = " /lib/ld-linux-armhf.so.3 " ;
2024-05-12 03:19:01 -04:00
# ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
// Use ARM Sysroot Linker
2024-05-20 16:37:55 -04:00
linker = binary_directory + " /sysroot " + linker ;
2024-05-12 03:19:01 -04:00
# endif
// Patch
2024-06-17 18:09:30 -04:00
patch_mcpi_elf_dependencies ( game_binary . c_str ( ) , new_mcpi_exe_path ) ;
2024-05-12 03:19:01 -04:00
// Verify
if ( ! starts_with ( new_mcpi_exe_path , MCPI_PATCHED_DIR ) ) {
IMPOSSIBLE ( ) ;
}
}
// Set MCPI_VANILLA_ASSETS_PATH
{
2024-06-17 18:09:30 -04:00
std : : string assets_path = game_binary ;
chop_last_component ( assets_path ) ;
assets_path + = " /data " ;
set_and_print_env ( _MCPI_VANILLA_ASSETS_PATH_ENV , assets_path . c_str ( ) ) ;
2024-05-12 03:19:01 -04:00
}
// Configure Library Search Path
2024-05-20 16:37:55 -04:00
std : : string mcpi_ld_path = " " ;
2024-05-12 03:19:01 -04:00
{
// Log
DEBUG ( " Setting Linker Search Paths... " ) ;
// Library Search Path For ARM Components
{
// Add ARM Library Directory
mcpi_ld_path + = binary_directory + " /lib/arm: " ;
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
# ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
mcpi_ld_path + = binary_directory + " /sysroot/lib: " ;
mcpi_ld_path + = binary_directory + " /sysroot/lib/arm-linux-gnueabihf: " ;
mcpi_ld_path + = binary_directory + " /sysroot/usr/lib: " ;
mcpi_ld_path + = binary_directory + " /sysroot/usr/lib/arm-linux-gnueabihf: " ;
# endif
}
}
// Configure Preloaded Objects
2024-05-20 16:37:55 -04:00
std : : string mcpi_ld_preload ;
2024-05-12 03:19:01 -04:00
{
// Log
DEBUG ( " Locating Mods... " ) ;
// ARM Components
2024-05-20 16:37:55 -04:00
mcpi_ld_preload = bootstrap_mods ( binary_directory ) ;
2024-05-12 03:19:01 -04:00
}
// Start Game
INFO ( " Starting Game... " ) ;
// Arguments
std : : vector < std : : string > args ;
2024-06-08 16:30:39 -04:00
// Use Extra If Needed
# ifdef MCPI_BUILD_RUNTIME
args . push_back ( " runtime " ) ;
2024-06-04 18:29:13 -04:00
# endif
// Fix QEMU Bug
2024-06-08 16:30:39 -04:00
# ifdef MCPI_RUNTIME_IS_QEMU
2024-05-20 16:37:55 -04:00
args . push_back ( " -B " ) ;
2024-06-04 18:29:13 -04:00
args . push_back ( " 0x40000 " ) ; // Arbitrary Value (Aligns To 4k And 16k Page Sizes)
2024-05-12 03:19:01 -04:00
# endif
2024-05-20 16:37:55 -04:00
// Setup Linker
args . push_back ( linker ) ;
args . push_back ( " --library-path " ) ;
args . push_back ( mcpi_ld_path ) ;
args . push_back ( " --preload " ) ;
args . push_back ( mcpi_ld_preload ) ;
2024-05-12 03:19:01 -04:00
// Specify MCPI Binary
args . push_back ( new_mcpi_exe_path ) ;
// Run
const char * new_argv [ args . size ( ) + 1 ] ;
for ( std : : vector < std : : string > : : size_type i = 0 ; i < args . size ( ) ; i + + ) {
new_argv [ i ] = args [ i ] . c_str ( ) ;
}
new_argv [ args . size ( ) ] = nullptr ;
safe_execvpe ( new_argv , environ ) ;
}