minecraft-pi-reborn/launcher/src/bootstrap.c

362 lines
10 KiB
C
Raw Normal View History

2021-06-17 21:32:24 +00:00
#define _FILE_OFFSET_BITS 64
#include <libreborn/libreborn.h>
2023-11-25 03:16:13 +00:00
#include "util.h"
2021-06-17 21:32:24 +00:00
#include "bootstrap.h"
2022-03-25 02:47:34 +00:00
#include "patchelf.h"
2022-05-14 02:36:12 +00:00
#include "crash-report.h"
2021-06-17 21:32:24 +00:00
2022-03-09 23:47:31 +00:00
#define MCPI_BINARY "minecraft-pi"
#define QEMU_BINARY "qemu-arm"
2021-06-17 21:32:24 +00:00
2023-11-24 08:07:06 +00:00
#define REQUIRED_PAGE_SIZE 4096
#define _STR(x) #x
#define STR(x) _STR(x)
2022-05-14 02:36:12 +00:00
// Exit Handler
static void exit_handler(__attribute__((unused)) int signal_id) {
// Pass Signal To Child
murder_children();
while (wait(NULL) > 0) {}
_exit(EXIT_SUCCESS);
}
2023-11-24 08:07:06 +00:00
// Debug Information
static void run_debug_command(const char *const command[], const char *prefix) {
int status = 0;
char *output = run_command(command, &status, NULL);
if (output != NULL) {
// 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", NULL};
run_debug_command(command, "System Information");
// Version
DEBUG("Reborn Version: v%s", MCPI_VERSION);
// Architecture
const char *arch = "Unknown";
#ifdef __x86_64__
arch = "AMD64";
#elif defined(__aarch64__)
arch = "ARM64";
#elif defined(__arm__)
arch = "ARM32";
#endif
DEBUG("Reborn Target Architecture: %s", arch);
}
2022-03-10 04:29:37 +00:00
// Pre-Bootstrap
void pre_bootstrap(int argc, char *argv[]) {
2022-09-22 21:43:21 +00:00
// Set Debug Tag
reborn_debug_tag = "(Launcher) ";
2022-10-02 04:47:11 +00:00
// Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0);
2022-07-20 06:58:14 +00:00
// Print Version
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
// Print
2022-06-10 01:31:40 +00:00
printf("Reborn v%s\n", MCPI_VERSION);
fflush(stdout);
exit(EXIT_SUCCESS);
}
}
2022-10-02 04:47:11 +00:00
// Setup Logging
setup_log_file();
2022-03-15 01:51:38 +00:00
2022-10-02 04:47:11 +00:00
// --debug
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--debug") == 0) {
set_and_print_env("MCPI_DEBUG", "1");
break;
}
}
2022-10-02 04:47:11 +00:00
// Set Default Native Component Environment
#define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name));
for_each_special_environmental_variable(set_variable_default);
// GTK Dark Mode
#ifndef MCPI_SERVER_MODE
set_and_print_env("GTK_THEME", "Adwaita:dark");
2022-03-09 23:47:31 +00:00
#endif
2022-03-12 01:02:38 +00:00
// Configure PATH
{
2024-01-24 02:57:57 +00:00
// Get Binary Directory
char *binary_directory = get_binary_directory();
2022-03-12 01:02:38 +00:00
// Add Library Directory
2022-08-01 22:41:08 +00:00
char *new_path = NULL;
2022-03-12 01:02:38 +00:00
safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH
{
2022-07-20 06:58:14 +00:00
char *value = getenv("PATH");
if (value != NULL && strlen(value) > 0) {
2022-03-12 01:02:38 +00:00
string_append(&new_path, ":%s", value);
}
}
// Set And Free
set_and_print_env("PATH", new_path);
free(new_path);
2024-01-24 02:57:57 +00:00
// Free Binary Directory
free(binary_directory);
2022-03-12 01:02:38 +00:00
}
2024-01-24 02:57:57 +00:00
// --copy-sdk
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--copy-sdk") == 0) {
char *binary_directory = get_binary_directory();
copy_sdk(binary_directory, 0);
free(binary_directory);
fflush(stdout);
exit(EXIT_SUCCESS);
}
}
2022-05-14 02:36:12 +00:00
// Setup Crash Reports
setup_crash_report();
2022-10-02 04:47:11 +00:00
// AppImage
#ifdef MCPI_IS_APPIMAGE_BUILD
{
char *owd = getenv("OWD");
if (owd != NULL && chdir(owd) != 0) {
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
}
}
#endif
2022-05-14 02:36:12 +00:00
// Install Signal Handlers
struct sigaction act_sigint;
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
act_sigint.sa_flags = SA_RESTART;
act_sigint.sa_handler = &exit_handler;
sigaction(SIGINT, &act_sigint, NULL);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
2023-11-24 08:07:06 +00:00
// Check Page Size (Not Needed When Using QEMU)
2024-02-04 02:07:53 +00:00
#ifndef MCPI_USE_QEMU
2023-11-24 08:07:06 +00:00
long page_size = sysconf(_SC_PAGESIZE);
if (page_size != REQUIRED_PAGE_SIZE) {
2023-11-24 08:43:15 +00:00
ERR("Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes.", (long) REQUIRED_PAGE_SIZE, page_size);
2023-11-24 08:07:06 +00:00
}
#endif
// Debug Information
print_debug_information();
2022-03-10 04:29:37 +00:00
}
// Bootstrap
void bootstrap(int argc, char *argv[]) {
2022-04-15 01:12:42 +00:00
INFO("Configuring Game...");
2022-03-09 23:47:31 +00:00
2021-06-17 21:32:24 +00:00
// Get Binary Directory
char *binary_directory = get_binary_directory();
2023-11-24 22:57:39 +00:00
DEBUG("Binary Directory: %s", binary_directory);
2021-06-17 21:32:24 +00:00
2022-06-25 21:30:08 +00:00
// Copy SDK
2024-01-24 02:57:57 +00:00
copy_sdk(binary_directory, 1);
2022-06-25 21:30:08 +00:00
2022-05-30 02:54:57 +00:00
// Set MCPI_REBORN_ASSETS_PATH
{
char *assets_path = realpath("/proc/self/exe", NULL);
ALLOC_CHECK(assets_path);
chop_last_component(&assets_path);
string_append(&assets_path, "/data");
set_and_print_env("MCPI_REBORN_ASSETS_PATH", assets_path);
free(assets_path);
}
2022-03-25 02:47:34 +00:00
// Resolve Binary Path & Set MCPI_DIRECTORY
2022-05-30 02:54:57 +00:00
char *resolved_path = NULL;
2022-03-25 02:47:34 +00:00
{
// Log
2022-04-15 01:12:42 +00:00
DEBUG("Resolving File Paths...");
2022-03-25 02:47:34 +00:00
// Resolve Full Binary Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
2022-05-30 02:54:57 +00:00
resolved_path = realpath(full_path, NULL);
2022-03-25 02:47:34 +00:00
ALLOC_CHECK(resolved_path);
free(full_path);
}
// Fix MCPI Dependencies
2022-06-04 02:25:22 +00:00
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
2022-03-25 02:47:34 +00:00
{
// Log
2022-04-15 01:12:42 +00:00
DEBUG("Patching ELF Dependencies...");
2022-03-25 02:47:34 +00:00
// Find Linker
char *linker = NULL;
2022-05-03 02:44:10 +00:00
// Select Linker
2022-07-07 22:54:11 +00:00
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
2022-05-03 02:44:10 +00:00
// Use ARM Sysroot Linker
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
#else
// Use Current Linker
2022-09-25 19:47:36 +00:00
linker = patch_get_interpreter();
2022-03-25 02:47:34 +00:00
#endif
// Patch
2022-06-04 02:25:22 +00:00
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
2022-03-25 02:47:34 +00:00
// Free Linker Path
2022-04-15 01:12:42 +00:00
if (linker != NULL) {
free(linker);
}
2022-03-25 02:47:34 +00:00
// Verify
2022-06-04 02:25:22 +00:00
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
2022-03-25 02:47:34 +00:00
IMPOSSIBLE();
}
}
2022-05-30 02:54:57 +00:00
// Set MCPI_VANILLA_ASSETS_PATH
{
char *assets_path = strdup(resolved_path);
ALLOC_CHECK(assets_path);
chop_last_component(&assets_path);
string_append(&assets_path, "/data");
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path);
free(assets_path);
}
// Free Resolved Path
free(resolved_path);
2022-07-02 22:14:23 +00:00
// Configure Library Search Path
2021-06-17 21:32:24 +00:00
{
2022-03-25 02:47:34 +00:00
// Log
2022-04-15 01:12:42 +00:00
DEBUG("Setting Linker Search Paths...");
2022-03-25 02:47:34 +00:00
2022-07-02 22:14:23 +00:00
// Prepare
2022-07-20 06:58:14 +00:00
char *transitive_ld_path = NULL;
char *mcpi_ld_path = NULL;
2022-03-09 23:47:31 +00:00
2022-07-20 06:58:14 +00:00
// Library Search Path For Native Components
2021-06-17 21:32:24 +00:00
{
2022-07-20 06:58:14 +00:00
// Add Native Library Directory
safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&transitive_ld_path, ":%s", value);
}
2021-06-17 21:32:24 +00:00
}
2022-03-09 23:47:31 +00:00
2022-07-20 06:58:14 +00:00
// Set
set_and_print_env("MCPI_NATIVE_LD_LIBRARY_PATH", transitive_ld_path);
free(transitive_ld_path);
}
2022-07-02 22:14:23 +00:00
2022-07-20 06:58:14 +00:00
// Library Search Path For ARM Components
{
// Add ARM Library Directory
safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory);
2022-07-02 22:14:23 +00:00
2022-07-20 06:58:14 +00:00
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
2022-07-07 22:54:11 +00:00
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
2022-07-20 06:58:14 +00:00
string_append(&mcpi_ld_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory);
2022-07-02 22:14:23 +00:00
#endif
2022-07-20 06:58:14 +00:00
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
2022-08-01 22:41:08 +00:00
string_append(&mcpi_ld_path, ":%s", value);
2022-07-20 06:58:14 +00:00
}
}
// Set
set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path);
free(mcpi_ld_path);
}
2021-06-17 21:32:24 +00:00
}
2022-07-20 06:58:14 +00:00
// Configure Preloaded Objects
2021-06-17 21:32:24 +00:00
{
2022-03-25 02:47:34 +00:00
// Log
2022-04-15 01:12:42 +00:00
DEBUG("Locating Mods...");
2022-03-25 02:47:34 +00:00
2022-07-20 06:58:14 +00:00
// Native Components
char *host_ld_preload = getenv("LD_PRELOAD");
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
2022-07-20 06:58:14 +00:00
// ARM Components
2024-01-24 02:57:57 +00:00
bootstrap_mods(binary_directory);
2021-06-17 21:32:24 +00:00
}
// Free Binary Directory
free(binary_directory);
2022-03-09 23:47:31 +00:00
// Start Game
2022-04-15 01:12:42 +00:00
INFO("Starting Game...");
2022-03-09 23:47:31 +00:00
// Arguments
2022-03-25 02:47:34 +00:00
int argv_start = 1; // argv = &new_args[argv_start]
2022-07-20 06:58:14 +00:00
const char *new_args[argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
2022-03-09 23:47:31 +00:00
// Copy Existing Arguments
for (int i = 1; i < argc; i++) {
2022-07-20 06:58:14 +00:00
new_args[i + argv_start] = argv[i];
2022-03-09 23:47:31 +00:00
}
// NULL-Terminator
2022-07-20 06:58:14 +00:00
new_args[argv_start + argc] = NULL;
2022-03-09 23:47:31 +00:00
// Set Executable Argument
2022-07-20 06:58:14 +00:00
new_args[argv_start] = new_mcpi_exe_path;
2022-03-09 23:47:31 +00:00
// Non-ARM Systems Need QEMU
2024-02-04 02:07:53 +00:00
#ifdef MCPI_USE_QEMU
2022-03-09 23:47:31 +00:00
argv_start--;
new_args[argv_start] = QEMU_BINARY;
2023-11-24 08:07:06 +00:00
// Use 4k Page Size
set_and_print_env("QEMU_PAGESIZE", STR(REQUIRED_PAGE_SIZE));
2022-03-09 23:47:31 +00:00
#endif
2022-07-20 06:58:14 +00:00
// Setup Environment
setup_exec_environment(1);
// Pass LD_* Variables Through QEMU
2024-02-04 02:07:53 +00:00
#ifdef MCPI_USE_QEMU
2022-07-20 06:58:14 +00:00
char *qemu_set_env = NULL;
#define pass_variable_through_qemu(name) string_append(&qemu_set_env, "%s%s=%s", qemu_set_env == NULL ? "" : ",", name, getenv(name));
for_each_special_environmental_variable(pass_variable_through_qemu);
set_and_print_env("QEMU_SET_ENV", qemu_set_env);
free(qemu_set_env);
// Treat QEMU Itself As A Native Component
setup_exec_environment(0);
#endif
2022-03-09 23:47:31 +00:00
// Run
2022-03-14 23:09:25 +00:00
const char **new_argv = &new_args[argv_start];
safe_execvpe(new_argv, (const char *const *) environ);
2021-06-17 21:32:24 +00:00
}